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