2 *******************************************************************************
4 * Copyright (C) 1999-2014, International Business Machines
5 * Corporation and others. All Rights Reserved.
7 *******************************************************************************
10 #include "unicode/utypes.h"
11 #include "unicode/ubidi.h"
12 #include "unicode/uscript.h"
13 #include "unicode/ctest.h"
15 #include "layout/LETypes.h"
16 #include "layout/LEScripts.h"
17 #include "layout/loengine.h"
19 #include "layout/playout.h"
20 #include "layout/plruns.h"
27 #include "xmlreader.h"
28 #include "putilimp.h" /* for U_FILE_SEP_STRING */
34 #define CH_COMMA 0x002C
37 static void U_CALLCONV
ParamTest(void)
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;
47 float x
= 0.0, y
= 0.0;
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." */
55 glyphCount
= le_getGlyphCount(engine
, &status
);
56 if (glyphCount
!= 0) {
57 log_err("Calling getGlyphCount() on an empty layout returned %d.\n", glyphCount
);
60 glyphs
= NEW_ARRAY(LEGlyphID
, glyphCount
+ 10);
61 indices
= NEW_ARRAY(le_int32
, glyphCount
+ 10);
62 positions
= NEW_ARRAY(float, glyphCount
+ 10);
64 le_getGlyphs(engine
, NULL
, &status
);
66 if (status
!= LE_ILLEGAL_ARGUMENT_ERROR
) {
67 log_err("Calling getGlyphs(NULL, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n");
71 le_getGlyphs(engine
, glyphs
, &status
);
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");
78 le_getCharIndices(engine
, NULL
, &status
);
80 if (status
!= LE_ILLEGAL_ARGUMENT_ERROR
) {
81 log_err("Calling getCharIndices(NULL, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n");
85 le_getCharIndices(engine
, indices
, &status
);
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");
92 le_getCharIndicesWithBase(engine
, NULL
, 1024, &status
);
94 if (status
!= LE_ILLEGAL_ARGUMENT_ERROR
) {
95 log_err("Calling getCharIndices(NULL, 1024, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n");
99 le_getCharIndicesWithBase(engine
, indices
, 1024, &status
);
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");
105 status
= LE_NO_ERROR
;
106 le_getGlyphPositions(engine
, NULL
, &status
);
108 if (status
!= LE_ILLEGAL_ARGUMENT_ERROR
) {
109 log_err("Calling getGlyphPositions(NULL, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n");
112 status
= LE_NO_ERROR
;
113 le_getGlyphPositions(engine
, positions
, &status
);
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");
119 DELETE_ARRAY(positions
);
120 DELETE_ARRAY(indices
);
121 DELETE_ARRAY(glyphs
);
123 status
= LE_NO_ERROR
;
124 glyphCount
= le_layoutChars(engine
, NULL
, 0, 0, 0, FALSE
, 0.0, 0.0, &status
);
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");
130 status
= LE_NO_ERROR
;
131 glyphCount
= le_layoutChars(engine
, chars
, -1, 6, 20, TRUE
, 0.0, 0.0, &status
);
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");
137 status
= LE_NO_ERROR
;
138 glyphCount
= le_layoutChars(engine
, chars
, 8, -1, 20, TRUE
, 0.0, 0.0, &status
);
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");
144 status
= LE_NO_ERROR
;
145 glyphCount
= le_layoutChars(engine
, chars
, 8, 6, -1, TRUE
, 0.0, 0.0, &status
);
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");
151 status
= LE_NO_ERROR
;
152 glyphCount
= le_layoutChars(engine
, chars
, 8, 6, 10, TRUE
, 0.0, 0.0, &status
);
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");
158 status
= LE_NO_ERROR
;
159 glyphCount
= le_layoutChars(engine
, chars
, 8, 6, 20, TRUE
, 0.0, 0.0, &status
);
161 if (LE_FAILURE(status
)) {
162 log_err("Calling layoutChars(chars, 8, 6, 20, TRUE, 0.0, 0.0, status) failed.\n");
166 le_getGlyphPosition(engine
, -1, &x
, &y
, &status
);
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");
172 status
= LE_NO_ERROR
;
173 le_getGlyphPosition(engine
, glyphCount
+ 1, &x
, &y
, &status
);
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");
186 static void U_CALLCONV
FactoryTest(void)
188 LEErrorCode status
= LE_NO_ERROR
;
189 le_font
*font
= le_simpleFontOpen(12, &status
);
190 le_engine
*engine
= NULL
;
193 for(scriptCode
= 0; scriptCode
< scriptCodeCount
; scriptCode
+= 1) {
194 status
= LE_NO_ERROR
;
195 engine
= le_create(font
, scriptCode
, -1, 0, &status
);
197 if (LE_FAILURE(status
)) {
198 log_err("Could not create a LayoutEngine for script \'%s\'.\n", uscript_getShortName((UScriptCode
)scriptCode
));
209 static void U_CALLCONV
AccessTest(void)
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
);
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." */
224 if (LE_FAILURE(status
)) {
225 log_err("Could not create LayoutEngine.\n");
229 glyphCount
= le_layoutChars(engine
, chars
, 8, 6, 20, TRUE
, 0.0, 0.0, &status
);
231 if (LE_FAILURE(status
) || glyphCount
!= 6) {
232 log_err("layoutChars(chars, 8, 6, 20, TRUE, 0.0, 0.0, status) failed.\n");
236 le_getGlyphs(engine
, glyphs
, &status
);
237 le_getCharIndices(engine
, indices
, &status
);
238 le_getGlyphPositions(engine
, positions
, &status
);
240 if (LE_FAILURE(status
)) {
241 log_err("Could not get glyph, indices and position arrays.\n");
245 status
= LE_NO_ERROR
;
246 le_getCharIndicesWithBase(engine
, biasedIndices
, 1024, &status
);
248 if (LE_FAILURE(status
)) {
249 log_err("getCharIndices(biasedIndices, 1024, status) failed.\n");
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
]);
260 status
= LE_NO_ERROR
;
261 for (glyph
= 0; glyph
<= glyphCount
; glyph
+= 1) {
262 float x
= 0.0, y
= 0.0;
264 le_getGlyphPosition(engine
, glyph
, &x
, &y
, &status
);
266 if (LE_FAILURE(status
)) {
267 log_err("getGlyphPosition(%d, x, y, status) failed.\n", glyph
);
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]);
284 static le_bool
compareResults(const char *testID
, TestResult
*expected
, TestResult
*actual
)
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
);
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
]);
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
]);
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]);
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]);
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]);
335 static void checkFontVersion(le_font
*font
, const char *testVersionString
,
336 le_uint32 testChecksum
, const char *testID
)
338 le_uint32 fontChecksum
= le_getFontChecksum(font
);
340 if (fontChecksum
!= testChecksum
) {
341 const char *fontVersionString
= le_getNameString(font
, NAME_VERSION_STRING
,
342 PLATFORM_MACINTOSH
, MACINTOSH_ROMAN
, MACINTOSH_ENGLISH
);
343 const LEUnicode16
*uFontVersionString
= NULL
;
345 if (fontVersionString
== NULL
) {
346 uFontVersionString
= le_getUnicodeNameString(font
, NAME_VERSION_STRING
,
347 PLATFORM_MICROSOFT
, MICROSOFT_UNICODE_BMP
, MICROSOFT_ENGLISH
);
350 log_info("Test %s: this may not be the same font used to generate the test data.\n", testID
);
352 if (uFontVersionString
!= NULL
) {
353 log_info("Your font's version string is \"%S\"\n", uFontVersionString
);
354 le_deleteUnicodeNameString(font
, uFontVersionString
);
356 log_info("Your font's version string is \"%s\"\n", fontVersionString
);
357 le_deleteNameString(font
, fontVersionString
);
360 log_info("The expected version string is \"%s\"\n", testVersionString
);
361 log_info("If you see errors, they may be due to the version of the font you're using.\n");
365 /* Returns the path to icu/source/test/testdata/ */
366 static const char *getSourceTestData() {
368 const char *srcDataDir
= U_TOPSRCDIR U_FILE_SEP_STRING
"test"U_FILE_SEP_STRING
"testdata"U_FILE_SEP_STRING
;
370 const char *srcDataDir
= ".."U_FILE_SEP_STRING
".."U_FILE_SEP_STRING
"test"U_FILE_SEP_STRING
"testdata"U_FILE_SEP_STRING
;
371 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 /* We're in icu/source/test/letest/ */
377 /* We're in icu/source/test/letest/(Debug|Release) */
378 srcDataDir
= ".."U_FILE_SEP_STRING
".."U_FILE_SEP_STRING
".."U_FILE_SEP_STRING
"test"U_FILE_SEP_STRING
"testdata"U_FILE_SEP_STRING
;
385 static const char *getPath(char buffer
[2048], const char *filename
) {
386 const char *testDataDirectory
= getSourceTestData();
388 strcpy(buffer
, testDataDirectory
);
389 strcat(buffer
, filename
);
394 static le_font
*openFont(const char *fontName
, const char *checksum
, const char *version
, const char *testID
)
398 LEErrorCode fontStatus
= LE_NO_ERROR
;
400 if (fontName
!= NULL
) {
401 font
= le_portableFontOpen(getPath(path
, fontName
), 12, &fontStatus
);
403 if (LE_FAILURE(fontStatus
)) {
404 log_info("Test %s: can't open font %s - test skipped.\n", testID
, fontName
);
410 sscanf(checksum
, "%x", &cksum
);
412 checkFontVersion(font
, version
, cksum
, testID
);
415 font
= le_simpleFontOpen(12, &fontStatus
);
421 static le_bool
getRTL(const LEUnicode
*text
, le_int32 charCount
)
425 UErrorCode status
= U_ZERO_ERROR
;
426 UBiDi
*ubidi
= ubidi_openSized(charCount
, 0, &status
);
428 ubidi_setPara(ubidi
, text
, charCount
, UBIDI_DEFAULT_LTR
, NULL
, &status
);
430 /* TODO: Should check that there's only a single logical run... */
431 ubidi_getLogicalRun(ubidi
, 0, &limit
, &level
);
438 static void doTestCase (const char *testID
,
439 const char *fontName
,
440 const char *fontVersion
,
441 const char *fontChecksum
,
443 le_int32 languageCode
,
444 const LEUnicode
*text
,
446 TestResult
*expected
)
448 LEErrorCode status
= LE_NO_ERROR
;
450 le_font
*font
= openFont(fontName
, fontChecksum
, fontVersion
, testID
);
451 le_int32 typoFlags
= 3; /* kerning + ligatures */
455 /* error message already printed. */
459 if (fontName
== NULL
) {
460 typoFlags
|= 0x80000000L
; /* use CharSubstitutionFilter... */
463 engine
= le_create(font
, scriptCode
, languageCode
, typoFlags
, &status
);
465 if (LE_FAILURE(status
)) {
466 log_err("Test %s: could not create a LayoutEngine.\n", testID
);
470 actual
.glyphCount
= le_layoutChars(engine
, text
, 0, charCount
, charCount
, getRTL(text
, charCount
), 0, 0, &status
);
472 actual
.glyphs
= NEW_ARRAY(LEGlyphID
, actual
.glyphCount
);
473 actual
.indices
= NEW_ARRAY(le_int32
, actual
.glyphCount
);
474 actual
.positions
= NEW_ARRAY(float, actual
.glyphCount
* 2 + 2);
476 le_getGlyphs(engine
, actual
.glyphs
, &status
);
477 le_getCharIndices(engine
, actual
.indices
, &status
);
478 le_getGlyphPositions(engine
, actual
.positions
, &status
);
480 compareResults(testID
, expected
, &actual
);
482 DELETE_ARRAY(actual
.positions
);
483 DELETE_ARRAY(actual
.indices
);
484 DELETE_ARRAY(actual
.glyphs
);
492 static void U_CALLCONV
DataDrivenTest(void)
495 const char *testFilePath
= getPath(path
, "letest.xml");
497 readTestFile(testFilePath
, doTestCase
);
503 * Build a paragraph that contains a mixture of left to right and right to left text.
504 * Break it into multiple lines and make sure that the glyphToCharMap for run in each
507 * Note: it might be a good idea to also check the glyphs and positions for each run,
508 * that we get the expected number of runs per line and that the line breaks are where
509 * we expect them to be. Really, it would be a good idea to make a whole test suite
512 static void U_CALLCONV
GlyphToCharTest(void)
514 #if !UCONFIG_NO_BREAK_ITERATION
515 LEErrorCode status
= LE_NO_ERROR
;
517 pl_fontRuns
*fontRuns
;
518 pl_paragraph
*paragraph
;
521 * This is the same text that's in <icu>/source/samples/layout/Sample.txt
523 LEUnicode chars
[] = {
524 /*BOM*/ 0x0054, 0x0068, 0x0065, 0x0020, 0x004c, 0x0061, 0x0079,
525 0x006f, 0x0075, 0x0074, 0x0045, 0x006e, 0x0067, 0x0069, 0x006e,
526 0x0065, 0x0020, 0x0064, 0x006f, 0x0065, 0x0073, 0x0020, 0x0061,
527 0x006c, 0x006c, 0x0020, 0x0074, 0x0068, 0x0065, 0x0020, 0x0077,
528 0x006f, 0x0072, 0x006b, 0x0020, 0x006e, 0x0065, 0x0063, 0x0065,
529 0x0073, 0x0073, 0x0061, 0x0072, 0x0079, 0x0020, 0x0074, 0x006f,
530 0x0020, 0x0064, 0x0069, 0x0073, 0x0070, 0x006c, 0x0061, 0x0079,
531 0x0020, 0x0055, 0x006e, 0x0069, 0x0063, 0x006f, 0x0064, 0x0065,
532 0x0020, 0x0074, 0x0065, 0x0078, 0x0074, 0x0020, 0x0077, 0x0072,
533 0x0069, 0x0074, 0x0074, 0x0065, 0x006e, 0x0020, 0x0069, 0x006e,
534 0x0020, 0x006c, 0x0061, 0x006e, 0x0067, 0x0075, 0x0061, 0x0067,
535 0x0065, 0x0073, 0x0020, 0x0077, 0x0069, 0x0074, 0x0068, 0x0020,
536 0x0063, 0x006f, 0x006d, 0x0070, 0x006c, 0x0065, 0x0078, 0x0020,
537 0x0077, 0x0072, 0x0069, 0x0074, 0x0069, 0x006e, 0x0067, 0x0020,
538 0x0073, 0x0079, 0x0073, 0x0074, 0x0065, 0x006d, 0x0073, 0x0020,
539 0x0073, 0x0075, 0x0063, 0x0068, 0x0020, 0x0061, 0x0073, 0x0020,
540 0x0048, 0x0069, 0x006e, 0x0064, 0x0069, 0x0020, 0x0028, 0x0939,
541 0x093f, 0x0928, 0x094d, 0x0926, 0x0940, 0x0029, 0x0020, 0x0054,
542 0x0068, 0x0061, 0x0069, 0x0020, 0x0028, 0x0e44, 0x0e17, 0x0e22,
543 0x0029, 0x0020, 0x0061, 0x006e, 0x0064, 0x0020, 0x0041, 0x0072,
544 0x0061, 0x0062, 0x0069, 0x0063, 0x0020, 0x0028, 0x0627, 0x0644,
545 0x0639, 0x0631, 0x0628, 0x064a, 0x0629, 0x0029, 0x002e, 0x0020,
546 0x0048, 0x0065, 0x0072, 0x0065, 0x0027, 0x0073, 0x0020, 0x0061,
547 0x0020, 0x0073, 0x0061, 0x006d, 0x0070, 0x006c, 0x0065, 0x0020,
548 0x006f, 0x0066, 0x0020, 0x0073, 0x006f, 0x006d, 0x0065, 0x0020,
549 0x0074, 0x0065, 0x0078, 0x0074, 0x0020, 0x0077, 0x0072, 0x0069,
550 0x0074, 0x0074, 0x0065, 0x006e, 0x0020, 0x0069, 0x006e, 0x0020,
551 0x0053, 0x0061, 0x006e, 0x0073, 0x006b, 0x0072, 0x0069, 0x0074,
552 0x003a, 0x0020, 0x0936, 0x094d, 0x0930, 0x0940, 0x092e, 0x0926,
553 0x094d, 0x0020, 0x092d, 0x0917, 0x0935, 0x0926, 0x094d, 0x0917,
554 0x0940, 0x0924, 0x093e, 0x0020, 0x0905, 0x0927, 0x094d, 0x092f,
555 0x093e, 0x092f, 0x0020, 0x0905, 0x0930, 0x094d, 0x091c, 0x0941,
556 0x0928, 0x0020, 0x0935, 0x093f, 0x0937, 0x093e, 0x0926, 0x0020,
557 0x092f, 0x094b, 0x0917, 0x0020, 0x0927, 0x0943, 0x0924, 0x0930,
558 0x093e, 0x0937, 0x094d, 0x091f, 0x094d, 0x0930, 0x0020, 0x0909,
559 0x0935, 0x093e, 0x091a, 0x0964, 0x0020, 0x0927, 0x0930, 0x094d,
560 0x092e, 0x0915, 0x094d, 0x0937, 0x0947, 0x0924, 0x094d, 0x0930,
561 0x0947, 0x0020, 0x0915, 0x0941, 0x0930, 0x0941, 0x0915, 0x094d,
562 0x0937, 0x0947, 0x0924, 0x094d, 0x0930, 0x0947, 0x0020, 0x0938,
563 0x092e, 0x0935, 0x0947, 0x0924, 0x093e, 0x0020, 0x092f, 0x0941,
564 0x092f, 0x0941, 0x0924, 0x094d, 0x0938, 0x0935, 0x0903, 0x0020,
565 0x092e, 0x093e, 0x092e, 0x0915, 0x093e, 0x0903, 0x0020, 0x092a,
566 0x093e, 0x0923, 0x094d, 0x0921, 0x0935, 0x093e, 0x0936, 0x094d,
567 0x091a, 0x0948, 0x0935, 0x0020, 0x0915, 0x093f, 0x092e, 0x0915,
568 0x0941, 0x0930, 0x094d, 0x0935, 0x0924, 0x0020, 0x0938, 0x0902,
569 0x091c, 0x092f, 0x0020, 0x0048, 0x0065, 0x0072, 0x0065, 0x0027,
570 0x0073, 0x0020, 0x0061, 0x0020, 0x0073, 0x0061, 0x006d, 0x0070,
571 0x006c, 0x0065, 0x0020, 0x006f, 0x0066, 0x0020, 0x0073, 0x006f,
572 0x006d, 0x0065, 0x0020, 0x0074, 0x0065, 0x0078, 0x0074, 0x0020,
573 0x0077, 0x0072, 0x0069, 0x0074, 0x0074, 0x0065, 0x006e, 0x0020,
574 0x0069, 0x006e, 0x0020, 0x0041, 0x0072, 0x0061, 0x0062, 0x0069,
575 0x0063, 0x003a, 0x0020, 0x0623, 0x0633, 0x0627, 0x0633, 0x064b,
576 0x0627, 0x060c, 0x0020, 0x062a, 0x062a, 0x0639, 0x0627, 0x0645,
577 0x0644, 0x0020, 0x0627, 0x0644, 0x062d, 0x0648, 0x0627, 0x0633,
578 0x064a, 0x0628, 0x0020, 0x0641, 0x0642, 0x0637, 0x0020, 0x0645,
579 0x0639, 0x0020, 0x0627, 0x0644, 0x0623, 0x0631, 0x0642, 0x0627,
580 0x0645, 0x060c, 0x0020, 0x0648, 0x062a, 0x0642, 0x0648, 0x0645,
581 0x0020, 0x0628, 0x062a, 0x062e, 0x0632, 0x064a, 0x0646, 0x0020,
582 0x0627, 0x0644, 0x0623, 0x062d, 0x0631, 0x0641, 0x0020, 0x0648,
583 0x0627, 0x0644, 0x0645, 0x062d, 0x0627, 0x0631, 0x0641, 0x0020,
584 0x0627, 0x0644, 0x0623, 0x062e, 0x0631, 0x0649, 0x0020, 0x0628,
585 0x0639, 0x062f, 0x0020, 0x0623, 0x0646, 0x0020, 0x062a, 0x064f,
586 0x0639, 0x0637, 0x064a, 0x0020, 0x0631, 0x0642, 0x0645, 0x0627,
587 0x0020, 0x0645, 0x0639, 0x064a, 0x0646, 0x0627, 0x0020, 0x0644,
588 0x0643, 0x0644, 0x0020, 0x0648, 0x0627, 0x062d, 0x062f, 0x0020,
589 0x0645, 0x0646, 0x0647, 0x0627, 0x002e, 0x0020, 0x0648, 0x0642,
590 0x0628, 0x0644, 0x0020, 0x0627, 0x062e, 0x062a, 0x0631, 0x0627,
591 0x0639, 0x0020, 0x0022, 0x064a, 0x0648, 0x0646, 0x0650, 0x0643,
592 0x0648, 0x062f, 0x0022, 0x060c, 0x0020, 0x0643, 0x0627, 0x0646,
593 0x0020, 0x0647, 0x0646, 0x0627, 0x0643, 0x0020, 0x0645, 0x0626,
594 0x0627, 0x062a, 0x0020, 0x0627, 0x0644, 0x0623, 0x0646, 0x0638,
595 0x0645, 0x0629, 0x0020, 0x0644, 0x0644, 0x062a, 0x0634, 0x0641,
596 0x064a, 0x0631, 0x0020, 0x0648, 0x062a, 0x062e, 0x0635, 0x064a,
597 0x0635, 0x0020, 0x0647, 0x0630, 0x0647, 0x0020, 0x0627, 0x0644,
598 0x0623, 0x0631, 0x0642, 0x0627, 0x0645, 0x0020, 0x0644, 0x0644,
599 0x0645, 0x062d, 0x0627, 0x0631, 0x0641, 0x060c, 0x0020, 0x0648,
600 0x0644, 0x0645, 0x0020, 0x064a, 0x0648, 0x062c, 0x062f, 0x0020,
601 0x0646, 0x0638, 0x0627, 0x0645, 0x0020, 0x062a, 0x0634, 0x0641,
602 0x064a, 0x0631, 0x0020, 0x0648, 0x0627, 0x062d, 0x062f, 0x0020,
603 0x064a, 0x062d, 0x062a, 0x0648, 0x064a, 0x0020, 0x0639, 0x0644,
604 0x0649, 0x0020, 0x062c, 0x0645, 0x064a, 0x0639, 0x0020, 0x0627,
605 0x0644, 0x0645, 0x062d, 0x0627, 0x0631, 0x0641, 0x0020, 0x0627,
606 0x0644, 0x0636, 0x0631, 0x0648, 0x0631, 0x064a, 0x0629, 0x0020,
607 0x0061, 0x006e, 0x0064, 0x0020, 0x0068, 0x0065, 0x0072, 0x0065,
608 0x0027, 0x0073, 0x0020, 0x0061, 0x0020, 0x0073, 0x0061, 0x006d,
609 0x0070, 0x006c, 0x0065, 0x0020, 0x006f, 0x0066, 0x0020, 0x0073,
610 0x006f, 0x006d, 0x0065, 0x0020, 0x0074, 0x0065, 0x0078, 0x0074,
611 0x0020, 0x0077, 0x0072, 0x0069, 0x0074, 0x0074, 0x0065, 0x006e,
612 0x0020, 0x0069, 0x006e, 0x0020, 0x0054, 0x0068, 0x0061, 0x0069,
613 0x003a, 0x0020, 0x0e1a, 0x0e17, 0x0e17, 0x0e35, 0x0e48, 0x0e51,
614 0x0e1e, 0x0e32, 0x0e22, 0x0e38, 0x0e44, 0x0e0b, 0x0e42, 0x0e04,
615 0x0e25, 0x0e19, 0x0e42, 0x0e14, 0x0e42, 0x0e23, 0x0e18, 0x0e35,
616 0x0e2d, 0x0e32, 0x0e28, 0x0e31, 0x0e22, 0x0e2d, 0x0e22, 0x0e39,
617 0x0e48, 0x0e17, 0x0e48, 0x0e32, 0x0e21, 0x0e01, 0x0e25, 0x0e32,
618 0x0e07, 0x0e17, 0x0e38, 0x0e48, 0x0e07, 0x0e43, 0x0e2b, 0x0e0d,
619 0x0e48, 0x0e43, 0x0e19, 0x0e41, 0x0e04, 0x0e19, 0x0e0b, 0x0e31,
620 0x0e2a, 0x0e01, 0x0e31, 0x0e1a, 0x0e25, 0x0e38, 0x0e07, 0x0e40,
621 0x0e2e, 0x0e19, 0x0e23, 0x0e35, 0x0e0a, 0x0e32, 0x0e27, 0x0e44,
622 0x0e23, 0x0e48, 0x0e41, 0x0e25, 0x0e30, 0x0e1b, 0x0e49, 0x0e32,
623 0x0e40, 0x0e2d, 0x0e47, 0x0e21, 0x0e20, 0x0e23, 0x0e23, 0x0e22,
624 0x0e32, 0x0e0a, 0x0e32, 0x0e27, 0x0e44, 0x0e23, 0x0e48, 0x0e1a,
625 0x0e49, 0x0e32, 0x0e19, 0x0e02, 0x0e2d, 0x0e07, 0x0e1e, 0x0e27,
626 0x0e01, 0x0e40, 0x0e02, 0x0e32, 0x0e2b, 0x0e25, 0x0e31, 0x0e07,
627 0x0e40, 0x0e25, 0x0e47, 0x0e01, 0x0e40, 0x0e1e, 0x0e23, 0x0e32,
628 0x0e30, 0x0e44, 0x0e21, 0x0e49, 0x0e2a, 0x0e23, 0x0e49, 0x0e32,
629 0x0e07, 0x0e1a, 0x0e49, 0x0e32, 0x0e19, 0x0e15, 0x0e49, 0x0e2d,
630 0x0e07, 0x0e02, 0x0e19, 0x0e21, 0x0e32, 0x0e14, 0x0e49, 0x0e27,
631 0x0e22, 0x0e40, 0x0e01, 0x0e27, 0x0e35, 0x0e22, 0x0e19, 0x0e40,
632 0x0e1b, 0x0e47, 0x0e19, 0x0e23, 0x0e30, 0x0e22, 0x0e30, 0x0e17,
633 0x0e32, 0x0e07, 0x0e2b, 0x0e25, 0x0e32, 0x0e22, 0x0e44, 0x0e21,
636 le_int32 charCount
= LE_ARRAY_SIZE(chars
);
637 le_int32 charIndex
= 0, lineNumber
= 1;
639 const float lineWidth
= 600;
641 font
= le_simpleFontOpen(12, &status
);
643 if (LE_FAILURE(status
)) {
644 log_err("le_simpleFontOpen(12, &status) failed");
648 fontRuns
= pl_openEmptyFontRuns(0);
649 pl_addFontRun(fontRuns
, font
, charCount
);
651 paragraph
= pl_create(chars
, charCount
, fontRuns
, NULL
, NULL
, NULL
, 0, FALSE
, &status
);
653 pl_closeFontRuns(fontRuns
);
655 if (LE_FAILURE(status
)) {
656 log_err("pl_create failed.");
660 pl_reflow(paragraph
);
661 while ((line
= pl_nextLine(paragraph
, lineWidth
)) != NULL
) {
662 le_int32 runCount
= pl_countLineRuns(line
);
664 for(run
= 0; run
< runCount
; run
+= 1) {
665 const pl_visualRun
*visualRun
= pl_getLineVisualRun(line
, run
);
666 const le_int32 glyphCount
= pl_getVisualRunGlyphCount(visualRun
);
667 const le_int32
*glyphToCharMap
= pl_getVisualRunGlyphToCharMap(visualRun
);
669 if (pl_getVisualRunDirection(visualRun
) == UBIDI_RTL
) {
671 * For a right to left run, make sure that the character indices
672 * increase from the right most glyph to the left most glyph. If
673 * there are any one to many glyph substitutions, we might get several
674 * glyphs in a row with the same character index.
676 for(i
= glyphCount
- 1; i
>= 0; i
-= 1) {
677 le_int32 ix
= glyphToCharMap
[i
];
679 if (ix
!= charIndex
) {
680 if (ix
!= charIndex
- 1) {
681 log_err("Bad glyph to char index for glyph %d on line %d: expected %d, got %d\n",
682 i
, lineNumber
, charIndex
, ix
);
683 goto close_paragraph
; /* once there's one error, we can't count on anything else... */
691 * We can't just check the order of the character indices
692 * for left to right runs because Indic text might have been
693 * reordered. What we can do is find the minimum and maximum
694 * character indices in the run and make sure that the minimum
695 * is equal to charIndex and then advance charIndex to the maximum.
697 le_int32 minIndex
= 0x7FFFFFFF, maxIndex
= -1;
699 for(i
= 0; i
< glyphCount
; i
+= 1) {
700 le_int32 ix
= glyphToCharMap
[i
];
711 if (minIndex
!= charIndex
) {
712 log_err("Bad minIndex for run %d on line %d: expected %d, got %d\n",
713 run
, lineNumber
, charIndex
, minIndex
);
714 goto close_paragraph
; /* once there's one error, we can't count on anything else... */
717 charIndex
= maxIndex
+ 1;
735 U_CFUNC
void addCTests(TestNode
**root
)
737 addTest(root
, &ParamTest
, "c_api/ParameterTest");
738 addTest(root
, &FactoryTest
, "c_api/FactoryTest");
739 addTest(root
, &AccessTest
, "c_layout/AccessTest");
740 addTest(root
, &DataDrivenTest
, "c_layout/DataDrivenTest");
741 addTest(root
, &GlyphToCharTest
, "c_paragraph/GlyphToCharTest");