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