| OLD | NEW |
| (Empty) |
| 1 /***************************************************************************/ | |
| 2 /* */ | |
| 3 /* ttpload.c */ | |
| 4 /* */ | |
| 5 /* TrueType-specific tables loader (body). */ | |
| 6 /* */ | |
| 7 /* Copyright 1996-2002, 2004-2013 by */ | |
| 8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */ | |
| 9 /* */ | |
| 10 /* This file is part of the FreeType project, and may only be used, */ | |
| 11 /* modified, and distributed under the terms of the FreeType project */ | |
| 12 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ | |
| 13 /* this file you indicate that you have read the license and */ | |
| 14 /* understand and accept it fully. */ | |
| 15 /* */ | |
| 16 /***************************************************************************/ | |
| 17 | |
| 18 | |
| 19 #include "../../include/ft2build.h" | |
| 20 #include "../../include/freetype/internal/ftdebug.h" | |
| 21 #include "../../include/freetype/internal/ftobjs.h" | |
| 22 #include "../../include/freetype/internal/ftstream.h" | |
| 23 #include "../../include/freetype/tttags.h" | |
| 24 | |
| 25 #include "ttpload.h" | |
| 26 | |
| 27 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT | |
| 28 #include "ttgxvar.h" | |
| 29 #endif | |
| 30 | |
| 31 #include "tterrors.h" | |
| 32 | |
| 33 | |
| 34 /*************************************************************************/ | |
| 35 /* */ | |
| 36 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ | |
| 37 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ | |
| 38 /* messages during execution. */ | |
| 39 /* */ | |
| 40 #undef FT_COMPONENT | |
| 41 #define FT_COMPONENT trace_ttpload | |
| 42 | |
| 43 | |
| 44 /*************************************************************************/ | |
| 45 /* */ | |
| 46 /* <Function> */ | |
| 47 /* tt_face_load_loca */ | |
| 48 /* */ | |
| 49 /* <Description> */ | |
| 50 /* Load the locations table. */ | |
| 51 /* */ | |
| 52 /* <InOut> */ | |
| 53 /* face :: A handle to the target face object. */ | |
| 54 /* */ | |
| 55 /* <Input> */ | |
| 56 /* stream :: The input stream. */ | |
| 57 /* */ | |
| 58 /* <Return> */ | |
| 59 /* FreeType error code. 0 means success. */ | |
| 60 /* */ | |
| 61 FT_LOCAL_DEF( FT_Error ) | |
| 62 tt_face_load_loca( TT_Face face, | |
| 63 FT_Stream stream ) | |
| 64 { | |
| 65 FT_Error error; | |
| 66 FT_ULong table_len; | |
| 67 FT_Int shift; | |
| 68 | |
| 69 | |
| 70 /* we need the size of the `glyf' table for malformed `loca' tables */ | |
| 71 error = face->goto_table( face, TTAG_glyf, stream, &face->glyf_len ); | |
| 72 | |
| 73 /* it is possible that a font doesn't have a glyf table at all */ | |
| 74 /* or its size is zero */ | |
| 75 if ( FT_ERR_EQ( error, Table_Missing ) ) | |
| 76 face->glyf_len = 0; | |
| 77 else if ( error ) | |
| 78 goto Exit; | |
| 79 | |
| 80 FT_TRACE2(( "Locations " )); | |
| 81 error = face->goto_table( face, TTAG_loca, stream, &table_len ); | |
| 82 if ( error ) | |
| 83 { | |
| 84 error = FT_THROW( Locations_Missing ); | |
| 85 goto Exit; | |
| 86 } | |
| 87 | |
| 88 if ( face->header.Index_To_Loc_Format != 0 ) | |
| 89 { | |
| 90 shift = 2; | |
| 91 | |
| 92 if ( table_len >= 0x40000L ) | |
| 93 { | |
| 94 FT_TRACE2(( "table too large\n" )); | |
| 95 error = FT_THROW( Invalid_Table ); | |
| 96 goto Exit; | |
| 97 } | |
| 98 face->num_locations = table_len >> shift; | |
| 99 } | |
| 100 else | |
| 101 { | |
| 102 shift = 1; | |
| 103 | |
| 104 if ( table_len >= 0x20000L ) | |
| 105 { | |
| 106 FT_TRACE2(( "table too large\n" )); | |
| 107 error = FT_THROW( Invalid_Table ); | |
| 108 goto Exit; | |
| 109 } | |
| 110 face->num_locations = table_len >> shift; | |
| 111 } | |
| 112 /* | |
| 113 * Extract the frame. We don't need to decompress it since | |
| 114 * we are able to parse it directly. | |
| 115 */ | |
| 116 if ( FT_FRAME_EXTRACT( table_len, face->glyph_locations ) ) | |
| 117 goto Exit; | |
| 118 | |
| 119 FT_TRACE2(( "loaded\n" )); | |
| 120 | |
| 121 Exit: | |
| 122 return error; | |
| 123 } | |
| 124 | |
| 125 | |
| 126 FT_LOCAL_DEF( FT_ULong ) | |
| 127 tt_face_get_location( TT_Face face, | |
| 128 FT_UInt gindex, | |
| 129 FT_UInt *asize ) | |
| 130 { | |
| 131 FT_ULong pos1 = 0, pos2 = 0; | |
| 132 FT_Byte* p = NULL; | |
| 133 | |
| 134 if (!face || gindex >= face->num_locations) | |
| 135 { | |
| 136 if (asize) | |
| 137 *asize = 0; | |
| 138 | |
| 139 return 0; | |
| 140 } | |
| 141 | |
| 142 if ( face->header.Index_To_Loc_Format != 0 ) | |
| 143 { | |
| 144 p = face->glyph_locations + gindex * 4; | |
| 145 pos1 = FT_NEXT_ULONG(p); | |
| 146 pos2 = pos1; | |
| 147 //p has been moved to next location in the previous FT_NEXT_ULONG. | |
| 148 if ( gindex < face->num_locations - 1 ) | |
| 149 pos2 = FT_NEXT_ULONG(p); | |
| 150 } | |
| 151 else | |
| 152 { | |
| 153 p = face->glyph_locations + gindex * 2; | |
| 154 pos1 = FT_NEXT_USHORT(p); | |
| 155 pos2 = pos1; | |
| 156 //p has been moved to next location in the previous FT_NEXT_USHORT. | |
| 157 if ( gindex < face->num_locations - 1 ) | |
| 158 pos2 = FT_NEXT_USHORT( p ); | |
| 159 | |
| 160 pos1 <<= 1; | |
| 161 pos2 <<= 1; | |
| 162 } | |
| 163 | |
| 164 /* Check broken location data */ | |
| 165 if ( pos1 > face->glyf_len ) | |
| 166 { | |
| 167 FT_TRACE1(( "tt_face_get_location:" | |
| 168 " too large offset=0x%08lx found for gid=0x%04lx," | |
| 169 " exceeding the end of glyf table (0x%08lx)\n", | |
| 170 pos1, gindex, face->glyf_len )); | |
| 171 *asize = 0; | |
| 172 return 0; | |
| 173 } | |
| 174 | |
| 175 if ( pos2 > face->glyf_len ) | |
| 176 { | |
| 177 FT_TRACE1(( "tt_face_get_location:" | |
| 178 " too large offset=0x%08lx found for gid=0x%04lx," | |
| 179 " truncate at the end of glyf table (0x%08lx)\n", | |
| 180 pos2, gindex + 1, face->glyf_len )); | |
| 181 pos2 = face->glyf_len; | |
| 182 } | |
| 183 | |
| 184 /* The `loca' table must be ordered; it refers to the length of */ | |
| 185 /* an entry as the difference between the current and the next */ | |
| 186 /* position. However, there do exist (malformed) fonts which */ | |
| 187 /* don't obey this rule, so we are only able to provide an */ | |
| 188 /* upper bound for the size. */ | |
| 189 /* */ | |
| 190 /* We get (intentionally) a wrong, non-zero result in case the */ | |
| 191 /* `glyf' table is missing. */ | |
| 192 if ( pos2 >= pos1 ) | |
| 193 *asize = (FT_UInt)( pos2 - pos1 ); | |
| 194 else | |
| 195 *asize = (FT_UInt)( face->glyf_len - pos1 ); | |
| 196 | |
| 197 return pos1; | |
| 198 } | |
| 199 | |
| 200 | |
| 201 FT_LOCAL_DEF( void ) | |
| 202 tt_face_done_loca( TT_Face face ) | |
| 203 { | |
| 204 FT_Stream stream = face->root.stream; | |
| 205 | |
| 206 | |
| 207 FT_FRAME_RELEASE( face->glyph_locations ); | |
| 208 face->num_locations = 0; | |
| 209 } | |
| 210 | |
| 211 | |
| 212 | |
| 213 /*************************************************************************/ | |
| 214 /* */ | |
| 215 /* <Function> */ | |
| 216 /* tt_face_load_cvt */ | |
| 217 /* */ | |
| 218 /* <Description> */ | |
| 219 /* Load the control value table into a face object. */ | |
| 220 /* */ | |
| 221 /* <InOut> */ | |
| 222 /* face :: A handle to the target face object. */ | |
| 223 /* */ | |
| 224 /* <Input> */ | |
| 225 /* stream :: A handle to the input stream. */ | |
| 226 /* */ | |
| 227 /* <Return> */ | |
| 228 /* FreeType error code. 0 means success. */ | |
| 229 /* */ | |
| 230 FT_LOCAL_DEF( FT_Error ) | |
| 231 tt_face_load_cvt( TT_Face face, | |
| 232 FT_Stream stream ) | |
| 233 { | |
| 234 #ifdef TT_USE_BYTECODE_INTERPRETER | |
| 235 | |
| 236 FT_Error error; | |
| 237 FT_Memory memory = stream->memory; | |
| 238 FT_ULong table_len; | |
| 239 | |
| 240 | |
| 241 FT_TRACE2(( "CVT " )); | |
| 242 | |
| 243 error = face->goto_table( face, TTAG_cvt, stream, &table_len ); | |
| 244 if ( error ) | |
| 245 { | |
| 246 FT_TRACE2(( "is missing\n" )); | |
| 247 | |
| 248 face->cvt_size = 0; | |
| 249 face->cvt = NULL; | |
| 250 error = FT_Err_Ok; | |
| 251 | |
| 252 goto Exit; | |
| 253 } | |
| 254 | |
| 255 face->cvt_size = table_len / 2; | |
| 256 | |
| 257 if ( FT_NEW_ARRAY( face->cvt, face->cvt_size ) ) | |
| 258 goto Exit; | |
| 259 | |
| 260 if ( FT_FRAME_ENTER( face->cvt_size * 2L ) ) | |
| 261 goto Exit; | |
| 262 | |
| 263 { | |
| 264 FT_Short* cur = face->cvt; | |
| 265 FT_Short* limit = cur + face->cvt_size; | |
| 266 | |
| 267 | |
| 268 for ( ; cur < limit; cur++ ) | |
| 269 *cur = FT_GET_SHORT(); | |
| 270 } | |
| 271 | |
| 272 FT_FRAME_EXIT(); | |
| 273 FT_TRACE2(( "loaded\n" )); | |
| 274 | |
| 275 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT | |
| 276 if ( face->doblend ) | |
| 277 error = tt_face_vary_cvt( face, stream ); | |
| 278 #endif | |
| 279 | |
| 280 Exit: | |
| 281 return error; | |
| 282 | |
| 283 #else /* !TT_USE_BYTECODE_INTERPRETER */ | |
| 284 | |
| 285 FT_UNUSED( face ); | |
| 286 FT_UNUSED( stream ); | |
| 287 | |
| 288 return FT_Err_Ok; | |
| 289 | |
| 290 #endif | |
| 291 } | |
| 292 | |
| 293 | |
| 294 /*************************************************************************/ | |
| 295 /* */ | |
| 296 /* <Function> */ | |
| 297 /* tt_face_load_fpgm */ | |
| 298 /* */ | |
| 299 /* <Description> */ | |
| 300 /* Load the font program. */ | |
| 301 /* */ | |
| 302 /* <InOut> */ | |
| 303 /* face :: A handle to the target face object. */ | |
| 304 /* */ | |
| 305 /* <Input> */ | |
| 306 /* stream :: A handle to the input stream. */ | |
| 307 /* */ | |
| 308 /* <Return> */ | |
| 309 /* FreeType error code. 0 means success. */ | |
| 310 /* */ | |
| 311 FT_LOCAL_DEF( FT_Error ) | |
| 312 tt_face_load_fpgm( TT_Face face, | |
| 313 FT_Stream stream ) | |
| 314 { | |
| 315 #ifdef TT_USE_BYTECODE_INTERPRETER | |
| 316 | |
| 317 FT_Error error; | |
| 318 FT_ULong table_len; | |
| 319 | |
| 320 | |
| 321 FT_TRACE2(( "Font program " )); | |
| 322 | |
| 323 /* The font program is optional */ | |
| 324 error = face->goto_table( face, TTAG_fpgm, stream, &table_len ); | |
| 325 if ( error ) | |
| 326 { | |
| 327 face->font_program = NULL; | |
| 328 face->font_program_size = 0; | |
| 329 error = FT_Err_Ok; | |
| 330 | |
| 331 FT_TRACE2(( "is missing\n" )); | |
| 332 } | |
| 333 else | |
| 334 { | |
| 335 face->font_program_size = table_len; | |
| 336 if ( FT_FRAME_EXTRACT( table_len, face->font_program ) ) | |
| 337 goto Exit; | |
| 338 | |
| 339 FT_TRACE2(( "loaded, %12d bytes\n", face->font_program_size )); | |
| 340 } | |
| 341 | |
| 342 Exit: | |
| 343 return error; | |
| 344 | |
| 345 #else /* !TT_USE_BYTECODE_INTERPRETER */ | |
| 346 | |
| 347 FT_UNUSED( face ); | |
| 348 FT_UNUSED( stream ); | |
| 349 | |
| 350 return FT_Err_Ok; | |
| 351 | |
| 352 #endif | |
| 353 } | |
| 354 | |
| 355 | |
| 356 /*************************************************************************/ | |
| 357 /* */ | |
| 358 /* <Function> */ | |
| 359 /* tt_face_load_prep */ | |
| 360 /* */ | |
| 361 /* <Description> */ | |
| 362 /* Load the cvt program. */ | |
| 363 /* */ | |
| 364 /* <InOut> */ | |
| 365 /* face :: A handle to the target face object. */ | |
| 366 /* */ | |
| 367 /* <Input> */ | |
| 368 /* stream :: A handle to the input stream. */ | |
| 369 /* */ | |
| 370 /* <Return> */ | |
| 371 /* FreeType error code. 0 means success. */ | |
| 372 /* */ | |
| 373 FT_LOCAL_DEF( FT_Error ) | |
| 374 tt_face_load_prep( TT_Face face, | |
| 375 FT_Stream stream ) | |
| 376 { | |
| 377 #ifdef TT_USE_BYTECODE_INTERPRETER | |
| 378 | |
| 379 FT_Error error; | |
| 380 FT_ULong table_len; | |
| 381 | |
| 382 | |
| 383 FT_TRACE2(( "Prep program " )); | |
| 384 | |
| 385 error = face->goto_table( face, TTAG_prep, stream, &table_len ); | |
| 386 if ( error ) | |
| 387 { | |
| 388 face->cvt_program = NULL; | |
| 389 face->cvt_program_size = 0; | |
| 390 error = FT_Err_Ok; | |
| 391 | |
| 392 FT_TRACE2(( "is missing\n" )); | |
| 393 } | |
| 394 else | |
| 395 { | |
| 396 face->cvt_program_size = table_len; | |
| 397 if ( FT_FRAME_EXTRACT( table_len, face->cvt_program ) ) | |
| 398 goto Exit; | |
| 399 | |
| 400 FT_TRACE2(( "loaded, %12d bytes\n", face->cvt_program_size )); | |
| 401 } | |
| 402 | |
| 403 Exit: | |
| 404 return error; | |
| 405 | |
| 406 #else /* !TT_USE_BYTECODE_INTERPRETER */ | |
| 407 | |
| 408 FT_UNUSED( face ); | |
| 409 FT_UNUSED( stream ); | |
| 410 | |
| 411 return FT_Err_Ok; | |
| 412 | |
| 413 #endif | |
| 414 } | |
| 415 | |
| 416 | |
| 417 /*************************************************************************/ | |
| 418 /* */ | |
| 419 /* <Function> */ | |
| 420 /* tt_face_load_hdmx */ | |
| 421 /* */ | |
| 422 /* <Description> */ | |
| 423 /* Load the `hdmx' table into the face object. */ | |
| 424 /* */ | |
| 425 /* <Input> */ | |
| 426 /* face :: A handle to the target face object. */ | |
| 427 /* */ | |
| 428 /* stream :: A handle to the input stream. */ | |
| 429 /* */ | |
| 430 /* <Return> */ | |
| 431 /* FreeType error code. 0 means success. */ | |
| 432 /* */ | |
| 433 | |
| 434 FT_LOCAL_DEF( FT_Error ) | |
| 435 tt_face_load_hdmx( TT_Face face, | |
| 436 FT_Stream stream ) | |
| 437 { | |
| 438 FT_Error error; | |
| 439 FT_Memory memory = stream->memory; | |
| 440 FT_UInt version, nn, num_records; | |
| 441 FT_ULong table_size, record_size; | |
| 442 FT_Byte* p; | |
| 443 FT_Byte* limit; | |
| 444 | |
| 445 | |
| 446 /* this table is optional */ | |
| 447 error = face->goto_table( face, TTAG_hdmx, stream, &table_size ); | |
| 448 if ( error || table_size < 8 ) | |
| 449 return FT_Err_Ok; | |
| 450 | |
| 451 if ( FT_FRAME_EXTRACT( table_size, face->hdmx_table ) ) | |
| 452 goto Exit; | |
| 453 | |
| 454 p = face->hdmx_table; | |
| 455 limit = p + table_size; | |
| 456 | |
| 457 version = FT_NEXT_USHORT( p ); | |
| 458 num_records = FT_NEXT_USHORT( p ); | |
| 459 record_size = FT_NEXT_ULONG( p ); | |
| 460 | |
| 461 /* The maximum number of bytes in an hdmx device record is the */ | |
| 462 /* maximum number of glyphs + 2; this is 0xFFFF + 2; this is */ | |
| 463 /* the reason why `record_size' is a long (which we read as */ | |
| 464 /* unsigned long for convenience). In practice, two bytes */ | |
| 465 /* sufficient to hold the size value. */ | |
| 466 /* */ | |
| 467 /* There are at least two fonts, HANNOM-A and HANNOM-B version */ | |
| 468 /* 2.0 (2005), which get this wrong: The upper two bytes of */ | |
| 469 /* the size value are set to 0xFF instead of 0x00. We catch */ | |
| 470 /* and fix this. */ | |
| 471 | |
| 472 if ( record_size >= 0xFFFF0000UL ) | |
| 473 record_size &= 0xFFFFU; | |
| 474 | |
| 475 /* The limit for `num_records' is a heuristic value. */ | |
| 476 | |
| 477 if ( version != 0 || num_records > 255 || record_size > 0x10001L ) | |
| 478 { | |
| 479 error = FT_THROW( Invalid_File_Format ); | |
| 480 goto Fail; | |
| 481 } | |
| 482 | |
| 483 if ( FT_NEW_ARRAY( face->hdmx_record_sizes, num_records ) ) | |
| 484 goto Fail; | |
| 485 | |
| 486 for ( nn = 0; nn < num_records; nn++ ) | |
| 487 { | |
| 488 if ( p + record_size > limit ) | |
| 489 break; | |
| 490 | |
| 491 face->hdmx_record_sizes[nn] = p[0]; | |
| 492 p += record_size; | |
| 493 } | |
| 494 | |
| 495 face->hdmx_record_count = nn; | |
| 496 face->hdmx_table_size = table_size; | |
| 497 face->hdmx_record_size = record_size; | |
| 498 | |
| 499 Exit: | |
| 500 return error; | |
| 501 | |
| 502 Fail: | |
| 503 FT_FRAME_RELEASE( face->hdmx_table ); | |
| 504 face->hdmx_table_size = 0; | |
| 505 goto Exit; | |
| 506 } | |
| 507 | |
| 508 | |
| 509 FT_LOCAL_DEF( void ) | |
| 510 tt_face_free_hdmx( TT_Face face ) | |
| 511 { | |
| 512 FT_Stream stream = face->root.stream; | |
| 513 FT_Memory memory = stream->memory; | |
| 514 | |
| 515 | |
| 516 FT_FREE( face->hdmx_record_sizes ); | |
| 517 FT_FRAME_RELEASE( face->hdmx_table ); | |
| 518 } | |
| 519 | |
| 520 | |
| 521 /*************************************************************************/ | |
| 522 /* */ | |
| 523 /* Return the advance width table for a given pixel size if it is found */ | |
| 524 /* in the font's `hdmx' table (if any). */ | |
| 525 /* */ | |
| 526 FT_LOCAL_DEF( FT_Byte* ) | |
| 527 tt_face_get_device_metrics( TT_Face face, | |
| 528 FT_UInt ppem, | |
| 529 FT_UInt gindex ) | |
| 530 { | |
| 531 FT_UInt nn; | |
| 532 FT_Byte* result = NULL; | |
| 533 FT_ULong record_size = face->hdmx_record_size; | |
| 534 FT_Byte* record = face->hdmx_table + 8; | |
| 535 | |
| 536 | |
| 537 for ( nn = 0; nn < face->hdmx_record_count; nn++ ) | |
| 538 if ( face->hdmx_record_sizes[nn] == ppem ) | |
| 539 { | |
| 540 gindex += 2; | |
| 541 if ( gindex < record_size ) | |
| 542 result = record + nn * record_size + gindex; | |
| 543 break; | |
| 544 } | |
| 545 | |
| 546 return result; | |
| 547 } | |
| 548 | |
| 549 | |
| 550 /* END */ | |
| OLD | NEW |