2 *******************************************************************************
4 * Copyright (C) 1999-2014, International Business Machines
5 * Corporation and others. All Rights Reserved.
7 *******************************************************************************
10 #ifndef USING_ICULEHB /* C API not available under HB */
12 #include "unicode/utypes.h"
13 #include "unicode/ubidi.h"
14 #include "unicode/uscript.h"
15 #include "unicode/ctest.h"
17 #include "layout/LETypes.h"
18 #include "layout/LEScripts.h"
19 #include "layout/loengine.h"
21 #include "layout/playout.h"
22 #include "layout/plruns.h"
29 #include "xmlreader.h"
30 #include "putilimp.h" /* for U_FILE_SEP_STRING */
36 #define CH_COMMA 0x002C
39 static void U_CALLCONV
ParamTest(void)
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;
49 float x
= 0.0, y
= 0.0;
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." */
57 glyphCount
= le_getGlyphCount(engine
, &status
);
58 if (glyphCount
!= 0) {
59 log_err("Calling getGlyphCount() on an empty layout returned %d.\n", glyphCount
);
62 glyphs
= NEW_ARRAY(LEGlyphID
, glyphCount
+ 10);
63 indices
= NEW_ARRAY(le_int32
, glyphCount
+ 10);
64 positions
= NEW_ARRAY(float, glyphCount
+ 10);
66 le_getGlyphs(engine
, NULL
, &status
);
68 if (status
!= LE_ILLEGAL_ARGUMENT_ERROR
) {
69 log_err("Calling getGlyphs(NULL, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n");
73 le_getGlyphs(engine
, glyphs
, &status
);
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");
80 le_getCharIndices(engine
, NULL
, &status
);
82 if (status
!= LE_ILLEGAL_ARGUMENT_ERROR
) {
83 log_err("Calling getCharIndices(NULL, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n");
87 le_getCharIndices(engine
, indices
, &status
);
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");
94 le_getCharIndicesWithBase(engine
, NULL
, 1024, &status
);
96 if (status
!= LE_ILLEGAL_ARGUMENT_ERROR
) {
97 log_err("Calling getCharIndices(NULL, 1024, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n");
100 status
= LE_NO_ERROR
;
101 le_getCharIndicesWithBase(engine
, indices
, 1024, &status
);
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");
107 status
= LE_NO_ERROR
;
108 le_getGlyphPositions(engine
, NULL
, &status
);
110 if (status
!= LE_ILLEGAL_ARGUMENT_ERROR
) {
111 log_err("Calling getGlyphPositions(NULL, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n");
114 status
= LE_NO_ERROR
;
115 le_getGlyphPositions(engine
, positions
, &status
);
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");
121 DELETE_ARRAY(positions
);
122 DELETE_ARRAY(indices
);
123 DELETE_ARRAY(glyphs
);
125 status
= LE_NO_ERROR
;
126 glyphCount
= le_layoutChars(engine
, NULL
, 0, 0, 0, FALSE
, 0.0, 0.0, &status
);
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");
132 status
= LE_NO_ERROR
;
133 glyphCount
= le_layoutChars(engine
, chars
, -1, 6, 20, TRUE
, 0.0, 0.0, &status
);
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");
139 status
= LE_NO_ERROR
;
140 glyphCount
= le_layoutChars(engine
, chars
, 8, -1, 20, TRUE
, 0.0, 0.0, &status
);
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");
146 status
= LE_NO_ERROR
;
147 glyphCount
= le_layoutChars(engine
, chars
, 8, 6, -1, TRUE
, 0.0, 0.0, &status
);
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");
153 status
= LE_NO_ERROR
;
154 glyphCount
= le_layoutChars(engine
, chars
, 8, 6, 10, TRUE
, 0.0, 0.0, &status
);
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");
160 status
= LE_NO_ERROR
;
161 glyphCount
= le_layoutChars(engine
, chars
, 8, 6, 20, TRUE
, 0.0, 0.0, &status
);
163 if (LE_FAILURE(status
)) {
164 log_err("Calling layoutChars(chars, 8, 6, 20, TRUE, 0.0, 0.0, status) failed.\n");
168 le_getGlyphPosition(engine
, -1, &x
, &y
, &status
);
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");
174 status
= LE_NO_ERROR
;
175 le_getGlyphPosition(engine
, glyphCount
+ 1, &x
, &y
, &status
);
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");
188 static void U_CALLCONV
FactoryTest(void)
190 LEErrorCode status
= LE_NO_ERROR
;
191 le_font
*font
= le_simpleFontOpen(12, &status
);
192 le_engine
*engine
= NULL
;
195 for(scriptCode
= 0; scriptCode
< scriptCodeCount
; scriptCode
+= 1) {
196 status
= LE_NO_ERROR
;
197 engine
= le_create(font
, scriptCode
, -1, 0, &status
);
199 if (LE_FAILURE(status
)) {
200 log_err("Could not create a LayoutEngine for script \'%s\'.\n", uscript_getShortName((UScriptCode
)scriptCode
));
211 static void U_CALLCONV
AccessTest(void)
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
);
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." */
226 if (LE_FAILURE(status
)) {
227 log_err("Could not create LayoutEngine.\n");
231 glyphCount
= le_layoutChars(engine
, chars
, 8, 6, 20, TRUE
, 0.0, 0.0, &status
);
233 if (LE_FAILURE(status
) || glyphCount
!= 6) {
234 log_err("layoutChars(chars, 8, 6, 20, TRUE, 0.0, 0.0, status) failed.\n");
238 le_getGlyphs(engine
, glyphs
, &status
);
239 le_getCharIndices(engine
, indices
, &status
);
240 le_getGlyphPositions(engine
, positions
, &status
);
242 if (LE_FAILURE(status
)) {
243 log_err("Could not get glyph, indices and position arrays.\n");
247 status
= LE_NO_ERROR
;
248 le_getCharIndicesWithBase(engine
, biasedIndices
, 1024, &status
);
250 if (LE_FAILURE(status
)) {
251 log_err("getCharIndices(biasedIndices, 1024, status) failed.\n");
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
]);
262 status
= LE_NO_ERROR
;
263 for (glyph
= 0; glyph
<= glyphCount
; glyph
+= 1) {
264 float x
= 0.0, y
= 0.0;
266 le_getGlyphPosition(engine
, glyph
, &x
, &y
, &status
);
268 if (LE_FAILURE(status
)) {
269 log_err("getGlyphPosition(%d, x, y, status) failed.\n", glyph
);
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]);
286 static le_bool
compareResults(const char *testID
, TestResult
*expected
, TestResult
*actual
)
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
);
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
]);
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
]);
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]);
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]);
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]);
337 static void checkFontVersion(le_font
*font
, const char *testVersionString
,
338 le_uint32 testChecksum
, const char *testID
)
340 le_uint32 fontChecksum
= le_getFontChecksum(font
);
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
;
347 if (fontVersionString
== NULL
) {
348 uFontVersionString
= le_getUnicodeNameString(font
, NAME_VERSION_STRING
,
349 PLATFORM_MICROSOFT
, MICROSOFT_UNICODE_BMP
, MICROSOFT_ENGLISH
);
352 log_info("Test %s: this may not be the same font used to generate the test data.\n", testID
);
354 if (uFontVersionString
!= NULL
) {
355 log_info("Your font's version string is \"%S\"\n", uFontVersionString
);
356 le_deleteUnicodeNameString(font
, uFontVersionString
);
358 log_info("Your font's version string is \"%s\"\n", fontVersionString
);
359 le_deleteNameString(font
, fontVersionString
);
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");
367 /* Returns the path to icu/source/test/testdata/ */
368 static const char *getSourceTestData() {
370 const char *srcDataDir
= U_TOPSRCDIR U_FILE_SEP_STRING
"test"U_FILE_SEP_STRING
"testdata"U_FILE_SEP_STRING
;
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");
376 /* We're in icu/source/test/letest/ */
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
;
387 static const char *getPath(char buffer
[2048], const char *filename
) {
388 const char *testDataDirectory
= getSourceTestData();
390 strcpy(buffer
, testDataDirectory
);
391 strcat(buffer
, filename
);
396 static le_font
*openFont(const char *fontName
, const char *checksum
, const char *version
, const char *testID
)
400 LEErrorCode fontStatus
= LE_NO_ERROR
;
402 if (fontName
!= NULL
) {
403 font
= le_portableFontOpen(getPath(path
, fontName
), 12, &fontStatus
);
405 if (LE_FAILURE(fontStatus
)) {
406 log_info("Test %s: can't open font %s - test skipped.\n", testID
, fontName
);
412 sscanf(checksum
, "%x", &cksum
);
414 checkFontVersion(font
, version
, cksum
, testID
);
417 font
= le_simpleFontOpen(12, &fontStatus
);
423 static le_bool
getRTL(const LEUnicode
*text
, le_int32 charCount
)
427 UErrorCode status
= U_ZERO_ERROR
;
428 UBiDi
*ubidi
= ubidi_openSized(charCount
, 0, &status
);
430 ubidi_setPara(ubidi
, text
, charCount
, UBIDI_DEFAULT_LTR
, NULL
, &status
);
432 /* TODO: Should check that there's only a single logical run... */
433 ubidi_getLogicalRun(ubidi
, 0, &limit
, &level
);
440 static void doTestCase (const char *testID
,
441 const char *fontName
,
442 const char *fontVersion
,
443 const char *fontChecksum
,
445 le_int32 languageCode
,
446 const LEUnicode
*text
,
448 TestResult
*expected
)
450 LEErrorCode status
= LE_NO_ERROR
;
452 le_font
*font
= openFont(fontName
, fontChecksum
, fontVersion
, testID
);
453 le_int32 typoFlags
= 3; /* kerning + ligatures */
457 /* error message already printed. */
461 if (fontName
== NULL
) {
462 typoFlags
|= 0x80000000L
; /* use CharSubstitutionFilter... */
465 engine
= le_create(font
, scriptCode
, languageCode
, typoFlags
, &status
);
467 if (LE_FAILURE(status
)) {
468 log_err("Test %s: could not create a LayoutEngine.\n", testID
);
472 actual
.glyphCount
= le_layoutChars(engine
, text
, 0, charCount
, charCount
, getRTL(text
, charCount
), 0, 0, &status
);
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);
478 le_getGlyphs(engine
, actual
.glyphs
, &status
);
479 le_getCharIndices(engine
, actual
.indices
, &status
);
480 le_getGlyphPositions(engine
, actual
.positions
, &status
);
482 compareResults(testID
, expected
, &actual
);
484 DELETE_ARRAY(actual
.positions
);
485 DELETE_ARRAY(actual
.indices
);
486 DELETE_ARRAY(actual
.glyphs
);
494 static void U_CALLCONV
DataDrivenTest(void)
497 const char *testFilePath
= getPath(path
, "letest.xml");
499 readTestFile(testFilePath
, doTestCase
);
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
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
514 static void U_CALLCONV
GlyphToCharTest(void)
516 #if !UCONFIG_NO_BREAK_ITERATION
517 LEErrorCode status
= LE_NO_ERROR
;
519 pl_fontRuns
*fontRuns
;
520 pl_paragraph
*paragraph
;
523 * This is the same text that's in <icu>/source/samples/layout/Sample.txt
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,
638 le_int32 charCount
= LE_ARRAY_SIZE(chars
);
639 le_int32 charIndex
= 0, lineNumber
= 1;
641 const float lineWidth
= 600;
643 font
= le_simpleFontOpen(12, &status
);
645 if (LE_FAILURE(status
)) {
646 log_err("le_simpleFontOpen(12, &status) failed");
650 fontRuns
= pl_openEmptyFontRuns(0);
651 pl_addFontRun(fontRuns
, font
, charCount
);
653 paragraph
= pl_create(chars
, charCount
, fontRuns
, NULL
, NULL
, NULL
, 0, FALSE
, &status
);
655 pl_closeFontRuns(fontRuns
);
657 if (LE_FAILURE(status
)) {
658 log_err("pl_create failed.");
662 pl_reflow(paragraph
);
663 while ((line
= pl_nextLine(paragraph
, lineWidth
)) != NULL
) {
664 le_int32 runCount
= pl_countLineRuns(line
);
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
);
671 if (pl_getVisualRunDirection(visualRun
) == UBIDI_RTL
) {
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.
678 for(i
= glyphCount
- 1; i
>= 0; i
-= 1) {
679 le_int32 ix
= glyphToCharMap
[i
];
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... */
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.
699 le_int32 minIndex
= 0x7FFFFFFF, maxIndex
= -1;
701 for(i
= 0; i
< glyphCount
; i
+= 1) {
702 le_int32 ix
= glyphToCharMap
[i
];
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... */
719 charIndex
= maxIndex
+ 1;
737 U_CFUNC
void addCTests(TestNode
**root
)
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");