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