1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 *******************************************************************************
6 * Copyright (C) 1999-2014, International Business Machines
7 * Corporation and others. All Rights Reserved.
9 *******************************************************************************
12 #ifndef USING_ICULEHB /* C API not available under HB */
14 #include "unicode/utypes.h"
15 #include "unicode/ubidi.h"
16 #include "unicode/uscript.h"
17 #include "unicode/ctest.h"
19 #include "layout/LETypes.h"
20 #include "layout/LEScripts.h"
21 #include "layout/loengine.h"
23 #include "layout/playout.h"
24 #include "layout/plruns.h"
31 #include "xmlreader.h"
32 #include "putilimp.h" /* for U_FILE_SEP_STRING */
38 #define CH_COMMA 0x002C
41 static void U_CALLCONV
ParamTest(void)
43 LEErrorCode status
= LE_NO_ERROR
;
44 le_font
*font
= le_simpleFontOpen(12, &status
);
45 le_engine
*engine
= le_create(font
, arabScriptCode
, -1, 0, &status
);
46 LEGlyphID
*glyphs
= NULL
;
47 le_int32
*indices
= NULL
;
48 float *positions
= NULL
;
49 le_int32 glyphCount
= 0;
51 float x
= 0.0, y
= 0.0;
53 0x0045, 0x006E, 0x0067, 0x006C, 0x0069, 0x0073, 0x0068, 0x0020, /* "English " */
54 0x0645, 0x0627, 0x0646, 0x062A, 0x0648, 0x0634, /* MEM ALIF KAF NOON TEH WAW SHEEN */
55 0x0020, 0x0074, 0x0065, 0x0078, 0x0074, 0x02E /* " text." */
59 glyphCount
= le_getGlyphCount(engine
, &status
);
60 if (glyphCount
!= 0) {
61 log_err("Calling getGlyphCount() on an empty layout returned %d.\n", glyphCount
);
64 glyphs
= NEW_ARRAY(LEGlyphID
, glyphCount
+ 10);
65 indices
= NEW_ARRAY(le_int32
, glyphCount
+ 10);
66 positions
= NEW_ARRAY(float, glyphCount
+ 10);
68 le_getGlyphs(engine
, NULL
, &status
);
70 if (status
!= LE_ILLEGAL_ARGUMENT_ERROR
) {
71 log_err("Calling getGlyphs(NULL, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n");
75 le_getGlyphs(engine
, glyphs
, &status
);
77 if (status
!= LE_NO_LAYOUT_ERROR
) {
78 log_err("Calling getGlyphs(glyphs, status) on an empty layout did not return LE_NO_LAYOUT_ERROR.\n");
82 le_getCharIndices(engine
, NULL
, &status
);
84 if (status
!= LE_ILLEGAL_ARGUMENT_ERROR
) {
85 log_err("Calling getCharIndices(NULL, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n");
89 le_getCharIndices(engine
, indices
, &status
);
91 if (status
!= LE_NO_LAYOUT_ERROR
) {
92 log_err("Calling getCharIndices(indices, status) on an empty layout did not return LE_NO_LAYOUT_ERROR.\n");
96 le_getCharIndicesWithBase(engine
, NULL
, 1024, &status
);
98 if (status
!= LE_ILLEGAL_ARGUMENT_ERROR
) {
99 log_err("Calling getCharIndices(NULL, 1024, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n");
102 status
= LE_NO_ERROR
;
103 le_getCharIndicesWithBase(engine
, indices
, 1024, &status
);
105 if (status
!= LE_NO_LAYOUT_ERROR
) {
106 log_err("Calling getCharIndices(indices, 1024, status) on an empty layout did not return LE_NO_LAYOUT_ERROR.\n");
109 status
= LE_NO_ERROR
;
110 le_getGlyphPositions(engine
, NULL
, &status
);
112 if (status
!= LE_ILLEGAL_ARGUMENT_ERROR
) {
113 log_err("Calling getGlyphPositions(NULL, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n");
116 status
= LE_NO_ERROR
;
117 le_getGlyphPositions(engine
, positions
, &status
);
119 if (status
!= LE_NO_LAYOUT_ERROR
) {
120 log_err("Calling getGlyphPositions(positions, status) on an empty layout did not return LE_NO_LAYOUT_ERROR.\n");
123 DELETE_ARRAY(positions
);
124 DELETE_ARRAY(indices
);
125 DELETE_ARRAY(glyphs
);
127 status
= LE_NO_ERROR
;
128 glyphCount
= le_layoutChars(engine
, NULL
, 0, 0, 0, FALSE
, 0.0, 0.0, &status
);
130 if (status
!= LE_ILLEGAL_ARGUMENT_ERROR
) {
131 log_err("Calling layoutChars(NULL, 0, 0, 0, FALSE, 0.0, 0.0, status) did not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n");
134 status
= LE_NO_ERROR
;
135 glyphCount
= le_layoutChars(engine
, chars
, -1, 6, 20, TRUE
, 0.0, 0.0, &status
);
137 if (status
!= LE_ILLEGAL_ARGUMENT_ERROR
) {
138 log_err("Calling layoutChars(chars, -1, 6, 20, TRUE, 0.0, 0.0, status) did not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n");
141 status
= LE_NO_ERROR
;
142 glyphCount
= le_layoutChars(engine
, chars
, 8, -1, 20, TRUE
, 0.0, 0.0, &status
);
144 if (status
!= LE_ILLEGAL_ARGUMENT_ERROR
) {
145 log_err("Calling layoutChars(chars, 8, -1, 20, TRUE, 0.0, 0.0, status) did not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n");
148 status
= LE_NO_ERROR
;
149 glyphCount
= le_layoutChars(engine
, chars
, 8, 6, -1, TRUE
, 0.0, 0.0, &status
);
151 if (status
!= LE_ILLEGAL_ARGUMENT_ERROR
) {
152 log_err("Calling layoutChars((chars, 8, 6, -1, TRUE, 0.0, 0.0, status) did not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n");
155 status
= LE_NO_ERROR
;
156 glyphCount
= le_layoutChars(engine
, chars
, 8, 6, 10, TRUE
, 0.0, 0.0, &status
);
158 if (status
!= LE_ILLEGAL_ARGUMENT_ERROR
) {
159 log_err("Calling layoutChars(chars, 8, 6, 10, TRUE, 0.0, 0.0, status) did not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n");
162 status
= LE_NO_ERROR
;
163 glyphCount
= le_layoutChars(engine
, chars
, 8, 6, 20, TRUE
, 0.0, 0.0, &status
);
165 if (LE_FAILURE(status
)) {
166 log_err("Calling layoutChars(chars, 8, 6, 20, TRUE, 0.0, 0.0, status) failed.\n");
170 le_getGlyphPosition(engine
, -1, &x
, &y
, &status
);
172 if (status
!= LE_INDEX_OUT_OF_BOUNDS_ERROR
) {
173 log_err("Calling getGlyphPosition(-1, x, y, status) did not fail w/ LE_INDEX_OUT_OF_BOUNDS_ERROR.\n");
176 status
= LE_NO_ERROR
;
177 le_getGlyphPosition(engine
, glyphCount
+ 1, &x
, &y
, &status
);
179 if (status
!= LE_INDEX_OUT_OF_BOUNDS_ERROR
) {
180 log_err("Calling getGlyphPosition(glyphCount + 1, x, y, status) did not fail w/ LE_INDEX_OUT_OF_BOUNDS_ERROR.\n");
190 static void U_CALLCONV
FactoryTest(void)
192 LEErrorCode status
= LE_NO_ERROR
;
193 le_font
*font
= le_simpleFontOpen(12, &status
);
194 le_engine
*engine
= NULL
;
197 for(scriptCode
= 0; scriptCode
< scriptCodeCount
; scriptCode
+= 1) {
198 status
= LE_NO_ERROR
;
199 engine
= le_create(font
, scriptCode
, -1, 0, &status
);
201 if (LE_FAILURE(status
)) {
202 log_err("Could not create a LayoutEngine for script \'%s\'.\n", uscript_getShortName((UScriptCode
)scriptCode
));
213 static void U_CALLCONV
AccessTest(void)
215 LEErrorCode status
= LE_NO_ERROR
;
216 le_font
*font
= le_simpleFontOpen(12, &status
);
217 le_engine
*engine
=le_create(font
, arabScriptCode
, -1, 0, &status
);
220 le_int32 biasedIndices
[6], indices
[6], glyph
;
221 float positions
[6 * 2 + 2];
222 LEUnicode chars
[] = {
223 0x0045, 0x006E, 0x0067, 0x006C, 0x0069, 0x0073, 0x0068, 0x0020, /* "English " */
224 0x0645, 0x0627, 0x0646, 0x062A, 0x0648, 0x0634, /* MEM ALIF KAF NOON TEH WAW SHEEN */
225 0x0020, 0x0074, 0x0065, 0x0078, 0x0074, 0x02E /* " text." */
228 if (LE_FAILURE(status
)) {
229 log_err("Could not create LayoutEngine.\n");
233 glyphCount
= le_layoutChars(engine
, chars
, 8, 6, 20, TRUE
, 0.0, 0.0, &status
);
235 if (LE_FAILURE(status
) || glyphCount
!= 6) {
236 log_err("layoutChars(chars, 8, 6, 20, TRUE, 0.0, 0.0, status) failed.\n");
240 le_getGlyphs(engine
, glyphs
, &status
);
241 le_getCharIndices(engine
, indices
, &status
);
242 le_getGlyphPositions(engine
, positions
, &status
);
244 if (LE_FAILURE(status
)) {
245 log_err("Could not get glyph, indices and position arrays.\n");
249 status
= LE_NO_ERROR
;
250 le_getCharIndicesWithBase(engine
, biasedIndices
, 1024, &status
);
252 if (LE_FAILURE(status
)) {
253 log_err("getCharIndices(biasedIndices, 1024, status) failed.\n");
255 for (glyph
= 0; glyph
< glyphCount
; glyph
+= 1) {
256 if (biasedIndices
[glyph
] != (indices
[glyph
] + 1024)) {
257 log_err("biasedIndices[%d] != indices[%d] + 1024: %8X, %8X\n",
258 glyph
, glyph
, biasedIndices
[glyph
], indices
[glyph
]);
264 status
= LE_NO_ERROR
;
265 for (glyph
= 0; glyph
<= glyphCount
; glyph
+= 1) {
266 float x
= 0.0, y
= 0.0;
268 le_getGlyphPosition(engine
, glyph
, &x
, &y
, &status
);
270 if (LE_FAILURE(status
)) {
271 log_err("getGlyphPosition(%d, x, y, status) failed.\n", glyph
);
275 if (x
!= positions
[glyph
*2] || y
!= positions
[glyph
*2 + 1]) {
276 log_err("getGlyphPosition(%d, x, y, status) returned bad position: (%f, %f) != (%f, %f)\n",
277 glyph
, x
, y
, positions
[glyph
*2], positions
[glyph
*2 + 1]);
288 static le_bool
compareResults(const char *testID
, TestResult
*expected
, TestResult
*actual
)
292 /* NOTE: we'll stop on the first failure 'cause once there's one error, it may cascade... */
293 if (actual
->glyphCount
!= expected
->glyphCount
) {
294 log_err("Test %s: incorrect glyph count: exptected %d, got %d\n",
295 testID
, expected
->glyphCount
, actual
->glyphCount
);
299 for (i
= 0; i
< actual
->glyphCount
; i
+= 1) {
300 if (actual
->glyphs
[i
] != expected
->glyphs
[i
]) {
301 log_err("Test %s: incorrect id for glyph %d: expected %4X, got %4X\n",
302 testID
, i
, expected
->glyphs
[i
], actual
->glyphs
[i
]);
307 for (i
= 0; i
< actual
->glyphCount
; i
+= 1) {
308 if (actual
->indices
[i
] != expected
->indices
[i
]) {
309 log_err("Test %s: incorrect index for glyph %d: expected %8X, got %8X\n",
310 testID
, i
, expected
->indices
[i
], actual
->indices
[i
]);
315 for (i
= 0; i
<= actual
->glyphCount
; i
+= 1) {
316 double xError
= uprv_fabs(actual
->positions
[i
* 2] - expected
->positions
[i
* 2]);
317 double yError
= uprv_fabs(actual
->positions
[i
* 2 + 1] - expected
->positions
[i
* 2 + 1]);
319 if (xError
> 0.0001) {
320 log_err("Test %s: incorrect x position for glyph %d: expected %f, got %f\n",
321 testID
, i
, expected
->positions
[i
* 2], actual
->positions
[i
* 2]);
329 if (yError
> 0.0001) {
330 log_err("Test %s: incorrect y position for glyph %d: expected %f, got %f\n",
331 testID
, i
, expected
->positions
[i
* 2 + 1], actual
->positions
[i
* 2 + 1]);
339 static void checkFontVersion(le_font
*font
, const char *testVersionString
,
340 le_uint32 testChecksum
, const char *testID
)
342 le_uint32 fontChecksum
= le_getFontChecksum(font
);
344 if (fontChecksum
!= testChecksum
) {
345 const char *fontVersionString
= le_getNameString(font
, NAME_VERSION_STRING
,
346 PLATFORM_MACINTOSH
, MACINTOSH_ROMAN
, MACINTOSH_ENGLISH
);
347 const LEUnicode16
*uFontVersionString
= NULL
;
349 if (fontVersionString
== NULL
) {
350 uFontVersionString
= le_getUnicodeNameString(font
, NAME_VERSION_STRING
,
351 PLATFORM_MICROSOFT
, MICROSOFT_UNICODE_BMP
, MICROSOFT_ENGLISH
);
354 log_info("Test %s: this may not be the same font used to generate the test data.\n", testID
);
356 if (uFontVersionString
!= NULL
) {
357 log_info("Your font's version string is \"%S\"\n", uFontVersionString
);
358 le_deleteUnicodeNameString(font
, uFontVersionString
);
360 log_info("Your font's version string is \"%s\"\n", fontVersionString
);
361 le_deleteNameString(font
, fontVersionString
);
364 log_info("The expected version string is \"%s\"\n", testVersionString
);
365 log_info("If you see errors, they may be due to the version of the font you're using.\n");
369 /* Returns the path to icu/source/test/testdata/ */
370 static const char *getSourceTestData() {
372 const char *srcDataDir
= U_TOPSRCDIR U_FILE_SEP_STRING
"test"U_FILE_SEP_STRING
"testdata"U_FILE_SEP_STRING
;
374 const char *srcDataDir
= ".."U_FILE_SEP_STRING
".."U_FILE_SEP_STRING
"test"U_FILE_SEP_STRING
"testdata"U_FILE_SEP_STRING
;
375 FILE *f
= fopen(".."U_FILE_SEP_STRING
".."U_FILE_SEP_STRING
"test"U_FILE_SEP_STRING
"testdata"U_FILE_SEP_STRING
"rbbitst.txt", "r");
378 /* We're in icu/source/test/letest/ */
381 /* We're in icu/source/test/letest/(Debug|Release) */
382 srcDataDir
= ".."U_FILE_SEP_STRING
".."U_FILE_SEP_STRING
".."U_FILE_SEP_STRING
"test"U_FILE_SEP_STRING
"testdata"U_FILE_SEP_STRING
;
389 static const char *getPath(char buffer
[2048], const char *filename
) {
390 const char *testDataDirectory
= getSourceTestData();
392 strcpy(buffer
, testDataDirectory
);
393 strcat(buffer
, filename
);
398 static le_font
*openFont(const char *fontName
, const char *checksum
, const char *version
, const char *testID
)
402 LEErrorCode fontStatus
= LE_NO_ERROR
;
404 if (fontName
!= NULL
) {
405 font
= le_portableFontOpen(getPath(path
, fontName
), 12, &fontStatus
);
407 if (LE_FAILURE(fontStatus
)) {
408 log_info("Test %s: can't open font %s - test skipped.\n", testID
, fontName
);
414 sscanf(checksum
, "%x", &cksum
);
416 checkFontVersion(font
, version
, cksum
, testID
);
419 font
= le_simpleFontOpen(12, &fontStatus
);
425 static le_bool
getRTL(const LEUnicode
*text
, le_int32 charCount
)
429 UErrorCode status
= U_ZERO_ERROR
;
430 UBiDi
*ubidi
= ubidi_openSized(charCount
, 0, &status
);
432 ubidi_setPara(ubidi
, text
, charCount
, UBIDI_DEFAULT_LTR
, NULL
, &status
);
434 /* TODO: Should check that there's only a single logical run... */
435 ubidi_getLogicalRun(ubidi
, 0, &limit
, &level
);
442 static void doTestCase (const char *testID
,
443 const char *fontName
,
444 const char *fontVersion
,
445 const char *fontChecksum
,
447 le_int32 languageCode
,
448 const LEUnicode
*text
,
450 TestResult
*expected
)
452 LEErrorCode status
= LE_NO_ERROR
;
454 le_font
*font
= openFont(fontName
, fontChecksum
, fontVersion
, testID
);
455 le_int32 typoFlags
= 3; /* kerning + ligatures */
459 /* error message already printed. */
463 if (fontName
== NULL
) {
464 typoFlags
|= 0x80000000L
; /* use CharSubstitutionFilter... */
467 engine
= le_create(font
, scriptCode
, languageCode
, typoFlags
, &status
);
469 if (LE_FAILURE(status
)) {
470 log_err("Test %s: could not create a LayoutEngine.\n", testID
);
474 actual
.glyphCount
= le_layoutChars(engine
, text
, 0, charCount
, charCount
, getRTL(text
, charCount
), 0, 0, &status
);
476 actual
.glyphs
= NEW_ARRAY(LEGlyphID
, actual
.glyphCount
);
477 actual
.indices
= NEW_ARRAY(le_int32
, actual
.glyphCount
);
478 actual
.positions
= NEW_ARRAY(float, actual
.glyphCount
* 2 + 2);
480 le_getGlyphs(engine
, actual
.glyphs
, &status
);
481 le_getCharIndices(engine
, actual
.indices
, &status
);
482 le_getGlyphPositions(engine
, actual
.positions
, &status
);
484 compareResults(testID
, expected
, &actual
);
486 DELETE_ARRAY(actual
.positions
);
487 DELETE_ARRAY(actual
.indices
);
488 DELETE_ARRAY(actual
.glyphs
);
496 static void U_CALLCONV
DataDrivenTest(void)
499 const char *testFilePath
= getPath(path
, "letest.xml");
501 readTestFile(testFilePath
, doTestCase
);
507 * Build a paragraph that contains a mixture of left to right and right to left text.
508 * Break it into multiple lines and make sure that the glyphToCharMap for run in each
511 * Note: it might be a good idea to also check the glyphs and positions for each run,
512 * that we get the expected number of runs per line and that the line breaks are where
513 * we expect them to be. Really, it would be a good idea to make a whole test suite
516 static void U_CALLCONV
GlyphToCharTest(void)
518 #if !UCONFIG_NO_BREAK_ITERATION
519 LEErrorCode status
= LE_NO_ERROR
;
521 pl_fontRuns
*fontRuns
;
522 pl_paragraph
*paragraph
;
525 * This is the same text that's in <icu>/source/samples/layout/Sample.txt
527 LEUnicode chars
[] = {
528 /*BOM*/ 0x0054, 0x0068, 0x0065, 0x0020, 0x004c, 0x0061, 0x0079,
529 0x006f, 0x0075, 0x0074, 0x0045, 0x006e, 0x0067, 0x0069, 0x006e,
530 0x0065, 0x0020, 0x0064, 0x006f, 0x0065, 0x0073, 0x0020, 0x0061,
531 0x006c, 0x006c, 0x0020, 0x0074, 0x0068, 0x0065, 0x0020, 0x0077,
532 0x006f, 0x0072, 0x006b, 0x0020, 0x006e, 0x0065, 0x0063, 0x0065,
533 0x0073, 0x0073, 0x0061, 0x0072, 0x0079, 0x0020, 0x0074, 0x006f,
534 0x0020, 0x0064, 0x0069, 0x0073, 0x0070, 0x006c, 0x0061, 0x0079,
535 0x0020, 0x0055, 0x006e, 0x0069, 0x0063, 0x006f, 0x0064, 0x0065,
536 0x0020, 0x0074, 0x0065, 0x0078, 0x0074, 0x0020, 0x0077, 0x0072,
537 0x0069, 0x0074, 0x0074, 0x0065, 0x006e, 0x0020, 0x0069, 0x006e,
538 0x0020, 0x006c, 0x0061, 0x006e, 0x0067, 0x0075, 0x0061, 0x0067,
539 0x0065, 0x0073, 0x0020, 0x0077, 0x0069, 0x0074, 0x0068, 0x0020,
540 0x0063, 0x006f, 0x006d, 0x0070, 0x006c, 0x0065, 0x0078, 0x0020,
541 0x0077, 0x0072, 0x0069, 0x0074, 0x0069, 0x006e, 0x0067, 0x0020,
542 0x0073, 0x0079, 0x0073, 0x0074, 0x0065, 0x006d, 0x0073, 0x0020,
543 0x0073, 0x0075, 0x0063, 0x0068, 0x0020, 0x0061, 0x0073, 0x0020,
544 0x0048, 0x0069, 0x006e, 0x0064, 0x0069, 0x0020, 0x0028, 0x0939,
545 0x093f, 0x0928, 0x094d, 0x0926, 0x0940, 0x0029, 0x0020, 0x0054,
546 0x0068, 0x0061, 0x0069, 0x0020, 0x0028, 0x0e44, 0x0e17, 0x0e22,
547 0x0029, 0x0020, 0x0061, 0x006e, 0x0064, 0x0020, 0x0041, 0x0072,
548 0x0061, 0x0062, 0x0069, 0x0063, 0x0020, 0x0028, 0x0627, 0x0644,
549 0x0639, 0x0631, 0x0628, 0x064a, 0x0629, 0x0029, 0x002e, 0x0020,
550 0x0048, 0x0065, 0x0072, 0x0065, 0x0027, 0x0073, 0x0020, 0x0061,
551 0x0020, 0x0073, 0x0061, 0x006d, 0x0070, 0x006c, 0x0065, 0x0020,
552 0x006f, 0x0066, 0x0020, 0x0073, 0x006f, 0x006d, 0x0065, 0x0020,
553 0x0074, 0x0065, 0x0078, 0x0074, 0x0020, 0x0077, 0x0072, 0x0069,
554 0x0074, 0x0074, 0x0065, 0x006e, 0x0020, 0x0069, 0x006e, 0x0020,
555 0x0053, 0x0061, 0x006e, 0x0073, 0x006b, 0x0072, 0x0069, 0x0074,
556 0x003a, 0x0020, 0x0936, 0x094d, 0x0930, 0x0940, 0x092e, 0x0926,
557 0x094d, 0x0020, 0x092d, 0x0917, 0x0935, 0x0926, 0x094d, 0x0917,
558 0x0940, 0x0924, 0x093e, 0x0020, 0x0905, 0x0927, 0x094d, 0x092f,
559 0x093e, 0x092f, 0x0020, 0x0905, 0x0930, 0x094d, 0x091c, 0x0941,
560 0x0928, 0x0020, 0x0935, 0x093f, 0x0937, 0x093e, 0x0926, 0x0020,
561 0x092f, 0x094b, 0x0917, 0x0020, 0x0927, 0x0943, 0x0924, 0x0930,
562 0x093e, 0x0937, 0x094d, 0x091f, 0x094d, 0x0930, 0x0020, 0x0909,
563 0x0935, 0x093e, 0x091a, 0x0964, 0x0020, 0x0927, 0x0930, 0x094d,
564 0x092e, 0x0915, 0x094d, 0x0937, 0x0947, 0x0924, 0x094d, 0x0930,
565 0x0947, 0x0020, 0x0915, 0x0941, 0x0930, 0x0941, 0x0915, 0x094d,
566 0x0937, 0x0947, 0x0924, 0x094d, 0x0930, 0x0947, 0x0020, 0x0938,
567 0x092e, 0x0935, 0x0947, 0x0924, 0x093e, 0x0020, 0x092f, 0x0941,
568 0x092f, 0x0941, 0x0924, 0x094d, 0x0938, 0x0935, 0x0903, 0x0020,
569 0x092e, 0x093e, 0x092e, 0x0915, 0x093e, 0x0903, 0x0020, 0x092a,
570 0x093e, 0x0923, 0x094d, 0x0921, 0x0935, 0x093e, 0x0936, 0x094d,
571 0x091a, 0x0948, 0x0935, 0x0020, 0x0915, 0x093f, 0x092e, 0x0915,
572 0x0941, 0x0930, 0x094d, 0x0935, 0x0924, 0x0020, 0x0938, 0x0902,
573 0x091c, 0x092f, 0x0020, 0x0048, 0x0065, 0x0072, 0x0065, 0x0027,
574 0x0073, 0x0020, 0x0061, 0x0020, 0x0073, 0x0061, 0x006d, 0x0070,
575 0x006c, 0x0065, 0x0020, 0x006f, 0x0066, 0x0020, 0x0073, 0x006f,
576 0x006d, 0x0065, 0x0020, 0x0074, 0x0065, 0x0078, 0x0074, 0x0020,
577 0x0077, 0x0072, 0x0069, 0x0074, 0x0074, 0x0065, 0x006e, 0x0020,
578 0x0069, 0x006e, 0x0020, 0x0041, 0x0072, 0x0061, 0x0062, 0x0069,
579 0x0063, 0x003a, 0x0020, 0x0623, 0x0633, 0x0627, 0x0633, 0x064b,
580 0x0627, 0x060c, 0x0020, 0x062a, 0x062a, 0x0639, 0x0627, 0x0645,
581 0x0644, 0x0020, 0x0627, 0x0644, 0x062d, 0x0648, 0x0627, 0x0633,
582 0x064a, 0x0628, 0x0020, 0x0641, 0x0642, 0x0637, 0x0020, 0x0645,
583 0x0639, 0x0020, 0x0627, 0x0644, 0x0623, 0x0631, 0x0642, 0x0627,
584 0x0645, 0x060c, 0x0020, 0x0648, 0x062a, 0x0642, 0x0648, 0x0645,
585 0x0020, 0x0628, 0x062a, 0x062e, 0x0632, 0x064a, 0x0646, 0x0020,
586 0x0627, 0x0644, 0x0623, 0x062d, 0x0631, 0x0641, 0x0020, 0x0648,
587 0x0627, 0x0644, 0x0645, 0x062d, 0x0627, 0x0631, 0x0641, 0x0020,
588 0x0627, 0x0644, 0x0623, 0x062e, 0x0631, 0x0649, 0x0020, 0x0628,
589 0x0639, 0x062f, 0x0020, 0x0623, 0x0646, 0x0020, 0x062a, 0x064f,
590 0x0639, 0x0637, 0x064a, 0x0020, 0x0631, 0x0642, 0x0645, 0x0627,
591 0x0020, 0x0645, 0x0639, 0x064a, 0x0646, 0x0627, 0x0020, 0x0644,
592 0x0643, 0x0644, 0x0020, 0x0648, 0x0627, 0x062d, 0x062f, 0x0020,
593 0x0645, 0x0646, 0x0647, 0x0627, 0x002e, 0x0020, 0x0648, 0x0642,
594 0x0628, 0x0644, 0x0020, 0x0627, 0x062e, 0x062a, 0x0631, 0x0627,
595 0x0639, 0x0020, 0x0022, 0x064a, 0x0648, 0x0646, 0x0650, 0x0643,
596 0x0648, 0x062f, 0x0022, 0x060c, 0x0020, 0x0643, 0x0627, 0x0646,
597 0x0020, 0x0647, 0x0646, 0x0627, 0x0643, 0x0020, 0x0645, 0x0626,
598 0x0627, 0x062a, 0x0020, 0x0627, 0x0644, 0x0623, 0x0646, 0x0638,
599 0x0645, 0x0629, 0x0020, 0x0644, 0x0644, 0x062a, 0x0634, 0x0641,
600 0x064a, 0x0631, 0x0020, 0x0648, 0x062a, 0x062e, 0x0635, 0x064a,
601 0x0635, 0x0020, 0x0647, 0x0630, 0x0647, 0x0020, 0x0627, 0x0644,
602 0x0623, 0x0631, 0x0642, 0x0627, 0x0645, 0x0020, 0x0644, 0x0644,
603 0x0645, 0x062d, 0x0627, 0x0631, 0x0641, 0x060c, 0x0020, 0x0648,
604 0x0644, 0x0645, 0x0020, 0x064a, 0x0648, 0x062c, 0x062f, 0x0020,
605 0x0646, 0x0638, 0x0627, 0x0645, 0x0020, 0x062a, 0x0634, 0x0641,
606 0x064a, 0x0631, 0x0020, 0x0648, 0x0627, 0x062d, 0x062f, 0x0020,
607 0x064a, 0x062d, 0x062a, 0x0648, 0x064a, 0x0020, 0x0639, 0x0644,
608 0x0649, 0x0020, 0x062c, 0x0645, 0x064a, 0x0639, 0x0020, 0x0627,
609 0x0644, 0x0645, 0x062d, 0x0627, 0x0631, 0x0641, 0x0020, 0x0627,
610 0x0644, 0x0636, 0x0631, 0x0648, 0x0631, 0x064a, 0x0629, 0x0020,
611 0x0061, 0x006e, 0x0064, 0x0020, 0x0068, 0x0065, 0x0072, 0x0065,
612 0x0027, 0x0073, 0x0020, 0x0061, 0x0020, 0x0073, 0x0061, 0x006d,
613 0x0070, 0x006c, 0x0065, 0x0020, 0x006f, 0x0066, 0x0020, 0x0073,
614 0x006f, 0x006d, 0x0065, 0x0020, 0x0074, 0x0065, 0x0078, 0x0074,
615 0x0020, 0x0077, 0x0072, 0x0069, 0x0074, 0x0074, 0x0065, 0x006e,
616 0x0020, 0x0069, 0x006e, 0x0020, 0x0054, 0x0068, 0x0061, 0x0069,
617 0x003a, 0x0020, 0x0e1a, 0x0e17, 0x0e17, 0x0e35, 0x0e48, 0x0e51,
618 0x0e1e, 0x0e32, 0x0e22, 0x0e38, 0x0e44, 0x0e0b, 0x0e42, 0x0e04,
619 0x0e25, 0x0e19, 0x0e42, 0x0e14, 0x0e42, 0x0e23, 0x0e18, 0x0e35,
620 0x0e2d, 0x0e32, 0x0e28, 0x0e31, 0x0e22, 0x0e2d, 0x0e22, 0x0e39,
621 0x0e48, 0x0e17, 0x0e48, 0x0e32, 0x0e21, 0x0e01, 0x0e25, 0x0e32,
622 0x0e07, 0x0e17, 0x0e38, 0x0e48, 0x0e07, 0x0e43, 0x0e2b, 0x0e0d,
623 0x0e48, 0x0e43, 0x0e19, 0x0e41, 0x0e04, 0x0e19, 0x0e0b, 0x0e31,
624 0x0e2a, 0x0e01, 0x0e31, 0x0e1a, 0x0e25, 0x0e38, 0x0e07, 0x0e40,
625 0x0e2e, 0x0e19, 0x0e23, 0x0e35, 0x0e0a, 0x0e32, 0x0e27, 0x0e44,
626 0x0e23, 0x0e48, 0x0e41, 0x0e25, 0x0e30, 0x0e1b, 0x0e49, 0x0e32,
627 0x0e40, 0x0e2d, 0x0e47, 0x0e21, 0x0e20, 0x0e23, 0x0e23, 0x0e22,
628 0x0e32, 0x0e0a, 0x0e32, 0x0e27, 0x0e44, 0x0e23, 0x0e48, 0x0e1a,
629 0x0e49, 0x0e32, 0x0e19, 0x0e02, 0x0e2d, 0x0e07, 0x0e1e, 0x0e27,
630 0x0e01, 0x0e40, 0x0e02, 0x0e32, 0x0e2b, 0x0e25, 0x0e31, 0x0e07,
631 0x0e40, 0x0e25, 0x0e47, 0x0e01, 0x0e40, 0x0e1e, 0x0e23, 0x0e32,
632 0x0e30, 0x0e44, 0x0e21, 0x0e49, 0x0e2a, 0x0e23, 0x0e49, 0x0e32,
633 0x0e07, 0x0e1a, 0x0e49, 0x0e32, 0x0e19, 0x0e15, 0x0e49, 0x0e2d,
634 0x0e07, 0x0e02, 0x0e19, 0x0e21, 0x0e32, 0x0e14, 0x0e49, 0x0e27,
635 0x0e22, 0x0e40, 0x0e01, 0x0e27, 0x0e35, 0x0e22, 0x0e19, 0x0e40,
636 0x0e1b, 0x0e47, 0x0e19, 0x0e23, 0x0e30, 0x0e22, 0x0e30, 0x0e17,
637 0x0e32, 0x0e07, 0x0e2b, 0x0e25, 0x0e32, 0x0e22, 0x0e44, 0x0e21,
640 le_int32 charCount
= LE_ARRAY_SIZE(chars
);
641 le_int32 charIndex
= 0, lineNumber
= 1;
643 const float lineWidth
= 600;
645 font
= le_simpleFontOpen(12, &status
);
647 if (LE_FAILURE(status
)) {
648 log_err("le_simpleFontOpen(12, &status) failed");
652 fontRuns
= pl_openEmptyFontRuns(0);
653 pl_addFontRun(fontRuns
, font
, charCount
);
655 paragraph
= pl_create(chars
, charCount
, fontRuns
, NULL
, NULL
, NULL
, 0, FALSE
, &status
);
657 pl_closeFontRuns(fontRuns
);
659 if (LE_FAILURE(status
)) {
660 log_err("pl_create failed.");
664 pl_reflow(paragraph
);
665 while ((line
= pl_nextLine(paragraph
, lineWidth
)) != NULL
) {
666 le_int32 runCount
= pl_countLineRuns(line
);
668 for(run
= 0; run
< runCount
; run
+= 1) {
669 const pl_visualRun
*visualRun
= pl_getLineVisualRun(line
, run
);
670 const le_int32 glyphCount
= pl_getVisualRunGlyphCount(visualRun
);
671 const le_int32
*glyphToCharMap
= pl_getVisualRunGlyphToCharMap(visualRun
);
673 if (pl_getVisualRunDirection(visualRun
) == UBIDI_RTL
) {
675 * For a right to left run, make sure that the character indices
676 * increase from the right most glyph to the left most glyph. If
677 * there are any one to many glyph substitutions, we might get several
678 * glyphs in a row with the same character index.
680 for(i
= glyphCount
- 1; i
>= 0; i
-= 1) {
681 le_int32 ix
= glyphToCharMap
[i
];
683 if (ix
!= charIndex
) {
684 if (ix
!= charIndex
- 1) {
685 log_err("Bad glyph to char index for glyph %d on line %d: expected %d, got %d\n",
686 i
, lineNumber
, charIndex
, ix
);
687 goto close_paragraph
; /* once there's one error, we can't count on anything else... */
695 * We can't just check the order of the character indices
696 * for left to right runs because Indic text might have been
697 * reordered. What we can do is find the minimum and maximum
698 * character indices in the run and make sure that the minimum
699 * is equal to charIndex and then advance charIndex to the maximum.
701 le_int32 minIndex
= 0x7FFFFFFF, maxIndex
= -1;
703 for(i
= 0; i
< glyphCount
; i
+= 1) {
704 le_int32 ix
= glyphToCharMap
[i
];
715 if (minIndex
!= charIndex
) {
716 log_err("Bad minIndex for run %d on line %d: expected %d, got %d\n",
717 run
, lineNumber
, charIndex
, minIndex
);
718 goto close_paragraph
; /* once there's one error, we can't count on anything else... */
721 charIndex
= maxIndex
+ 1;
739 U_CFUNC
void addCTests(TestNode
**root
)
741 addTest(root
, &ParamTest
, "c_api/ParameterTest");
742 addTest(root
, &FactoryTest
, "c_api/FactoryTest");
743 addTest(root
, &AccessTest
, "c_layout/AccessTest");
744 addTest(root
, &DataDrivenTest
, "c_layout/DataDrivenTest");
745 addTest(root
, &GlyphToCharTest
, "c_paragraph/GlyphToCharTest");