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