OLD | NEW |
(Empty) | |
| 1 /* |
| 2 ******************************************************************************* |
| 3 * |
| 4 * Copyright (C) 1999-2008, 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"testdata"U
_FILE_SEP_STRING; |
| 417 #else |
| 418 srcDataDir = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING"test"U_FILE_SEP_STRI
NG"testdata"U_FILE_SEP_STRING; |
| 419 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"); |
| 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_ST
RING"test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING; |
| 427 } |
| 428 #endif |
| 429 |
| 430 return srcDataDir; |
| 431 } |
| 432 |
| 433 const char *getPath(char buffer[2048], const char *filename) { |
| 434 const char *testDataDirectory = getSourceTestData(); |
| 435 |
| 436 strcpy(buffer, testDataDirectory); |
| 437 strcat(buffer, filename); |
| 438 |
| 439 return buffer; |
| 440 } |
| 441 |
| 442 le_uint32 *getHexArray(const UnicodeString &numbers, int32_t &arraySize) |
| 443 { |
| 444 int32_t offset = -1; |
| 445 |
| 446 arraySize = 1; |
| 447 while((offset = numbers.indexOf(CH_COMMA, offset + 1)) >= 0) { |
| 448 arraySize += 1; |
| 449 } |
| 450 |
| 451 le_uint32 *array = NEW_ARRAY(le_uint32, arraySize); |
| 452 char number[16]; |
| 453 le_int32 count = 0; |
| 454 le_int32 start = 0, end = 0; |
| 455 le_int32 len = 0; |
| 456 |
| 457 // trim leading whitespace |
| 458 while(u_isUWhiteSpace(numbers[start])) { |
| 459 start += 1; |
| 460 } |
| 461 |
| 462 while((end = numbers.indexOf(CH_COMMA, start)) >= 0) { |
| 463 len = numbers.extract(start, end - start, number, ARRAY_SIZE(number), US
_INV); |
| 464 number[len] = '\0'; |
| 465 start = end + 1; |
| 466 |
| 467 sscanf(number, "%x", &array[count++]); |
| 468 |
| 469 // trim whitespace following the comma |
| 470 while(u_isUWhiteSpace(numbers[start])) { |
| 471 start += 1; |
| 472 } |
| 473 } |
| 474 |
| 475 // trim trailing whitespace |
| 476 end = numbers.length(); |
| 477 while(u_isUWhiteSpace(numbers[end - 1])) { |
| 478 end -= 1; |
| 479 } |
| 480 |
| 481 len = numbers.extract(start, end - start, number, ARRAY_SIZE(number), US_INV
); |
| 482 number[len] = '\0'; |
| 483 sscanf(number, "%x", &array[count]); |
| 484 |
| 485 return array; |
| 486 } |
| 487 |
| 488 float *getFloatArray(const UnicodeString &numbers, int32_t &arraySize) |
| 489 { |
| 490 int32_t offset = -1; |
| 491 |
| 492 arraySize = 1; |
| 493 while((offset = numbers.indexOf(CH_COMMA, offset + 1)) >= 0) { |
| 494 arraySize += 1; |
| 495 } |
| 496 |
| 497 float *array = NEW_ARRAY(float, arraySize); |
| 498 char number[32]; |
| 499 le_int32 count = 0; |
| 500 le_int32 start = 0, end = 0; |
| 501 le_int32 len = 0; |
| 502 |
| 503 // trim leading whitespace |
| 504 while(u_isUWhiteSpace(numbers[start])) { |
| 505 start += 1; |
| 506 } |
| 507 |
| 508 while((end = numbers.indexOf(CH_COMMA, start)) >= 0) { |
| 509 len = numbers.extract(start, end - start, number, ARRAY_SIZE(number), US
_INV); |
| 510 number[len] = '\0'; |
| 511 start = end + 1; |
| 512 |
| 513 sscanf(number, "%f", &array[count++]); |
| 514 |
| 515 // trim whiteapce following the comma |
| 516 while(u_isUWhiteSpace(numbers[start])) { |
| 517 start += 1; |
| 518 } |
| 519 } |
| 520 |
| 521 while(u_isUWhiteSpace(numbers[start])) { |
| 522 start += 1; |
| 523 } |
| 524 |
| 525 // trim trailing whitespace |
| 526 end = numbers.length(); |
| 527 while(u_isUWhiteSpace(numbers[end - 1])) { |
| 528 end -= 1; |
| 529 } |
| 530 |
| 531 len = numbers.extract(start, end - start, number, ARRAY_SIZE(number), US_INV
); |
| 532 number[len] = '\0'; |
| 533 sscanf(number, "%f", &array[count]); |
| 534 |
| 535 return array; |
| 536 } |
| 537 |
| 538 LEFontInstance *openFont(const char *fontName, const char *checksum, const char
*version, const char *testID) |
| 539 { |
| 540 char path[2048]; |
| 541 PortableFontInstance *font; |
| 542 LEErrorCode fontStatus = LE_NO_ERROR; |
| 543 |
| 544 |
| 545 font = new PortableFontInstance(getPath(path, fontName), 12, fontStatus); |
| 546 |
| 547 if (LE_FAILURE(fontStatus)) { |
| 548 log_info("Test %s: can't open font %s - test skipped.\n", testID, fontNa
me); |
| 549 delete font; |
| 550 return NULL; |
| 551 } else { |
| 552 le_uint32 cksum = 0; |
| 553 |
| 554 sscanf(checksum, "%x", &cksum); |
| 555 |
| 556 checkFontVersion(font, version, cksum, testID); |
| 557 } |
| 558 |
| 559 return font; |
| 560 } |
| 561 |
| 562 U_CDECL_BEGIN |
| 563 static void U_CALLCONV DataDrivenTest(void) |
| 564 { |
| 565 #if !UCONFIG_NO_REGULAR_EXPRESSIONS |
| 566 UErrorCode status = U_ZERO_ERROR; |
| 567 char path[2048]; |
| 568 const char *testFilePath = getPath(path, "letest.xml"); |
| 569 |
| 570 UXMLParser *parser = UXMLParser::createParser(status); |
| 571 UXMLElement *root = parser->parseFile(testFilePath, status); |
| 572 |
| 573 if (root == NULL) { |
| 574 log_err("Could not open the test data file: %s\n", testFilePath); |
| 575 delete parser; |
| 576 return; |
| 577 } |
| 578 |
| 579 UnicodeString test_case = UNICODE_STRING_SIMPLE("test-case"); |
| 580 UnicodeString test_text = UNICODE_STRING_SIMPLE("test-text"); |
| 581 UnicodeString test_font = UNICODE_STRING_SIMPLE("test-font"); |
| 582 UnicodeString result_glyphs = UNICODE_STRING_SIMPLE("result-glyphs"); |
| 583 UnicodeString result_indices = UNICODE_STRING_SIMPLE("result-indices"); |
| 584 UnicodeString result_positions = UNICODE_STRING_SIMPLE("result-positions"); |
| 585 |
| 586 // test-case attributes |
| 587 UnicodeString id_attr = UNICODE_STRING_SIMPLE("id"); |
| 588 UnicodeString script_attr = UNICODE_STRING_SIMPLE("script"); |
| 589 UnicodeString lang_attr = UNICODE_STRING_SIMPLE("lang"); |
| 590 |
| 591 // test-font attributes |
| 592 UnicodeString name_attr = UNICODE_STRING_SIMPLE("name"); |
| 593 UnicodeString ver_attr = UNICODE_STRING_SIMPLE("version"); |
| 594 UnicodeString cksum_attr = UNICODE_STRING_SIMPLE("checksum"); |
| 595 |
| 596 const UXMLElement *testCase; |
| 597 int32_t tc = 0; |
| 598 |
| 599 while((testCase = root->nextChildElement(tc)) != NULL) { |
| 600 if (testCase->getTagName().compare(test_case) == 0) { |
| 601 char *id = getCString(testCase->getAttribute(id_attr)); |
| 602 char *script = getCString(testCase->getAttribute(script_attr)); |
| 603 char *lang = getCString(testCase->getAttribute(lang_attr)); |
| 604 LEFontInstance *font = NULL; |
| 605 const UXMLElement *element; |
| 606 int32_t ec = 0; |
| 607 int32_t charCount = 0; |
| 608 int32_t typoFlags = 3; // kerning + ligatures... |
| 609 UScriptCode scriptCode; |
| 610 le_int32 languageCode = -1; |
| 611 UnicodeString text, glyphs, indices, positions; |
| 612 int32_t glyphCount = 0, indexCount = 0, positionCount = 0; |
| 613 TestResult expected = {0, NULL, NULL, NULL}; |
| 614 TestResult actual = {0, NULL, NULL, NULL}; |
| 615 LEErrorCode success = LE_NO_ERROR; |
| 616 LayoutEngine *engine = NULL; |
| 617 |
| 618 uscript_getCode(script, &scriptCode, 1, &status); |
| 619 if (LE_FAILURE(status)) { |
| 620 log_err("invalid script name: %s.\n", script); |
| 621 goto free_c_strings; |
| 622 } |
| 623 |
| 624 if (lang != NULL) { |
| 625 languageCode = getLanguageCode(lang); |
| 626 |
| 627 if (languageCode < 0) { |
| 628 log_err("invalid language name: %s.\n", lang); |
| 629 goto free_c_strings; |
| 630 } |
| 631 } |
| 632 |
| 633 while((element = testCase->nextChildElement(ec)) != NULL) { |
| 634 UnicodeString tag = element->getTagName(); |
| 635 |
| 636 // TODO: make sure that each element is only used once. |
| 637 if (tag.compare(test_font) == 0) { |
| 638 char *fontName = getCString(element->getAttribute(name_attr
)); |
| 639 char *fontVer = getCString(element->getAttribute(ver_attr)
); |
| 640 char *fontCksum = getCString(element->getAttribute(cksum_att
r)); |
| 641 |
| 642 font = openFont(fontName, fontCksum, fontVer, id); |
| 643 freeCString(fontCksum); |
| 644 freeCString(fontVer); |
| 645 freeCString(fontName); |
| 646 |
| 647 if (font == NULL) { |
| 648 // warning message already displayed... |
| 649 goto free_c_strings; |
| 650 } |
| 651 } else if (tag.compare(test_text) == 0) { |
| 652 text = element->getText(TRUE); |
| 653 charCount = text.length(); |
| 654 } else if (tag.compare(result_glyphs) == 0) { |
| 655 glyphs = element->getText(TRUE); |
| 656 } else if (tag.compare(result_indices) == 0) { |
| 657 indices = element->getText(TRUE); |
| 658 } else if (tag.compare(result_positions) == 0) { |
| 659 positions = element->getText(TRUE); |
| 660 } else { |
| 661 // an unknown tag... |
| 662 char *cTag = getCString(&tag); |
| 663 |
| 664 log_info("Test %s: unknown element with tag \"%s\"\n", id, c
Tag); |
| 665 freeCString(cTag); |
| 666 } |
| 667 } |
| 668 |
| 669 // TODO: make sure that the font, test-text, result-glyphs, result-i
ndices and result-positions |
| 670 // have all been provided |
| 671 if (font == NULL) { |
| 672 LEErrorCode fontStatus = LE_NO_ERROR; |
| 673 |
| 674 font = new SimpleFontInstance(12, fontStatus); |
| 675 typoFlags |= 0x80000000L; // use CharSubstitutionFilter... |
| 676 } |
| 677 |
| 678 expected.glyphs = (LEGlyphID *) getHexArray(glyphs, glyphCount); |
| 679 expected.indices = (le_int32 *) getHexArray(indices, indexCount); |
| 680 expected.positions = getFloatArray(positions, positionCount); |
| 681 |
| 682 expected.glyphCount = glyphCount; |
| 683 |
| 684 if (glyphCount < charCount || indexCount != glyphCount || positionCo
unt < glyphCount * 2 + 2) { |
| 685 log_err("Test %s: inconsistent input data: charCount = %d, glyph
Count = %d, indexCount = %d, positionCount = %d\n", |
| 686 id, charCount, glyphCount, indexCount, positionCount); |
| 687 goto free_expected; |
| 688 }; |
| 689 |
| 690 engine = LayoutEngine::layoutEngineFactory(font, scriptCode, languag
eCode, typoFlags, success); |
| 691 |
| 692 if (LE_FAILURE(success)) { |
| 693 log_err("Test %s: could not create a LayoutEngine.\n", id); |
| 694 goto free_expected; |
| 695 } |
| 696 |
| 697 actual.glyphCount = engine->layoutChars(text.getBuffer(), 0, charCou
nt, charCount, getRTL(text), 0, 0, success); |
| 698 |
| 699 actual.glyphs = NEW_ARRAY(LEGlyphID, actual.glyphCount); |
| 700 actual.indices = NEW_ARRAY(le_int32, actual.glyphCount); |
| 701 actual.positions = NEW_ARRAY(float, actual.glyphCount * 2 + 2); |
| 702 |
| 703 engine->getGlyphs(actual.glyphs, success); |
| 704 engine->getCharIndices(actual.indices, success); |
| 705 engine->getGlyphPositions(actual.positions, success); |
| 706 |
| 707 compareResults(id, &expected, &actual); |
| 708 |
| 709 DELETE_ARRAY(actual.positions); |
| 710 DELETE_ARRAY(actual.indices); |
| 711 DELETE_ARRAY(actual.glyphs); |
| 712 |
| 713 delete engine; |
| 714 |
| 715 free_expected: |
| 716 DELETE_ARRAY(expected.positions); |
| 717 DELETE_ARRAY(expected.indices); |
| 718 DELETE_ARRAY(expected.glyphs); |
| 719 |
| 720 delete font; |
| 721 |
| 722 free_c_strings: |
| 723 freeCString(lang); |
| 724 freeCString(script); |
| 725 freeCString(id); |
| 726 } |
| 727 } |
| 728 |
| 729 delete root; |
| 730 delete parser; |
| 731 #endif |
| 732 } |
| 733 U_CDECL_END |
| 734 |
| 735 U_CDECL_BEGIN |
| 736 /* |
| 737 * From ticket:5923: |
| 738 * |
| 739 * Build a paragraph that contains a mixture of left to right and right to left
text. |
| 740 * Break it into multiple lines and make sure that the glyphToCharMap for run in
each |
| 741 * line is correct. |
| 742 * |
| 743 * Note: it might be a good idea to also check the glyphs and positions for each
run, |
| 744 * that we get the expected number of runs per line and that the line breaks are
where |
| 745 * we expect them to be. Really, it would be a good idea to make a whole test su
ite |
| 746 * for ParagraphLayout. |
| 747 */ |
| 748 static void U_CALLCONV GlyphToCharTest(void) |
| 749 { |
| 750 LEErrorCode status = LE_NO_ERROR; |
| 751 LEFontInstance *font; |
| 752 FontRuns fontRuns(0); |
| 753 ParagraphLayout *paragraphLayout; |
| 754 const ParagraphLayout::Line *line; |
| 755 /* |
| 756 * This is the same text that's in <icu>/source/samples/layout/Sample.txt |
| 757 */ |
| 758 LEUnicode chars[] = { |
| 759 /*BOM*/ 0x0054, 0x0068, 0x0065, 0x0020, 0x004c, 0x0061, 0x0079, |
| 760 0x006f, 0x0075, 0x0074, 0x0045, 0x006e, 0x0067, 0x0069, 0x006e, |
| 761 0x0065, 0x0020, 0x0064, 0x006f, 0x0065, 0x0073, 0x0020, 0x0061, |
| 762 0x006c, 0x006c, 0x0020, 0x0074, 0x0068, 0x0065, 0x0020, 0x0077, |
| 763 0x006f, 0x0072, 0x006b, 0x0020, 0x006e, 0x0065, 0x0063, 0x0065, |
| 764 0x0073, 0x0073, 0x0061, 0x0072, 0x0079, 0x0020, 0x0074, 0x006f, |
| 765 0x0020, 0x0064, 0x0069, 0x0073, 0x0070, 0x006c, 0x0061, 0x0079, |
| 766 0x0020, 0x0055, 0x006e, 0x0069, 0x0063, 0x006f, 0x0064, 0x0065, |
| 767 0x0020, 0x0074, 0x0065, 0x0078, 0x0074, 0x0020, 0x0077, 0x0072, |
| 768 0x0069, 0x0074, 0x0074, 0x0065, 0x006e, 0x0020, 0x0069, 0x006e, |
| 769 0x0020, 0x006c, 0x0061, 0x006e, 0x0067, 0x0075, 0x0061, 0x0067, |
| 770 0x0065, 0x0073, 0x0020, 0x0077, 0x0069, 0x0074, 0x0068, 0x0020, |
| 771 0x0063, 0x006f, 0x006d, 0x0070, 0x006c, 0x0065, 0x0078, 0x0020, |
| 772 0x0077, 0x0072, 0x0069, 0x0074, 0x0069, 0x006e, 0x0067, 0x0020, |
| 773 0x0073, 0x0079, 0x0073, 0x0074, 0x0065, 0x006d, 0x0073, 0x0020, |
| 774 0x0073, 0x0075, 0x0063, 0x0068, 0x0020, 0x0061, 0x0073, 0x0020, |
| 775 0x0048, 0x0069, 0x006e, 0x0064, 0x0069, 0x0020, 0x0028, 0x0939, |
| 776 0x093f, 0x0928, 0x094d, 0x0926, 0x0940, 0x0029, 0x0020, 0x0054, |
| 777 0x0068, 0x0061, 0x0069, 0x0020, 0x0028, 0x0e44, 0x0e17, 0x0e22, |
| 778 0x0029, 0x0020, 0x0061, 0x006e, 0x0064, 0x0020, 0x0041, 0x0072, |
| 779 0x0061, 0x0062, 0x0069, 0x0063, 0x0020, 0x0028, 0x0627, 0x0644, |
| 780 0x0639, 0x0631, 0x0628, 0x064a, 0x0629, 0x0029, 0x002e, 0x0020, |
| 781 0x0048, 0x0065, 0x0072, 0x0065, 0x0027, 0x0073, 0x0020, 0x0061, |
| 782 0x0020, 0x0073, 0x0061, 0x006d, 0x0070, 0x006c, 0x0065, 0x0020, |
| 783 0x006f, 0x0066, 0x0020, 0x0073, 0x006f, 0x006d, 0x0065, 0x0020, |
| 784 0x0074, 0x0065, 0x0078, 0x0074, 0x0020, 0x0077, 0x0072, 0x0069, |
| 785 0x0074, 0x0074, 0x0065, 0x006e, 0x0020, 0x0069, 0x006e, 0x0020, |
| 786 0x0053, 0x0061, 0x006e, 0x0073, 0x006b, 0x0072, 0x0069, 0x0074, |
| 787 0x003a, 0x0020, 0x0936, 0x094d, 0x0930, 0x0940, 0x092e, 0x0926, |
| 788 0x094d, 0x0020, 0x092d, 0x0917, 0x0935, 0x0926, 0x094d, 0x0917, |
| 789 0x0940, 0x0924, 0x093e, 0x0020, 0x0905, 0x0927, 0x094d, 0x092f, |
| 790 0x093e, 0x092f, 0x0020, 0x0905, 0x0930, 0x094d, 0x091c, 0x0941, |
| 791 0x0928, 0x0020, 0x0935, 0x093f, 0x0937, 0x093e, 0x0926, 0x0020, |
| 792 0x092f, 0x094b, 0x0917, 0x0020, 0x0927, 0x0943, 0x0924, 0x0930, |
| 793 0x093e, 0x0937, 0x094d, 0x091f, 0x094d, 0x0930, 0x0020, 0x0909, |
| 794 0x0935, 0x093e, 0x091a, 0x0964, 0x0020, 0x0927, 0x0930, 0x094d, |
| 795 0x092e, 0x0915, 0x094d, 0x0937, 0x0947, 0x0924, 0x094d, 0x0930, |
| 796 0x0947, 0x0020, 0x0915, 0x0941, 0x0930, 0x0941, 0x0915, 0x094d, |
| 797 0x0937, 0x0947, 0x0924, 0x094d, 0x0930, 0x0947, 0x0020, 0x0938, |
| 798 0x092e, 0x0935, 0x0947, 0x0924, 0x093e, 0x0020, 0x092f, 0x0941, |
| 799 0x092f, 0x0941, 0x0924, 0x094d, 0x0938, 0x0935, 0x0903, 0x0020, |
| 800 0x092e, 0x093e, 0x092e, 0x0915, 0x093e, 0x0903, 0x0020, 0x092a, |
| 801 0x093e, 0x0923, 0x094d, 0x0921, 0x0935, 0x093e, 0x0936, 0x094d, |
| 802 0x091a, 0x0948, 0x0935, 0x0020, 0x0915, 0x093f, 0x092e, 0x0915, |
| 803 0x0941, 0x0930, 0x094d, 0x0935, 0x0924, 0x0020, 0x0938, 0x0902, |
| 804 0x091c, 0x092f, 0x0020, 0x0048, 0x0065, 0x0072, 0x0065, 0x0027, |
| 805 0x0073, 0x0020, 0x0061, 0x0020, 0x0073, 0x0061, 0x006d, 0x0070, |
| 806 0x006c, 0x0065, 0x0020, 0x006f, 0x0066, 0x0020, 0x0073, 0x006f, |
| 807 0x006d, 0x0065, 0x0020, 0x0074, 0x0065, 0x0078, 0x0074, 0x0020, |
| 808 0x0077, 0x0072, 0x0069, 0x0074, 0x0074, 0x0065, 0x006e, 0x0020, |
| 809 0x0069, 0x006e, 0x0020, 0x0041, 0x0072, 0x0061, 0x0062, 0x0069, |
| 810 0x0063, 0x003a, 0x0020, 0x0623, 0x0633, 0x0627, 0x0633, 0x064b, |
| 811 0x0627, 0x060c, 0x0020, 0x062a, 0x062a, 0x0639, 0x0627, 0x0645, |
| 812 0x0644, 0x0020, 0x0627, 0x0644, 0x062d, 0x0648, 0x0627, 0x0633, |
| 813 0x064a, 0x0628, 0x0020, 0x0641, 0x0642, 0x0637, 0x0020, 0x0645, |
| 814 0x0639, 0x0020, 0x0627, 0x0644, 0x0623, 0x0631, 0x0642, 0x0627, |
| 815 0x0645, 0x060c, 0x0020, 0x0648, 0x062a, 0x0642, 0x0648, 0x0645, |
| 816 0x0020, 0x0628, 0x062a, 0x062e, 0x0632, 0x064a, 0x0646, 0x0020, |
| 817 0x0627, 0x0644, 0x0623, 0x062d, 0x0631, 0x0641, 0x0020, 0x0648, |
| 818 0x0627, 0x0644, 0x0645, 0x062d, 0x0627, 0x0631, 0x0641, 0x0020, |
| 819 0x0627, 0x0644, 0x0623, 0x062e, 0x0631, 0x0649, 0x0020, 0x0628, |
| 820 0x0639, 0x062f, 0x0020, 0x0623, 0x0646, 0x0020, 0x062a, 0x064f, |
| 821 0x0639, 0x0637, 0x064a, 0x0020, 0x0631, 0x0642, 0x0645, 0x0627, |
| 822 0x0020, 0x0645, 0x0639, 0x064a, 0x0646, 0x0627, 0x0020, 0x0644, |
| 823 0x0643, 0x0644, 0x0020, 0x0648, 0x0627, 0x062d, 0x062f, 0x0020, |
| 824 0x0645, 0x0646, 0x0647, 0x0627, 0x002e, 0x0020, 0x0648, 0x0642, |
| 825 0x0628, 0x0644, 0x0020, 0x0627, 0x062e, 0x062a, 0x0631, 0x0627, |
| 826 0x0639, 0x0020, 0x0022, 0x064a, 0x0648, 0x0646, 0x0650, 0x0643, |
| 827 0x0648, 0x062f, 0x0022, 0x060c, 0x0020, 0x0643, 0x0627, 0x0646, |
| 828 0x0020, 0x0647, 0x0646, 0x0627, 0x0643, 0x0020, 0x0645, 0x0626, |
| 829 0x0627, 0x062a, 0x0020, 0x0627, 0x0644, 0x0623, 0x0646, 0x0638, |
| 830 0x0645, 0x0629, 0x0020, 0x0644, 0x0644, 0x062a, 0x0634, 0x0641, |
| 831 0x064a, 0x0631, 0x0020, 0x0648, 0x062a, 0x062e, 0x0635, 0x064a, |
| 832 0x0635, 0x0020, 0x0647, 0x0630, 0x0647, 0x0020, 0x0627, 0x0644, |
| 833 0x0623, 0x0631, 0x0642, 0x0627, 0x0645, 0x0020, 0x0644, 0x0644, |
| 834 0x0645, 0x062d, 0x0627, 0x0631, 0x0641, 0x060c, 0x0020, 0x0648, |
| 835 0x0644, 0x0645, 0x0020, 0x064a, 0x0648, 0x062c, 0x062f, 0x0020, |
| 836 0x0646, 0x0638, 0x0627, 0x0645, 0x0020, 0x062a, 0x0634, 0x0641, |
| 837 0x064a, 0x0631, 0x0020, 0x0648, 0x0627, 0x062d, 0x062f, 0x0020, |
| 838 0x064a, 0x062d, 0x062a, 0x0648, 0x064a, 0x0020, 0x0639, 0x0644, |
| 839 0x0649, 0x0020, 0x062c, 0x0645, 0x064a, 0x0639, 0x0020, 0x0627, |
| 840 0x0644, 0x0645, 0x062d, 0x0627, 0x0631, 0x0641, 0x0020, 0x0627, |
| 841 0x0644, 0x0636, 0x0631, 0x0648, 0x0631, 0x064a, 0x0629, 0x0020, |
| 842 0x0061, 0x006e, 0x0064, 0x0020, 0x0068, 0x0065, 0x0072, 0x0065, |
| 843 0x0027, 0x0073, 0x0020, 0x0061, 0x0020, 0x0073, 0x0061, 0x006d, |
| 844 0x0070, 0x006c, 0x0065, 0x0020, 0x006f, 0x0066, 0x0020, 0x0073, |
| 845 0x006f, 0x006d, 0x0065, 0x0020, 0x0074, 0x0065, 0x0078, 0x0074, |
| 846 0x0020, 0x0077, 0x0072, 0x0069, 0x0074, 0x0074, 0x0065, 0x006e, |
| 847 0x0020, 0x0069, 0x006e, 0x0020, 0x0054, 0x0068, 0x0061, 0x0069, |
| 848 0x003a, 0x0020, 0x0e1a, 0x0e17, 0x0e17, 0x0e35, 0x0e48, 0x0e51, |
| 849 0x0e1e, 0x0e32, 0x0e22, 0x0e38, 0x0e44, 0x0e0b, 0x0e42, 0x0e04, |
| 850 0x0e25, 0x0e19, 0x0e42, 0x0e14, 0x0e42, 0x0e23, 0x0e18, 0x0e35, |
| 851 0x0e2d, 0x0e32, 0x0e28, 0x0e31, 0x0e22, 0x0e2d, 0x0e22, 0x0e39, |
| 852 0x0e48, 0x0e17, 0x0e48, 0x0e32, 0x0e21, 0x0e01, 0x0e25, 0x0e32, |
| 853 0x0e07, 0x0e17, 0x0e38, 0x0e48, 0x0e07, 0x0e43, 0x0e2b, 0x0e0d, |
| 854 0x0e48, 0x0e43, 0x0e19, 0x0e41, 0x0e04, 0x0e19, 0x0e0b, 0x0e31, |
| 855 0x0e2a, 0x0e01, 0x0e31, 0x0e1a, 0x0e25, 0x0e38, 0x0e07, 0x0e40, |
| 856 0x0e2e, 0x0e19, 0x0e23, 0x0e35, 0x0e0a, 0x0e32, 0x0e27, 0x0e44, |
| 857 0x0e23, 0x0e48, 0x0e41, 0x0e25, 0x0e30, 0x0e1b, 0x0e49, 0x0e32, |
| 858 0x0e40, 0x0e2d, 0x0e47, 0x0e21, 0x0e20, 0x0e23, 0x0e23, 0x0e22, |
| 859 0x0e32, 0x0e0a, 0x0e32, 0x0e27, 0x0e44, 0x0e23, 0x0e48, 0x0e1a, |
| 860 0x0e49, 0x0e32, 0x0e19, 0x0e02, 0x0e2d, 0x0e07, 0x0e1e, 0x0e27, |
| 861 0x0e01, 0x0e40, 0x0e02, 0x0e32, 0x0e2b, 0x0e25, 0x0e31, 0x0e07, |
| 862 0x0e40, 0x0e25, 0x0e47, 0x0e01, 0x0e40, 0x0e1e, 0x0e23, 0x0e32, |
| 863 0x0e30, 0x0e44, 0x0e21, 0x0e49, 0x0e2a, 0x0e23, 0x0e49, 0x0e32, |
| 864 0x0e07, 0x0e1a, 0x0e49, 0x0e32, 0x0e19, 0x0e15, 0x0e49, 0x0e2d, |
| 865 0x0e07, 0x0e02, 0x0e19, 0x0e21, 0x0e32, 0x0e14, 0x0e49, 0x0e27, |
| 866 0x0e22, 0x0e40, 0x0e01, 0x0e27, 0x0e35, 0x0e22, 0x0e19, 0x0e40, |
| 867 0x0e1b, 0x0e47, 0x0e19, 0x0e23, 0x0e30, 0x0e22, 0x0e30, 0x0e17, |
| 868 0x0e32, 0x0e07, 0x0e2b, 0x0e25, 0x0e32, 0x0e22, 0x0e44, 0x0e21, |
| 869 0x0e25, 0x0e4c |
| 870 }; |
| 871 le_int32 charCount = LE_ARRAY_SIZE(chars); |
| 872 le_int32 charIndex = 0, lineNumber = 1; |
| 873 const float lineWidth = 600; |
| 874 |
| 875 font = new SimpleFontInstance(12, status); |
| 876 |
| 877 if (LE_FAILURE(status)) { |
| 878 goto finish; |
| 879 } |
| 880 |
| 881 fontRuns.add(font, charCount); |
| 882 |
| 883 paragraphLayout = new ParagraphLayout(chars, charCount, &fontRuns, NULL, NUL
L, NULL, 0, FALSE, status); |
| 884 |
| 885 if (LE_FAILURE(status)) { |
| 886 goto close_font; |
| 887 } |
| 888 |
| 889 paragraphLayout->reflow(); |
| 890 while ((line = paragraphLayout->nextLine(lineWidth)) != NULL) { |
| 891 le_int32 runCount = line->countRuns(); |
| 892 |
| 893 for(le_int32 run = 0; run < runCount; run += 1) { |
| 894 const ParagraphLayout::VisualRun *visualRun = line->getVisualRun(run
); |
| 895 le_int32 glyphCount = visualRun->getGlyphCount(); |
| 896 const le_int32 *glyphToCharMap = visualRun->getGlyphToCharMap(); |
| 897 |
| 898 if (visualRun->getDirection() == UBIDI_RTL) { |
| 899 /* |
| 900 * For a right to left run, make sure that the character indices |
| 901 * increase from the right most glyph to the left most glyph. If |
| 902 * there are any one to many glyph substitutions, we might get s
everal |
| 903 * glyphs in a row with the same character index. |
| 904 */ |
| 905 for(le_int32 i = glyphCount - 1; i >= 0; i -= 1) { |
| 906 le_int32 ix = glyphToCharMap[i]; |
| 907 |
| 908 if (ix != charIndex) { |
| 909 if (ix != charIndex - 1) { |
| 910 log_err("Bad glyph to char index for glyph %d on lin
e %d: expected %d, got %d\n", |
| 911 i, lineNumber, charIndex, ix); |
| 912 goto close_paragraph; // once there's one error, we
can't count on anything else... |
| 913 } |
| 914 } else { |
| 915 charIndex += 1; |
| 916 } |
| 917 } |
| 918 } else { |
| 919 /* |
| 920 * We can't just check the order of the character indices |
| 921 * for left to right runs because Indic text might have been |
| 922 * reordered. What we can do is find the minimum and maximum |
| 923 * character indices in the run and make sure that the minimum |
| 924 * is equal to charIndex and then advance charIndex to the maxim
um. |
| 925 */ |
| 926 le_int32 minIndex = 0x7FFFFFFF, maxIndex = -1; |
| 927 |
| 928 for(le_int32 i = 0; i < glyphCount; i += 1) { |
| 929 le_int32 ix = glyphToCharMap[i]; |
| 930 |
| 931 if (ix > maxIndex) { |
| 932 maxIndex = ix; |
| 933 } |
| 934 |
| 935 if (ix < minIndex) { |
| 936 minIndex = ix; |
| 937 } |
| 938 } |
| 939 |
| 940 if (minIndex != charIndex) { |
| 941 log_err("Bad minIndex for run %d on line %d: expected %d, go
t %d\n", |
| 942 run, lineNumber, charIndex, minIndex); |
| 943 goto close_paragraph; // once there's one error, we can't co
unt on anything else... |
| 944 } |
| 945 |
| 946 charIndex = maxIndex + 1; |
| 947 } |
| 948 } |
| 949 |
| 950 lineNumber += 1; |
| 951 } |
| 952 close_paragraph: |
| 953 delete paragraphLayout; |
| 954 |
| 955 close_font: |
| 956 delete font; |
| 957 |
| 958 finish: |
| 959 return; |
| 960 } |
| 961 U_CDECL_END |
| 962 |
| 963 static void addAllTests(TestNode **root) |
| 964 { |
| 965 addTest(root, &ScriptTest, "api/ScriptTest"); |
| 966 addTest(root, &ParamTest, "api/ParameterTest"); |
| 967 addTest(root, &FactoryTest, "api/FactoryTest"); |
| 968 addTest(root, &AccessTest, "layout/AccessTest"); |
| 969 addTest(root, &DataDrivenTest, "layout/DataDrivenTest"); |
| 970 addTest(root, &GlyphToCharTest, "paragraph/GlyphToCharTest"); |
| 971 |
| 972 addCTests(root); |
| 973 } |
| 974 |
| 975 /* returns the path to icu/source/data/out */ |
| 976 static const char *ctest_dataOutDir() |
| 977 { |
| 978 static const char *dataOutDir = NULL; |
| 979 |
| 980 if(dataOutDir) { |
| 981 return dataOutDir; |
| 982 } |
| 983 |
| 984 /* U_TOPBUILDDIR is set by the makefiles on UNIXes when building cintltst an
d intltst |
| 985 // to point to the top of the build hierarchy, which may or |
| 986 // may not be the same as the source directory, depending on |
| 987 // the configure options used. At any rate, |
| 988 // set the data path to the built data from this directory. |
| 989 // The value is complete with quotes, so it can be used |
| 990 // as-is as a string constant. |
| 991 */ |
| 992 #if defined (U_TOPBUILDDIR) |
| 993 { |
| 994 dataOutDir = U_TOPBUILDDIR "data"U_FILE_SEP_STRING"out"U_FILE_SEP_STRING
; |
| 995 } |
| 996 #else |
| 997 |
| 998 /* On Windows, the file name obtained from __FILE__ includes a full path. |
| 999 * This file is "wherever\icu\source\test\cintltst\cintltst.c" |
| 1000 * Change to "wherever\icu\source\data" |
| 1001 */ |
| 1002 { |
| 1003 static char p[sizeof(__FILE__) + 20]; |
| 1004 char *pBackSlash; |
| 1005 int i; |
| 1006 |
| 1007 strcpy(p, __FILE__); |
| 1008 /* We want to back over three '\' chars. */ |
| 1009 /* Only Windows should end up here, so looking for '\' is safe. */ |
| 1010 for (i=1; i<=3; i++) { |
| 1011 pBackSlash = strrchr(p, U_FILE_SEP_CHAR); |
| 1012 if (pBackSlash != NULL) { |
| 1013 *pBackSlash = 0; /* Truncate the string at the '\' */ |
| 1014 } |
| 1015 } |
| 1016 |
| 1017 if (pBackSlash != NULL) { |
| 1018 /* We found and truncated three names from the path. |
| 1019 * Now append "source\data" and set the environment |
| 1020 */ |
| 1021 strcpy(pBackSlash, U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "out"
U_FILE_SEP_STRING); |
| 1022 dataOutDir = p; |
| 1023 } |
| 1024 else { |
| 1025 /* __FILE__ on MSVC7 does not contain the directory */ |
| 1026 FILE *file = fopen(".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING "data"
U_FILE_SEP_STRING "Makefile.in", "r"); |
| 1027 if (file) { |
| 1028 fclose(file); |
| 1029 dataOutDir = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING "data" U
_FILE_SEP_STRING "out" U_FILE_SEP_STRING; |
| 1030 } |
| 1031 else { |
| 1032 dataOutDir = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING".."U_FIL
E_SEP_STRING "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING; |
| 1033 } |
| 1034 } |
| 1035 } |
| 1036 #endif |
| 1037 |
| 1038 return dataOutDir; |
| 1039 } |
| 1040 |
| 1041 /* ctest_setICU_DATA - if the ICU_DATA environment variable is not already |
| 1042 * set, try to deduce the directory in which ICU was built
, |
| 1043 * and set ICU_DATA to "icu/source/data" in that location. |
| 1044 * The intent is to allow the tests to have a good chance |
| 1045 * of running without requiring that the user manually set |
| 1046 * ICU_DATA. Common data isn't a problem, since it is |
| 1047 * picked up via a static (build time) reference, but the |
| 1048 * tests dynamically load some data. |
| 1049 */ |
| 1050 static void ctest_setICU_DATA() { |
| 1051 |
| 1052 /* No location for the data dir was identifiable. |
| 1053 * Add other fallbacks for the test data location here if the need arises |
| 1054 */ |
| 1055 if (getenv("ICU_DATA") == NULL) { |
| 1056 /* If ICU_DATA isn't set, set it to the usual location */ |
| 1057 u_setDataDirectory(ctest_dataOutDir()); |
| 1058 } |
| 1059 } |
| 1060 |
| 1061 int main(int argc, char* argv[]) |
| 1062 { |
| 1063 int32_t nerrors = 0; |
| 1064 TestNode *root = NULL; |
| 1065 UErrorCode errorCode = U_ZERO_ERROR; |
| 1066 UDate startTime, endTime; |
| 1067 int32_t diffTime; |
| 1068 |
| 1069 startTime = uprv_getUTCtime(); |
| 1070 |
| 1071 if (!initArgs(argc, argv, NULL, NULL)) { |
| 1072 /* Error already displayed. */ |
| 1073 return -1; |
| 1074 } |
| 1075 |
| 1076 /* Check whether ICU will initialize without forcing the build data director
y into |
| 1077 * the ICU_DATA path. Success here means either the data dll contains data,
or that |
| 1078 * this test program was run with ICU_DATA set externally. Failure of this
check |
| 1079 * is normal when ICU data is not packaged into a shared library. |
| 1080 * |
| 1081 * Whether or not this test succeeds, we want to cleanup and reinitialize |
| 1082 * with a data path so that data loading from individual files can be tested
. |
| 1083 */ |
| 1084 u_init(&errorCode); |
| 1085 |
| 1086 if (U_FAILURE(errorCode)) { |
| 1087 fprintf(stderr, |
| 1088 "#### Note: ICU Init without build-specific setDataDirectory() fail
ed.\n"); |
| 1089 } |
| 1090 |
| 1091 u_cleanup(); |
| 1092 errorCode = U_ZERO_ERROR; |
| 1093 |
| 1094 if (!initArgs(argc, argv, NULL, NULL)) { |
| 1095 /* Error already displayed. */ |
| 1096 return -1; |
| 1097 } |
| 1098 /* Initialize ICU */ |
| 1099 ctest_setICU_DATA(); /* u_setDataDirectory() must happen Before u_init()
*/ |
| 1100 u_init(&errorCode); |
| 1101 |
| 1102 if (U_FAILURE(errorCode)) { |
| 1103 fprintf(stderr, |
| 1104 "#### ERROR! %s: u_init() failed with status = \"%s\".\n" |
| 1105 "*** Check the ICU_DATA environment variable and \n" |
| 1106 "*** check that the data files are present.\n", argv[0], u_errorName
(errorCode)); |
| 1107 return 1; |
| 1108 } |
| 1109 |
| 1110 addAllTests(&root); |
| 1111 nerrors = runTestRequest(root, argc, argv); |
| 1112 |
| 1113 cleanUpTestTree(root); |
| 1114 u_cleanup(); |
| 1115 |
| 1116 endTime = uprv_getUTCtime(); |
| 1117 diffTime = (int32_t)(endTime - startTime); |
| 1118 printf("Elapsed Time: %02d:%02d:%02d.%03d\n", |
| 1119 (int)((diffTime%U_MILLIS_PER_DAY)/U_MILLIS_PER_HOUR), |
| 1120 (int)((diffTime%U_MILLIS_PER_HOUR)/U_MILLIS_PER_MINUTE), |
| 1121 (int)((diffTime%U_MILLIS_PER_MINUTE)/U_MILLIS_PER_SECOND), |
| 1122 (int)(diffTime%U_MILLIS_PER_SECOND)); |
| 1123 |
| 1124 return nerrors; |
| 1125 } |
| 1126 |
OLD | NEW |