1 /*
2 *******************************************************************************
3 *
4 * Copyright (C) 1999-2014, International Business Machines
5 * Corporation and others. All Rights Reserved.
6 *
7 *******************************************************************************
8 */
9
10 #ifndef USING_ICULEHB /* C API not available under HB */
11
12 #include "unicode/utypes.h"
13 #include "unicode/ubidi.h"
14 #include "unicode/uscript.h"
15 #include "unicode/ctest.h"
16
17 #include "layout/LETypes.h"
18 #include "layout/LEScripts.h"
19 #include "layout/loengine.h"
20
21 #include "layout/playout.h"
22 #include "layout/plruns.h"
23
24 #include "cfonts.h"
25
26 #include "letest.h"
27
28 #include "sfnt.h"
29 #include "xmlreader.h"
30 #include "putilimp.h" /* for U_FILE_SEP_STRING */
31
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <string.h>
35
36 #define CH_COMMA 0x002C
37
38 U_CDECL_BEGIN
ParamTest(void)39 static void U_CALLCONV ParamTest(void)
40 {
41 LEErrorCode status = LE_NO_ERROR;
42 le_font *font = le_simpleFontOpen(12, &status);
43 le_engine *engine = le_create(font, arabScriptCode, -1, 0, &status);
44 LEGlyphID *glyphs = NULL;
45 le_int32 *indices = NULL;
46 float *positions = NULL;
47 le_int32 glyphCount = 0;
48
49 float x = 0.0, y = 0.0;
50 LEUnicode chars[] = {
51 0x0045, 0x006E, 0x0067, 0x006C, 0x0069, 0x0073, 0x0068, 0x0020, /* "English " */
52 0x0645, 0x0627, 0x0646, 0x062A, 0x0648, 0x0634, /* MEM ALIF KAF NOON TEH WAW SHEEN */
53 0x0020, 0x0074, 0x0065, 0x0078, 0x0074, 0x02E /* " text." */
54 };
55
56
57 glyphCount = le_getGlyphCount(engine, &status);
58 if (glyphCount != 0) {
59 log_err("Calling getGlyphCount() on an empty layout returned %d.\n", glyphCount);
60 }
61
62 glyphs = NEW_ARRAY(LEGlyphID, glyphCount + 10);
63 indices = NEW_ARRAY(le_int32, glyphCount + 10);
64 positions = NEW_ARRAY(float, glyphCount + 10);
65
66 le_getGlyphs(engine, NULL, &status);
67
68 if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
69 log_err("Calling getGlyphs(NULL, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n");
70 }
71
72 status = LE_NO_ERROR;
73 le_getGlyphs(engine, glyphs, &status);
74
75 if (status != LE_NO_LAYOUT_ERROR) {
76 log_err("Calling getGlyphs(glyphs, status) on an empty layout did not return LE_NO_LAYOUT_ERROR.\n");
77 }
78
79 status = LE_NO_ERROR;
80 le_getCharIndices(engine, NULL, &status);
81
82 if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
83 log_err("Calling getCharIndices(NULL, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n");
84 }
85
86 status = LE_NO_ERROR;
87 le_getCharIndices(engine, indices, &status);
88
89 if (status != LE_NO_LAYOUT_ERROR) {
90 log_err("Calling getCharIndices(indices, status) on an empty layout did not return LE_NO_LAYOUT_ERROR.\n");
91 }
92
93 status = LE_NO_ERROR;
94 le_getCharIndicesWithBase(engine, NULL, 1024, &status);
95
96 if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
97 log_err("Calling getCharIndices(NULL, 1024, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n");
98 }
99
100 status = LE_NO_ERROR;
101 le_getCharIndicesWithBase(engine, indices, 1024, &status);
102
103 if (status != LE_NO_LAYOUT_ERROR) {
104 log_err("Calling getCharIndices(indices, 1024, status) on an empty layout did not return LE_NO_LAYOUT_ERROR.\n");
105 }
106
107 status = LE_NO_ERROR;
108 le_getGlyphPositions(engine, NULL, &status);
109
110 if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
111 log_err("Calling getGlyphPositions(NULL, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n");
112 }
113
114 status = LE_NO_ERROR;
115 le_getGlyphPositions(engine, positions, &status);
116
117 if (status != LE_NO_LAYOUT_ERROR) {
118 log_err("Calling getGlyphPositions(positions, status) on an empty layout did not return LE_NO_LAYOUT_ERROR.\n");
119 }
120
121 DELETE_ARRAY(positions);
122 DELETE_ARRAY(indices);
123 DELETE_ARRAY(glyphs);
124
125 status = LE_NO_ERROR;
126 glyphCount = le_layoutChars(engine, NULL, 0, 0, 0, FALSE, 0.0, 0.0, &status);
127
128 if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
129 log_err("Calling layoutChars(NULL, 0, 0, 0, FALSE, 0.0, 0.0, status) did not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n");
130 }
131
132 status = LE_NO_ERROR;
133 glyphCount = le_layoutChars(engine, chars, -1, 6, 20, TRUE, 0.0, 0.0, &status);
134
135 if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
136 log_err("Calling layoutChars(chars, -1, 6, 20, TRUE, 0.0, 0.0, status) did not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n");
137 }
138
139 status = LE_NO_ERROR;
140 glyphCount = le_layoutChars(engine, chars, 8, -1, 20, TRUE, 0.0, 0.0, &status);
141
142 if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
143 log_err("Calling layoutChars(chars, 8, -1, 20, TRUE, 0.0, 0.0, status) did not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n");
144 }
145
146 status = LE_NO_ERROR;
147 glyphCount = le_layoutChars(engine, chars, 8, 6, -1, TRUE, 0.0, 0.0, &status);
148
149 if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
150 log_err("Calling layoutChars((chars, 8, 6, -1, TRUE, 0.0, 0.0, status) did not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n");
151 }
152
153 status = LE_NO_ERROR;
154 glyphCount = le_layoutChars(engine, chars, 8, 6, 10, TRUE, 0.0, 0.0, &status);
155
156 if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
157 log_err("Calling layoutChars(chars, 8, 6, 10, TRUE, 0.0, 0.0, status) did not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n");
158 }
159
160 status = LE_NO_ERROR;
161 glyphCount = le_layoutChars(engine, chars, 8, 6, 20, TRUE, 0.0, 0.0, &status);
162
163 if (LE_FAILURE(status)) {
164 log_err("Calling layoutChars(chars, 8, 6, 20, TRUE, 0.0, 0.0, status) failed.\n");
165 goto bail;
166 }
167
168 le_getGlyphPosition(engine, -1, &x, &y, &status);
169
170 if (status != LE_INDEX_OUT_OF_BOUNDS_ERROR) {
171 log_err("Calling getGlyphPosition(-1, x, y, status) did not fail w/ LE_INDEX_OUT_OF_BOUNDS_ERROR.\n");
172 }
173
174 status = LE_NO_ERROR;
175 le_getGlyphPosition(engine, glyphCount + 1, &x, &y, &status);
176
177 if (status != LE_INDEX_OUT_OF_BOUNDS_ERROR) {
178 log_err("Calling getGlyphPosition(glyphCount + 1, x, y, status) did not fail w/ LE_INDEX_OUT_OF_BOUNDS_ERROR.\n");
179 }
180
181 bail:
182 le_close(engine);
183 le_fontClose(font);
184 }
185 U_CDECL_END
186
187 U_CDECL_BEGIN
FactoryTest(void)188 static void U_CALLCONV FactoryTest(void)
189 {
190 LEErrorCode status = LE_NO_ERROR;
191 le_font *font = le_simpleFontOpen(12, &status);
192 le_engine *engine = NULL;
193 le_int32 scriptCode;
194
195 for(scriptCode = 0; scriptCode < scriptCodeCount; scriptCode += 1) {
196 status = LE_NO_ERROR;
197 engine = le_create(font, scriptCode, -1, 0, &status);
198
199 if (LE_FAILURE(status)) {
200 log_err("Could not create a LayoutEngine for script \'%s\'.\n", uscript_getShortName((UScriptCode)scriptCode));
201 }
202
203 le_close(engine);
204 }
205
206 le_fontClose(font);
207 }
208 U_CDECL_END
209
210 U_CDECL_BEGIN
AccessTest(void)211 static void U_CALLCONV AccessTest(void)
212 {
213 LEErrorCode status = LE_NO_ERROR;
214 le_font *font = le_simpleFontOpen(12, &status);
215 le_engine *engine =le_create(font, arabScriptCode, -1, 0, &status);
216 le_int32 glyphCount;
217 LEGlyphID glyphs[6];
218 le_int32 biasedIndices[6], indices[6], glyph;
219 float positions[6 * 2 + 2];
220 LEUnicode chars[] = {
221 0x0045, 0x006E, 0x0067, 0x006C, 0x0069, 0x0073, 0x0068, 0x0020, /* "English " */
222 0x0645, 0x0627, 0x0646, 0x062A, 0x0648, 0x0634, /* MEM ALIF KAF NOON TEH WAW SHEEN */
223 0x0020, 0x0074, 0x0065, 0x0078, 0x0074, 0x02E /* " text." */
224 };
225
226 if (LE_FAILURE(status)) {
227 log_err("Could not create LayoutEngine.\n");
228 goto bail;
229 }
230
231 glyphCount = le_layoutChars(engine, chars, 8, 6, 20, TRUE, 0.0, 0.0, &status);
232
233 if (LE_FAILURE(status) || glyphCount != 6) {
234 log_err("layoutChars(chars, 8, 6, 20, TRUE, 0.0, 0.0, status) failed.\n");
235 goto bail;
236 }
237
238 le_getGlyphs(engine, glyphs, &status);
239 le_getCharIndices(engine, indices, &status);
240 le_getGlyphPositions(engine, positions, &status);
241
242 if (LE_FAILURE(status)) {
243 log_err("Could not get glyph, indices and position arrays.\n");
244 goto bail;
245 }
246
247 status = LE_NO_ERROR;
248 le_getCharIndicesWithBase(engine, biasedIndices, 1024, &status);
249
250 if (LE_FAILURE(status)) {
251 log_err("getCharIndices(biasedIndices, 1024, status) failed.\n");
252 } else {
253 for (glyph = 0; glyph < glyphCount; glyph += 1) {
254 if (biasedIndices[glyph] != (indices[glyph] + 1024)) {
255 log_err("biasedIndices[%d] != indices[%d] + 1024: %8X, %8X\n",
256 glyph, glyph, biasedIndices[glyph], indices[glyph]);
257 break;
258 }
259 }
260 }
261
262 status = LE_NO_ERROR;
263 for (glyph = 0; glyph <= glyphCount; glyph += 1) {
264 float x = 0.0, y = 0.0;
265
266 le_getGlyphPosition(engine, glyph, &x, &y, &status);
267
268 if (LE_FAILURE(status)) {
269 log_err("getGlyphPosition(%d, x, y, status) failed.\n", glyph);
270 break;
271 }
272
273 if (x != positions[glyph*2] || y != positions[glyph*2 + 1]) {
274 log_err("getGlyphPosition(%d, x, y, status) returned bad position: (%f, %f) != (%f, %f)\n",
275 glyph, x, y, positions[glyph*2], positions[glyph*2 + 1]);
276 break;
277 }
278 }
279
280 bail:
281 le_close(engine);
282 le_fontClose(font);
283 }
284 U_CDECL_END
285
compareResults(const char * testID,TestResult * expected,TestResult * actual)286 static le_bool compareResults(const char *testID, TestResult *expected, TestResult *actual)
287 {
288 le_int32 i;
289
290 /* NOTE: we'll stop on the first failure 'cause once there's one error, it may cascade... */
291 if (actual->glyphCount != expected->glyphCount) {
292 log_err("Test %s: incorrect glyph count: exptected %d, got %d\n",
293 testID, expected->glyphCount, actual->glyphCount);
294 return FALSE;
295 }
296
297 for (i = 0; i < actual->glyphCount; i += 1) {
298 if (actual->glyphs[i] != expected->glyphs[i]) {
299 log_err("Test %s: incorrect id for glyph %d: expected %4X, got %4X\n",
300 testID, i, expected->glyphs[i], actual->glyphs[i]);
301 return FALSE;
302 }
303 }
304
305 for (i = 0; i < actual->glyphCount; i += 1) {
306 if (actual->indices[i] != expected->indices[i]) {
307 log_err("Test %s: incorrect index for glyph %d: expected %8X, got %8X\n",
308 testID, i, expected->indices[i], actual->indices[i]);
309 return FALSE;
310 }
311 }
312
313 for (i = 0; i <= actual->glyphCount; i += 1) {
314 double xError = uprv_fabs(actual->positions[i * 2] - expected->positions[i * 2]);
315 double yError = uprv_fabs(actual->positions[i * 2 + 1] - expected->positions[i * 2 + 1]);
316
317 if (xError > 0.0001) {
318 log_err("Test %s: incorrect x position for glyph %d: expected %f, got %f\n",
319 testID, i, expected->positions[i * 2], actual->positions[i * 2]);
320 return FALSE;
321 }
322
323 if (yError < 0) {
324 yError = -yError;
325 }
326
327 if (yError > 0.0001) {
328 log_err("Test %s: incorrect y position for glyph %d: expected %f, got %f\n",
329 testID, i, expected->positions[i * 2 + 1], actual->positions[i * 2 + 1]);
330 return FALSE;
331 }
332 }
333
334 return TRUE;
335 }
336
checkFontVersion(le_font * font,const char * testVersionString,le_uint32 testChecksum,const char * testID)337 static void checkFontVersion(le_font *font, const char *testVersionString,
338 le_uint32 testChecksum, const char *testID)
339 {
340 le_uint32 fontChecksum = le_getFontChecksum(font);
341
342 if (fontChecksum != testChecksum) {
343 const char *fontVersionString = le_getNameString(font, NAME_VERSION_STRING,
344 PLATFORM_MACINTOSH, MACINTOSH_ROMAN, MACINTOSH_ENGLISH);
345 const LEUnicode16 *uFontVersionString = NULL;
346
347 if (fontVersionString == NULL) {
348 uFontVersionString = le_getUnicodeNameString(font, NAME_VERSION_STRING,
349 PLATFORM_MICROSOFT, MICROSOFT_UNICODE_BMP, MICROSOFT_ENGLISH);
350 }
351
352 log_info("Test %s: this may not be the same font used to generate the test data.\n", testID);
353
354 if (uFontVersionString != NULL) {
355 log_info("Your font's version string is \"%S\"\n", uFontVersionString);
356 le_deleteUnicodeNameString(font, uFontVersionString);
357 } else {
358 log_info("Your font's version string is \"%s\"\n", fontVersionString);
359 le_deleteNameString(font, fontVersionString);
360 }
361
362 log_info("The expected version string is \"%s\"\n", testVersionString);
363 log_info("If you see errors, they may be due to the version of the font you're using.\n");
364 }
365 }
366
367 /* Returns the path to icu/source/test/testdata/ */
getSourceTestData()368 static const char *getSourceTestData() {
369 #ifdef U_TOPSRCDIR
370 const char *srcDataDir = U_TOPSRCDIR U_FILE_SEP_STRING"test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING;
371 #else
372 const char *srcDataDir = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING"test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING;
373 FILE *f = fopen(".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING"test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING"rbbitst.txt", "r");
374
375 if (f != NULL) {
376 /* We're in icu/source/test/letest/ */
377 fclose(f);
378 } else {
379 /* We're in icu/source/test/letest/(Debug|Release) */
380 srcDataDir = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING"test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING;
381 }
382 #endif
383
384 return srcDataDir;
385 }
386
getPath(char buffer[2048],const char * filename)387 static const char *getPath(char buffer[2048], const char *filename) {
388 const char *testDataDirectory = getSourceTestData();
389
390 strcpy(buffer, testDataDirectory);
391 strcat(buffer, filename);
392
393 return buffer;
394 }
395
openFont(const char * fontName,const char * checksum,const char * version,const char * testID)396 static le_font *openFont(const char *fontName, const char *checksum, const char *version, const char *testID)
397 {
398 char path[2048];
399 le_font *font;
400 LEErrorCode fontStatus = LE_NO_ERROR;
401
402 if (fontName != NULL) {
403 font = le_portableFontOpen(getPath(path, fontName), 12, &fontStatus);
404
405 if (LE_FAILURE(fontStatus)) {
406 log_info("Test %s: can't open font %s - test skipped.\n", testID, fontName);
407 le_fontClose(font);
408 return NULL;
409 } else {
410 le_uint32 cksum = 0;
411
412 sscanf(checksum, "%x", &cksum);
413
414 checkFontVersion(font, version, cksum, testID);
415 }
416 } else {
417 font = le_simpleFontOpen(12, &fontStatus);
418 }
419
420 return font;
421 }
422
getRTL(const LEUnicode * text,le_int32 charCount)423 static le_bool getRTL(const LEUnicode *text, le_int32 charCount)
424 {
425 UBiDiLevel level;
426 le_int32 limit = -1;
427 UErrorCode status = U_ZERO_ERROR;
428 UBiDi *ubidi = ubidi_openSized(charCount, 0, &status);
429
430 ubidi_setPara(ubidi, text, charCount, UBIDI_DEFAULT_LTR, NULL, &status);
431
432 /* TODO: Should check that there's only a single logical run... */
433 ubidi_getLogicalRun(ubidi, 0, &limit, &level);
434
435 ubidi_close(ubidi);
436
437 return level & 1;
438 }
439
doTestCase(const char * testID,const char * fontName,const char * fontVersion,const char * fontChecksum,le_int32 scriptCode,le_int32 languageCode,const LEUnicode * text,le_int32 charCount,TestResult * expected)440 static void doTestCase (const char *testID,
441 const char *fontName,
442 const char *fontVersion,
443 const char *fontChecksum,
444 le_int32 scriptCode,
445 le_int32 languageCode,
446 const LEUnicode *text,
447 le_int32 charCount,
448 TestResult *expected)
449 {
450 LEErrorCode status = LE_NO_ERROR;
451 le_engine *engine;
452 le_font *font = openFont(fontName, fontChecksum, fontVersion, testID);
453 le_int32 typoFlags = 3; /* kerning + ligatures */
454 TestResult actual;
455
456 if (font == NULL) {
457 /* error message already printed. */
458 return;
459 }
460
461 if (fontName == NULL) {
462 typoFlags |= 0x80000000L; /* use CharSubstitutionFilter... */
463 }
464
465 engine = le_create(font, scriptCode, languageCode, typoFlags, &status);
466
467 if (LE_FAILURE(status)) {
468 log_err("Test %s: could not create a LayoutEngine.\n", testID);
469 goto free_expected;
470 }
471
472 actual.glyphCount = le_layoutChars(engine, text, 0, charCount, charCount, getRTL(text, charCount), 0, 0, &status);
473
474 actual.glyphs = NEW_ARRAY(LEGlyphID, actual.glyphCount);
475 actual.indices = NEW_ARRAY(le_int32, actual.glyphCount);
476 actual.positions = NEW_ARRAY(float, actual.glyphCount * 2 + 2);
477
478 le_getGlyphs(engine, actual.glyphs, &status);
479 le_getCharIndices(engine, actual.indices, &status);
480 le_getGlyphPositions(engine, actual.positions, &status);
481
482 compareResults(testID, expected, &actual);
483
484 DELETE_ARRAY(actual.positions);
485 DELETE_ARRAY(actual.indices);
486 DELETE_ARRAY(actual.glyphs);
487
488 le_close(engine);
489
490 free_expected:
491 le_fontClose(font);
492 }
493
DataDrivenTest(void)494 static void U_CALLCONV DataDrivenTest(void)
495 {
496 char path[2048];
497 const char *testFilePath = getPath(path, "letest.xml");
498
499 readTestFile(testFilePath, doTestCase);
500 }
501
502 /*
503 * From ticket:5923:
504 *
505 * Build a paragraph that contains a mixture of left to right and right to left text.
506 * Break it into multiple lines and make sure that the glyphToCharMap for run in each
507 * line is correct.
508 *
509 * Note: it might be a good idea to also check the glyphs and positions for each run,
510 * that we get the expected number of runs per line and that the line breaks are where
511 * we expect them to be. Really, it would be a good idea to make a whole test suite
512 * for pl_paragraph.
513 */
GlyphToCharTest(void)514 static void U_CALLCONV GlyphToCharTest(void)
515 {
516 #if !UCONFIG_NO_BREAK_ITERATION
517 LEErrorCode status = LE_NO_ERROR;
518 le_font *font;
519 pl_fontRuns *fontRuns;
520 pl_paragraph *paragraph;
521 const pl_line *line;
522 /*
523 * This is the same text that's in <icu>/source/samples/layout/Sample.txt
524 */
525 LEUnicode chars[] = {
526 /*BOM*/ 0x0054, 0x0068, 0x0065, 0x0020, 0x004c, 0x0061, 0x0079,
527 0x006f, 0x0075, 0x0074, 0x0045, 0x006e, 0x0067, 0x0069, 0x006e,
528 0x0065, 0x0020, 0x0064, 0x006f, 0x0065, 0x0073, 0x0020, 0x0061,
529 0x006c, 0x006c, 0x0020, 0x0074, 0x0068, 0x0065, 0x0020, 0x0077,
530 0x006f, 0x0072, 0x006b, 0x0020, 0x006e, 0x0065, 0x0063, 0x0065,
531 0x0073, 0x0073, 0x0061, 0x0072, 0x0079, 0x0020, 0x0074, 0x006f,
532 0x0020, 0x0064, 0x0069, 0x0073, 0x0070, 0x006c, 0x0061, 0x0079,
533 0x0020, 0x0055, 0x006e, 0x0069, 0x0063, 0x006f, 0x0064, 0x0065,
534 0x0020, 0x0074, 0x0065, 0x0078, 0x0074, 0x0020, 0x0077, 0x0072,
535 0x0069, 0x0074, 0x0074, 0x0065, 0x006e, 0x0020, 0x0069, 0x006e,
536 0x0020, 0x006c, 0x0061, 0x006e, 0x0067, 0x0075, 0x0061, 0x0067,
537 0x0065, 0x0073, 0x0020, 0x0077, 0x0069, 0x0074, 0x0068, 0x0020,
538 0x0063, 0x006f, 0x006d, 0x0070, 0x006c, 0x0065, 0x0078, 0x0020,
539 0x0077, 0x0072, 0x0069, 0x0074, 0x0069, 0x006e, 0x0067, 0x0020,
540 0x0073, 0x0079, 0x0073, 0x0074, 0x0065, 0x006d, 0x0073, 0x0020,
541 0x0073, 0x0075, 0x0063, 0x0068, 0x0020, 0x0061, 0x0073, 0x0020,
542 0x0048, 0x0069, 0x006e, 0x0064, 0x0069, 0x0020, 0x0028, 0x0939,
543 0x093f, 0x0928, 0x094d, 0x0926, 0x0940, 0x0029, 0x0020, 0x0054,
544 0x0068, 0x0061, 0x0069, 0x0020, 0x0028, 0x0e44, 0x0e17, 0x0e22,
545 0x0029, 0x0020, 0x0061, 0x006e, 0x0064, 0x0020, 0x0041, 0x0072,
546 0x0061, 0x0062, 0x0069, 0x0063, 0x0020, 0x0028, 0x0627, 0x0644,
547 0x0639, 0x0631, 0x0628, 0x064a, 0x0629, 0x0029, 0x002e, 0x0020,
548 0x0048, 0x0065, 0x0072, 0x0065, 0x0027, 0x0073, 0x0020, 0x0061,
549 0x0020, 0x0073, 0x0061, 0x006d, 0x0070, 0x006c, 0x0065, 0x0020,
550 0x006f, 0x0066, 0x0020, 0x0073, 0x006f, 0x006d, 0x0065, 0x0020,
551 0x0074, 0x0065, 0x0078, 0x0074, 0x0020, 0x0077, 0x0072, 0x0069,
552 0x0074, 0x0074, 0x0065, 0x006e, 0x0020, 0x0069, 0x006e, 0x0020,
553 0x0053, 0x0061, 0x006e, 0x0073, 0x006b, 0x0072, 0x0069, 0x0074,
554 0x003a, 0x0020, 0x0936, 0x094d, 0x0930, 0x0940, 0x092e, 0x0926,
555 0x094d, 0x0020, 0x092d, 0x0917, 0x0935, 0x0926, 0x094d, 0x0917,
556 0x0940, 0x0924, 0x093e, 0x0020, 0x0905, 0x0927, 0x094d, 0x092f,
557 0x093e, 0x092f, 0x0020, 0x0905, 0x0930, 0x094d, 0x091c, 0x0941,
558 0x0928, 0x0020, 0x0935, 0x093f, 0x0937, 0x093e, 0x0926, 0x0020,
559 0x092f, 0x094b, 0x0917, 0x0020, 0x0927, 0x0943, 0x0924, 0x0930,
560 0x093e, 0x0937, 0x094d, 0x091f, 0x094d, 0x0930, 0x0020, 0x0909,
561 0x0935, 0x093e, 0x091a, 0x0964, 0x0020, 0x0927, 0x0930, 0x094d,
562 0x092e, 0x0915, 0x094d, 0x0937, 0x0947, 0x0924, 0x094d, 0x0930,
563 0x0947, 0x0020, 0x0915, 0x0941, 0x0930, 0x0941, 0x0915, 0x094d,
564 0x0937, 0x0947, 0x0924, 0x094d, 0x0930, 0x0947, 0x0020, 0x0938,
565 0x092e, 0x0935, 0x0947, 0x0924, 0x093e, 0x0020, 0x092f, 0x0941,
566 0x092f, 0x0941, 0x0924, 0x094d, 0x0938, 0x0935, 0x0903, 0x0020,
567 0x092e, 0x093e, 0x092e, 0x0915, 0x093e, 0x0903, 0x0020, 0x092a,
568 0x093e, 0x0923, 0x094d, 0x0921, 0x0935, 0x093e, 0x0936, 0x094d,
569 0x091a, 0x0948, 0x0935, 0x0020, 0x0915, 0x093f, 0x092e, 0x0915,
570 0x0941, 0x0930, 0x094d, 0x0935, 0x0924, 0x0020, 0x0938, 0x0902,
571 0x091c, 0x092f, 0x0020, 0x0048, 0x0065, 0x0072, 0x0065, 0x0027,
572 0x0073, 0x0020, 0x0061, 0x0020, 0x0073, 0x0061, 0x006d, 0x0070,
573 0x006c, 0x0065, 0x0020, 0x006f, 0x0066, 0x0020, 0x0073, 0x006f,
574 0x006d, 0x0065, 0x0020, 0x0074, 0x0065, 0x0078, 0x0074, 0x0020,
575 0x0077, 0x0072, 0x0069, 0x0074, 0x0074, 0x0065, 0x006e, 0x0020,
576 0x0069, 0x006e, 0x0020, 0x0041, 0x0072, 0x0061, 0x0062, 0x0069,
577 0x0063, 0x003a, 0x0020, 0x0623, 0x0633, 0x0627, 0x0633, 0x064b,
578 0x0627, 0x060c, 0x0020, 0x062a, 0x062a, 0x0639, 0x0627, 0x0645,
579 0x0644, 0x0020, 0x0627, 0x0644, 0x062d, 0x0648, 0x0627, 0x0633,
580 0x064a, 0x0628, 0x0020, 0x0641, 0x0642, 0x0637, 0x0020, 0x0645,
581 0x0639, 0x0020, 0x0627, 0x0644, 0x0623, 0x0631, 0x0642, 0x0627,
582 0x0645, 0x060c, 0x0020, 0x0648, 0x062a, 0x0642, 0x0648, 0x0645,
583 0x0020, 0x0628, 0x062a, 0x062e, 0x0632, 0x064a, 0x0646, 0x0020,
584 0x0627, 0x0644, 0x0623, 0x062d, 0x0631, 0x0641, 0x0020, 0x0648,
585 0x0627, 0x0644, 0x0645, 0x062d, 0x0627, 0x0631, 0x0641, 0x0020,
586 0x0627, 0x0644, 0x0623, 0x062e, 0x0631, 0x0649, 0x0020, 0x0628,
587 0x0639, 0x062f, 0x0020, 0x0623, 0x0646, 0x0020, 0x062a, 0x064f,
588 0x0639, 0x0637, 0x064a, 0x0020, 0x0631, 0x0642, 0x0645, 0x0627,
589 0x0020, 0x0645, 0x0639, 0x064a, 0x0646, 0x0627, 0x0020, 0x0644,
590 0x0643, 0x0644, 0x0020, 0x0648, 0x0627, 0x062d, 0x062f, 0x0020,
591 0x0645, 0x0646, 0x0647, 0x0627, 0x002e, 0x0020, 0x0648, 0x0642,
592 0x0628, 0x0644, 0x0020, 0x0627, 0x062e, 0x062a, 0x0631, 0x0627,
593 0x0639, 0x0020, 0x0022, 0x064a, 0x0648, 0x0646, 0x0650, 0x0643,
594 0x0648, 0x062f, 0x0022, 0x060c, 0x0020, 0x0643, 0x0627, 0x0646,
595 0x0020, 0x0647, 0x0646, 0x0627, 0x0643, 0x0020, 0x0645, 0x0626,
596 0x0627, 0x062a, 0x0020, 0x0627, 0x0644, 0x0623, 0x0646, 0x0638,
597 0x0645, 0x0629, 0x0020, 0x0644, 0x0644, 0x062a, 0x0634, 0x0641,
598 0x064a, 0x0631, 0x0020, 0x0648, 0x062a, 0x062e, 0x0635, 0x064a,
599 0x0635, 0x0020, 0x0647, 0x0630, 0x0647, 0x0020, 0x0627, 0x0644,
600 0x0623, 0x0631, 0x0642, 0x0627, 0x0645, 0x0020, 0x0644, 0x0644,
601 0x0645, 0x062d, 0x0627, 0x0631, 0x0641, 0x060c, 0x0020, 0x0648,
602 0x0644, 0x0645, 0x0020, 0x064a, 0x0648, 0x062c, 0x062f, 0x0020,
603 0x0646, 0x0638, 0x0627, 0x0645, 0x0020, 0x062a, 0x0634, 0x0641,
604 0x064a, 0x0631, 0x0020, 0x0648, 0x0627, 0x062d, 0x062f, 0x0020,
605 0x064a, 0x062d, 0x062a, 0x0648, 0x064a, 0x0020, 0x0639, 0x0644,
606 0x0649, 0x0020, 0x062c, 0x0645, 0x064a, 0x0639, 0x0020, 0x0627,
607 0x0644, 0x0645, 0x062d, 0x0627, 0x0631, 0x0641, 0x0020, 0x0627,
608 0x0644, 0x0636, 0x0631, 0x0648, 0x0631, 0x064a, 0x0629, 0x0020,
609 0x0061, 0x006e, 0x0064, 0x0020, 0x0068, 0x0065, 0x0072, 0x0065,
610 0x0027, 0x0073, 0x0020, 0x0061, 0x0020, 0x0073, 0x0061, 0x006d,
611 0x0070, 0x006c, 0x0065, 0x0020, 0x006f, 0x0066, 0x0020, 0x0073,
612 0x006f, 0x006d, 0x0065, 0x0020, 0x0074, 0x0065, 0x0078, 0x0074,
613 0x0020, 0x0077, 0x0072, 0x0069, 0x0074, 0x0074, 0x0065, 0x006e,
614 0x0020, 0x0069, 0x006e, 0x0020, 0x0054, 0x0068, 0x0061, 0x0069,
615 0x003a, 0x0020, 0x0e1a, 0x0e17, 0x0e17, 0x0e35, 0x0e48, 0x0e51,
616 0x0e1e, 0x0e32, 0x0e22, 0x0e38, 0x0e44, 0x0e0b, 0x0e42, 0x0e04,
617 0x0e25, 0x0e19, 0x0e42, 0x0e14, 0x0e42, 0x0e23, 0x0e18, 0x0e35,
618 0x0e2d, 0x0e32, 0x0e28, 0x0e31, 0x0e22, 0x0e2d, 0x0e22, 0x0e39,
619 0x0e48, 0x0e17, 0x0e48, 0x0e32, 0x0e21, 0x0e01, 0x0e25, 0x0e32,
620 0x0e07, 0x0e17, 0x0e38, 0x0e48, 0x0e07, 0x0e43, 0x0e2b, 0x0e0d,
621 0x0e48, 0x0e43, 0x0e19, 0x0e41, 0x0e04, 0x0e19, 0x0e0b, 0x0e31,
622 0x0e2a, 0x0e01, 0x0e31, 0x0e1a, 0x0e25, 0x0e38, 0x0e07, 0x0e40,
623 0x0e2e, 0x0e19, 0x0e23, 0x0e35, 0x0e0a, 0x0e32, 0x0e27, 0x0e44,
624 0x0e23, 0x0e48, 0x0e41, 0x0e25, 0x0e30, 0x0e1b, 0x0e49, 0x0e32,
625 0x0e40, 0x0e2d, 0x0e47, 0x0e21, 0x0e20, 0x0e23, 0x0e23, 0x0e22,
626 0x0e32, 0x0e0a, 0x0e32, 0x0e27, 0x0e44, 0x0e23, 0x0e48, 0x0e1a,
627 0x0e49, 0x0e32, 0x0e19, 0x0e02, 0x0e2d, 0x0e07, 0x0e1e, 0x0e27,
628 0x0e01, 0x0e40, 0x0e02, 0x0e32, 0x0e2b, 0x0e25, 0x0e31, 0x0e07,
629 0x0e40, 0x0e25, 0x0e47, 0x0e01, 0x0e40, 0x0e1e, 0x0e23, 0x0e32,
630 0x0e30, 0x0e44, 0x0e21, 0x0e49, 0x0e2a, 0x0e23, 0x0e49, 0x0e32,
631 0x0e07, 0x0e1a, 0x0e49, 0x0e32, 0x0e19, 0x0e15, 0x0e49, 0x0e2d,
632 0x0e07, 0x0e02, 0x0e19, 0x0e21, 0x0e32, 0x0e14, 0x0e49, 0x0e27,
633 0x0e22, 0x0e40, 0x0e01, 0x0e27, 0x0e35, 0x0e22, 0x0e19, 0x0e40,
634 0x0e1b, 0x0e47, 0x0e19, 0x0e23, 0x0e30, 0x0e22, 0x0e30, 0x0e17,
635 0x0e32, 0x0e07, 0x0e2b, 0x0e25, 0x0e32, 0x0e22, 0x0e44, 0x0e21,
636 0x0e25, 0x0e4c
637 };
638 le_int32 charCount = LE_ARRAY_SIZE(chars);
639 le_int32 charIndex = 0, lineNumber = 1;
640 le_int32 run, i;
641 const float lineWidth = 600;
642
643 font = le_simpleFontOpen(12, &status);
644
645 if (LE_FAILURE(status)) {
646 log_err("le_simpleFontOpen(12, &status) failed");
647 goto finish;
648 }
649
650 fontRuns = pl_openEmptyFontRuns(0);
651 pl_addFontRun(fontRuns, font, charCount);
652
653 paragraph = pl_create(chars, charCount, fontRuns, NULL, NULL, NULL, 0, FALSE, &status);
654
655 pl_closeFontRuns(fontRuns);
656
657 if (LE_FAILURE(status)) {
658 log_err("pl_create failed.");
659 goto close_font;
660 }
661
662 pl_reflow(paragraph);
663 while ((line = pl_nextLine(paragraph, lineWidth)) != NULL) {
664 le_int32 runCount = pl_countLineRuns(line);
665
666 for(run = 0; run < runCount; run += 1) {
667 const pl_visualRun *visualRun = pl_getLineVisualRun(line, run);
668 const le_int32 glyphCount = pl_getVisualRunGlyphCount(visualRun);
669 const le_int32 *glyphToCharMap = pl_getVisualRunGlyphToCharMap(visualRun);
670
671 if (pl_getVisualRunDirection(visualRun) == UBIDI_RTL) {
672 /*
673 * For a right to left run, make sure that the character indices
674 * increase from the right most glyph to the left most glyph. If
675 * there are any one to many glyph substitutions, we might get several
676 * glyphs in a row with the same character index.
677 */
678 for(i = glyphCount - 1; i >= 0; i -= 1) {
679 le_int32 ix = glyphToCharMap[i];
680
681 if (ix != charIndex) {
682 if (ix != charIndex - 1) {
683 log_err("Bad glyph to char index for glyph %d on line %d: expected %d, got %d\n",
684 i, lineNumber, charIndex, ix);
685 goto close_paragraph; /* once there's one error, we can't count on anything else... */
686 }
687 } else {
688 charIndex += 1;
689 }
690 }
691 } else {
692 /*
693 * We can't just check the order of the character indices
694 * for left to right runs because Indic text might have been
695 * reordered. What we can do is find the minimum and maximum
696 * character indices in the run and make sure that the minimum
697 * is equal to charIndex and then advance charIndex to the maximum.
698 */
699 le_int32 minIndex = 0x7FFFFFFF, maxIndex = -1;
700
701 for(i = 0; i < glyphCount; i += 1) {
702 le_int32 ix = glyphToCharMap[i];
703
704 if (ix > maxIndex) {
705 maxIndex = ix;
706 }
707
708 if (ix < minIndex) {
709 minIndex = ix;
710 }
711 }
712
713 if (minIndex != charIndex) {
714 log_err("Bad minIndex for run %d on line %d: expected %d, got %d\n",
715 run, lineNumber, charIndex, minIndex);
716 goto close_paragraph; /* once there's one error, we can't count on anything else... */
717 }
718
719 charIndex = maxIndex + 1;
720 }
721 }
722
723 lineNumber += 1;
724 }
725
726 close_paragraph:
727 pl_close(paragraph);
728
729 close_font:
730 le_fontClose(font);
731
732 finish:
733 return;
734 #endif
735 }
736
addCTests(TestNode ** root)737 U_CFUNC void addCTests(TestNode **root)
738 {
739 addTest(root, &ParamTest, "c_api/ParameterTest");
740 addTest(root, &FactoryTest, "c_api/FactoryTest");
741 addTest(root, &AccessTest, "c_layout/AccessTest");
742 addTest(root, &DataDrivenTest, "c_layout/DataDrivenTest");
743 addTest(root, &GlyphToCharTest, "c_paragraph/GlyphToCharTest");
744 }
745
746
747 #endif
748