1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the test suite of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
21 | ** included in the packaging of this file. Please review the following |
22 | ** information to ensure the GNU General Public License requirements will |
23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
24 | ** |
25 | ** $QT_END_LICENSE$ |
26 | ** |
27 | ****************************************************************************/ |
28 | |
29 | #include <QtTest/QtTest> |
30 | #include <private/qfontengine_p.h> |
31 | #include <private/qtextengine_p.h> |
32 | #include <qtextlayout.h> |
33 | #include <qfontdatabase.h> |
34 | #include <qfontinfo.h> |
35 | |
36 | class tst_QTextScriptEngine : public QObject |
37 | { |
38 | Q_OBJECT |
39 | |
40 | public: |
41 | tst_QTextScriptEngine(); |
42 | |
43 | private slots: |
44 | void initTestCase(); |
45 | void devanagari_data(); |
46 | void devanagari(); |
47 | void bengali_data(); |
48 | void bengali(); |
49 | void gurmukhi_data(); |
50 | void gurmukhi(); |
51 | // gujarati missing |
52 | void oriya_data(); |
53 | void oriya(); |
54 | void tamil_data(); |
55 | void tamil(); |
56 | void telugu_data(); |
57 | void telugu(); |
58 | void kannada_data(); |
59 | void kannada(); |
60 | void malayalam_data(); |
61 | void malayalam(); |
62 | void sinhala_data(); |
63 | void sinhala(); |
64 | void khmer_data(); |
65 | void khmer(); |
66 | void linearB_data(); |
67 | void linearB(); |
68 | void greek_data(); |
69 | void greek(); |
70 | |
71 | void mirroredChars_data(); |
72 | void mirroredChars(); |
73 | |
74 | void controlInSyllable_qtbug14204(); |
75 | void combiningMarks_qtbug15675_data(); |
76 | void combiningMarks_qtbug15675(); |
77 | |
78 | void thaiIsolatedSaraAm(); |
79 | void thaiWithZWJ(); |
80 | void thaiMultipleVowels(); |
81 | |
82 | void shapingDisabledDevanagari(); |
83 | void shapingDisabledLatin(); |
84 | private: |
85 | bool haveTestFonts; |
86 | }; |
87 | |
88 | tst_QTextScriptEngine::tst_QTextScriptEngine() |
89 | : haveTestFonts(qgetenv(varName: "QT_HAVE_TEST_FONTS" ) == QByteArray("1" )) |
90 | { |
91 | } |
92 | |
93 | void tst_QTextScriptEngine::initTestCase() |
94 | { |
95 | if (!haveTestFonts) { |
96 | qWarning( |
97 | msg: "Some of these tests depend on the internals of some test fonts which are not freely " |
98 | "distributable.\n" |
99 | "These tests will be skipped.\n" |
100 | "If you have the fonts available, set QT_HAVE_TEST_FONTS=1 in your environment and " |
101 | "run the test again." |
102 | ); |
103 | } |
104 | } |
105 | |
106 | struct ShapeTable { |
107 | unsigned short unicode[16]; |
108 | unsigned short glyphs[16]; |
109 | }; |
110 | |
111 | static void prepareShapingTest(const QFont &font, const ShapeTable *shape_table) |
112 | { |
113 | for (const ShapeTable *s = shape_table; s->unicode[0]; ++s) { |
114 | QByteArray testName = font.family().toLatin1() + ':'; |
115 | QString string; |
116 | for (const ushort *u = s->unicode; *u; ++u) { |
117 | string.append(c: QChar(*u)); |
118 | testName.append(a: " 0x" + QByteArray::number(*u, base: 16)); |
119 | } |
120 | QVector<ushort> glyphs; |
121 | for (const ushort *g = s->glyphs; *g; ++g) |
122 | glyphs.append(t: *g); |
123 | |
124 | QTest::newRow(dataTag: testName.constData()) << font << string << glyphs; |
125 | } |
126 | } |
127 | |
128 | static void doShapingTests() |
129 | { |
130 | QFETCH(QFont, font); |
131 | QFETCH(QString, string); |
132 | QFETCH(QVector<ushort>, glyphs); |
133 | |
134 | QVERIFY(!string.isEmpty()); |
135 | |
136 | QTextLayout layout(string, font); |
137 | QTextEngine *e = layout.engine(); |
138 | e->itemize(); |
139 | e->shape(item: 0); |
140 | |
141 | QVERIFY(!e->layoutData->items.isEmpty()); |
142 | if (e->fontEngine(si: e->layoutData->items[0])->type() == QFontEngine::Box) |
143 | QSKIP("OpenType support missing for script" ); |
144 | |
145 | QCOMPARE(e->fontEngine(e->layoutData->items[0])->fontDef.family, font.family()); |
146 | |
147 | ushort nglyphs = glyphs.size(); |
148 | if (!glyphs.isEmpty()) { |
149 | QCOMPARE(e->layoutData->items[0].num_glyphs, nglyphs); |
150 | for (ushort i = 0; i < glyphs.size(); ++i) { |
151 | ushort glyph = (e->layoutData->glyphLayout.glyphs[i] & 0xffffff); |
152 | QCOMPARE(glyph, glyphs.at(i)); |
153 | } |
154 | } else { |
155 | // decomposed shaping |
156 | if (string.at(i: 0) == QChar(0x1fc1) || string.at(i: 0) == QChar(0x1fed)) |
157 | return; |
158 | if (string.normalized(mode: QString::NormalizationForm_D).normalized(mode: QString::NormalizationForm_C) != string) |
159 | return; |
160 | |
161 | QTextLayout decomposedLayout(string.normalized(mode: QString::NormalizationForm_D), font); |
162 | QTextEngine *de = decomposedLayout.engine(); |
163 | de->itemize(); |
164 | de->shape(item: 0); |
165 | |
166 | QCOMPARE(de->layoutData->items[0].num_glyphs, e->layoutData->items[0].num_glyphs); |
167 | for (ushort i = 0; i < nglyphs; ++i) { |
168 | ushort glyph = (e->layoutData->glyphLayout.glyphs[i] & 0xffffff); |
169 | ushort glyph2 = (de->layoutData->glyphLayout.glyphs[i] & 0xffffff); |
170 | QCOMPARE(glyph2, glyph); |
171 | } |
172 | } |
173 | } |
174 | |
175 | void tst_QTextScriptEngine::devanagari_data() |
176 | { |
177 | QTest::addColumn<QFont>(name: "font" ); |
178 | QTest::addColumn<QString>(name: "string" ); |
179 | QTest::addColumn<QVector<ushort> >(name: "glyphs" ); |
180 | |
181 | if (!haveTestFonts) |
182 | QSKIP("Test fonts are not available" ); |
183 | |
184 | { |
185 | if (QFontDatabase().families(writingSystem: QFontDatabase::Devanagari).contains(str: "Raghindi" )) { |
186 | QFont f("Raghindi" ); |
187 | const ShapeTable shape_table [] = { |
188 | // Ka |
189 | { .unicode: { 0x0915, 0x0 }, |
190 | .glyphs: { 0x0080, 0x0 } }, |
191 | // Ka Halant |
192 | { .unicode: { 0x0915, 0x094d, 0x0 }, |
193 | .glyphs: { 0x0080, 0x0051, 0x0 } }, |
194 | // Ka Halant Ka |
195 | { .unicode: { 0x0915, 0x094d, 0x0915, 0x0 }, |
196 | .glyphs: { 0x00c8, 0x0080, 0x0 } }, |
197 | // Ka MatraI |
198 | { .unicode: { 0x0915, 0x093f, 0x0 }, |
199 | .glyphs: { 0x01d1, 0x0080, 0x0 } }, |
200 | // Ra Halant Ka |
201 | { .unicode: { 0x0930, 0x094d, 0x0915, 0x0 }, |
202 | .glyphs: { 0x0080, 0x005b, 0x0 } }, |
203 | // Ra Halant Ka MatraI |
204 | { .unicode: { 0x0930, 0x094d, 0x0915, 0x093f, 0x0 }, |
205 | .glyphs: { 0x01d1, 0x0080, 0x005b, 0x0 } }, |
206 | // MatraI |
207 | { .unicode: { 0x093f, 0x0 }, |
208 | .glyphs: { 0x01d4, 0x029c, 0x0 } }, |
209 | // Ka Nukta |
210 | { .unicode: { 0x0915, 0x093c, 0x0 }, |
211 | .glyphs: { 0x00a4, 0x0 } }, |
212 | // Ka Halant Ra |
213 | { .unicode: { 0x0915, 0x094d, 0x0930, 0x0 }, |
214 | .glyphs: { 0x0110, 0x0 } }, |
215 | // Ka Halant Ra Halant Ka |
216 | { .unicode: { 0x0915, 0x094d, 0x0930, 0x094d, 0x0915, 0x0 }, |
217 | .glyphs: { 0x0158, 0x0080, 0x0 } }, |
218 | { .unicode: { 0x0930, 0x094d, 0x200d, 0x0 }, |
219 | .glyphs: { 0x00e2, 0x0 } }, |
220 | { .unicode: { 0x0915, 0x094d, 0x0930, 0x094d, 0x200d, 0x0 }, |
221 | .glyphs: { 0x0158, 0x0 } }, |
222 | |
223 | { .unicode: {0}, .glyphs: {0} } |
224 | }; |
225 | prepareShapingTest(font: f, shape_table); |
226 | } else |
227 | QSKIP("couldn't find Raghindi" ); |
228 | } |
229 | |
230 | { |
231 | if (QFontDatabase().families(writingSystem: QFontDatabase::Devanagari).contains(str: "Mangal" )) { |
232 | QFont f("Mangal" ); |
233 | const ShapeTable shape_table [] = { |
234 | // Ka |
235 | { .unicode: { 0x0915, 0x0 }, |
236 | .glyphs: { 0x0080, 0x0 } }, |
237 | // Ka Halant |
238 | { .unicode: { 0x0915, 0x094d, 0x0 }, |
239 | .glyphs: { 0x0080, 0x0051, 0x0 } }, |
240 | // Ka Halant Ka |
241 | { .unicode: { 0x0915, 0x094d, 0x0915, 0x0 }, |
242 | .glyphs: { 0x00c8, 0x0080, 0x0 } }, |
243 | // Ka MatraI |
244 | { .unicode: { 0x0915, 0x093f, 0x0 }, |
245 | .glyphs: { 0x01d1, 0x0080, 0x0 } }, |
246 | // Ra Halant Ka |
247 | { .unicode: { 0x0930, 0x094d, 0x0915, 0x0 }, |
248 | .glyphs: { 0x0080, 0x005b, 0x0 } }, |
249 | // Ra Halant Ka MatraI |
250 | { .unicode: { 0x0930, 0x094d, 0x0915, 0x093f, 0x0 }, |
251 | .glyphs: { 0x01d1, 0x0080, 0x005b, 0x0 } }, |
252 | // MatraI |
253 | { .unicode: { 0x093f, 0x0 }, |
254 | .glyphs: { 0x01d4, 0x029c, 0x0 } }, |
255 | // Ka Nukta |
256 | { .unicode: { 0x0915, 0x093c, 0x0 }, |
257 | .glyphs: { 0x00a4, 0x0 } }, |
258 | // Ka Halant Ra |
259 | { .unicode: { 0x0915, 0x094d, 0x0930, 0x0 }, |
260 | .glyphs: { 0x0110, 0x0 } }, |
261 | // Ka Halant Ra Halant Ka |
262 | { .unicode: { 0x0915, 0x094d, 0x0930, 0x094d, 0x0915, 0x0 }, |
263 | .glyphs: { 0x0158, 0x0080, 0x0 } }, |
264 | |
265 | { .unicode: { 0x92b, 0x94d, 0x930, 0x0 }, |
266 | .glyphs: { 0x125, 0x0 } }, |
267 | { .unicode: { 0x92b, 0x93c, 0x94d, 0x930, 0x0 }, |
268 | .glyphs: { 0x149, 0x0 } }, |
269 | { .unicode: {0}, .glyphs: {0} } |
270 | }; |
271 | prepareShapingTest(font: f, shape_table); |
272 | } else |
273 | QSKIP("couldn't find mangal" ); |
274 | } |
275 | } |
276 | |
277 | void tst_QTextScriptEngine::devanagari() |
278 | { |
279 | doShapingTests(); |
280 | } |
281 | |
282 | void tst_QTextScriptEngine::bengali_data() |
283 | { |
284 | QTest::addColumn<QFont>(name: "font" ); |
285 | QTest::addColumn<QString>(name: "string" ); |
286 | QTest::addColumn<QVector<ushort> >(name: "glyphs" ); |
287 | |
288 | if (!haveTestFonts) |
289 | QSKIP("Test fonts are not available" ); |
290 | |
291 | { |
292 | if (QFontDatabase().families(writingSystem: QFontDatabase::Bengali).contains(str: "Akaash" )) { |
293 | QFont f("Akaash" ); |
294 | const ShapeTable shape_table [] = { |
295 | // Ka |
296 | { .unicode: { 0x0995, 0x0 }, |
297 | .glyphs: { 0x0151, 0x0 } }, |
298 | // Ka Halant |
299 | { .unicode: { 0x0995, 0x09cd, 0x0 }, |
300 | .glyphs: { 0x0151, 0x017d, 0x0 } }, |
301 | // Ka Halant Ka |
302 | { .unicode: { 0x0995, 0x09cd, 0x0995, 0x0 }, |
303 | .glyphs: { 0x019b, 0x0 } }, |
304 | // Ka MatraI |
305 | { .unicode: { 0x0995, 0x09bf, 0x0 }, |
306 | .glyphs: { 0x0173, 0x0151, 0x0 } }, |
307 | // Ra Halant Ka |
308 | { .unicode: { 0x09b0, 0x09cd, 0x0995, 0x0 }, |
309 | .glyphs: { 0x0151, 0x0276, 0x0 } }, |
310 | // Ra Halant Ka MatraI |
311 | { .unicode: { 0x09b0, 0x09cd, 0x0995, 0x09bf, 0x0 }, |
312 | .glyphs: { 0x0173, 0x0151, 0x0276, 0x0 } }, |
313 | // Ka Nukta |
314 | { .unicode: { 0x0995, 0x09bc, 0x0 }, |
315 | .glyphs: { 0x0151, 0x0171, 0x0 } }, |
316 | // Ka Halant Ra |
317 | { .unicode: { 0x0995, 0x09cd, 0x09b0, 0x0 }, |
318 | .glyphs: { 0x01f4, 0x0 } }, |
319 | // Ka Halant Ra Halant Ka |
320 | { .unicode: { 0x0995, 0x09cd, 0x09b0, 0x09cd, 0x0995, 0x0 }, |
321 | .glyphs: { 0x025c, 0x0276, 0x0151, 0x0 } }, |
322 | // Ya + Halant |
323 | { .unicode: { 0x09af, 0x09cd, 0x0 }, |
324 | .glyphs: { 0x016a, 0x017d, 0x0 } }, |
325 | // Da Halant Ya -> Da Ya-Phala |
326 | { .unicode: { 0x09a6, 0x09cd, 0x09af, 0x0 }, |
327 | .glyphs: { 0x01e5, 0x0 } }, |
328 | // A Halant Ya -> A Ya-phala |
329 | { .unicode: { 0x0985, 0x09cd, 0x09af, 0x0 }, |
330 | .glyphs: { 0x0145, 0x01cf, 0x0 } }, |
331 | // Na Halant Ka |
332 | { .unicode: { 0x09a8, 0x09cd, 0x0995, 0x0 }, |
333 | .glyphs: { 0x026f, 0x0151, 0x0 } }, |
334 | // Na Halant ZWNJ Ka |
335 | { .unicode: { 0x09a8, 0x09cd, 0x200c, 0x0995, 0x0 }, |
336 | .glyphs: { 0x0164, 0x017d, 0x0151, 0x0 } }, |
337 | // Na Halant ZWJ Ka |
338 | { .unicode: { 0x09a8, 0x09cd, 0x200d, 0x0995, 0x0 }, |
339 | .glyphs: { 0x026f, 0x0151, 0x0 } }, |
340 | // Ka Halant ZWNJ Ka |
341 | { .unicode: { 0x0995, 0x09cd, 0x200c, 0x0995, 0x0 }, |
342 | .glyphs: { 0x0151, 0x017d, 0x0151, 0x0 } }, |
343 | // Ka Halant ZWJ Ka |
344 | { .unicode: { 0x0995, 0x09cd, 0x200d, 0x0995, 0x0 }, |
345 | .glyphs: { 0x025c, 0x0151, 0x0 } }, |
346 | // Na Halant Ra |
347 | { .unicode: { 0x09a8, 0x09cd, 0x09b0, 0x0 }, |
348 | .glyphs: { 0x0207, 0x0 } }, |
349 | // Na Halant ZWNJ Ra |
350 | { .unicode: { 0x09a8, 0x09cd, 0x200c, 0x09b0, 0x0 }, |
351 | .glyphs: { 0x0164, 0x017d, 0x016b, 0x0 } }, |
352 | // Na Halant ZWJ Ra |
353 | { .unicode: { 0x09a8, 0x09cd, 0x200d, 0x09b0, 0x0 }, |
354 | .glyphs: { 0x026f, 0x016b, 0x0 } }, |
355 | // Na Halant Ba |
356 | { .unicode: { 0x09a8, 0x09cd, 0x09ac, 0x0 }, |
357 | .glyphs: { 0x022f, 0x0 } }, |
358 | // Na Halant ZWNJ Ba |
359 | { .unicode: { 0x09a8, 0x09cd, 0x200c, 0x09ac, 0x0 }, |
360 | .glyphs: { 0x0164, 0x017d, 0x0167, 0x0 } }, |
361 | // Na Halant ZWJ Ba |
362 | { .unicode: { 0x09a8, 0x09cd, 0x200d, 0x09ac, 0x0 }, |
363 | .glyphs: { 0x026f, 0x0167, 0x0 } }, |
364 | // Na Halant Dha |
365 | { .unicode: { 0x09a8, 0x09cd, 0x09a7, 0x0 }, |
366 | .glyphs: { 0x01d3, 0x0 } }, |
367 | // Na Halant ZWNJ Dha |
368 | { .unicode: { 0x09a8, 0x09cd, 0x200c, 0x09a7, 0x0 }, |
369 | .glyphs: { 0x0164, 0x017d, 0x0163, 0x0 } }, |
370 | // Na Halant ZWJ Dha |
371 | { .unicode: { 0x09a8, 0x09cd, 0x200d, 0x09a7, 0x0 }, |
372 | .glyphs: { 0x026f, 0x0163, 0x0 } }, |
373 | // Ra Halant Ka MatraAU |
374 | { .unicode: { 0x09b0, 0x09cd, 0x0995, 0x09cc, 0x0 }, |
375 | .glyphs: { 0x0179, 0x0151, 0x0276, 0x017e, 0x0 } }, |
376 | // Ra Halant Ba Halant Ba |
377 | { .unicode: { 0x09b0, 0x09cd, 0x09ac, 0x09cd, 0x09ac, 0x0 }, |
378 | .glyphs: { 0x0232, 0x0276, 0x0 } }, |
379 | { .unicode: { 0x9b0, 0x9cd, 0x995, 0x9be, 0x982, 0x0 }, |
380 | .glyphs: { 0x151, 0x276, 0x172, 0x143, 0x0 } }, |
381 | { .unicode: { 0x9b0, 0x9cd, 0x995, 0x9be, 0x983, 0x0 }, |
382 | .glyphs: { 0x151, 0x276, 0x172, 0x144, 0x0 } }, |
383 | // test decomposed two parts matras |
384 | { .unicode: { 0x995, 0x9c7, 0x9be, 0x0 }, |
385 | .glyphs: { 0x179, 0x151, 0x172, 0x0 } }, |
386 | { .unicode: { 0x995, 0x9c7, 0x9d7, 0x0 }, |
387 | .glyphs: { 0x179, 0x151, 0x17e, 0x0 } }, |
388 | { .unicode: {0}, .glyphs: {0} } |
389 | }; |
390 | prepareShapingTest(font: f, shape_table); |
391 | } else |
392 | QSKIP("couldn't find Akaash" ); |
393 | } |
394 | { |
395 | if (QFontDatabase().families(writingSystem: QFontDatabase::Bengali).contains(str: "Mukti Narrow" )) { |
396 | QFont f("Mukti Narrow" ); |
397 | const ShapeTable shape_table [] = { |
398 | // Ka |
399 | { .unicode: { 0x0995, 0x0 }, |
400 | .glyphs: { 0x0073, 0x0 } }, |
401 | // Ka Halant |
402 | { .unicode: { 0x0995, 0x09cd, 0x0 }, |
403 | .glyphs: { 0x00b9, 0x0 } }, |
404 | // Ka Halant Ka |
405 | { .unicode: { 0x0995, 0x09cd, 0x0995, 0x0 }, |
406 | .glyphs: { 0x0109, 0x0 } }, |
407 | // Ka MatraI |
408 | { .unicode: { 0x0995, 0x09bf, 0x0 }, |
409 | .glyphs: { 0x0095, 0x0073, 0x0 } }, |
410 | // Ra Halant Ka |
411 | { .unicode: { 0x09b0, 0x09cd, 0x0995, 0x0 }, |
412 | .glyphs: { 0x0073, 0x00e1, 0x0 } }, |
413 | // Ra Halant Ka MatraI |
414 | { .unicode: { 0x09b0, 0x09cd, 0x0995, 0x09bf, 0x0 }, |
415 | .glyphs: { 0x0095, 0x0073, 0x00e1, 0x0 } }, |
416 | // MatraI |
417 | { .unicode: { 0x09bf, 0x0 }, |
418 | .glyphs: { 0x0095, 0x01c8, 0x0 } }, |
419 | // Ka Nukta |
420 | { .unicode: { 0x0995, 0x09bc, 0x0 }, |
421 | .glyphs: { 0x0073, 0x0093, 0x0 } }, |
422 | // Ka Halant Ra |
423 | { .unicode: { 0x0995, 0x09cd, 0x09b0, 0x0 }, |
424 | .glyphs: { 0x00e5, 0x0 } }, |
425 | // Ka Halant Ra Halant Ka |
426 | { .unicode: { 0x995, 0x9cd, 0x9b0, 0x9cd, 0x995, 0x0 }, |
427 | .glyphs: { 0x234, 0x24e, 0x73, 0x0 } }, |
428 | // Ya + Halant |
429 | { .unicode: { 0x09af, 0x09cd, 0x0 }, |
430 | .glyphs: { 0x00d2, 0x0 } }, |
431 | // Da Halant Ya -> Da Ya-Phala |
432 | { .unicode: { 0x09a6, 0x09cd, 0x09af, 0x0 }, |
433 | .glyphs: { 0x0084, 0x00e2, 0x0 } }, |
434 | // A Halant Ya -> A Ya-phala |
435 | { .unicode: { 0x0985, 0x09cd, 0x09af, 0x0 }, |
436 | .glyphs: { 0x0067, 0x00e2, 0x0 } }, |
437 | // Na Halant Ka |
438 | { .unicode: { 0x09a8, 0x09cd, 0x0995, 0x0 }, |
439 | .glyphs: { 0x0188, 0x0 } }, |
440 | // Na Halant ZWNJ Ka |
441 | { .unicode: { 0x9a8, 0x9cd, 0x200c, 0x995, 0x0 }, |
442 | .glyphs: { 0xcc, 0x73, 0x0 } }, |
443 | // Na Halant ZWJ Ka |
444 | { .unicode: { 0x9a8, 0x9cd, 0x200d, 0x995, 0x0 }, |
445 | .glyphs: { 0x247, 0x73, 0x0 } }, |
446 | // Ka Halant ZWNJ Ka |
447 | { .unicode: { 0x9a8, 0x9cd, 0x200d, 0x995, 0x0 }, |
448 | .glyphs: { 0x247, 0x73, 0x0 } }, |
449 | // Ka Halant ZWJ Ka |
450 | { .unicode: { 0x9a8, 0x9cd, 0x200d, 0x995, 0x0 }, |
451 | .glyphs: { 0x247, 0x73, 0x0 } }, |
452 | // Na Halant Ra |
453 | { .unicode: { 0x09a8, 0x09cd, 0x09b0, 0x0 }, |
454 | .glyphs: { 0x00f8, 0x0 } }, |
455 | // Na Halant ZWNJ Ra |
456 | { .unicode: { 0x09a8, 0x09cd, 0x200c, 0x09b0, 0x0 }, |
457 | .glyphs: { 0xcc, 0x8d, 0x0 } }, |
458 | // Na Halant ZWJ Ra |
459 | { .unicode: { 0x9a8, 0x9cd, 0x200d, 0x9b0, 0x0 }, |
460 | .glyphs: { 0x247, 0x8d, 0x0 } }, |
461 | // Na Halant Ba |
462 | { .unicode: { 0x09a8, 0x09cd, 0x09ac, 0x0 }, |
463 | .glyphs: { 0x0139, 0x0 } }, |
464 | // Na Halant ZWNJ Ba |
465 | { .unicode: { 0x9a8, 0x9cd, 0x200c, 0x9ac, 0x0 }, |
466 | .glyphs: { 0xcc, 0x89, 0x0 } }, |
467 | // Na Halant ZWJ Ba |
468 | { .unicode: { 0x9a8, 0x9cd, 0x200d, 0x9ac, 0x0 }, |
469 | .glyphs: { 0x247, 0x89, 0x0 } }, |
470 | // Na Halant Dha |
471 | { .unicode: { 0x09a8, 0x09cd, 0x09a7, 0x0 }, |
472 | .glyphs: { 0x0145, 0x0 } }, |
473 | // Na Halant ZWNJ Dha |
474 | { .unicode: { 0x09a8, 0x09cd, 0x200c, 0x09a7, 0x0 }, |
475 | .glyphs: { 0xcc, 0x85, 0x0 } }, |
476 | // Na Halant ZWJ Dha |
477 | { .unicode: { 0x09a8, 0x09cd, 0x200d, 0x09a7, 0x0 }, |
478 | .glyphs: { 0x247, 0x85, 0x0 } }, |
479 | // Ra Halant Ka MatraAU |
480 | { .unicode: { 0x9b0, 0x9cd, 0x995, 0x9cc, 0x0 }, |
481 | .glyphs: { 0x232, 0x73, 0xe1, 0xa0, 0x0 } }, |
482 | // Ra Halant Ba Halant Ba |
483 | { .unicode: { 0x09b0, 0x09cd, 0x09ac, 0x09cd, 0x09ac, 0x0 }, |
484 | .glyphs: { 0x013b, 0x00e1, 0x0 } }, |
485 | |
486 | { .unicode: {0}, .glyphs: {0} } |
487 | }; |
488 | prepareShapingTest(font: f, shape_table); |
489 | } else |
490 | QSKIP("couldn't find Mukti" ); |
491 | } |
492 | { |
493 | if (QFontDatabase().families(writingSystem: QFontDatabase::Bengali).contains(str: "Likhan" )) { |
494 | QFont f("Likhan" ); |
495 | const ShapeTable shape_table [] = { |
496 | { .unicode: { 0x9a8, 0x9cd, 0x9af, 0x0 }, |
497 | .glyphs: { 0x1ca, 0x0 } }, |
498 | { .unicode: { 0x09b8, 0x09cd, 0x09af, 0x0 }, |
499 | .glyphs: { 0x020e, 0x0 } }, |
500 | { .unicode: { 0x09b6, 0x09cd, 0x09af, 0x0 }, |
501 | .glyphs: { 0x01f4, 0x0 } }, |
502 | { .unicode: { 0x09b7, 0x09cd, 0x09af, 0x0 }, |
503 | .glyphs: { 0x01fe, 0x0 } }, |
504 | { .unicode: { 0x09b0, 0x09cd, 0x09a8, 0x09cd, 0x200d, 0x0 }, |
505 | .glyphs: { 0x10b, 0x167, 0x0 } }, |
506 | |
507 | { .unicode: {0}, .glyphs: {0} } |
508 | }; |
509 | prepareShapingTest(font: f, shape_table); |
510 | } else |
511 | QSKIP("couldn't find Likhan" ); |
512 | } |
513 | } |
514 | |
515 | void tst_QTextScriptEngine::bengali() |
516 | { |
517 | doShapingTests(); |
518 | } |
519 | |
520 | void tst_QTextScriptEngine::gurmukhi_data() |
521 | { |
522 | QTest::addColumn<QFont>(name: "font" ); |
523 | QTest::addColumn<QString>(name: "string" ); |
524 | QTest::addColumn<QVector<ushort> >(name: "glyphs" ); |
525 | |
526 | if (!haveTestFonts) |
527 | QSKIP("Test fonts are not available" ); |
528 | |
529 | { |
530 | if (QFontDatabase().families(writingSystem: QFontDatabase::Gurmukhi).contains(str: "Lohit Punjabi" )) { |
531 | QFont f("Lohit Punjabi" ); |
532 | const ShapeTable shape_table [] = { |
533 | { .unicode: { 0xA15, 0xA4D, 0xa39, 0x0 }, |
534 | .glyphs: { 0x3b, 0x8b, 0x0 } }, |
535 | { .unicode: {0}, .glyphs: {0} } |
536 | }; |
537 | prepareShapingTest(font: f, shape_table); |
538 | } else |
539 | QSKIP("couldn't find Lohit Punjabi" ); |
540 | } |
541 | } |
542 | |
543 | void tst_QTextScriptEngine::gurmukhi() |
544 | { |
545 | doShapingTests(); |
546 | } |
547 | |
548 | void tst_QTextScriptEngine::oriya_data() |
549 | { |
550 | QTest::addColumn<QFont>(name: "font" ); |
551 | QTest::addColumn<QString>(name: "string" ); |
552 | QTest::addColumn<QVector<ushort> >(name: "glyphs" ); |
553 | |
554 | if (!haveTestFonts) |
555 | QSKIP("Test fonts are not available" ); |
556 | |
557 | { |
558 | if (QFontDatabase().families(writingSystem: QFontDatabase::Oriya).contains(str: "utkal" )) { |
559 | QFont f("utkal" ); |
560 | const ShapeTable shape_table [] = { |
561 | { .unicode: { 0xb15, 0xb4d, 0xb24, 0xb4d, 0xb30, 0x0 }, |
562 | .glyphs: { 0x150, 0x125, 0x0 } }, |
563 | { .unicode: { 0xb24, 0xb4d, 0xb24, 0xb4d, 0xb2c, 0x0 }, |
564 | .glyphs: { 0x151, 0x120, 0x0 } }, |
565 | { .unicode: { 0xb28, 0xb4d, 0xb24, 0xb4d, 0xb2c, 0x0 }, |
566 | .glyphs: { 0x152, 0x120, 0x0 } }, |
567 | { .unicode: { 0xb28, 0xb4d, 0xb24, 0xb4d, 0xb2c, 0x0 }, |
568 | .glyphs: { 0x152, 0x120, 0x0 } }, |
569 | { .unicode: { 0xb28, 0xb4d, 0xb24, 0xb4d, 0xb30, 0x0 }, |
570 | .glyphs: { 0x176, 0x0 } }, |
571 | { .unicode: { 0xb38, 0xb4d, 0xb24, 0xb4d, 0xb30, 0x0 }, |
572 | .glyphs: { 0x177, 0x0 } }, |
573 | { .unicode: { 0xb28, 0xb4d, 0xb24, 0xb4d, 0xb30, 0xb4d, 0xb2f, 0x0 }, |
574 | .glyphs: { 0x176, 0x124, 0x0 } }, |
575 | { .unicode: {0}, .glyphs: {0} } |
576 | |
577 | }; |
578 | prepareShapingTest(font: f, shape_table); |
579 | } else |
580 | QSKIP("couldn't find utkal" ); |
581 | } |
582 | } |
583 | |
584 | void tst_QTextScriptEngine::oriya() |
585 | { |
586 | doShapingTests(); |
587 | } |
588 | |
589 | void tst_QTextScriptEngine::tamil_data() |
590 | { |
591 | QTest::addColumn<QFont>(name: "font" ); |
592 | QTest::addColumn<QString>(name: "string" ); |
593 | QTest::addColumn<QVector<ushort> >(name: "glyphs" ); |
594 | |
595 | if (!haveTestFonts) |
596 | QSKIP("Test fonts are not available" ); |
597 | |
598 | { |
599 | if (QFontDatabase().families(writingSystem: QFontDatabase::Tamil).contains(str: "AkrutiTml1" )) { |
600 | QFont f("AkrutiTml1" ); |
601 | const ShapeTable shape_table [] = { |
602 | { .unicode: { 0x0b95, 0x0bc2, 0x0 }, |
603 | .glyphs: { 0x004e, 0x0 } }, |
604 | { .unicode: { 0x0bae, 0x0bc2, 0x0 }, |
605 | .glyphs: { 0x009e, 0x0 } }, |
606 | { .unicode: { 0x0b9a, 0x0bc2, 0x0 }, |
607 | .glyphs: { 0x0058, 0x0 } }, |
608 | { .unicode: { 0x0b99, 0x0bc2, 0x0 }, |
609 | .glyphs: { 0x0053, 0x0 } }, |
610 | { .unicode: { 0x0bb0, 0x0bc2, 0x0 }, |
611 | .glyphs: { 0x00a8, 0x0 } }, |
612 | { .unicode: { 0x0ba4, 0x0bc2, 0x0 }, |
613 | .glyphs: { 0x008e, 0x0 } }, |
614 | { .unicode: { 0x0b9f, 0x0bc2, 0x0 }, |
615 | .glyphs: { 0x0062, 0x0 } }, |
616 | { .unicode: { 0x0b95, 0x0bc6, 0x0 }, |
617 | .glyphs: { 0x000a, 0x0031, 0x0 } }, |
618 | { .unicode: { 0x0b95, 0x0bca, 0x0 }, |
619 | .glyphs: { 0x000a, 0x0031, 0x0007, 0x0 } }, |
620 | { .unicode: { 0x0b95, 0x0bc6, 0x0bbe, 0x0 }, |
621 | .glyphs: { 0x000a, 0x0031, 0x007, 0x0 } }, |
622 | { .unicode: { 0x0b95, 0x0bcd, 0x0bb7, 0x0 }, |
623 | .glyphs: { 0x0049, 0x0 } }, |
624 | { .unicode: { 0x0b95, 0x0bcd, 0x0bb7, 0x0bca, 0x0 }, |
625 | .glyphs: { 0x000a, 0x0049, 0x007, 0x0 } }, |
626 | { .unicode: { 0x0b95, 0x0bcd, 0x0bb7, 0x0bc6, 0x0bbe, 0x0 }, |
627 | .glyphs: { 0x000a, 0x0049, 0x007, 0x0 } }, |
628 | { .unicode: { 0x0b9f, 0x0bbf, 0x0 }, |
629 | .glyphs: { 0x005f, 0x0 } }, |
630 | { .unicode: { 0x0b9f, 0x0bc0, 0x0 }, |
631 | .glyphs: { 0x0060, 0x0 } }, |
632 | { .unicode: { 0x0bb2, 0x0bc0, 0x0 }, |
633 | .glyphs: { 0x00ab, 0x0 } }, |
634 | { .unicode: { 0x0bb2, 0x0bbf, 0x0 }, |
635 | .glyphs: { 0x00aa, 0x0 } }, |
636 | { .unicode: { 0x0bb0, 0x0bcd, 0x0 }, |
637 | .glyphs: { 0x00a4, 0x0 } }, |
638 | { .unicode: { 0x0bb0, 0x0bbf, 0x0 }, |
639 | .glyphs: { 0x00a5, 0x0 } }, |
640 | { .unicode: { 0x0bb0, 0x0bc0, 0x0 }, |
641 | .glyphs: { 0x00a6, 0x0 } }, |
642 | { .unicode: { 0x0b83, 0x0 }, |
643 | .glyphs: { 0x0025, 0x0 } }, |
644 | { .unicode: { 0x0b83, 0x0b95, 0x0 }, |
645 | .glyphs: { 0x0025, 0x0031, 0x0 } }, |
646 | { .unicode: { 0xb95, 0xbc6, 0xbbe, 0x0 }, |
647 | .glyphs: { 0xa, 0x31, 0x7, 0x0 } }, |
648 | { .unicode: { 0xb95, 0xbc7, 0xbbe, 0x0 }, |
649 | .glyphs: { 0xb, 0x31, 0x7, 0x0 } }, |
650 | { .unicode: { 0xb95, 0xbc6, 0xbd7, 0x0 }, |
651 | .glyphs: { 0xa, 0x31, 0x40, 0x0 } }, |
652 | |
653 | { .unicode: {0}, .glyphs: {0} } |
654 | }; |
655 | prepareShapingTest(font: f, shape_table); |
656 | } else |
657 | QSKIP("couldn't find AkrutiTml1" ); |
658 | } |
659 | } |
660 | |
661 | void tst_QTextScriptEngine::tamil() |
662 | { |
663 | doShapingTests(); |
664 | } |
665 | |
666 | void tst_QTextScriptEngine::telugu_data() |
667 | { |
668 | QTest::addColumn<QFont>(name: "font" ); |
669 | QTest::addColumn<QString>(name: "string" ); |
670 | QTest::addColumn<QVector<ushort> >(name: "glyphs" ); |
671 | |
672 | if (!haveTestFonts) |
673 | QSKIP("Test fonts are not available" ); |
674 | |
675 | { |
676 | if (QFontDatabase().families(writingSystem: QFontDatabase::Telugu).contains(str: "Pothana2000" )) { |
677 | QFont f("Pothana2000" ); |
678 | const ShapeTable shape_table [] = { |
679 | { .unicode: { 0xc15, 0xc4d, 0x0 }, |
680 | .glyphs: { 0xbb, 0x0 } }, |
681 | { .unicode: { 0xc15, 0xc4d, 0xc37, 0x0 }, |
682 | .glyphs: { 0x4b, 0x0 } }, |
683 | { .unicode: { 0xc15, 0xc4d, 0xc37, 0xc4d, 0x0 }, |
684 | .glyphs: { 0xe0, 0x0 } }, |
685 | { .unicode: { 0xc15, 0xc4d, 0xc37, 0xc4d, 0xc23, 0x0 }, |
686 | .glyphs: { 0x4b, 0x91, 0x0 } }, |
687 | { .unicode: { 0xc15, 0xc4d, 0xc30, 0x0 }, |
688 | .glyphs: { 0x5a, 0xb2, 0x0 } }, |
689 | { .unicode: { 0xc15, 0xc4d, 0xc30, 0xc4d, 0x0 }, |
690 | .glyphs: { 0xbb, 0xb2, 0x0 } }, |
691 | { .unicode: { 0xc15, 0xc4d, 0xc30, 0xc4d, 0xc15, 0x0 }, |
692 | .glyphs: { 0x5a, 0xb2, 0x83, 0x0 } }, |
693 | { .unicode: { 0xc15, 0xc4d, 0xc30, 0xc3f, 0x0 }, |
694 | .glyphs: { 0xe2, 0xb2, 0x0 } }, |
695 | { .unicode: { 0xc15, 0xc4d, 0xc15, 0xc48, 0x0 }, |
696 | .glyphs: { 0xe6, 0xb3, 0x83, 0x0 } }, |
697 | { .unicode: { 0xc15, 0xc4d, 0xc30, 0xc48, 0x0 }, |
698 | .glyphs: { 0xe6, 0xb3, 0x9f, 0x0 } }, |
699 | { .unicode: { 0xc15, 0xc46, 0xc56, 0x0 }, |
700 | .glyphs: { 0xe6, 0xb3, 0x0 } }, |
701 | { .unicode: {0}, .glyphs: {0} } |
702 | |
703 | }; |
704 | prepareShapingTest(font: f, shape_table); |
705 | } else |
706 | QSKIP("couldn't find Pothana2000" ); |
707 | } |
708 | } |
709 | |
710 | void tst_QTextScriptEngine::telugu() |
711 | { |
712 | doShapingTests(); |
713 | } |
714 | |
715 | void tst_QTextScriptEngine::kannada_data() |
716 | { |
717 | QTest::addColumn<QFont>(name: "font" ); |
718 | QTest::addColumn<QString>(name: "string" ); |
719 | QTest::addColumn<QVector<ushort> >(name: "glyphs" ); |
720 | |
721 | if (!haveTestFonts) |
722 | QSKIP("Test fonts are not available" ); |
723 | |
724 | { |
725 | if (QFontDatabase().families(writingSystem: QFontDatabase::Kannada).contains(str: "Sampige" )) { |
726 | QFont f("Sampige" ); |
727 | const ShapeTable shape_table [] = { |
728 | { .unicode: { 0x0ca8, 0x0ccd, 0x0ca8, 0x0 }, |
729 | .glyphs: { 0x0049, 0x00ba, 0x0 } }, |
730 | { .unicode: { 0x0ca8, 0x0ccd, 0x0ca1, 0x0 }, |
731 | .glyphs: { 0x0049, 0x00b3, 0x0 } }, |
732 | { .unicode: { 0x0caf, 0x0cc2, 0x0 }, |
733 | .glyphs: { 0x004f, 0x005d, 0x0 } }, |
734 | { .unicode: { 0x0ce0, 0x0 }, |
735 | .glyphs: { 0x006a, 0x0 } }, |
736 | { .unicode: { 0x0ce6, 0x0ce7, 0x0ce8, 0x0 }, |
737 | .glyphs: { 0x006b, 0x006c, 0x006d, 0x0 } }, |
738 | { .unicode: { 0x0cb5, 0x0ccb, 0x0 }, |
739 | .glyphs: { 0x015f, 0x0067, 0x0 } }, |
740 | { .unicode: { 0x0cb0, 0x0ccd, 0x0cae, 0x0 }, |
741 | .glyphs: { 0x004e, 0x0082, 0x0 } }, |
742 | { .unicode: { 0x0cb0, 0x0ccd, 0x0c95, 0x0 }, |
743 | .glyphs: { 0x0036, 0x0082, 0x0 } }, |
744 | { .unicode: { 0x0c95, 0x0ccd, 0x0cb0, 0x0 }, |
745 | .glyphs: { 0x0036, 0x00c1, 0x0 } }, |
746 | { .unicode: { 0x0cb0, 0x0ccd, 0x200d, 0x0c95, 0x0 }, |
747 | .glyphs: { 0x0050, 0x00a7, 0x0 } }, |
748 | |
749 | { .unicode: {0}, .glyphs: {0} } |
750 | }; |
751 | prepareShapingTest(font: f, shape_table); |
752 | } else |
753 | QSKIP("couldn't find Sampige" ); |
754 | } |
755 | { |
756 | if (QFontDatabase().families(writingSystem: QFontDatabase::Kannada).contains(str: "Tunga" )) { |
757 | QFont f("Tunga" ); |
758 | const ShapeTable shape_table [] = { |
759 | { .unicode: { 0x0cb7, 0x0cc6, 0x0 }, |
760 | .glyphs: { 0x00b0, 0x006c, 0x0 } }, |
761 | { .unicode: { 0x0cb7, 0x0ccd, 0x0 }, |
762 | .glyphs: { 0x0163, 0x0 } }, |
763 | { .unicode: { 0xc95, 0xcbf, 0xcd5, 0x0 }, |
764 | .glyphs: { 0x114, 0x73, 0x0 } }, |
765 | { .unicode: { 0xc95, 0xcc6, 0xcd5, 0x0 }, |
766 | .glyphs: { 0x90, 0x6c, 0x73, 0x0 } }, |
767 | { .unicode: { 0xc95, 0xcc6, 0xcd6, 0x0 }, |
768 | .glyphs: { 0x90, 0x6c, 0x74, 0x0 } }, |
769 | { .unicode: { 0xc95, 0xcc6, 0xcc2, 0x0 }, |
770 | .glyphs: { 0x90, 0x6c, 0x69, 0x0 } }, |
771 | { .unicode: { 0xc95, 0xcca, 0xcd5, 0x0 }, |
772 | .glyphs: { 0x90, 0x6c, 0x69, 0x73, 0x0 } }, |
773 | { .unicode: {0}, .glyphs: {0} } |
774 | }; |
775 | prepareShapingTest(font: f, shape_table); |
776 | } else |
777 | QSKIP("couldn't find Tunga" ); |
778 | } |
779 | } |
780 | |
781 | void tst_QTextScriptEngine::kannada() |
782 | { |
783 | doShapingTests(); |
784 | } |
785 | |
786 | void tst_QTextScriptEngine::malayalam_data() |
787 | { |
788 | QTest::addColumn<QFont>(name: "font" ); |
789 | QTest::addColumn<QString>(name: "string" ); |
790 | QTest::addColumn<QVector<ushort> >(name: "glyphs" ); |
791 | |
792 | if (!haveTestFonts) |
793 | QSKIP("Test fonts are not available" ); |
794 | |
795 | { |
796 | if (QFontDatabase().families(writingSystem: QFontDatabase::Malayalam).contains(str: "AkrutiMal2" )) { |
797 | QFont f("AkrutiMal2" ); |
798 | const ShapeTable shape_table [] = { |
799 | { .unicode: { 0x0d15, 0x0d46, 0x0 }, |
800 | .glyphs: { 0x005e, 0x0034, 0x0 } }, |
801 | { .unicode: { 0x0d15, 0x0d47, 0x0 }, |
802 | .glyphs: { 0x005f, 0x0034, 0x0 } }, |
803 | { .unicode: { 0x0d15, 0x0d4b, 0x0 }, |
804 | .glyphs: { 0x005f, 0x0034, 0x0058, 0x0 } }, |
805 | { .unicode: { 0x0d15, 0x0d48, 0x0 }, |
806 | .glyphs: { 0x0060, 0x0034, 0x0 } }, |
807 | { .unicode: { 0x0d15, 0x0d4a, 0x0 }, |
808 | .glyphs: { 0x005e, 0x0034, 0x0058, 0x0 } }, |
809 | { .unicode: { 0x0d30, 0x0d4d, 0x0d15, 0x0 }, |
810 | .glyphs: { 0x009e, 0x0034, 0x0 } }, |
811 | { .unicode: { 0x0d15, 0x0d4d, 0x0d35, 0x0 }, |
812 | .glyphs: { 0x0034, 0x007a, 0x0 } }, |
813 | { .unicode: { 0x0d15, 0x0d4d, 0x0d2f, 0x0 }, |
814 | .glyphs: { 0x0034, 0x00a2, 0x0 } }, |
815 | { .unicode: { 0x0d1f, 0x0d4d, 0x0d1f, 0x0 }, |
816 | .glyphs: { 0x0069, 0x0 } }, |
817 | { .unicode: { 0x0d26, 0x0d4d, 0x0d26, 0x0 }, |
818 | .glyphs: { 0x0074, 0x0 } }, |
819 | { .unicode: { 0x0d30, 0x0d4d, 0x0 }, |
820 | .glyphs: { 0x009e, 0x0 } }, |
821 | { .unicode: { 0x0d30, 0x0d4d, 0x200c, 0x0 }, |
822 | .glyphs: { 0x009e, 0x0 } }, |
823 | { .unicode: { 0x0d30, 0x0d4d, 0x200d, 0x0 }, |
824 | .glyphs: { 0x009e, 0x0 } }, |
825 | { .unicode: { 0xd15, 0xd46, 0xd3e, 0x0 }, |
826 | .glyphs: { 0x5e, 0x34, 0x58, 0x0 } }, |
827 | { .unicode: { 0xd15, 0xd47, 0xd3e, 0x0 }, |
828 | .glyphs: { 0x5f, 0x34, 0x58, 0x0 } }, |
829 | { .unicode: { 0xd15, 0xd46, 0xd57, 0x0 }, |
830 | .glyphs: { 0x5e, 0x34, 0x65, 0x0 } }, |
831 | { .unicode: { 0xd15, 0xd57, 0x0 }, |
832 | .glyphs: { 0x34, 0x65, 0x0 } }, |
833 | { .unicode: {0}, .glyphs: {0} } |
834 | }; |
835 | prepareShapingTest(font: f, shape_table); |
836 | } else |
837 | QSKIP("couldn't find AkrutiMal2" ); |
838 | } |
839 | { |
840 | if (QFontDatabase().families(writingSystem: QFontDatabase::Malayalam).contains(str: "Rachana" )) { |
841 | QFont f("Rachana" ); |
842 | const ShapeTable shape_table [] = { |
843 | { .unicode: { 0xd37, 0xd4d, 0xd1f, 0xd4d, 0xd30, 0xd40, 0x0 }, |
844 | .glyphs: { 0x385, 0xa3, 0x0 } }, |
845 | { .unicode: { 0xd2f, 0xd4d, 0xd15, 0xd4d, 0xd15, 0xd41, 0x0 }, |
846 | .glyphs: { 0x2ff, 0x0 } }, |
847 | { .unicode: { 0xd33, 0xd4d, 0xd33, 0x0 }, |
848 | .glyphs: { 0x3f8, 0x0 } }, |
849 | { .unicode: { 0xd2f, 0xd4d, 0xd15, 0xd4d, 0xd15, 0xd41, 0x0 }, |
850 | .glyphs: { 0x2ff, 0x0 } }, |
851 | { .unicode: { 0xd30, 0xd4d, 0x200d, 0xd35, 0xd4d, 0xd35, 0x0 }, |
852 | .glyphs: { 0xf3, 0x350, 0x0 } }, |
853 | |
854 | { .unicode: {0}, .glyphs: {0} } |
855 | }; |
856 | prepareShapingTest(font: f, shape_table); |
857 | } else |
858 | QSKIP("couldn't find Rachana" ); |
859 | } |
860 | } |
861 | |
862 | void tst_QTextScriptEngine::malayalam() |
863 | { |
864 | doShapingTests(); |
865 | } |
866 | |
867 | void tst_QTextScriptEngine::sinhala_data() |
868 | { |
869 | QTest::addColumn<QFont>(name: "font" ); |
870 | QTest::addColumn<QString>(name: "string" ); |
871 | QTest::addColumn<QVector<ushort> >(name: "glyphs" ); |
872 | |
873 | if (!haveTestFonts) |
874 | QSKIP("Test fonts are not available" ); |
875 | |
876 | { |
877 | if (QFontDatabase().families(writingSystem: QFontDatabase::Sinhala).contains(str: "Malithi Web" )) { |
878 | QFont f("Malithi Web" ); |
879 | const ShapeTable shape_table [] = { |
880 | { .unicode: { 0xd9a, 0xdd9, 0xdcf, 0x0 }, |
881 | .glyphs: { 0x4a, 0x61, 0x42, 0x0 } }, |
882 | { .unicode: { 0xd9a, 0xdd9, 0xddf, 0x0 }, |
883 | .glyphs: { 0x4a, 0x61, 0x50, 0x0 } }, |
884 | { .unicode: { 0xd9a, 0xdd9, 0xdca, 0x0 }, |
885 | .glyphs: { 0x4a, 0x62, 0x0 } }, |
886 | { .unicode: { 0xd9a, 0xddc, 0xdca, 0x0 }, |
887 | .glyphs: { 0x4a, 0x61, 0x42, 0x41, 0x0 } }, |
888 | { .unicode: { 0xd9a, 0xdda, 0x0 }, |
889 | .glyphs: { 0x4a, 0x62, 0x0 } }, |
890 | { .unicode: { 0xd9a, 0xddd, 0x0 }, |
891 | .glyphs: { 0x4a, 0x61, 0x42, 0x41, 0x0 } }, |
892 | { .unicode: {0}, .glyphs: {0} } |
893 | }; |
894 | prepareShapingTest(font: f, shape_table); |
895 | } else |
896 | QSKIP("couldn't find Malithi Web" ); |
897 | } |
898 | } |
899 | |
900 | void tst_QTextScriptEngine::sinhala() |
901 | { |
902 | doShapingTests(); |
903 | } |
904 | |
905 | void tst_QTextScriptEngine::khmer_data() |
906 | { |
907 | QTest::addColumn<QFont>(name: "font" ); |
908 | QTest::addColumn<QString>(name: "string" ); |
909 | QTest::addColumn<QVector<ushort> >(name: "glyphs" ); |
910 | |
911 | if (!haveTestFonts) |
912 | QSKIP("Test fonts are not available" ); |
913 | |
914 | { |
915 | if (QFontDatabase().families(writingSystem: QFontDatabase::Khmer).contains(str: "Khmer OS" )) { |
916 | QFont f("Khmer OS" ); |
917 | const ShapeTable shape_table [] = { |
918 | { .unicode: { 0x179a, 0x17cd, 0x0 }, |
919 | .glyphs: { 0x24c, 0x27f, 0x0 } }, |
920 | { .unicode: { 0x179f, 0x17c5, 0x0 }, |
921 | .glyphs: { 0x273, 0x203, 0x0 } }, |
922 | { .unicode: { 0x1790, 0x17d2, 0x1784, 0x17c3, 0x0 }, |
923 | .glyphs: { 0x275, 0x242, 0x182, 0x0 } }, |
924 | { .unicode: { 0x179a, 0x0 }, |
925 | .glyphs: { 0x24c, 0x0 } }, |
926 | { .unicode: { 0x1781, 0x17d2, 0x1798, 0x17c2, 0x0 }, |
927 | .glyphs: { 0x274, 0x233, 0x197, 0x0 } }, |
928 | { .unicode: { 0x1798, 0x17b6, 0x0 }, |
929 | .glyphs: { 0x1cb, 0x0 } }, |
930 | { .unicode: { 0x179a, 0x17b8, 0x0 }, |
931 | .glyphs: { 0x24c, 0x26a, 0x0 } }, |
932 | { .unicode: { 0x1787, 0x17b6, 0x0 }, |
933 | .glyphs: { 0x1ba, 0x0 } }, |
934 | { .unicode: { 0x1798, 0x17d2, 0x1796, 0x17bb, 0x0 }, |
935 | .glyphs: { 0x24a, 0x195, 0x26d, 0x0 } }, |
936 | { .unicode: {0}, .glyphs: {0} } |
937 | }; |
938 | prepareShapingTest(font: f, shape_table); |
939 | } else |
940 | QSKIP("couldn't find Khmer OS" ); |
941 | } |
942 | } |
943 | |
944 | void tst_QTextScriptEngine::khmer() |
945 | { |
946 | doShapingTests(); |
947 | } |
948 | |
949 | void tst_QTextScriptEngine::linearB_data() |
950 | { |
951 | QTest::addColumn<QFont>(name: "font" ); |
952 | QTest::addColumn<QString>(name: "string" ); |
953 | QTest::addColumn<QVector<ushort> >(name: "glyphs" ); |
954 | |
955 | if (!haveTestFonts) |
956 | QSKIP("Test fonts are not available" ); |
957 | |
958 | { |
959 | if (QFontDatabase().families(writingSystem: QFontDatabase::Any).contains(str: "Penuturesu" )) { |
960 | QFont f("Penuturesu" ); |
961 | const ShapeTable shape_table [] = { |
962 | { .unicode: { 0xd800, 0xdc01, 0xd800, 0xdc02, 0xd800, 0xdc03, 0 }, |
963 | .glyphs: { 0x5, 0x6, 0x7, 0 } }, |
964 | { .unicode: {0}, .glyphs: {0} } |
965 | }; |
966 | prepareShapingTest(font: f, shape_table); |
967 | } else |
968 | QSKIP("couldn't find Penuturesu" ); |
969 | } |
970 | } |
971 | |
972 | void tst_QTextScriptEngine::linearB() |
973 | { |
974 | doShapingTests(); |
975 | } |
976 | |
977 | void tst_QTextScriptEngine::greek_data() |
978 | { |
979 | QTest::addColumn<QFont>(name: "font" ); |
980 | QTest::addColumn<QString>(name: "string" ); |
981 | QTest::addColumn<QVector<ushort> >(name: "glyphs" ); |
982 | |
983 | if (!haveTestFonts) |
984 | QSKIP("Test fonts are not available" ); |
985 | |
986 | { |
987 | if (QFontDatabase().families(writingSystem: QFontDatabase::Any).contains(str: "DejaVu Sans" )) { |
988 | QFont f("DejaVu Sans" ); |
989 | for (int uc = 0x1f00; uc <= 0x1fff; ++uc) { |
990 | QString string; |
991 | string.append(c: QChar(uc)); |
992 | QByteArray testName = f.family().toLatin1() + ": 0x" + QByteArray::number(uc, base: 16); |
993 | QTest::newRow(dataTag: testName.constData()) << f << string << QVector<ushort>(); |
994 | } |
995 | } else |
996 | QSKIP("couldn't find DejaVu Sans" ); |
997 | } |
998 | |
999 | { |
1000 | if (QFontDatabase().families(writingSystem: QFontDatabase::Any).contains(str: "SBL Greek" )) { |
1001 | QFont f("SBL Greek" ); |
1002 | for (int uc = 0x1f00; uc <= 0x1fff; ++uc) { |
1003 | QString string; |
1004 | string.append(c: QChar(uc)); |
1005 | QByteArray testName = f.family().toLatin1() + ": 0x" + QByteArray::number(uc, base: 16); |
1006 | QTest::newRow(dataTag: testName.constData()) << f << string << QVector<ushort>(); |
1007 | } |
1008 | |
1009 | const ShapeTable shape_table [] = { |
1010 | { .unicode: { 0x3b1, 0x300, 0x313, 0x0 }, |
1011 | .glyphs: { 0xb8, 0x3d3, 0x3c7, 0x0 } }, |
1012 | { .unicode: { 0x3b1, 0x313, 0x300, 0x0 }, |
1013 | .glyphs: { 0xd4, 0x0 } }, |
1014 | |
1015 | { .unicode: {0}, .glyphs: {0} } |
1016 | }; |
1017 | prepareShapingTest(font: f, shape_table); |
1018 | } else |
1019 | QSKIP("couldn't find SBL_grk" ); |
1020 | } |
1021 | } |
1022 | |
1023 | void tst_QTextScriptEngine::greek() |
1024 | { |
1025 | doShapingTests(); |
1026 | } |
1027 | |
1028 | void tst_QTextScriptEngine::mirroredChars_data() |
1029 | { |
1030 | QTest::addColumn<QString>(name: "s" ); |
1031 | |
1032 | QTest::newRow(dataTag: "()" ) << QStringLiteral("()" ); |
1033 | QTest::newRow(dataTag: "[]" ) << QStringLiteral("[]" ); |
1034 | QTest::newRow(dataTag: "{}" ) << QStringLiteral("{}" ); |
1035 | } |
1036 | |
1037 | void tst_QTextScriptEngine::mirroredChars() |
1038 | { |
1039 | QFETCH(QString, s); |
1040 | |
1041 | glyph_t leftParenthesis; |
1042 | glyph_t rightParenthesis; |
1043 | { |
1044 | QTextLayout layout(s); |
1045 | layout.setCacheEnabled(true); |
1046 | layout.beginLayout(); |
1047 | layout.createLine(); |
1048 | layout.endLayout(); |
1049 | |
1050 | QTextEngine *e = layout.engine(); |
1051 | e->itemize(); |
1052 | QCOMPARE(e->layoutData->items.size(), 1); |
1053 | |
1054 | e->shape(item: 0); |
1055 | QCOMPARE(e->layoutData->items[0].num_glyphs, ushort(2)); |
1056 | |
1057 | const QGlyphLayout glyphLayout = e->shapedGlyphs(si: &e->layoutData->items[0]); |
1058 | leftParenthesis = glyphLayout.glyphs[0]; |
1059 | rightParenthesis = glyphLayout.glyphs[1]; |
1060 | } |
1061 | |
1062 | { |
1063 | QTextLayout layout(s); |
1064 | layout.setFlags(Qt::TextForceRightToLeft); |
1065 | |
1066 | QTextEngine *e = layout.engine(); |
1067 | e->itemize(); |
1068 | QCOMPARE(e->layoutData->items.size(), 1); |
1069 | |
1070 | e->shape(item: 0); |
1071 | QCOMPARE(e->layoutData->items[0].num_glyphs, ushort(2)); |
1072 | |
1073 | const QGlyphLayout glyphLayout = e->shapedGlyphs(si: &e->layoutData->items[0]); |
1074 | QCOMPARE(glyphLayout.glyphs[0], rightParenthesis); |
1075 | QCOMPARE(glyphLayout.glyphs[1], leftParenthesis); |
1076 | } |
1077 | } |
1078 | |
1079 | void tst_QTextScriptEngine::controlInSyllable_qtbug14204() |
1080 | { |
1081 | QFontDatabase db; |
1082 | if (!db.families().contains(QStringLiteral("Aparajita" ))) |
1083 | QSKIP("couldn't find 'Aparajita' font" ); |
1084 | |
1085 | QFont font(QStringLiteral("Aparajita" )); |
1086 | font.setStyleStrategy(QFont::NoFontMerging); |
1087 | |
1088 | QString s; |
1089 | s.append(c: QChar(0x0915)); |
1090 | s.append(c: QChar(0x094d)); |
1091 | s.append(c: QChar(0x200d)); |
1092 | s.append(c: QChar(0x0915)); |
1093 | |
1094 | QTextLayout layout(s, font); |
1095 | QTextEngine *e = layout.engine(); |
1096 | e->itemize(); |
1097 | QCOMPARE(e->layoutData->items.size(), 1); |
1098 | |
1099 | QFontEngine *fe = e->fontEngine(si: e->layoutData->items[0]); |
1100 | if (fe->type() == QFontEngine::Box) |
1101 | QSKIP("OpenType support missing for script" ); |
1102 | QCOMPARE(fe->fontDef.family, font.family()); |
1103 | |
1104 | e->shape(item: 0); |
1105 | QCOMPARE(e->layoutData->items[0].num_glyphs, ushort(3)); |
1106 | |
1107 | const ushort *log_clusters = e->logClusters(si: &e->layoutData->items[0]); |
1108 | QCOMPARE(log_clusters[0], ushort(0)); |
1109 | QCOMPARE(log_clusters[1], ushort(0)); |
1110 | QCOMPARE(log_clusters[2], ushort(0)); |
1111 | QCOMPARE(log_clusters[3], ushort(2)); |
1112 | } |
1113 | |
1114 | void tst_QTextScriptEngine::combiningMarks_qtbug15675_data() |
1115 | { |
1116 | QTest::addColumn<QFont>(name: "font" ); |
1117 | QTest::addColumn<QString>(name: "string" ); |
1118 | |
1119 | QSKIP("Result differs for HarfBuzz-NG, skip test." ); |
1120 | |
1121 | bool hasTests = false; |
1122 | |
1123 | QStringList families; |
1124 | families << QStringLiteral("Monaco" ); |
1125 | families << QStringLiteral("DejaVu Sans Mono" ); |
1126 | |
1127 | foreach (const QString &family, families) { |
1128 | QFont font(family); |
1129 | font.setStyleStrategy(QFont::NoFontMerging); |
1130 | if (QFontInfo(font).family() != family) |
1131 | continue; |
1132 | |
1133 | hasTests = true; |
1134 | |
1135 | QString s(QStringLiteral("ab cd" )); |
1136 | for (ushort uc = 0x0300; uc < 0x0370; ++uc) { |
1137 | s[2] = QChar(uc); |
1138 | QByteArray testName = family.toLatin1() + ": ab<U+" + QByteArray::number(uc, base: 16).rightJustified(width: 4, fill: '0') + ">cd" ; |
1139 | QTest::newRow(dataTag: testName.constData()) << font << s; |
1140 | } |
1141 | } |
1142 | |
1143 | if (!hasTests) |
1144 | QSKIP("Couldn't find required fonts, skip test." ); |
1145 | } |
1146 | |
1147 | void tst_QTextScriptEngine::combiningMarks_qtbug15675() |
1148 | { |
1149 | QFETCH(QFont, font); |
1150 | QFETCH(QString, string); |
1151 | |
1152 | QTextLayout layout(string, font); |
1153 | QTextEngine *e = layout.engine(); |
1154 | e->itemize(); |
1155 | QCOMPARE(e->layoutData->items.size(), 1); |
1156 | |
1157 | QFontEngine *fe = e->fontEngine(si: e->layoutData->items[0]); |
1158 | if (fe->type() == QFontEngine::Box) |
1159 | QSKIP("OpenType support missing for script" ); |
1160 | QCOMPARE(fe->fontDef.family, font.family()); |
1161 | |
1162 | e->shape(item: 0); |
1163 | const int diff = e->layoutData->items[0].num_glyphs - string.size(); |
1164 | QVERIFY(diff >= -1 && diff <= 1); // could compose or decompose exactly one character |
1165 | |
1166 | const ushort *log_clusters = e->logClusters(si: &e->layoutData->items[0]); |
1167 | QCOMPARE(log_clusters[0], ushort(0)); |
1168 | QCOMPARE(log_clusters[1], ushort(1)); |
1169 | QCOMPARE(log_clusters[2], ushort(1)); |
1170 | QCOMPARE(log_clusters[3], ushort(3 + diff)); |
1171 | QCOMPARE(log_clusters[4], ushort(4 + diff)); |
1172 | |
1173 | const QGlyphLayout glyphLayout = e->shapedGlyphs(si: &e->layoutData->items[0]); |
1174 | for (int i = 0; i < glyphLayout.numGlyphs; ++i) { |
1175 | if ((diff >= 0 && i == 2) || (diff > 0 && i == 2 + diff)) |
1176 | QCOMPARE(glyphLayout.advances[i].toInt(), 0); |
1177 | else |
1178 | QVERIFY(glyphLayout.advances[i].toInt() != 0); |
1179 | } |
1180 | } |
1181 | |
1182 | void tst_QTextScriptEngine::thaiIsolatedSaraAm() |
1183 | { |
1184 | QFontDatabase db; |
1185 | if (!db.families().contains(str: "Waree" )) |
1186 | QSKIP("couldn't find 'Waree' font" ); |
1187 | |
1188 | QFont font(QStringLiteral("Waree" )); |
1189 | font.setStyleStrategy(QFont::NoFontMerging); |
1190 | |
1191 | QString s; |
1192 | s.append(c: QChar(0x0e33)); |
1193 | |
1194 | QTextLayout layout(s, font); |
1195 | QTextEngine *e = layout.engine(); |
1196 | e->itemize(); |
1197 | QCOMPARE(e->layoutData->items.size(), 1); |
1198 | |
1199 | QFontEngine *fe = e->fontEngine(si: e->layoutData->items[0]); |
1200 | if (fe->type() == QFontEngine::Box) |
1201 | QSKIP("OpenType support missing for script" ); |
1202 | QCOMPARE(fe->fontDef.family, font.family()); |
1203 | |
1204 | e->shape(item: 0); |
1205 | QVERIFY(e->layoutData->items[0].num_glyphs > 0); |
1206 | |
1207 | const ushort *log_clusters = e->logClusters(si: &e->layoutData->items[0]); |
1208 | QCOMPARE(log_clusters[0], ushort(0)); |
1209 | } |
1210 | |
1211 | void tst_QTextScriptEngine::thaiWithZWJ() |
1212 | { |
1213 | QFontDatabase db; |
1214 | if (!db.families().contains(str: "Waree" )) |
1215 | QSKIP("couldn't find 'Waree' font" ); |
1216 | |
1217 | QFont font(QStringLiteral("Waree" )); |
1218 | font.setStyleStrategy(QFont::NoFontMerging); |
1219 | |
1220 | if (QFontInfo(font).styleName() != QStringLiteral("Book" )) |
1221 | QSKIP("couldn't find 'Waree Book' font" ); |
1222 | |
1223 | QString s(QString::fromUtf8(str: "\xe0\xb8\xa3\xe2\x80\x8d\xe0\xb8\xa3\xe2\x80" |
1224 | "\x8c\x2e\xe0\xb8\xa3\x2e\xe2\x80\x9c\xe0\xb8" |
1225 | "\xa3\xe2\x80\xa6\xe0\xb8\xa3\xe2\x80\x9d\xe0" |
1226 | "\xb8\xa3\xa0\xe0\xb8\xa3\xe6\x9c\xac\xe0\xb8\xa3" ) |
1227 | + QChar(0x0363)/*superscript 'a', for testing Inherited class*/); |
1228 | |
1229 | QTextLayout layout(s, font); |
1230 | QTextEngine *e = layout.engine(); |
1231 | e->itemize(); |
1232 | QCOMPARE(e->layoutData->items.size(), 3); |
1233 | |
1234 | for (int item = 0; item < e->layoutData->items.size(); ++item) |
1235 | e->shape(item); |
1236 | |
1237 | QCOMPARE(e->layoutData->items[0].num_glyphs, ushort(15)); // Thai, Inherited and Common |
1238 | QCOMPARE(e->layoutData->items[1].num_glyphs, ushort(1)); // Japanese: Kanji for tree |
1239 | QCOMPARE(e->layoutData->items[2].num_glyphs, ushort(2)); // Thai: Thai character followed by superscript "a" which is of inherited type |
1240 | |
1241 | //A quick sanity check - check all the characters are individual clusters |
1242 | // A thai implementation could either remove the ZWJ and ZWNJ characters, or hide them. |
1243 | // The current implementation hides them, so we test for that. |
1244 | unsigned short *logClusters = e->layoutData->logClustersPtr; |
1245 | QCOMPARE(logClusters[0], ushort(0)); |
1246 | QCOMPARE(logClusters[1], ushort(0)); |
1247 | QCOMPARE(logClusters[2], ushort(2)); |
1248 | QCOMPARE(logClusters[3], ushort(2)); |
1249 | for (int i = 4; i < 15; i++) |
1250 | QCOMPARE(logClusters[i], ushort(i)); |
1251 | for (int i = 0; i < 3; i++) |
1252 | QCOMPARE(logClusters[i+15], ushort(0)); |
1253 | |
1254 | // The only characters that we should be hiding are the ZWJ and ZWNJ characters in position 1 and 3. |
1255 | const QGlyphLayout glyphLayout = e->layoutData->glyphLayout; |
1256 | for (int i = 0; i < 18; i++) { |
1257 | if (i == 1 || i == 3) |
1258 | QCOMPARE(glyphLayout.advances[i].toInt(), 0); |
1259 | else |
1260 | QVERIFY(glyphLayout.advances[i].toInt() != 0); |
1261 | } |
1262 | } |
1263 | |
1264 | void tst_QTextScriptEngine::thaiMultipleVowels() |
1265 | { |
1266 | QString s(QString::fromUtf8(str: "\xe0\xb8\xaa" )); |
1267 | for (int i = 0; i < 100; i++) |
1268 | s += QChar(0x0E47); // Add lots of "VOWEL SIGN MAI TAI KHU N/S-T" stacked on top of the character |
1269 | s += QChar(0x200D); // Now add a zero width joiner (which adds a circle which is hidden) |
1270 | for (int i = 0; i < 100; i++) |
1271 | s += QChar(0x0E47); //Add lots of "VOWEL SIGN MAI TAI KHU N/S-T" stacked on top of the ZWJ |
1272 | |
1273 | for (int i = 0; i < 10; i++) |
1274 | s += s; //Repeat the string to make it more likely to crash if we have a buffer overflow |
1275 | |
1276 | QTextLayout layout(s); |
1277 | QTextEngine *e = layout.engine(); |
1278 | e->itemize(); |
1279 | |
1280 | for (int item = 0; item < e->layoutData->items.size(); ++item) |
1281 | e->shape(item); |
1282 | |
1283 | // If we haven't crashed at this point, then the test has passed. |
1284 | } |
1285 | |
1286 | void tst_QTextScriptEngine::shapingDisabledLatin() |
1287 | { |
1288 | QString s("fi" ); |
1289 | |
1290 | QFont font("Calibri" ); |
1291 | font.setStyleStrategy(QFont::PreferNoShaping); |
1292 | |
1293 | QTextLayout layout(s); |
1294 | layout.setFont(font); |
1295 | layout.beginLayout(); |
1296 | layout.createLine(); |
1297 | layout.endLayout(); |
1298 | |
1299 | QList<QGlyphRun> runs = layout.glyphRuns(); |
1300 | |
1301 | QCOMPARE(runs.size(), 1); |
1302 | QCOMPARE(runs.first().glyphIndexes().size(), 2); |
1303 | } |
1304 | |
1305 | void tst_QTextScriptEngine::shapingDisabledDevanagari() |
1306 | { |
1307 | QString s; |
1308 | s += QChar(0x0915); // KA |
1309 | s += QChar(0x094D); // VIRAMA |
1310 | s += QChar(0x0915); // KA |
1311 | |
1312 | |
1313 | QList<QGlyphRun> normalRuns; |
1314 | { |
1315 | QTextLayout layout(s); |
1316 | layout.beginLayout(); |
1317 | layout.createLine(); |
1318 | layout.endLayout(); |
1319 | |
1320 | normalRuns = layout.glyphRuns(); |
1321 | } |
1322 | |
1323 | QFont font; |
1324 | font.setStyleStrategy(QFont::PreferNoShaping); |
1325 | |
1326 | QList<QGlyphRun> noShapingRuns; |
1327 | { |
1328 | QTextLayout layout(s); |
1329 | layout.setFont(font); |
1330 | layout.beginLayout(); |
1331 | layout.createLine(); |
1332 | layout.endLayout(); |
1333 | |
1334 | noShapingRuns = layout.glyphRuns(); |
1335 | } |
1336 | |
1337 | // Even though shaping is disabled, Devanagari requires it, so the flag should be ignored. |
1338 | QCOMPARE(normalRuns.size(), 1); |
1339 | QCOMPARE(noShapingRuns.size(), 1); |
1340 | QCOMPARE(noShapingRuns.first().glyphIndexes().size(), normalRuns.first().glyphIndexes().size()); |
1341 | } |
1342 | |
1343 | QTEST_MAIN(tst_QTextScriptEngine) |
1344 | #include "tst_qtextscriptengine.moc" |
1345 | |