OLD | NEW |
| (Empty) |
1 /* | |
2 ******************************************************************************* | |
3 * | |
4 * Copyright (C) 1999-2014, International Business Machines | |
5 * Corporation and others. All Rights Reserved. | |
6 * | |
7 ******************************************************************************* | |
8 * file name: letest.cpp | |
9 * | |
10 * created on: 11/06/2000 | |
11 * created by: Eric R. Mader | |
12 */ | |
13 | |
14 #include "unicode/utypes.h" | |
15 #include "unicode/uclean.h" | |
16 #include "unicode/uchar.h" | |
17 #include "unicode/unistr.h" | |
18 #include "unicode/uscript.h" | |
19 #include "unicode/putil.h" | |
20 #include "unicode/ctest.h" | |
21 | |
22 #include "layout/LETypes.h" | |
23 #include "layout/LEScripts.h" | |
24 #include "layout/LayoutEngine.h" | |
25 | |
26 #include "layout/ParagraphLayout.h" | |
27 #include "layout/RunArrays.h" | |
28 | |
29 #include "PortableFontInstance.h" | |
30 #include "SimpleFontInstance.h" | |
31 | |
32 #include "letsutil.h" | |
33 #include "letest.h" | |
34 | |
35 #include "xmlparser.h" | |
36 #include "putilimp.h" // for uprv_getUTCtime() | |
37 | |
38 #include <stdlib.h> | |
39 #include <string.h> | |
40 | |
41 U_NAMESPACE_USE | |
42 | |
43 #define CH_COMMA 0x002C | |
44 | |
45 U_CDECL_BEGIN | |
46 | |
47 static void U_CALLCONV ScriptTest(void) | |
48 { | |
49 if ((int)scriptCodeCount != (int)USCRIPT_CODE_LIMIT) { | |
50 log_err("ScriptCodes::scriptCodeCount = %d, but UScriptCode::USCRIPT_COD
E_LIMIT = %d\n", scriptCodeCount, USCRIPT_CODE_LIMIT); | |
51 } | |
52 } | |
53 | |
54 static void U_CALLCONV ParamTest(void) | |
55 { | |
56 LEErrorCode status = LE_NO_ERROR; | |
57 SimpleFontInstance *font = new SimpleFontInstance(12, status); | |
58 LayoutEngine *engine = LayoutEngine::layoutEngineFactory(font, arabScriptCod
e, -1, status); | |
59 LEGlyphID *glyphs = NULL; | |
60 le_int32 *indices = NULL; | |
61 float *positions = NULL; | |
62 le_int32 glyphCount = 0; | |
63 | |
64 glyphCount = engine->getGlyphCount(); | |
65 if (glyphCount != 0) { | |
66 log_err("Calling getGlyphCount() on an empty layout returned %d.\n", gly
phCount); | |
67 } | |
68 | |
69 glyphs = NEW_ARRAY(LEGlyphID, glyphCount + 10); | |
70 indices = NEW_ARRAY(le_int32, glyphCount + 10); | |
71 positions = NEW_ARRAY(float, glyphCount + 10); | |
72 | |
73 engine->getGlyphs(NULL, status); | |
74 | |
75 if (status != LE_ILLEGAL_ARGUMENT_ERROR) { | |
76 log_err("Calling getGlyphs(NULL, status) did not return LE_ILLEGAL_ARGUM
ENT_ERROR.\n"); | |
77 } | |
78 | |
79 status = LE_NO_ERROR; | |
80 engine->getGlyphs(glyphs, status); | |
81 | |
82 if (status != LE_NO_LAYOUT_ERROR) { | |
83 log_err("Calling getGlyphs(glyphs, status) on an empty layout did not re
turn LE_NO_LAYOUT_ERROR.\n"); | |
84 } | |
85 | |
86 status = LE_NO_ERROR; | |
87 engine->getGlyphs(NULL, 0xFF000000L, status); | |
88 | |
89 if (status != LE_ILLEGAL_ARGUMENT_ERROR) { | |
90 log_err("Calling getGlyphs(NULL, 0xFF000000L, status) did not return LE_
ILLEGAL_ARGUMENT_ERROR.\n"); | |
91 } | |
92 | |
93 status = LE_NO_ERROR; | |
94 engine->getGlyphs(glyphs, 0xFF000000L, status); | |
95 | |
96 if (status != LE_NO_LAYOUT_ERROR) { | |
97 log_err("Calling getGlyphs(glyphs, 0xFF000000L, status) on an empty layo
ut did not return LE_NO_LAYOUT_ERROR.\n"); | |
98 } | |
99 | |
100 status = LE_NO_ERROR; | |
101 engine->getCharIndices(NULL, status); | |
102 | |
103 if (status != LE_ILLEGAL_ARGUMENT_ERROR) { | |
104 log_err("Calling getCharIndices(NULL, status) did not return LE_ILLEGAL_
ARGUMENT_ERROR.\n"); | |
105 } | |
106 | |
107 status = LE_NO_ERROR; | |
108 engine->getCharIndices(indices, status); | |
109 | |
110 if (status != LE_NO_LAYOUT_ERROR) { | |
111 log_err("Calling getCharIndices(indices, status) on an empty layout did
not return LE_NO_LAYOUT_ERROR.\n"); | |
112 } | |
113 | |
114 status = LE_NO_ERROR; | |
115 engine->getCharIndices(NULL, 1024, status); | |
116 | |
117 if (status != LE_ILLEGAL_ARGUMENT_ERROR) { | |
118 log_err("Calling getCharIndices(NULL, 1024, status) did not return LE_IL
LEGAL_ARGUMENT_ERROR.\n"); | |
119 } | |
120 | |
121 status = LE_NO_ERROR; | |
122 engine->getCharIndices(indices, 1024, status); | |
123 | |
124 if (status != LE_NO_LAYOUT_ERROR) { | |
125 log_err("Calling getCharIndices(indices, 1024, status) on an empty layou
t did not return LE_NO_LAYOUT_ERROR.\n"); | |
126 } | |
127 | |
128 status = LE_NO_ERROR; | |
129 engine->getGlyphPositions(NULL, status); | |
130 | |
131 if (status != LE_ILLEGAL_ARGUMENT_ERROR) { | |
132 log_err("Calling getGlyphPositions(NULL, status) did not return LE_ILLEG
AL_ARGUMENT_ERROR.\n"); | |
133 } | |
134 | |
135 status = LE_NO_ERROR; | |
136 engine->getGlyphPositions(positions, status); | |
137 | |
138 if (status != LE_NO_LAYOUT_ERROR) { | |
139 log_err("Calling getGlyphPositions(positions, status) on an empty layout
did not return LE_NO_LAYOUT_ERROR.\n"); | |
140 } | |
141 | |
142 DELETE_ARRAY(positions); | |
143 DELETE_ARRAY(indices); | |
144 DELETE_ARRAY(glyphs); | |
145 | |
146 status = LE_NO_ERROR; | |
147 glyphCount = engine->layoutChars(NULL, 0, 0, 0, FALSE, 0.0, 0.0, status); | |
148 | |
149 if (status != LE_ILLEGAL_ARGUMENT_ERROR) { | |
150 log_err("Calling layoutChars(NULL, 0, 0, 0, FALSE, 0.0, 0.0, status) did
not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n"); | |
151 } | |
152 | |
153 LEUnicode chars[] = { | |
154 0x0045, 0x006E, 0x0067, 0x006C, 0x0069, 0x0073, 0x0068, 0x0020, // "Engl
ish " | |
155 0x0645, 0x0627, 0x0646, 0x062A, 0x0648, 0x0634, // MEM A
LIF KAF NOON TEH WAW SHEEN | |
156 0x0020, 0x0074, 0x0065, 0x0078, 0x0074, 0x02E // " tex
t." | |
157 }; | |
158 | |
159 status = LE_NO_ERROR; | |
160 glyphCount = engine->layoutChars(chars, -1, 6, 20, TRUE, 0.0, 0.0, status); | |
161 | |
162 if (status != LE_ILLEGAL_ARGUMENT_ERROR) { | |
163 log_err("Calling layoutChars(chars, -1, 6, 20, TRUE, 0.0, 0.0, status) d
id not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n"); | |
164 } | |
165 | |
166 status = LE_NO_ERROR; | |
167 glyphCount = engine->layoutChars(chars, 8, -1, 20, TRUE, 0.0, 0.0, status); | |
168 | |
169 if (status != LE_ILLEGAL_ARGUMENT_ERROR) { | |
170 log_err("Calling layoutChars(chars, 8, -1, 20, TRUE, 0.0, 0.0, status) d
id not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n"); | |
171 } | |
172 | |
173 status = LE_NO_ERROR; | |
174 glyphCount = engine->layoutChars(chars, 8, 6, -1, TRUE, 0.0, 0.0, status); | |
175 | |
176 if (status != LE_ILLEGAL_ARGUMENT_ERROR) { | |
177 log_err("Calling layoutChars((chars, 8, 6, -1, TRUE, 0.0, 0.0, status) d
id not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n"); | |
178 } | |
179 | |
180 status = LE_NO_ERROR; | |
181 glyphCount = engine->layoutChars(chars, 8, 6, 10, TRUE, 0.0, 0.0, status); | |
182 | |
183 if (status != LE_ILLEGAL_ARGUMENT_ERROR) { | |
184 log_err("Calling layoutChars(chars, 8, 6, 10, TRUE, 0.0, 0.0, status) di
d not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n"); | |
185 } | |
186 | |
187 float x = 0.0, y = 0.0; | |
188 | |
189 status = LE_NO_ERROR; | |
190 glyphCount = engine->layoutChars(chars, 8, 6, 20, TRUE, 0.0, 0.0, status); | |
191 | |
192 if (LE_FAILURE(status)) { | |
193 log_err("Calling layoutChars(chars, 8, 6, 20, TRUE, 0.0, 0.0, status) fa
iled.\n"); | |
194 goto bail; | |
195 } | |
196 | |
197 engine->getGlyphPosition(-1, x, y, status); | |
198 | |
199 if (status != LE_INDEX_OUT_OF_BOUNDS_ERROR) { | |
200 log_err("Calling getGlyphPosition(-1, x, y, status) did not fail w/ LE_I
NDEX_OUT_OF_BOUNDS_ERROR.\n"); | |
201 } | |
202 | |
203 status = LE_NO_ERROR; | |
204 engine->getGlyphPosition(glyphCount + 1, x, y, status); | |
205 | |
206 if (status != LE_INDEX_OUT_OF_BOUNDS_ERROR) { | |
207 log_err("Calling getGlyphPosition(glyphCount + 1, x, y, status) did not
fail w/ LE_INDEX_OUT_OF_BOUNDS_ERROR.\n"); | |
208 } | |
209 | |
210 bail: | |
211 delete engine; | |
212 delete font; | |
213 } | |
214 U_CDECL_END | |
215 | |
216 U_CDECL_BEGIN | |
217 static void U_CALLCONV FactoryTest(void) | |
218 { | |
219 LEErrorCode status = LE_NO_ERROR; | |
220 SimpleFontInstance *font = new SimpleFontInstance(12, status); | |
221 LayoutEngine *engine = NULL; | |
222 | |
223 for(le_int32 scriptCode = 0; scriptCode < scriptCodeCount; scriptCode += 1)
{ | |
224 status = LE_NO_ERROR; | |
225 engine = LayoutEngine::layoutEngineFactory(font, scriptCode, -1, status)
; | |
226 | |
227 if (LE_FAILURE(status)) { | |
228 log_err("Could not create a LayoutEngine for script \'%s\'.\n", uscr
ipt_getShortName((UScriptCode)scriptCode)); | |
229 } | |
230 | |
231 delete engine; | |
232 } | |
233 | |
234 delete font; | |
235 } | |
236 U_CDECL_END | |
237 | |
238 U_CDECL_BEGIN | |
239 static void U_CALLCONV AccessTest(void) | |
240 { | |
241 LEErrorCode status = LE_NO_ERROR; | |
242 SimpleFontInstance *font = new SimpleFontInstance(12, status); | |
243 LayoutEngine *engine = LayoutEngine::layoutEngineFactory(font, arabScriptCod
e, -1, status); | |
244 le_int32 glyphCount; | |
245 LEGlyphID glyphs[6], extraBitGlyphs[6];; | |
246 le_int32 biasedIndices[6], indices[6], glyph; | |
247 float positions[6 * 2 + 2]; | |
248 LEUnicode chars[] = { | |
249 0x0045, 0x006E, 0x0067, 0x006C, 0x0069, 0x0073, 0x0068, 0x0020, // "Engl
ish " | |
250 0x0645, 0x0627, 0x0646, 0x062A, 0x0648, 0x0634, // MEM A
LIF KAF NOON TEH WAW SHEEN | |
251 0x0020, 0x0074, 0x0065, 0x0078, 0x0074, 0x02E // " tex
t." | |
252 }; | |
253 | |
254 if (LE_FAILURE(status)) { | |
255 log_err("Could not create LayoutEngine.\n"); | |
256 goto bail; | |
257 } | |
258 | |
259 glyphCount = engine->layoutChars(chars, 8, 6, 20, TRUE, 0.0, 0.0, status); | |
260 | |
261 if (LE_FAILURE(status) || glyphCount != 6) { | |
262 log_err("layoutChars(chars, 8, 6, 20, TRUE, 0.0, 0.0, status) failed.\n"
); | |
263 goto bail; | |
264 } | |
265 | |
266 engine->getGlyphs(glyphs, status); | |
267 engine->getCharIndices(indices, status); | |
268 engine->getGlyphPositions(positions, status); | |
269 | |
270 if (LE_FAILURE(status)) { | |
271 log_err("Could not get glyph, indices and position arrays.\n"); | |
272 goto bail; | |
273 } | |
274 | |
275 engine->getGlyphs(extraBitGlyphs, 0xFF000000L, status); | |
276 | |
277 if (LE_FAILURE(status)) { | |
278 log_err("getGlyphs(extraBitGlyphs, 0xFF000000L, status); failed.\n"); | |
279 } else { | |
280 for(glyph = 0; glyph < glyphCount; glyph += 1) { | |
281 if (extraBitGlyphs[glyph] != (glyphs[glyph] | 0xFF000000L)) { | |
282 log_err("extraBigGlyphs[%d] != glyphs[%d] | 0xFF000000L: %8X, %8
X\n", | |
283 glyph, glyph, extraBitGlyphs[glyph], glyphs[glyph]); | |
284 break; | |
285 } | |
286 } | |
287 } | |
288 | |
289 status = LE_NO_ERROR; | |
290 engine->getCharIndices(biasedIndices, 1024, status); | |
291 | |
292 if (LE_FAILURE(status)) { | |
293 log_err("getCharIndices(biasedIndices, 1024, status) failed.\n"); | |
294 } else { | |
295 for (glyph = 0; glyph < glyphCount; glyph += 1) { | |
296 if (biasedIndices[glyph] != (indices[glyph] + 1024)) { | |
297 log_err("biasedIndices[%d] != indices[%d] + 1024: %8X, %8X\n", | |
298 glyph, glyph, biasedIndices[glyph], indices[glyph]); | |
299 break; | |
300 } | |
301 } | |
302 } | |
303 | |
304 status = LE_NO_ERROR; | |
305 for (glyph = 0; glyph <= glyphCount; glyph += 1) { | |
306 float x = 0.0, y = 0.0; | |
307 | |
308 engine->getGlyphPosition(glyph, x, y, status); | |
309 | |
310 if (LE_FAILURE(status)) { | |
311 log_err("getGlyphPosition(%d, x, y, status) failed.\n", glyph); | |
312 break; | |
313 } | |
314 | |
315 if (x != positions[glyph*2] || y != positions[glyph*2 + 1]) { | |
316 log_err("getGlyphPosition(%d, x, y, status) returned bad position: (
%f, %f) != (%f, %f)\n", | |
317 glyph, x, y, positions[glyph*2], positions[glyph*2 + 1]); | |
318 break; | |
319 } | |
320 } | |
321 | |
322 bail: | |
323 delete engine; | |
324 delete font; | |
325 } | |
326 U_CDECL_END | |
327 | |
328 le_bool compareResults(const char *testID, TestResult *expected, TestResult *act
ual) | |
329 { | |
330 /* NOTE: we'll stop on the first failure 'cause once there's one error, it m
ay cascade... */ | |
331 if (actual->glyphCount != expected->glyphCount) { | |
332 log_err("Test %s: incorrect glyph count: exptected %d, got %d\n", | |
333 testID, expected->glyphCount, actual->glyphCount); | |
334 return FALSE; | |
335 } | |
336 | |
337 le_int32 i; | |
338 | |
339 for (i = 0; i < actual->glyphCount; i += 1) { | |
340 if (actual->glyphs[i] != expected->glyphs[i]) { | |
341 log_err("Test %s: incorrect id for glyph %d: expected %4X, got %4X\n
", | |
342 testID, i, expected->glyphs[i], actual->glyphs[i]); | |
343 return FALSE; | |
344 } | |
345 } | |
346 | |
347 for (i = 0; i < actual->glyphCount; i += 1) { | |
348 if (actual->indices[i] != expected->indices[i]) { | |
349 log_err("Test %s: incorrect index for glyph %d: expected %8X, got %8
X\n", | |
350 testID, i, expected->indices[i], actual->indices[i]); | |
351 return FALSE; | |
352 } | |
353 } | |
354 | |
355 for (i = 0; i <= actual->glyphCount; i += 1) { | |
356 double xError = uprv_fabs(actual->positions[i * 2] - expected->positions
[i * 2]); | |
357 | |
358 if (xError > 0.0001) { | |
359 log_err("Test %s: incorrect x position for glyph %d: expected %f, go
t %f\n", | |
360 testID, i, expected->positions[i * 2], actual->positions[i * 2])
; | |
361 return FALSE; | |
362 } | |
363 | |
364 double yError = uprv_fabs(actual->positions[i * 2 + 1] - expected->posit
ions[i * 2 + 1]); | |
365 | |
366 if (yError < 0) { | |
367 yError = -yError; | |
368 } | |
369 | |
370 if (yError > 0.0001) { | |
371 log_err("Test %s: incorrect y position for glyph %d: expected %f, go
t %f\n", | |
372 testID, i, expected->positions[i * 2 + 1], actual->positions[i *
2 + 1]); | |
373 return FALSE; | |
374 } | |
375 } | |
376 | |
377 return TRUE; | |
378 } | |
379 | |
380 static void checkFontVersion(PortableFontInstance *fontInstance, const char *tes
tVersionString, | |
381 le_uint32 testChecksum, const char *testID) | |
382 { | |
383 le_uint32 fontChecksum = fontInstance->getFontChecksum(); | |
384 | |
385 if (fontChecksum != testChecksum) { | |
386 const char *fontVersionString = fontInstance->getNameString(NAME_VERSION
_STRING, | |
387 PLATFORM_MACINTOSH, MACINTOSH_ROMAN, MACINTOSH_ENGLISH); | |
388 const LEUnicode *uFontVersionString = NULL; | |
389 | |
390 // The standard recommends that the Macintosh Roman/English name str
ing be present, but | |
391 // if it's not, try the Microsoft Unicode/English string. | |
392 if (fontVersionString == NULL) { | |
393 uFontVersionString = fontInstance->getUnicodeNameString(NAME_VER
SION_STRING, | |
394 PLATFORM_MICROSOFT, MICROSOFT_UNICODE_BMP, MICROSOFT_ENGLISH
); | |
395 } | |
396 | |
397 log_info("Test %s: this may not be the same font used to generate the te
st data.\n", testID); | |
398 | |
399 if (uFontVersionString != NULL) { | |
400 log_info("Your font's version string is \"%S\"\n", uFontVersionStrin
g); | |
401 fontInstance->deleteNameString(uFontVersionString); | |
402 } else { | |
403 log_info("Your font's version string is \"%s\"\n", fontVersionString
); | |
404 fontInstance->deleteNameString(fontVersionString); | |
405 } | |
406 | |
407 log_info("The expected version string is \"%s\"\n", testVersionString); | |
408 log_info("If you see errors, they may be due to the version of the font
you're using.\n"); | |
409 } | |
410 } | |
411 | |
412 /* Returns the path to icu/source/test/testdata/ */ | |
413 const char *getSourceTestData() { | |
414 const char *srcDataDir = NULL; | |
415 #ifdef U_TOPSRCDIR | |
416 srcDataDir = U_TOPSRCDIR U_FILE_SEP_STRING "test" U_FILE_SEP_STRING "testdat
a" U_FILE_SEP_STRING; | |
417 #else | |
418 srcDataDir = ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING "test" U_FILE_SEP
_STRING "testdata" U_FILE_SEP_STRING; | |
419 FILE *f = fopen(".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING "test" U_FILE_
SEP_STRING "testdata" U_FILE_SEP_STRING "rbbitst.txt", "r"); | |
420 | |
421 if (f != NULL) { | |
422 /* We're in icu/source/test/letest/ */ | |
423 fclose(f); | |
424 } else { | |
425 /* We're in icu/source/test/letest/(Debug|Release) */ | |
426 srcDataDir = ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING ".." U_FILE_
SEP_STRING "test" | |
427 U_FILE_SEP_STRING "testdata" U_FILE_SEP_STRING; | |
428 } | |
429 #endif | |
430 | |
431 return srcDataDir; | |
432 } | |
433 | |
434 const char *getPath(char buffer[2048], const char *filename) { | |
435 const char *testDataDirectory = getSourceTestData(); | |
436 | |
437 strcpy(buffer, testDataDirectory); | |
438 strcat(buffer, filename); | |
439 | |
440 return buffer; | |
441 } | |
442 | |
443 le_uint32 *getHexArray(const UnicodeString &numbers, int32_t &arraySize) | |
444 { | |
445 int32_t offset = -1; | |
446 | |
447 arraySize = 1; | |
448 while((offset = numbers.indexOf(CH_COMMA, offset + 1)) >= 0) { | |
449 arraySize += 1; | |
450 } | |
451 | |
452 le_uint32 *array = NEW_ARRAY(le_uint32, arraySize); | |
453 char number[16]; | |
454 le_int32 count = 0; | |
455 le_int32 start = 0, end = 0; | |
456 le_int32 len = 0; | |
457 | |
458 // trim leading whitespace | |
459 while(u_isUWhiteSpace(numbers[start])) { | |
460 start += 1; | |
461 } | |
462 | |
463 while((end = numbers.indexOf(CH_COMMA, start)) >= 0) { | |
464 len = numbers.extract(start, end - start, number, ARRAY_SIZE(number), US
_INV); | |
465 number[len] = '\0'; | |
466 start = end + 1; | |
467 | |
468 sscanf(number, "%x", &array[count++]); | |
469 | |
470 // trim whitespace following the comma | |
471 while(u_isUWhiteSpace(numbers[start])) { | |
472 start += 1; | |
473 } | |
474 } | |
475 | |
476 // trim trailing whitespace | |
477 end = numbers.length(); | |
478 while(u_isUWhiteSpace(numbers[end - 1])) { | |
479 end -= 1; | |
480 } | |
481 | |
482 len = numbers.extract(start, end - start, number, ARRAY_SIZE(number), US_INV
); | |
483 number[len] = '\0'; | |
484 sscanf(number, "%x", &array[count]); | |
485 | |
486 return array; | |
487 } | |
488 | |
489 float *getFloatArray(const UnicodeString &numbers, int32_t &arraySize) | |
490 { | |
491 int32_t offset = -1; | |
492 | |
493 arraySize = 1; | |
494 while((offset = numbers.indexOf(CH_COMMA, offset + 1)) >= 0) { | |
495 arraySize += 1; | |
496 } | |
497 | |
498 float *array = NEW_ARRAY(float, arraySize); | |
499 char number[32]; | |
500 le_int32 count = 0; | |
501 le_int32 start = 0, end = 0; | |
502 le_int32 len = 0; | |
503 | |
504 // trim leading whitespace | |
505 while(u_isUWhiteSpace(numbers[start])) { | |
506 start += 1; | |
507 } | |
508 | |
509 while((end = numbers.indexOf(CH_COMMA, start)) >= 0) { | |
510 len = numbers.extract(start, end - start, number, ARRAY_SIZE(number), US
_INV); | |
511 number[len] = '\0'; | |
512 start = end + 1; | |
513 | |
514 sscanf(number, "%f", &array[count++]); | |
515 | |
516 // trim whiteapce following the comma | |
517 while(u_isUWhiteSpace(numbers[start])) { | |
518 start += 1; | |
519 } | |
520 } | |
521 | |
522 while(u_isUWhiteSpace(numbers[start])) { | |
523 start += 1; | |
524 } | |
525 | |
526 // trim trailing whitespace | |
527 end = numbers.length(); | |
528 while(u_isUWhiteSpace(numbers[end - 1])) { | |
529 end -= 1; | |
530 } | |
531 | |
532 len = numbers.extract(start, end - start, number, ARRAY_SIZE(number), US_INV
); | |
533 number[len] = '\0'; | |
534 sscanf(number, "%f", &array[count]); | |
535 | |
536 return array; | |
537 } | |
538 | |
539 LEFontInstance *openFont(const char *fontName, const char *checksum, const char
*version, const char *testID) | |
540 { | |
541 char path[2048]; | |
542 PortableFontInstance *font; | |
543 LEErrorCode fontStatus = LE_NO_ERROR; | |
544 | |
545 | |
546 font = new PortableFontInstance(getPath(path, fontName), 12, fontStatus); | |
547 | |
548 if (LE_FAILURE(fontStatus)) { | |
549 log_info("Test %s: can't open font %s - test skipped.\n", testID, fontNa
me); | |
550 delete font; | |
551 return NULL; | |
552 } else { | |
553 le_uint32 cksum = 0; | |
554 | |
555 sscanf(checksum, "%x", &cksum); | |
556 | |
557 checkFontVersion(font, version, cksum, testID); | |
558 } | |
559 | |
560 return font; | |
561 } | |
562 | |
563 U_CDECL_BEGIN | |
564 static void U_CALLCONV DataDrivenTest(void) | |
565 { | |
566 #if !UCONFIG_NO_REGULAR_EXPRESSIONS | |
567 UErrorCode status = U_ZERO_ERROR; | |
568 char path[2048]; | |
569 const char *testFilePath = getPath(path, "letest.xml"); | |
570 | |
571 UXMLParser *parser = UXMLParser::createParser(status); | |
572 UXMLElement *root = parser->parseFile(testFilePath, status); | |
573 | |
574 if (root == NULL) { | |
575 log_err("Could not open the test data file: %s\n", testFilePath); | |
576 delete parser; | |
577 return; | |
578 } | |
579 | |
580 UnicodeString test_case = UNICODE_STRING_SIMPLE("test-case"); | |
581 UnicodeString test_text = UNICODE_STRING_SIMPLE("test-text"); | |
582 UnicodeString test_font = UNICODE_STRING_SIMPLE("test-font"); | |
583 UnicodeString result_glyphs = UNICODE_STRING_SIMPLE("result-glyphs"); | |
584 UnicodeString result_indices = UNICODE_STRING_SIMPLE("result-indices"); | |
585 UnicodeString result_positions = UNICODE_STRING_SIMPLE("result-positions"); | |
586 | |
587 // test-case attributes | |
588 UnicodeString id_attr = UNICODE_STRING_SIMPLE("id"); | |
589 UnicodeString script_attr = UNICODE_STRING_SIMPLE("script"); | |
590 UnicodeString lang_attr = UNICODE_STRING_SIMPLE("lang"); | |
591 | |
592 // test-font attributes | |
593 UnicodeString name_attr = UNICODE_STRING_SIMPLE("name"); | |
594 UnicodeString ver_attr = UNICODE_STRING_SIMPLE("version"); | |
595 UnicodeString cksum_attr = UNICODE_STRING_SIMPLE("checksum"); | |
596 | |
597 const UXMLElement *testCase; | |
598 int32_t tc = 0; | |
599 | |
600 while((testCase = root->nextChildElement(tc)) != NULL) { | |
601 if (testCase->getTagName().compare(test_case) == 0) { | |
602 char *id = getCString(testCase->getAttribute(id_attr)); | |
603 char *script = getCString(testCase->getAttribute(script_attr)); | |
604 char *lang = getCString(testCase->getAttribute(lang_attr)); | |
605 LEFontInstance *font = NULL; | |
606 const UXMLElement *element; | |
607 int32_t ec = 0; | |
608 int32_t charCount = 0; | |
609 int32_t typoFlags = 3; // kerning + ligatures... | |
610 UScriptCode scriptCode; | |
611 le_int32 languageCode = -1; | |
612 UnicodeString text, glyphs, indices, positions; | |
613 int32_t glyphCount = 0, indexCount = 0, positionCount = 0; | |
614 TestResult expected = {0, NULL, NULL, NULL}; | |
615 TestResult actual = {0, NULL, NULL, NULL}; | |
616 LEErrorCode success = LE_NO_ERROR; | |
617 LayoutEngine *engine = NULL; | |
618 | |
619 uscript_getCode(script, &scriptCode, 1, &status); | |
620 if (LE_FAILURE(status)) { | |
621 log_err("invalid script name: %s.\n", script); | |
622 goto free_c_strings; | |
623 } | |
624 | |
625 if (lang != NULL) { | |
626 languageCode = getLanguageCode(lang); | |
627 | |
628 if (languageCode < 0) { | |
629 log_err("invalid language name: %s.\n", lang); | |
630 goto free_c_strings; | |
631 } | |
632 } | |
633 | |
634 while((element = testCase->nextChildElement(ec)) != NULL) { | |
635 UnicodeString tag = element->getTagName(); | |
636 | |
637 // TODO: make sure that each element is only used once. | |
638 if (tag.compare(test_font) == 0) { | |
639 char *fontName = getCString(element->getAttribute(name_attr
)); | |
640 char *fontVer = getCString(element->getAttribute(ver_attr)
); | |
641 char *fontCksum = getCString(element->getAttribute(cksum_att
r)); | |
642 | |
643 font = openFont(fontName, fontCksum, fontVer, id); | |
644 freeCString(fontCksum); | |
645 freeCString(fontVer); | |
646 freeCString(fontName); | |
647 | |
648 if (font == NULL) { | |
649 // warning message already displayed... | |
650 goto free_c_strings; | |
651 } | |
652 } else if (tag.compare(test_text) == 0) { | |
653 text = element->getText(TRUE); | |
654 charCount = text.length(); | |
655 } else if (tag.compare(result_glyphs) == 0) { | |
656 glyphs = element->getText(TRUE); | |
657 } else if (tag.compare(result_indices) == 0) { | |
658 indices = element->getText(TRUE); | |
659 } else if (tag.compare(result_positions) == 0) { | |
660 positions = element->getText(TRUE); | |
661 } else { | |
662 // an unknown tag... | |
663 char *cTag = getCString(&tag); | |
664 | |
665 log_info("Test %s: unknown element with tag \"%s\"\n", id, c
Tag); | |
666 freeCString(cTag); | |
667 } | |
668 } | |
669 | |
670 // TODO: make sure that the font, test-text, result-glyphs, result-i
ndices and result-positions | |
671 // have all been provided | |
672 if (font == NULL) { | |
673 LEErrorCode fontStatus = LE_NO_ERROR; | |
674 | |
675 font = new SimpleFontInstance(12, fontStatus); | |
676 typoFlags |= 0x80000000L; // use CharSubstitutionFilter... | |
677 } | |
678 | |
679 expected.glyphs = (LEGlyphID *) getHexArray(glyphs, glyphCount); | |
680 expected.indices = (le_int32 *) getHexArray(indices, indexCount); | |
681 expected.positions = getFloatArray(positions, positionCount); | |
682 | |
683 expected.glyphCount = glyphCount; | |
684 | |
685 if (glyphCount < charCount || indexCount != glyphCount || positionCo
unt < glyphCount * 2 + 2) { | |
686 log_err("Test %s: inconsistent input data: charCount = %d, glyph
Count = %d, indexCount = %d, positionCount = %d\n", | |
687 id, charCount, glyphCount, indexCount, positionCount); | |
688 goto free_expected; | |
689 }; | |
690 | |
691 engine = LayoutEngine::layoutEngineFactory(font, scriptCode, languag
eCode, typoFlags, success); | |
692 | |
693 if (LE_FAILURE(success)) { | |
694 log_err("Test %s: could not create a LayoutEngine.\n", id); | |
695 goto free_expected; | |
696 } | |
697 | |
698 actual.glyphCount = engine->layoutChars(text.getBuffer(), 0, charCou
nt, charCount, getRTL(text), 0, 0, success); | |
699 | |
700 actual.glyphs = NEW_ARRAY(LEGlyphID, actual.glyphCount); | |
701 actual.indices = NEW_ARRAY(le_int32, actual.glyphCount); | |
702 actual.positions = NEW_ARRAY(float, actual.glyphCount * 2 + 2); | |
703 | |
704 engine->getGlyphs(actual.glyphs, success); | |
705 engine->getCharIndices(actual.indices, success); | |
706 engine->getGlyphPositions(actual.positions, success); | |
707 | |
708 compareResults(id, &expected, &actual); | |
709 | |
710 DELETE_ARRAY(actual.positions); | |
711 DELETE_ARRAY(actual.indices); | |
712 DELETE_ARRAY(actual.glyphs); | |
713 | |
714 delete engine; | |
715 | |
716 log_verbose("OK - %4d glyphs: %s\n", actual.glyphCount, id); | |
717 free_expected: | |
718 DELETE_ARRAY(expected.positions); | |
719 DELETE_ARRAY(expected.indices); | |
720 DELETE_ARRAY(expected.glyphs); | |
721 | |
722 delete font; | |
723 | |
724 free_c_strings: | |
725 freeCString(lang); | |
726 freeCString(script); | |
727 freeCString(id); | |
728 } | |
729 } | |
730 | |
731 delete root; | |
732 delete parser; | |
733 #endif | |
734 } | |
735 U_CDECL_END | |
736 | |
737 U_CDECL_BEGIN | |
738 /* | |
739 * From ticket:5923: | |
740 * | |
741 * Build a paragraph that contains a mixture of left to right and right to left
text. | |
742 * Break it into multiple lines and make sure that the glyphToCharMap for run in
each | |
743 * line is correct. | |
744 * | |
745 * Note: it might be a good idea to also check the glyphs and positions for each
run, | |
746 * that we get the expected number of runs per line and that the line breaks are
where | |
747 * we expect them to be. Really, it would be a good idea to make a whole test su
ite | |
748 * for ParagraphLayout. | |
749 */ | |
750 static void U_CALLCONV GlyphToCharTest(void) | |
751 { | |
752 #if !UCONFIG_NO_BREAK_ITERATION | |
753 LEErrorCode status = LE_NO_ERROR; | |
754 LEFontInstance *font; | |
755 FontRuns fontRuns(0); | |
756 ParagraphLayout *paragraphLayout; | |
757 const ParagraphLayout::Line *line; | |
758 /* | |
759 * This is the same text that's in <icu>/source/samples/layout/Sample.txt | |
760 */ | |
761 LEUnicode chars[] = { | |
762 /*BOM*/ 0x0054, 0x0068, 0x0065, 0x0020, 0x004c, 0x0061, 0x0079, | |
763 0x006f, 0x0075, 0x0074, 0x0045, 0x006e, 0x0067, 0x0069, 0x006e, | |
764 0x0065, 0x0020, 0x0064, 0x006f, 0x0065, 0x0073, 0x0020, 0x0061, | |
765 0x006c, 0x006c, 0x0020, 0x0074, 0x0068, 0x0065, 0x0020, 0x0077, | |
766 0x006f, 0x0072, 0x006b, 0x0020, 0x006e, 0x0065, 0x0063, 0x0065, | |
767 0x0073, 0x0073, 0x0061, 0x0072, 0x0079, 0x0020, 0x0074, 0x006f, | |
768 0x0020, 0x0064, 0x0069, 0x0073, 0x0070, 0x006c, 0x0061, 0x0079, | |
769 0x0020, 0x0055, 0x006e, 0x0069, 0x0063, 0x006f, 0x0064, 0x0065, | |
770 0x0020, 0x0074, 0x0065, 0x0078, 0x0074, 0x0020, 0x0077, 0x0072, | |
771 0x0069, 0x0074, 0x0074, 0x0065, 0x006e, 0x0020, 0x0069, 0x006e, | |
772 0x0020, 0x006c, 0x0061, 0x006e, 0x0067, 0x0075, 0x0061, 0x0067, | |
773 0x0065, 0x0073, 0x0020, 0x0077, 0x0069, 0x0074, 0x0068, 0x0020, | |
774 0x0063, 0x006f, 0x006d, 0x0070, 0x006c, 0x0065, 0x0078, 0x0020, | |
775 0x0077, 0x0072, 0x0069, 0x0074, 0x0069, 0x006e, 0x0067, 0x0020, | |
776 0x0073, 0x0079, 0x0073, 0x0074, 0x0065, 0x006d, 0x0073, 0x0020, | |
777 0x0073, 0x0075, 0x0063, 0x0068, 0x0020, 0x0061, 0x0073, 0x0020, | |
778 0x0048, 0x0069, 0x006e, 0x0064, 0x0069, 0x0020, 0x0028, 0x0939, | |
779 0x093f, 0x0928, 0x094d, 0x0926, 0x0940, 0x0029, 0x0020, 0x0054, | |
780 0x0068, 0x0061, 0x0069, 0x0020, 0x0028, 0x0e44, 0x0e17, 0x0e22, | |
781 0x0029, 0x0020, 0x0061, 0x006e, 0x0064, 0x0020, 0x0041, 0x0072, | |
782 0x0061, 0x0062, 0x0069, 0x0063, 0x0020, 0x0028, 0x0627, 0x0644, | |
783 0x0639, 0x0631, 0x0628, 0x064a, 0x0629, 0x0029, 0x002e, 0x0020, | |
784 0x0048, 0x0065, 0x0072, 0x0065, 0x0027, 0x0073, 0x0020, 0x0061, | |
785 0x0020, 0x0073, 0x0061, 0x006d, 0x0070, 0x006c, 0x0065, 0x0020, | |
786 0x006f, 0x0066, 0x0020, 0x0073, 0x006f, 0x006d, 0x0065, 0x0020, | |
787 0x0074, 0x0065, 0x0078, 0x0074, 0x0020, 0x0077, 0x0072, 0x0069, | |
788 0x0074, 0x0074, 0x0065, 0x006e, 0x0020, 0x0069, 0x006e, 0x0020, | |
789 0x0053, 0x0061, 0x006e, 0x0073, 0x006b, 0x0072, 0x0069, 0x0074, | |
790 0x003a, 0x0020, 0x0936, 0x094d, 0x0930, 0x0940, 0x092e, 0x0926, | |
791 0x094d, 0x0020, 0x092d, 0x0917, 0x0935, 0x0926, 0x094d, 0x0917, | |
792 0x0940, 0x0924, 0x093e, 0x0020, 0x0905, 0x0927, 0x094d, 0x092f, | |
793 0x093e, 0x092f, 0x0020, 0x0905, 0x0930, 0x094d, 0x091c, 0x0941, | |
794 0x0928, 0x0020, 0x0935, 0x093f, 0x0937, 0x093e, 0x0926, 0x0020, | |
795 0x092f, 0x094b, 0x0917, 0x0020, 0x0927, 0x0943, 0x0924, 0x0930, | |
796 0x093e, 0x0937, 0x094d, 0x091f, 0x094d, 0x0930, 0x0020, 0x0909, | |
797 0x0935, 0x093e, 0x091a, 0x0964, 0x0020, 0x0927, 0x0930, 0x094d, | |
798 0x092e, 0x0915, 0x094d, 0x0937, 0x0947, 0x0924, 0x094d, 0x0930, | |
799 0x0947, 0x0020, 0x0915, 0x0941, 0x0930, 0x0941, 0x0915, 0x094d, | |
800 0x0937, 0x0947, 0x0924, 0x094d, 0x0930, 0x0947, 0x0020, 0x0938, | |
801 0x092e, 0x0935, 0x0947, 0x0924, 0x093e, 0x0020, 0x092f, 0x0941, | |
802 0x092f, 0x0941, 0x0924, 0x094d, 0x0938, 0x0935, 0x0903, 0x0020, | |
803 0x092e, 0x093e, 0x092e, 0x0915, 0x093e, 0x0903, 0x0020, 0x092a, | |
804 0x093e, 0x0923, 0x094d, 0x0921, 0x0935, 0x093e, 0x0936, 0x094d, | |
805 0x091a, 0x0948, 0x0935, 0x0020, 0x0915, 0x093f, 0x092e, 0x0915, | |
806 0x0941, 0x0930, 0x094d, 0x0935, 0x0924, 0x0020, 0x0938, 0x0902, | |
807 0x091c, 0x092f, 0x0020, 0x0048, 0x0065, 0x0072, 0x0065, 0x0027, | |
808 0x0073, 0x0020, 0x0061, 0x0020, 0x0073, 0x0061, 0x006d, 0x0070, | |
809 0x006c, 0x0065, 0x0020, 0x006f, 0x0066, 0x0020, 0x0073, 0x006f, | |
810 0x006d, 0x0065, 0x0020, 0x0074, 0x0065, 0x0078, 0x0074, 0x0020, | |
811 0x0077, 0x0072, 0x0069, 0x0074, 0x0074, 0x0065, 0x006e, 0x0020, | |
812 0x0069, 0x006e, 0x0020, 0x0041, 0x0072, 0x0061, 0x0062, 0x0069, | |
813 0x0063, 0x003a, 0x0020, 0x0623, 0x0633, 0x0627, 0x0633, 0x064b, | |
814 0x0627, 0x060c, 0x0020, 0x062a, 0x062a, 0x0639, 0x0627, 0x0645, | |
815 0x0644, 0x0020, 0x0627, 0x0644, 0x062d, 0x0648, 0x0627, 0x0633, | |
816 0x064a, 0x0628, 0x0020, 0x0641, 0x0642, 0x0637, 0x0020, 0x0645, | |
817 0x0639, 0x0020, 0x0627, 0x0644, 0x0623, 0x0631, 0x0642, 0x0627, | |
818 0x0645, 0x060c, 0x0020, 0x0648, 0x062a, 0x0642, 0x0648, 0x0645, | |
819 0x0020, 0x0628, 0x062a, 0x062e, 0x0632, 0x064a, 0x0646, 0x0020, | |
820 0x0627, 0x0644, 0x0623, 0x062d, 0x0631, 0x0641, 0x0020, 0x0648, | |
821 0x0627, 0x0644, 0x0645, 0x062d, 0x0627, 0x0631, 0x0641, 0x0020, | |
822 0x0627, 0x0644, 0x0623, 0x062e, 0x0631, 0x0649, 0x0020, 0x0628, | |
823 0x0639, 0x062f, 0x0020, 0x0623, 0x0646, 0x0020, 0x062a, 0x064f, | |
824 0x0639, 0x0637, 0x064a, 0x0020, 0x0631, 0x0642, 0x0645, 0x0627, | |
825 0x0020, 0x0645, 0x0639, 0x064a, 0x0646, 0x0627, 0x0020, 0x0644, | |
826 0x0643, 0x0644, 0x0020, 0x0648, 0x0627, 0x062d, 0x062f, 0x0020, | |
827 0x0645, 0x0646, 0x0647, 0x0627, 0x002e, 0x0020, 0x0648, 0x0642, | |
828 0x0628, 0x0644, 0x0020, 0x0627, 0x062e, 0x062a, 0x0631, 0x0627, | |
829 0x0639, 0x0020, 0x0022, 0x064a, 0x0648, 0x0646, 0x0650, 0x0643, | |
830 0x0648, 0x062f, 0x0022, 0x060c, 0x0020, 0x0643, 0x0627, 0x0646, | |
831 0x0020, 0x0647, 0x0646, 0x0627, 0x0643, 0x0020, 0x0645, 0x0626, | |
832 0x0627, 0x062a, 0x0020, 0x0627, 0x0644, 0x0623, 0x0646, 0x0638, | |
833 0x0645, 0x0629, 0x0020, 0x0644, 0x0644, 0x062a, 0x0634, 0x0641, | |
834 0x064a, 0x0631, 0x0020, 0x0648, 0x062a, 0x062e, 0x0635, 0x064a, | |
835 0x0635, 0x0020, 0x0647, 0x0630, 0x0647, 0x0020, 0x0627, 0x0644, | |
836 0x0623, 0x0631, 0x0642, 0x0627, 0x0645, 0x0020, 0x0644, 0x0644, | |
837 0x0645, 0x062d, 0x0627, 0x0631, 0x0641, 0x060c, 0x0020, 0x0648, | |
838 0x0644, 0x0645, 0x0020, 0x064a, 0x0648, 0x062c, 0x062f, 0x0020, | |
839 0x0646, 0x0638, 0x0627, 0x0645, 0x0020, 0x062a, 0x0634, 0x0641, | |
840 0x064a, 0x0631, 0x0020, 0x0648, 0x0627, 0x062d, 0x062f, 0x0020, | |
841 0x064a, 0x062d, 0x062a, 0x0648, 0x064a, 0x0020, 0x0639, 0x0644, | |
842 0x0649, 0x0020, 0x062c, 0x0645, 0x064a, 0x0639, 0x0020, 0x0627, | |
843 0x0644, 0x0645, 0x062d, 0x0627, 0x0631, 0x0641, 0x0020, 0x0627, | |
844 0x0644, 0x0636, 0x0631, 0x0648, 0x0631, 0x064a, 0x0629, 0x0020, | |
845 0x0061, 0x006e, 0x0064, 0x0020, 0x0068, 0x0065, 0x0072, 0x0065, | |
846 0x0027, 0x0073, 0x0020, 0x0061, 0x0020, 0x0073, 0x0061, 0x006d, | |
847 0x0070, 0x006c, 0x0065, 0x0020, 0x006f, 0x0066, 0x0020, 0x0073, | |
848 0x006f, 0x006d, 0x0065, 0x0020, 0x0074, 0x0065, 0x0078, 0x0074, | |
849 0x0020, 0x0077, 0x0072, 0x0069, 0x0074, 0x0074, 0x0065, 0x006e, | |
850 0x0020, 0x0069, 0x006e, 0x0020, 0x0054, 0x0068, 0x0061, 0x0069, | |
851 0x003a, 0x0020, 0x0e1a, 0x0e17, 0x0e17, 0x0e35, 0x0e48, 0x0e51, | |
852 0x0e1e, 0x0e32, 0x0e22, 0x0e38, 0x0e44, 0x0e0b, 0x0e42, 0x0e04, | |
853 0x0e25, 0x0e19, 0x0e42, 0x0e14, 0x0e42, 0x0e23, 0x0e18, 0x0e35, | |
854 0x0e2d, 0x0e32, 0x0e28, 0x0e31, 0x0e22, 0x0e2d, 0x0e22, 0x0e39, | |
855 0x0e48, 0x0e17, 0x0e48, 0x0e32, 0x0e21, 0x0e01, 0x0e25, 0x0e32, | |
856 0x0e07, 0x0e17, 0x0e38, 0x0e48, 0x0e07, 0x0e43, 0x0e2b, 0x0e0d, | |
857 0x0e48, 0x0e43, 0x0e19, 0x0e41, 0x0e04, 0x0e19, 0x0e0b, 0x0e31, | |
858 0x0e2a, 0x0e01, 0x0e31, 0x0e1a, 0x0e25, 0x0e38, 0x0e07, 0x0e40, | |
859 0x0e2e, 0x0e19, 0x0e23, 0x0e35, 0x0e0a, 0x0e32, 0x0e27, 0x0e44, | |
860 0x0e23, 0x0e48, 0x0e41, 0x0e25, 0x0e30, 0x0e1b, 0x0e49, 0x0e32, | |
861 0x0e40, 0x0e2d, 0x0e47, 0x0e21, 0x0e20, 0x0e23, 0x0e23, 0x0e22, | |
862 0x0e32, 0x0e0a, 0x0e32, 0x0e27, 0x0e44, 0x0e23, 0x0e48, 0x0e1a, | |
863 0x0e49, 0x0e32, 0x0e19, 0x0e02, 0x0e2d, 0x0e07, 0x0e1e, 0x0e27, | |
864 0x0e01, 0x0e40, 0x0e02, 0x0e32, 0x0e2b, 0x0e25, 0x0e31, 0x0e07, | |
865 0x0e40, 0x0e25, 0x0e47, 0x0e01, 0x0e40, 0x0e1e, 0x0e23, 0x0e32, | |
866 0x0e30, 0x0e44, 0x0e21, 0x0e49, 0x0e2a, 0x0e23, 0x0e49, 0x0e32, | |
867 0x0e07, 0x0e1a, 0x0e49, 0x0e32, 0x0e19, 0x0e15, 0x0e49, 0x0e2d, | |
868 0x0e07, 0x0e02, 0x0e19, 0x0e21, 0x0e32, 0x0e14, 0x0e49, 0x0e27, | |
869 0x0e22, 0x0e40, 0x0e01, 0x0e27, 0x0e35, 0x0e22, 0x0e19, 0x0e40, | |
870 0x0e1b, 0x0e47, 0x0e19, 0x0e23, 0x0e30, 0x0e22, 0x0e30, 0x0e17, | |
871 0x0e32, 0x0e07, 0x0e2b, 0x0e25, 0x0e32, 0x0e22, 0x0e44, 0x0e21, | |
872 0x0e25, 0x0e4c | |
873 }; | |
874 le_int32 charCount = LE_ARRAY_SIZE(chars); | |
875 le_int32 charIndex = 0, lineNumber = 1; | |
876 const float lineWidth = 600; | |
877 | |
878 font = new SimpleFontInstance(12, status); | |
879 | |
880 if (LE_FAILURE(status)) { | |
881 goto finish; | |
882 } | |
883 | |
884 fontRuns.add(font, charCount); | |
885 | |
886 paragraphLayout = new ParagraphLayout(chars, charCount, &fontRuns, NULL, NUL
L, NULL, 0, FALSE, status); | |
887 | |
888 if (LE_FAILURE(status)) { | |
889 goto close_font; | |
890 } | |
891 | |
892 paragraphLayout->reflow(); | |
893 while ((line = paragraphLayout->nextLine(lineWidth)) != NULL) { | |
894 le_int32 runCount = line->countRuns(); | |
895 | |
896 for(le_int32 run = 0; run < runCount; run += 1) { | |
897 const ParagraphLayout::VisualRun *visualRun = line->getVisualRun(run
); | |
898 le_int32 glyphCount = visualRun->getGlyphCount(); | |
899 const le_int32 *glyphToCharMap = visualRun->getGlyphToCharMap(); | |
900 | |
901 if (visualRun->getDirection() == UBIDI_RTL) { | |
902 /* | |
903 * For a right to left run, make sure that the character indices | |
904 * increase from the right most glyph to the left most glyph. If | |
905 * there are any one to many glyph substitutions, we might get s
everal | |
906 * glyphs in a row with the same character index. | |
907 */ | |
908 for(le_int32 i = glyphCount - 1; i >= 0; i -= 1) { | |
909 le_int32 ix = glyphToCharMap[i]; | |
910 | |
911 if (ix != charIndex) { | |
912 if (ix != charIndex - 1) { | |
913 log_err("Bad glyph to char index for glyph %d on lin
e %d: expected %d, got %d\n", | |
914 i, lineNumber, charIndex, ix); | |
915 goto close_paragraph; // once there's one error, we
can't count on anything else... | |
916 } | |
917 } else { | |
918 charIndex += 1; | |
919 } | |
920 } | |
921 } else { | |
922 /* | |
923 * We can't just check the order of the character indices | |
924 * for left to right runs because Indic text might have been | |
925 * reordered. What we can do is find the minimum and maximum | |
926 * character indices in the run and make sure that the minimum | |
927 * is equal to charIndex and then advance charIndex to the maxim
um. | |
928 */ | |
929 le_int32 minIndex = 0x7FFFFFFF, maxIndex = -1; | |
930 | |
931 for(le_int32 i = 0; i < glyphCount; i += 1) { | |
932 le_int32 ix = glyphToCharMap[i]; | |
933 | |
934 if (ix > maxIndex) { | |
935 maxIndex = ix; | |
936 } | |
937 | |
938 if (ix < minIndex) { | |
939 minIndex = ix; | |
940 } | |
941 } | |
942 | |
943 if (minIndex != charIndex) { | |
944 log_err("Bad minIndex for run %d on line %d: expected %d, go
t %d\n", | |
945 run, lineNumber, charIndex, minIndex); | |
946 goto close_paragraph; // once there's one error, we can't co
unt on anything else... | |
947 } | |
948 | |
949 charIndex = maxIndex + 1; | |
950 } | |
951 } | |
952 | |
953 lineNumber += 1; | |
954 } | |
955 close_paragraph: | |
956 delete paragraphLayout; | |
957 | |
958 close_font: | |
959 delete font; | |
960 | |
961 finish: | |
962 return; | |
963 #endif | |
964 } | |
965 U_CDECL_END | |
966 | |
967 static void addAllTests(TestNode **root) | |
968 { | |
969 addTest(root, &ScriptTest, "api/ScriptTest"); | |
970 addTest(root, &ParamTest, "api/ParameterTest"); | |
971 addTest(root, &FactoryTest, "api/FactoryTest"); | |
972 addTest(root, &AccessTest, "layout/AccessTest"); | |
973 addTest(root, &DataDrivenTest, "layout/DataDrivenTest"); | |
974 addTest(root, &GlyphToCharTest, "paragraph/GlyphToCharTest"); | |
975 | |
976 #ifndef USING_ICULEHB | |
977 addCTests(root); | |
978 #endif | |
979 } | |
980 | |
981 /* returns the path to icu/source/data/out */ | |
982 static const char *ctest_dataOutDir() | |
983 { | |
984 static const char *dataOutDir = NULL; | |
985 | |
986 if(dataOutDir) { | |
987 return dataOutDir; | |
988 } | |
989 | |
990 /* U_TOPBUILDDIR is set by the makefiles on UNIXes when building cintltst an
d intltst | |
991 // to point to the top of the build hierarchy, which may or | |
992 // may not be the same as the source directory, depending on | |
993 // the configure options used. At any rate, | |
994 // set the data path to the built data from this directory. | |
995 // The value is complete with quotes, so it can be used | |
996 // as-is as a string constant. | |
997 */ | |
998 #if defined (U_TOPBUILDDIR) | |
999 { | |
1000 dataOutDir = U_TOPBUILDDIR "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STR
ING; | |
1001 } | |
1002 #else | |
1003 | |
1004 /* On Windows, the file name obtained from __FILE__ includes a full path. | |
1005 * This file is "wherever\icu\source\test\cintltst\cintltst.c" | |
1006 * Change to "wherever\icu\source\data" | |
1007 */ | |
1008 { | |
1009 static char p[sizeof(__FILE__) + 20]; | |
1010 char *pBackSlash; | |
1011 int i; | |
1012 | |
1013 strcpy(p, __FILE__); | |
1014 /* We want to back over three '\' chars. */ | |
1015 /* Only Windows should end up here, so looking for '\' is safe. */ | |
1016 for (i=1; i<=3; i++) { | |
1017 pBackSlash = strrchr(p, U_FILE_SEP_CHAR); | |
1018 if (pBackSlash != NULL) { | |
1019 *pBackSlash = 0; /* Truncate the string at the '\' */ | |
1020 } | |
1021 } | |
1022 | |
1023 if (pBackSlash != NULL) { | |
1024 /* We found and truncated three names from the path. | |
1025 * Now append "source\data" and set the environment | |
1026 */ | |
1027 strcpy(pBackSlash, U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "out"
U_FILE_SEP_STRING); | |
1028 dataOutDir = p; | |
1029 } | |
1030 else { | |
1031 /* __FILE__ on MSVC7 does not contain the directory */ | |
1032 FILE *file = fopen(".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING "da
ta" U_FILE_SEP_STRING "Makefile.in", "r"); | |
1033 if (file) { | |
1034 fclose(file); | |
1035 dataOutDir = ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING "data
" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING; | |
1036 } | |
1037 else { | |
1038 dataOutDir = ".." U_FILE_SEP_STRING".." U_FILE_SEP_STRING".." U_
FILE_SEP_STRING "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING; | |
1039 } | |
1040 } | |
1041 } | |
1042 #endif | |
1043 | |
1044 return dataOutDir; | |
1045 } | |
1046 | |
1047 /* ctest_setICU_DATA - if the ICU_DATA environment variable is not already | |
1048 * set, try to deduce the directory in which ICU was built
, | |
1049 * and set ICU_DATA to "icu/source/data" in that location. | |
1050 * The intent is to allow the tests to have a good chance | |
1051 * of running without requiring that the user manually set | |
1052 * ICU_DATA. Common data isn't a problem, since it is | |
1053 * picked up via a static (build time) reference, but the | |
1054 * tests dynamically load some data. | |
1055 */ | |
1056 static void ctest_setICU_DATA() { | |
1057 | |
1058 /* No location for the data dir was identifiable. | |
1059 * Add other fallbacks for the test data location here if the need arises | |
1060 */ | |
1061 if (getenv("ICU_DATA") == NULL) { | |
1062 /* If ICU_DATA isn't set, set it to the usual location */ | |
1063 u_setDataDirectory(ctest_dataOutDir()); | |
1064 } | |
1065 } | |
1066 | |
1067 int main(int argc, char* argv[]) | |
1068 { | |
1069 int32_t nerrors = 0; | |
1070 TestNode *root = NULL; | |
1071 UErrorCode errorCode = U_ZERO_ERROR; | |
1072 UDate startTime, endTime; | |
1073 int32_t diffTime; | |
1074 | |
1075 startTime = uprv_getUTCtime(); | |
1076 | |
1077 if (!initArgs(argc, argv, NULL, NULL)) { | |
1078 /* Error already displayed. */ | |
1079 return -1; | |
1080 } | |
1081 | |
1082 /* Check whether ICU will initialize without forcing the build data director
y into | |
1083 * the ICU_DATA path. Success here means either the data dll contains data,
or that | |
1084 * this test program was run with ICU_DATA set externally. Failure of this
check | |
1085 * is normal when ICU data is not packaged into a shared library. | |
1086 * | |
1087 * Whether or not this test succeeds, we want to cleanup and reinitialize | |
1088 * with a data path so that data loading from individual files can be tested
. | |
1089 */ | |
1090 u_init(&errorCode); | |
1091 | |
1092 if (U_FAILURE(errorCode)) { | |
1093 fprintf(stderr, | |
1094 "#### Note: ICU Init without build-specific setDataDirectory() fail
ed.\n"); | |
1095 } | |
1096 | |
1097 u_cleanup(); | |
1098 errorCode = U_ZERO_ERROR; | |
1099 | |
1100 if (!initArgs(argc, argv, NULL, NULL)) { | |
1101 /* Error already displayed. */ | |
1102 return -1; | |
1103 } | |
1104 /* Initialize ICU */ | |
1105 ctest_setICU_DATA(); /* u_setDataDirectory() must happen Before u_init()
*/ | |
1106 u_init(&errorCode); | |
1107 | |
1108 if (U_FAILURE(errorCode)) { | |
1109 fprintf(stderr, | |
1110 "#### ERROR! %s: u_init() failed with status = \"%s\".\n" | |
1111 "*** Check the ICU_DATA environment variable and \n" | |
1112 "*** check that the data files are present.\n", argv[0], u_errorName
(errorCode)); | |
1113 return 1; | |
1114 } | |
1115 | |
1116 addAllTests(&root); | |
1117 nerrors = runTestRequest(root, argc, argv); | |
1118 | |
1119 cleanUpTestTree(root); | |
1120 u_cleanup(); | |
1121 | |
1122 endTime = uprv_getUTCtime(); | |
1123 diffTime = (int32_t)(endTime - startTime); | |
1124 printf("Elapsed Time: %02d:%02d:%02d.%03d\n", | |
1125 (int)((diffTime%U_MILLIS_PER_DAY)/U_MILLIS_PER_HOUR), | |
1126 (int)((diffTime%U_MILLIS_PER_HOUR)/U_MILLIS_PER_MINUTE), | |
1127 (int)((diffTime%U_MILLIS_PER_MINUTE)/U_MILLIS_PER_SECOND), | |
1128 (int)(diffTime%U_MILLIS_PER_SECOND)); | |
1129 | |
1130 return nerrors; | |
1131 } | |
1132 | |
OLD | NEW |