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