1 /***************************************************************************/ 2 /* */ 3 /* t1load.c */ 4 /* */ 5 /* Type 1 font loader (body). */ 6 /* */ 7 /* Copyright 1996-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 /*************************************************************************/ 20 /* */ 21 /* This is the new and improved Type 1 data loader for FreeType 2. The */ 22 /* old loader has several problems: it is slow, complex, difficult to */ 23 /* maintain, and contains incredible hacks to make it accept some */ 24 /* ill-formed Type 1 fonts without hiccup-ing. Moreover, about 5% of */ 25 /* the Type 1 fonts on my machine still aren't loaded correctly by it. */ 26 /* */ 27 /* This version is much simpler, much faster and also easier to read and */ 28 /* maintain by a great order of magnitude. The idea behind it is to */ 29 /* _not_ try to read the Type 1 token stream with a state machine (i.e. */ 30 /* a Postscript-like interpreter) but rather to perform simple pattern */ 31 /* matching. */ 32 /* */ 33 /* Indeed, nearly all data definitions follow a simple pattern like */ 34 /* */ 35 /* ... /Field <data> ... */ 36 /* */ 37 /* where <data> can be a number, a boolean, a string, or an array of */ 38 /* numbers. There are a few exceptions, namely the encoding, font name, */ 39 /* charstrings, and subrs; they are handled with a special pattern */ 40 /* matching routine. */ 41 /* */ 42 /* All other common cases are handled very simply. The matching rules */ 43 /* are defined in the file `t1tokens.h' through the use of several */ 44 /* macros calls PARSE_XXX. This file is included twice here; the first */ 45 /* time to generate parsing callback functions, the second time to */ 46 /* generate a table of keywords (with pointers to the associated */ 47 /* callback functions). */ 48 /* */ 49 /* The function `parse_dict' simply scans *linearly* a given dictionary */ 50 /* (either the top-level or private one) and calls the appropriate */ 51 /* callback when it encounters an immediate keyword. */ 52 /* */ 53 /* This is by far the fastest way one can find to parse and read all */ 54 /* data. */ 55 /* */ 56 /* This led to tremendous code size reduction. Note that later, the */ 57 /* glyph loader will also be _greatly_ simplified, and the automatic */ 58 /* hinter will replace the clumsy `t1hinter'. */ 59 /* */ 60 /*************************************************************************/ 61 62 63 #include "../../include/ft2build.h" 64 #include "../../include/freetype/internal/ftdebug.h" 65 #include "../../include/freetype/config/ftconfig.h" 66 #include "../../include/freetype/ftmm.h" 67 #include "../../include/freetype/internal/t1types.h" 68 #include "../../include/freetype/internal/ftcalc.h" 69 70 #include "t1load.h" 71 #include "t1errors.h" 72 73 74 #ifdef FT_CONFIG_OPTION_INCREMENTAL 75 #define IS_INCREMENTAL (FT_Bool)( face->root.internal->incremental_interface != 0 ) 76 #else 77 #define IS_INCREMENTAL 0 78 #endif 79 80 81 /*************************************************************************/ 82 /* */ 83 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 84 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 85 /* messages during execution. */ 86 /* */ 87 #undef FT_COMPONENT 88 #define FT_COMPONENT trace_t1load 89 90 91 #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT 92 93 94 /*************************************************************************/ 95 /*************************************************************************/ 96 /***** *****/ 97 /***** MULTIPLE MASTERS SUPPORT *****/ 98 /***** *****/ 99 /*************************************************************************/ 100 /*************************************************************************/ 101 102 static FT_Error 103 t1_allocate_blend( T1_Face face, 104 FT_UInt num_designs, 105 FT_UInt num_axis ) 106 { 107 PS_Blend blend; 108 FT_Memory memory = face->root.memory; 109 FT_Error error = FT_Err_Ok; 110 111 112 blend = face->blend; 113 if ( !blend ) 114 { 115 if ( FT_NEW( blend ) ) 116 goto Exit; 117 118 blend->num_default_design_vector = 0; 119 120 face->blend = blend; 121 } 122 123 /* allocate design data if needed */ 124 if ( num_designs > 0 ) 125 { 126 if ( blend->num_designs == 0 ) 127 { 128 FT_UInt nn; 129 130 131 /* allocate the blend `private' and `font_info' dictionaries */ 132 if ( FT_NEW_ARRAY( blend->font_infos[1], num_designs ) || 133 FT_NEW_ARRAY( blend->privates [1], num_designs ) || 134 FT_NEW_ARRAY( blend->bboxes [1], num_designs ) || 135 FT_NEW_ARRAY( blend->weight_vector, num_designs * 2 ) ) 136 goto Exit; 137 138 blend->default_weight_vector = blend->weight_vector + num_designs; 139 140 blend->font_infos[0] = &face->type1.font_info; 141 blend->privates [0] = &face->type1.private_dict; 142 blend->bboxes [0] = &face->type1.font_bbox; 143 144 for ( nn = 2; nn <= num_designs; nn++ ) 145 { 146 blend->font_infos[nn] = blend->font_infos[nn - 1] + 1; 147 blend->privates [nn] = blend->privates [nn - 1] + 1; 148 blend->bboxes [nn] = blend->bboxes [nn - 1] + 1; 149 } 150 151 blend->num_designs = num_designs; 152 } 153 else if ( blend->num_designs != num_designs ) 154 goto Fail; 155 } 156 157 /* allocate axis data if needed */ 158 if ( num_axis > 0 ) 159 { 160 if ( blend->num_axis != 0 && blend->num_axis != num_axis ) 161 goto Fail; 162 163 blend->num_axis = num_axis; 164 } 165 166 /* allocate the blend design pos table if needed */ 167 num_designs = blend->num_designs; 168 num_axis = blend->num_axis; 169 if ( num_designs && num_axis && blend->design_pos[0] == 0 ) 170 { 171 FT_UInt n; 172 173 174 if ( FT_NEW_ARRAY( blend->design_pos[0], num_designs * num_axis ) ) 175 goto Exit; 176 177 for ( n = 1; n < num_designs; n++ ) 178 blend->design_pos[n] = blend->design_pos[0] + num_axis * n; 179 } 180 181 Exit: 182 return error; 183 184 Fail: 185 error = FT_THROW( Invalid_File_Format ); 186 goto Exit; 187 } 188 189 190 FT_LOCAL_DEF( FT_Error ) 191 T1_Get_Multi_Master( T1_Face face, 192 FT_Multi_Master* master ) 193 { 194 PS_Blend blend = face->blend; 195 FT_UInt n; 196 FT_Error error; 197 198 199 error = FT_THROW( Invalid_Argument ); 200 201 if ( blend ) 202 { 203 master->num_axis = blend->num_axis; 204 master->num_designs = blend->num_designs; 205 206 for ( n = 0; n < blend->num_axis; n++ ) 207 { 208 FT_MM_Axis* axis = master->axis + n; 209 PS_DesignMap map = blend->design_map + n; 210 211 212 axis->name = blend->axis_names[n]; 213 axis->minimum = map->design_points[0]; 214 axis->maximum = map->design_points[map->num_points - 1]; 215 } 216 217 error = FT_Err_Ok; 218 } 219 220 return error; 221 } 222 223 224 /*************************************************************************/ 225 /* */ 226 /* Given a normalized (blend) coordinate, figure out the design */ 227 /* coordinate appropriate for that value. */ 228 /* */ 229 FT_LOCAL_DEF( FT_Fixed ) 230 mm_axis_unmap( PS_DesignMap axismap, 231 FT_Fixed ncv ) 232 { 233 int j; 234 235 236 if ( ncv <= axismap->blend_points[0] ) 237 return INT_TO_FIXED( axismap->design_points[0] ); 238 239 for ( j = 1; j < axismap->num_points; ++j ) 240 { 241 if ( ncv <= axismap->blend_points[j] ) 242 return INT_TO_FIXED( axismap->design_points[j - 1] ) + 243 ( axismap->design_points[j] - axismap->design_points[j - 1] ) * 244 FT_DivFix( ncv - axismap->blend_points[j - 1], 245 axismap->blend_points[j] - 246 axismap->blend_points[j - 1] ); 247 } 248 249 return INT_TO_FIXED( axismap->design_points[axismap->num_points - 1] ); 250 } 251 252 253 /*************************************************************************/ 254 /* */ 255 /* Given a vector of weights, one for each design, figure out the */ 256 /* normalized axis coordinates which gave rise to those weights. */ 257 /* */ 258 FT_LOCAL_DEF( void ) 259 mm_weights_unmap( FT_Fixed* weights, 260 FT_Fixed* axiscoords, 261 FT_UInt axis_count ) 262 { 263 FT_ASSERT( axis_count <= T1_MAX_MM_AXIS ); 264 265 if ( axis_count == 1 ) 266 axiscoords[0] = weights[1]; 267 268 else if ( axis_count == 2 ) 269 { 270 axiscoords[0] = weights[3] + weights[1]; 271 axiscoords[1] = weights[3] + weights[2]; 272 } 273 274 else if ( axis_count == 3 ) 275 { 276 axiscoords[0] = weights[7] + weights[5] + weights[3] + weights[1]; 277 axiscoords[1] = weights[7] + weights[6] + weights[3] + weights[2]; 278 axiscoords[2] = weights[7] + weights[6] + weights[5] + weights[4]; 279 } 280 281 else 282 { 283 axiscoords[0] = weights[15] + weights[13] + weights[11] + weights[9] + 284 weights[7] + weights[5] + weights[3] + weights[1]; 285 axiscoords[1] = weights[15] + weights[14] + weights[11] + weights[10] + 286 weights[7] + weights[6] + weights[3] + weights[2]; 287 axiscoords[2] = weights[15] + weights[14] + weights[13] + weights[12] + 288 weights[7] + weights[6] + weights[5] + weights[4]; 289 axiscoords[3] = weights[15] + weights[14] + weights[13] + weights[12] + 290 weights[11] + weights[10] + weights[9] + weights[8]; 291 } 292 } 293 294 295 /*************************************************************************/ 296 /* */ 297 /* Just a wrapper around T1_Get_Multi_Master to support the different */ 298 /* arguments needed by the GX var distortable fonts. */ 299 /* */ 300 FT_LOCAL_DEF( FT_Error ) 301 T1_Get_MM_Var( T1_Face face, 302 FT_MM_Var* *master ) 303 { 304 FT_Memory memory = face->root.memory; 305 FT_MM_Var *mmvar = NULL; 306 FT_Multi_Master mmaster; 307 FT_Error error; 308 FT_UInt i; 309 FT_Fixed axiscoords[T1_MAX_MM_AXIS]; 310 PS_Blend blend = face->blend; 311 312 313 error = T1_Get_Multi_Master( face, &mmaster ); 314 if ( error ) 315 goto Exit; 316 if ( FT_ALLOC( mmvar, 317 sizeof ( FT_MM_Var ) + 318 mmaster.num_axis * sizeof ( FT_Var_Axis ) ) ) 319 goto Exit; 320 321 mmvar->num_axis = mmaster.num_axis; 322 mmvar->num_designs = mmaster.num_designs; 323 mmvar->num_namedstyles = ~0U; /* Does not apply */ 324 mmvar->axis = (FT_Var_Axis*)&mmvar[1]; 325 /* Point to axes after MM_Var struct */ 326 mmvar->namedstyle = NULL; 327 328 for ( i = 0 ; i < mmaster.num_axis; ++i ) 329 { 330 mmvar->axis[i].name = mmaster.axis[i].name; 331 mmvar->axis[i].minimum = INT_TO_FIXED( mmaster.axis[i].minimum); 332 mmvar->axis[i].maximum = INT_TO_FIXED( mmaster.axis[i].maximum); 333 mmvar->axis[i].def = ( mmvar->axis[i].minimum + 334 mmvar->axis[i].maximum ) / 2; 335 /* Does not apply. But this value is in range */ 336 mmvar->axis[i].strid = ~0U; /* Does not apply */ 337 mmvar->axis[i].tag = ~0U; /* Does not apply */ 338 339 if ( ft_strcmp( mmvar->axis[i].name, "Weight" ) == 0 ) 340 mmvar->axis[i].tag = FT_MAKE_TAG( 'w', 'g', 'h', 't' ); 341 else if ( ft_strcmp( mmvar->axis[i].name, "Width" ) == 0 ) 342 mmvar->axis[i].tag = FT_MAKE_TAG( 'w', 'd', 't', 'h' ); 343 else if ( ft_strcmp( mmvar->axis[i].name, "OpticalSize" ) == 0 ) 344 mmvar->axis[i].tag = FT_MAKE_TAG( 'o', 'p', 's', 'z' ); 345 } 346 347 if ( blend->num_designs == ( 1U << blend->num_axis ) ) 348 { 349 mm_weights_unmap( blend->default_weight_vector, 350 axiscoords, 351 blend->num_axis ); 352 353 for ( i = 0; i < mmaster.num_axis; ++i ) 354 mmvar->axis[i].def = mm_axis_unmap( &blend->design_map[i], 355 axiscoords[i] ); 356 } 357 358 *master = mmvar; 359 360 Exit: 361 return error; 362 } 363 364 365 FT_LOCAL_DEF( FT_Error ) 366 T1_Set_MM_Blend( T1_Face face, 367 FT_UInt num_coords, 368 FT_Fixed* coords ) 369 { 370 PS_Blend blend = face->blend; 371 FT_Error error; 372 FT_UInt n, m; 373 374 375 error = FT_ERR( Invalid_Argument ); 376 377 if ( blend && blend->num_axis == num_coords ) 378 { 379 /* recompute the weight vector from the blend coordinates */ 380 error = FT_Err_Ok; 381 382 for ( n = 0; n < blend->num_designs; n++ ) 383 { 384 FT_Fixed result = 0x10000L; /* 1.0 fixed */ 385 386 387 for ( m = 0; m < blend->num_axis; m++ ) 388 { 389 FT_Fixed factor; 390 391 392 /* get current blend axis position */ 393 factor = coords[m]; 394 if ( factor < 0 ) 395 factor = 0; 396 if ( factor > 0x10000L ) 397 factor = 0x10000L; 398 399 if ( ( n & ( 1 << m ) ) == 0 ) 400 factor = 0x10000L - factor; 401 402 result = FT_MulFix( result, factor ); 403 } 404 blend->weight_vector[n] = result; 405 } 406 407 error = FT_Err_Ok; 408 } 409 410 return error; 411 } 412 413 414 FT_LOCAL_DEF( FT_Error ) 415 T1_Set_MM_Design( T1_Face face, 416 FT_UInt num_coords, 417 FT_Long* coords ) 418 { 419 PS_Blend blend = face->blend; 420 FT_Error error; 421 FT_UInt n, p; 422 423 424 error = FT_ERR( Invalid_Argument ); 425 if ( blend && blend->num_axis == num_coords ) 426 { 427 /* compute the blend coordinates through the blend design map */ 428 FT_Fixed final_blends[T1_MAX_MM_DESIGNS]; 429 430 431 for ( n = 0; n < blend->num_axis; n++ ) 432 { 433 FT_Long design = coords[n]; 434 FT_Fixed the_blend; 435 PS_DesignMap map = blend->design_map + n; 436 FT_Long* designs = map->design_points; 437 FT_Fixed* blends = map->blend_points; 438 FT_Int before = -1, after = -1; 439 440 441 for ( p = 0; p < (FT_UInt)map->num_points; p++ ) 442 { 443 FT_Long p_design = designs[p]; 444 445 446 /* exact match? */ 447 if ( design == p_design ) 448 { 449 the_blend = blends[p]; 450 goto Found; 451 } 452 453 if ( design < p_design ) 454 { 455 after = p; 456 break; 457 } 458 459 before = p; 460 } 461 462 /* now interpolate if necessary */ 463 if ( before < 0 ) 464 the_blend = blends[0]; 465 466 else if ( after < 0 ) 467 the_blend = blends[map->num_points - 1]; 468 469 else 470 the_blend = FT_MulDiv( design - designs[before], 471 blends [after] - blends [before], 472 designs[after] - designs[before] ); 473 474 Found: 475 final_blends[n] = the_blend; 476 } 477 478 error = T1_Set_MM_Blend( face, num_coords, final_blends ); 479 } 480 481 return error; 482 } 483 484 485 /*************************************************************************/ 486 /* */ 487 /* Just a wrapper around T1_Set_MM_Design to support the different */ 488 /* arguments needed by the GX var distortable fonts. */ 489 /* */ 490 FT_LOCAL_DEF( FT_Error ) 491 T1_Set_Var_Design( T1_Face face, 492 FT_UInt num_coords, 493 FT_Fixed* coords ) 494 { 495 FT_Long lcoords[4]; /* maximum axis count is 4 */ 496 FT_UInt i; 497 FT_Error error; 498 499 500 error = FT_ERR( Invalid_Argument ); 501 if ( num_coords <= 4 && num_coords > 0 ) 502 { 503 for ( i = 0; i < num_coords; ++i ) 504 lcoords[i] = FIXED_TO_INT( coords[i] ); 505 error = T1_Set_MM_Design( face, num_coords, lcoords ); 506 } 507 508 return error; 509 } 510 511 512 FT_LOCAL_DEF( void ) 513 T1_Done_Blend( T1_Face face ) 514 { 515 FT_Memory memory = face->root.memory; 516 PS_Blend blend = face->blend; 517 518 519 if ( blend ) 520 { 521 FT_UInt num_designs = blend->num_designs; 522 FT_UInt num_axis = blend->num_axis; 523 FT_UInt n; 524 525 526 /* release design pos table */ 527 FT_FREE( blend->design_pos[0] ); 528 for ( n = 1; n < num_designs; n++ ) 529 blend->design_pos[n] = NULL; 530 531 /* release blend `private' and `font info' dictionaries */ 532 FT_FREE( blend->privates[1] ); 533 FT_FREE( blend->font_infos[1] ); 534 FT_FREE( blend->bboxes[1] ); 535 536 for ( n = 0; n < num_designs; n++ ) 537 { 538 blend->privates [n] = NULL; 539 blend->font_infos[n] = NULL; 540 blend->bboxes [n] = NULL; 541 } 542 543 /* release weight vectors */ 544 FT_FREE( blend->weight_vector ); 545 blend->default_weight_vector = NULL; 546 547 /* release axis names */ 548 for ( n = 0; n < num_axis; n++ ) 549 FT_FREE( blend->axis_names[n] ); 550 551 /* release design map */ 552 for ( n = 0; n < num_axis; n++ ) 553 { 554 PS_DesignMap dmap = blend->design_map + n; 555 556 557 FT_FREE( dmap->design_points ); 558 dmap->num_points = 0; 559 } 560 561 FT_FREE( face->blend ); 562 } 563 } 564 565 566 static void 567 parse_blend_axis_types( T1_Face face, 568 T1_Loader loader ) 569 { 570 T1_TokenRec axis_tokens[T1_MAX_MM_AXIS]; 571 FT_Int n, num_axis; 572 FT_Error error = FT_Err_Ok; 573 PS_Blend blend; 574 FT_Memory memory; 575 576 577 /* take an array of objects */ 578 T1_ToTokenArray( &loader->parser, axis_tokens, 579 T1_MAX_MM_AXIS, &num_axis ); 580 if ( num_axis < 0 ) 581 { 582 error = FT_ERR( Ignore ); 583 goto Exit; 584 } 585 if ( num_axis == 0 || num_axis > T1_MAX_MM_AXIS ) 586 { 587 FT_ERROR(( "parse_blend_axis_types: incorrect number of axes: %d\n", 588 num_axis )); 589 error = FT_THROW( Invalid_File_Format ); 590 goto Exit; 591 } 592 593 /* allocate blend if necessary */ 594 error = t1_allocate_blend( face, 0, (FT_UInt)num_axis ); 595 if ( error ) 596 goto Exit; 597 598 blend = face->blend; 599 memory = face->root.memory; 600 601 /* each token is an immediate containing the name of the axis */ 602 for ( n = 0; n < num_axis; n++ ) 603 { 604 T1_Token token = axis_tokens + n; 605 FT_Byte* name; 606 FT_PtrDist len; 607 608 609 /* skip first slash, if any */ 610 if ( token->start[0] == '/' ) 611 token->start++; 612 613 len = token->limit - token->start; 614 if ( len == 0 ) 615 { 616 error = FT_THROW( Invalid_File_Format ); 617 goto Exit; 618 } 619 620 if ( FT_ALLOC( blend->axis_names[n], (FT_Long)( len + 1 ) ) ) 621 goto Exit; 622 623 name = (FT_Byte*)blend->axis_names[n]; 624 FT_MEM_COPY( name, token->start, len ); 625 name[len] = '\0'; 626 } 627 628 Exit: 629 loader->parser.root.error = error; 630 } 631 632 633 static void 634 parse_blend_design_positions( T1_Face face, 635 T1_Loader loader ) 636 { 637 T1_TokenRec design_tokens[T1_MAX_MM_DESIGNS]; 638 FT_Int num_designs; 639 FT_Int num_axis; 640 T1_Parser parser = &loader->parser; 641 642 FT_Error error = FT_Err_Ok; 643 PS_Blend blend; 644 645 646 /* get the array of design tokens -- compute number of designs */ 647 T1_ToTokenArray( parser, design_tokens, 648 T1_MAX_MM_DESIGNS, &num_designs ); 649 if ( num_designs < 0 ) 650 { 651 error = FT_ERR( Ignore ); 652 goto Exit; 653 } 654 if ( num_designs == 0 || num_designs > T1_MAX_MM_DESIGNS ) 655 { 656 FT_ERROR(( "parse_blend_design_positions:" 657 " incorrect number of designs: %d\n", 658 num_designs )); 659 error = FT_THROW( Invalid_File_Format ); 660 goto Exit; 661 } 662 663 { 664 FT_Byte* old_cursor = parser->root.cursor; 665 FT_Byte* old_limit = parser->root.limit; 666 FT_Int n; 667 668 669 blend = face->blend; 670 num_axis = 0; /* make compiler happy */ 671 672 for ( n = 0; n < num_designs; n++ ) 673 { 674 T1_TokenRec axis_tokens[T1_MAX_MM_AXIS]; 675 T1_Token token; 676 FT_Int axis, n_axis; 677 678 679 /* read axis/coordinates tokens */ 680 token = design_tokens + n; 681 parser->root.cursor = token->start; 682 parser->root.limit = token->limit; 683 T1_ToTokenArray( parser, axis_tokens, T1_MAX_MM_AXIS, &n_axis ); 684 685 if ( n == 0 ) 686 { 687 if ( n_axis <= 0 || n_axis > T1_MAX_MM_AXIS ) 688 { 689 FT_ERROR(( "parse_blend_design_positions:" 690 " invalid number of axes: %d\n", 691 n_axis )); 692 error = FT_THROW( Invalid_File_Format ); 693 goto Exit; 694 } 695 696 num_axis = n_axis; 697 error = t1_allocate_blend( face, num_designs, num_axis ); 698 if ( error ) 699 goto Exit; 700 blend = face->blend; 701 } 702 else if ( n_axis != num_axis ) 703 { 704 FT_ERROR(( "parse_blend_design_positions: incorrect table\n" )); 705 error = FT_THROW( Invalid_File_Format ); 706 goto Exit; 707 } 708 709 /* now read each axis token into the design position */ 710 for ( axis = 0; axis < n_axis; axis++ ) 711 { 712 T1_Token token2 = axis_tokens + axis; 713 714 715 parser->root.cursor = token2->start; 716 parser->root.limit = token2->limit; 717 blend->design_pos[n][axis] = T1_ToFixed( parser, 0 ); 718 } 719 } 720 721 loader->parser.root.cursor = old_cursor; 722 loader->parser.root.limit = old_limit; 723 } 724 725 Exit: 726 loader->parser.root.error = error; 727 } 728 729 730 static void 731 parse_blend_design_map( T1_Face face, 732 T1_Loader loader ) 733 { 734 FT_Error error = FT_Err_Ok; 735 T1_Parser parser = &loader->parser; 736 PS_Blend blend; 737 T1_TokenRec axis_tokens[T1_MAX_MM_AXIS]; 738 FT_Int n, num_axis; 739 FT_Byte* old_cursor; 740 FT_Byte* old_limit; 741 FT_Memory memory = face->root.memory; 742 743 744 T1_ToTokenArray( parser, axis_tokens, 745 T1_MAX_MM_AXIS, &num_axis ); 746 if ( num_axis < 0 ) 747 { 748 error = FT_ERR( Ignore ); 749 goto Exit; 750 } 751 if ( num_axis == 0 || num_axis > T1_MAX_MM_AXIS ) 752 { 753 FT_ERROR(( "parse_blend_design_map: incorrect number of axes: %d\n", 754 num_axis )); 755 error = FT_THROW( Invalid_File_Format ); 756 goto Exit; 757 } 758 759 old_cursor = parser->root.cursor; 760 old_limit = parser->root.limit; 761 762 error = t1_allocate_blend( face, 0, num_axis ); 763 if ( error ) 764 goto Exit; 765 blend = face->blend; 766 767 /* now read each axis design map */ 768 for ( n = 0; n < num_axis; n++ ) 769 { 770 PS_DesignMap map = blend->design_map + n; 771 T1_Token axis_token; 772 T1_TokenRec point_tokens[T1_MAX_MM_MAP_POINTS]; 773 FT_Int p, num_points; 774 775 776 axis_token = axis_tokens + n; 777 778 parser->root.cursor = axis_token->start; 779 parser->root.limit = axis_token->limit; 780 T1_ToTokenArray( parser, point_tokens, 781 T1_MAX_MM_MAP_POINTS, &num_points ); 782 783 if ( num_points <= 0 || num_points > T1_MAX_MM_MAP_POINTS ) 784 { 785 FT_ERROR(( "parse_blend_design_map: incorrect table\n" )); 786 error = FT_THROW( Invalid_File_Format ); 787 goto Exit; 788 } 789 790 /* allocate design map data */ 791 if ( FT_NEW_ARRAY( map->design_points, num_points * 2 ) ) 792 goto Exit; 793 map->blend_points = map->design_points + num_points; 794 map->num_points = (FT_Byte)num_points; 795 796 for ( p = 0; p < num_points; p++ ) 797 { 798 T1_Token point_token; 799 800 801 point_token = point_tokens + p; 802 803 /* don't include delimiting brackets */ 804 parser->root.cursor = point_token->start + 1; 805 parser->root.limit = point_token->limit - 1; 806 807 map->design_points[p] = T1_ToInt( parser ); 808 map->blend_points [p] = T1_ToFixed( parser, 0 ); 809 } 810 } 811 812 parser->root.cursor = old_cursor; 813 parser->root.limit = old_limit; 814 815 Exit: 816 parser->root.error = error; 817 } 818 819 820 static void 821 parse_weight_vector( T1_Face face, 822 T1_Loader loader ) 823 { 824 T1_TokenRec design_tokens[T1_MAX_MM_DESIGNS]; 825 FT_Int num_designs; 826 FT_Error error = FT_Err_Ok; 827 T1_Parser parser = &loader->parser; 828 PS_Blend blend = face->blend; 829 T1_Token token; 830 FT_Int n; 831 FT_Byte* old_cursor; 832 FT_Byte* old_limit; 833 834 835 T1_ToTokenArray( parser, design_tokens, 836 T1_MAX_MM_DESIGNS, &num_designs ); 837 if ( num_designs < 0 ) 838 { 839 error = FT_ERR( Ignore ); 840 goto Exit; 841 } 842 if ( num_designs == 0 || num_designs > T1_MAX_MM_DESIGNS ) 843 { 844 FT_ERROR(( "parse_weight_vector:" 845 " incorrect number of designs: %d\n", 846 num_designs )); 847 error = FT_THROW( Invalid_File_Format ); 848 goto Exit; 849 } 850 851 if ( !blend || !blend->num_designs ) 852 { 853 error = t1_allocate_blend( face, num_designs, 0 ); 854 if ( error ) 855 goto Exit; 856 blend = face->blend; 857 } 858 else if ( blend->num_designs != (FT_UInt)num_designs ) 859 { 860 FT_ERROR(( "parse_weight_vector:" 861 " /BlendDesignPosition and /WeightVector have\n" 862 " " 863 " different number of elements\n" )); 864 error = FT_THROW( Invalid_File_Format ); 865 goto Exit; 866 } 867 868 old_cursor = parser->root.cursor; 869 old_limit = parser->root.limit; 870 871 for ( n = 0; n < num_designs; n++ ) 872 { 873 token = design_tokens + n; 874 parser->root.cursor = token->start; 875 parser->root.limit = token->limit; 876 877 blend->default_weight_vector[n] = 878 blend->weight_vector[n] = T1_ToFixed( parser, 0 ); 879 } 880 881 parser->root.cursor = old_cursor; 882 parser->root.limit = old_limit; 883 884 Exit: 885 parser->root.error = error; 886 } 887 888 889 /* e.g., /BuildCharArray [0 0 0 0 0 0 0 0] def */ 890 /* we're only interested in the number of array elements */ 891 static void 892 parse_buildchar( T1_Face face, 893 T1_Loader loader ) 894 { 895 face->len_buildchar = T1_ToFixedArray( &loader->parser, 0, NULL, 0 ); 896 897 return; 898 } 899 900 901 #endif /* !T1_CONFIG_OPTION_NO_MM_SUPPORT */ 902 903 904 905 906 /*************************************************************************/ 907 /*************************************************************************/ 908 /***** *****/ 909 /***** TYPE 1 SYMBOL PARSING *****/ 910 /***** *****/ 911 /*************************************************************************/ 912 /*************************************************************************/ 913 914 static FT_Error 915 t1_load_keyword( T1_Face face, 916 T1_Loader loader, 917 const T1_Field field ) 918 { 919 FT_Error error; 920 void* dummy_object; 921 void** objects; 922 FT_UInt max_objects; 923 PS_Blend blend = face->blend; 924 925 926 if ( blend && blend->num_designs == 0 ) 927 blend = NULL; 928 929 /* if the keyword has a dedicated callback, call it */ 930 if ( field->type == T1_FIELD_TYPE_CALLBACK ) 931 { 932 field->reader( (FT_Face)face, loader ); 933 error = loader->parser.root.error; 934 goto Exit; 935 } 936 937 /* now, the keyword is either a simple field, or a table of fields; */ 938 /* we are now going to take care of it */ 939 switch ( field->location ) 940 { 941 case T1_FIELD_LOCATION_FONT_INFO: 942 dummy_object = &face->type1.font_info; 943 objects = &dummy_object; 944 max_objects = 0; 945 946 if ( blend ) 947 { 948 objects = (void**)blend->font_infos; 949 max_objects = blend->num_designs; 950 } 951 break; 952 953 case T1_FIELD_LOCATION_FONT_EXTRA: 954 dummy_object = &face->type1.font_extra; 955 objects = &dummy_object; 956 max_objects = 0; 957 break; 958 959 case T1_FIELD_LOCATION_PRIVATE: 960 dummy_object = &face->type1.private_dict; 961 objects = &dummy_object; 962 max_objects = 0; 963 964 if ( blend ) 965 { 966 objects = (void**)blend->privates; 967 max_objects = blend->num_designs; 968 } 969 break; 970 971 case T1_FIELD_LOCATION_BBOX: 972 dummy_object = &face->type1.font_bbox; 973 objects = &dummy_object; 974 max_objects = 0; 975 976 if ( blend ) 977 { 978 objects = (void**)blend->bboxes; 979 max_objects = blend->num_designs; 980 } 981 break; 982 983 case T1_FIELD_LOCATION_LOADER: 984 dummy_object = loader; 985 objects = &dummy_object; 986 max_objects = 0; 987 break; 988 989 case T1_FIELD_LOCATION_FACE: 990 dummy_object = face; 991 objects = &dummy_object; 992 max_objects = 0; 993 break; 994 995 #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT 996 case T1_FIELD_LOCATION_BLEND: 997 dummy_object = face->blend; 998 objects = &dummy_object; 999 max_objects = 0; 1000 break; 1001 #endif 1002 1003 default: 1004 dummy_object = &face->type1; 1005 objects = &dummy_object; 1006 max_objects = 0; 1007 } 1008 1009 if ( *objects ) 1010 { 1011 if ( field->type == T1_FIELD_TYPE_INTEGER_ARRAY || 1012 field->type == T1_FIELD_TYPE_FIXED_ARRAY ) 1013 error = T1_Load_Field_Table( &loader->parser, field, 1014 objects, max_objects, 0 ); 1015 else 1016 error = T1_Load_Field( &loader->parser, field, 1017 objects, max_objects, 0 ); 1018 } 1019 else 1020 { 1021 FT_TRACE1(( "t1_load_keyword: ignoring keyword `%s'" 1022 " which is not valid at this point\n" 1023 " (probably due to missing keywords)\n", 1024 field->ident )); 1025 error = FT_Err_Ok; 1026 } 1027 1028 Exit: 1029 return error; 1030 } 1031 1032 1033 static void 1034 parse_private( T1_Face face, 1035 T1_Loader loader ) 1036 { 1037 FT_UNUSED( face ); 1038 1039 loader->keywords_encountered |= T1_PRIVATE; 1040 } 1041 1042 1043 static int 1044 read_binary_data( T1_Parser parser, 1045 FT_Long* size, 1046 FT_Byte** base, 1047 FT_Bool incremental ) 1048 { 1049 FT_Byte* cur; 1050 FT_Byte* limit = parser->root.limit; 1051 1052 1053 /* the binary data has one of the following formats */ 1054 /* */ 1055 /* `size' [white*] RD white ....... ND */ 1056 /* `size' [white*] -| white ....... |- */ 1057 /* */ 1058 1059 T1_Skip_Spaces( parser ); 1060 1061 cur = parser->root.cursor; 1062 1063 if ( cur < limit && ft_isdigit( *cur ) ) 1064 { 1065 FT_Long s = T1_ToInt( parser ); 1066 1067 1068 T1_Skip_PS_Token( parser ); /* `RD' or `-|' or something else */ 1069 1070 /* there is only one whitespace char after the */ 1071 /* `RD' or `-|' token */ 1072 *base = parser->root.cursor + 1; 1073 1074 if ( s >= 0 && s < limit - *base ) 1075 { 1076 parser->root.cursor += s + 1; 1077 *size = s; 1078 return !parser->root.error; 1079 } 1080 } 1081 1082 if( !incremental ) 1083 { 1084 FT_ERROR(( "read_binary_data: invalid size field\n" )); 1085 parser->root.error = FT_THROW( Invalid_File_Format ); 1086 } 1087 1088 return 0; 1089 } 1090 1091 1092 /* We now define the routines to handle the `/Encoding', `/Subrs', */ 1093 /* and `/CharStrings' dictionaries. */ 1094 1095 static void 1096 t1_parse_font_matrix( T1_Face face, 1097 T1_Loader loader ) 1098 { 1099 T1_Parser parser = &loader->parser; 1100 FT_Matrix* matrix = &face->type1.font_matrix; 1101 FT_Vector* offset = &face->type1.font_offset; 1102 FT_Face root = (FT_Face)&face->root; 1103 FT_Fixed temp[6]; 1104 FT_Fixed temp_scale; 1105 FT_Int result; 1106 1107 1108 result = T1_ToFixedArray( parser, 6, temp, 3 ); 1109 1110 if ( result < 0 ) 1111 { 1112 parser->root.error = FT_THROW( Invalid_File_Format ); 1113 return; 1114 } 1115 1116 temp_scale = FT_ABS( temp[3] ); 1117 1118 if ( temp_scale == 0 ) 1119 { 1120 FT_ERROR(( "t1_parse_font_matrix: invalid font matrix\n" )); 1121 parser->root.error = FT_THROW( Invalid_File_Format ); 1122 return; 1123 } 1124 1125 /* Set Units per EM based on FontMatrix values. We set the value to */ 1126 /* 1000 / temp_scale, because temp_scale was already multiplied by */ 1127 /* 1000 (in t1_tofixed, from psobjs.c). */ 1128 1129 root->units_per_EM = (FT_UShort)FT_DivFix( 1000, temp_scale ); 1130 1131 /* we need to scale the values by 1.0/temp_scale */ 1132 if ( temp_scale != 0x10000L ) 1133 { 1134 temp[0] = FT_DivFix( temp[0], temp_scale ); 1135 temp[1] = FT_DivFix( temp[1], temp_scale ); 1136 temp[2] = FT_DivFix( temp[2], temp_scale ); 1137 temp[4] = FT_DivFix( temp[4], temp_scale ); 1138 temp[5] = FT_DivFix( temp[5], temp_scale ); 1139 temp[3] = temp[3] < 0 ? -0x10000L : 0x10000L; 1140 } 1141 1142 matrix->xx = temp[0]; 1143 matrix->yx = temp[1]; 1144 matrix->xy = temp[2]; 1145 matrix->yy = temp[3]; 1146 1147 /* note that the offsets must be expressed in integer font units */ 1148 offset->x = temp[4] >> 16; 1149 offset->y = temp[5] >> 16; 1150 } 1151 1152 1153 static void 1154 parse_encoding( T1_Face face, 1155 T1_Loader loader ) 1156 { 1157 T1_Parser parser = &loader->parser; 1158 FT_Byte* cur; 1159 FT_Byte* limit = parser->root.limit; 1160 1161 PSAux_Service psaux = (PSAux_Service)face->psaux; 1162 1163 1164 T1_Skip_Spaces( parser ); 1165 cur = parser->root.cursor; 1166 if ( cur >= limit ) 1167 { 1168 FT_ERROR(( "parse_encoding: out of bounds\n" )); 1169 parser->root.error = FT_THROW( Invalid_File_Format ); 1170 return; 1171 } 1172 1173 /* if we have a number or `[', the encoding is an array, */ 1174 /* and we must load it now */ 1175 if ( ft_isdigit( *cur ) || *cur == '[' ) 1176 { 1177 T1_Encoding encode = &face->type1.encoding; 1178 FT_Int count, n; 1179 PS_Table char_table = &loader->encoding_table; 1180 FT_Memory memory = parser->root.memory; 1181 FT_Error error; 1182 FT_Bool only_immediates = 0; 1183 1184 1185 /* read the number of entries in the encoding; should be 256 */ 1186 if ( *cur == '[' ) 1187 { 1188 count = 256; 1189 only_immediates = 1; 1190 parser->root.cursor++; 1191 } 1192 else 1193 count = (FT_Int)T1_ToInt( parser ); 1194 1195 T1_Skip_Spaces( parser ); 1196 if ( parser->root.cursor >= limit ) 1197 return; 1198 1199 /* we use a T1_Table to store our charnames */ 1200 loader->num_chars = encode->num_chars = count; 1201 if ( FT_NEW_ARRAY( encode->char_index, count ) || 1202 FT_NEW_ARRAY( encode->char_name, count ) || 1203 FT_SET_ERROR( psaux->ps_table_funcs->init( 1204 char_table, count, memory ) ) ) 1205 { 1206 parser->root.error = error; 1207 return; 1208 } 1209 1210 /* We need to `zero' out encoding_table.elements */ 1211 for ( n = 0; n < count; n++ ) 1212 { 1213 char* notdef = (char *)".notdef"; 1214 1215 1216 T1_Add_Table( char_table, n, notdef, 8 ); 1217 } 1218 1219 /* Now we need to read records of the form */ 1220 /* */ 1221 /* ... charcode /charname ... */ 1222 /* */ 1223 /* for each entry in our table. */ 1224 /* */ 1225 /* We simply look for a number followed by an immediate */ 1226 /* name. Note that this ignores correctly the sequence */ 1227 /* that is often seen in type1 fonts: */ 1228 /* */ 1229 /* 0 1 255 { 1 index exch /.notdef put } for dup */ 1230 /* */ 1231 /* used to clean the encoding array before anything else. */ 1232 /* */ 1233 /* Alternatively, if the array is directly given as */ 1234 /* */ 1235 /* /Encoding [ ... ] */ 1236 /* */ 1237 /* we only read immediates. */ 1238 1239 n = 0; 1240 T1_Skip_Spaces( parser ); 1241 1242 while ( parser->root.cursor < limit ) 1243 { 1244 cur = parser->root.cursor; 1245 1246 /* we stop when we encounter a `def' or `]' */ 1247 if ( *cur == 'd' && cur + 3 < limit ) 1248 { 1249 if ( cur[1] == 'e' && 1250 cur[2] == 'f' && 1251 IS_PS_DELIM( cur[3] ) ) 1252 { 1253 FT_TRACE6(( "encoding end\n" )); 1254 cur += 3; 1255 break; 1256 } 1257 } 1258 if ( *cur == ']' ) 1259 { 1260 FT_TRACE6(( "encoding end\n" )); 1261 cur++; 1262 break; 1263 } 1264 1265 /* check whether we've found an entry */ 1266 if ( ft_isdigit( *cur ) || only_immediates ) 1267 { 1268 FT_Int charcode; 1269 1270 1271 if ( only_immediates ) 1272 charcode = n; 1273 else 1274 { 1275 charcode = (FT_Int)T1_ToInt( parser ); 1276 T1_Skip_Spaces( parser ); 1277 } 1278 1279 cur = parser->root.cursor; 1280 1281 if ( cur + 2 < limit && *cur == '/' && n < count ) 1282 { 1283 FT_PtrDist len; 1284 1285 1286 cur++; 1287 1288 parser->root.cursor = cur; 1289 T1_Skip_PS_Token( parser ); 1290 if ( parser->root.cursor >= limit ) 1291 return; 1292 if ( parser->root.error ) 1293 return; 1294 1295 len = parser->root.cursor - cur; 1296 1297 parser->root.error = T1_Add_Table( char_table, charcode, 1298 cur, len + 1 ); 1299 if ( parser->root.error ) 1300 return; 1301 char_table->elements[charcode][len] = '\0'; 1302 1303 n++; 1304 } 1305 else if ( only_immediates ) 1306 { 1307 /* Since the current position is not updated for */ 1308 /* immediates-only mode we would get an infinite loop if */ 1309 /* we don't do anything here. */ 1310 /* */ 1311 /* This encoding array is not valid according to the type1 */ 1312 /* specification (it might be an encoding for a CID type1 */ 1313 /* font, however), so we conclude that this font is NOT a */ 1314 /* type1 font. */ 1315 parser->root.error = FT_THROW( Unknown_File_Format ); 1316 return; 1317 } 1318 } 1319 else 1320 { 1321 T1_Skip_PS_Token( parser ); 1322 if ( parser->root.error ) 1323 return; 1324 } 1325 1326 T1_Skip_Spaces( parser ); 1327 } 1328 1329 face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY; 1330 parser->root.cursor = cur; 1331 } 1332 1333 /* Otherwise, we should have either `StandardEncoding', */ 1334 /* `ExpertEncoding', or `ISOLatin1Encoding' */ 1335 else 1336 { 1337 if ( cur + 17 < limit && 1338 ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 ) 1339 face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD; 1340 1341 else if ( cur + 15 < limit && 1342 ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 ) 1343 face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT; 1344 1345 else if ( cur + 18 < limit && 1346 ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 ) 1347 face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1; 1348 1349 else 1350 parser->root.error = FT_ERR( Ignore ); 1351 } 1352 } 1353 1354 1355 static void 1356 parse_subrs( T1_Face face, 1357 T1_Loader loader ) 1358 { 1359 T1_Parser parser = &loader->parser; 1360 PS_Table table = &loader->subrs; 1361 FT_Memory memory = parser->root.memory; 1362 FT_Error error; 1363 FT_Int num_subrs; 1364 1365 PSAux_Service psaux = (PSAux_Service)face->psaux; 1366 1367 1368 T1_Skip_Spaces( parser ); 1369 1370 /* test for empty array */ 1371 if ( parser->root.cursor < parser->root.limit && 1372 *parser->root.cursor == '[' ) 1373 { 1374 T1_Skip_PS_Token( parser ); 1375 T1_Skip_Spaces ( parser ); 1376 if ( parser->root.cursor >= parser->root.limit || 1377 *parser->root.cursor != ']' ) 1378 parser->root.error = FT_THROW( Invalid_File_Format ); 1379 return; 1380 } 1381 1382 num_subrs = (FT_Int)T1_ToInt( parser ); 1383 1384 /* position the parser right before the `dup' of the first subr */ 1385 T1_Skip_PS_Token( parser ); /* `array' */ 1386 if ( parser->root.error ) 1387 return; 1388 T1_Skip_Spaces( parser ); 1389 1390 /* initialize subrs array -- with synthetic fonts it is possible */ 1391 /* we get here twice */ 1392 if ( !loader->num_subrs ) 1393 { 1394 error = psaux->ps_table_funcs->init( table, num_subrs, memory ); 1395 if ( error ) 1396 goto Fail; 1397 } 1398 1399 /* the format is simple: */ 1400 /* */ 1401 /* `index' + binary data */ 1402 /* */ 1403 for (;;) 1404 { 1405 FT_Long idx, size; 1406 FT_Byte* base; 1407 1408 1409 /* If we are out of data, or if the next token isn't `dup', */ 1410 /* we are done. */ 1411 if ( parser->root.cursor + 4 >= parser->root.limit || 1412 ft_strncmp( (char*)parser->root.cursor, "dup", 3 ) != 0 ) 1413 break; 1414 1415 T1_Skip_PS_Token( parser ); /* `dup' */ 1416 1417 idx = T1_ToInt( parser ); 1418 1419 if ( !read_binary_data( parser, &size, &base, IS_INCREMENTAL ) ) 1420 return; 1421 1422 /* The binary string is followed by one token, e.g. `NP' */ 1423 /* (bound to `noaccess put') or by two separate tokens: */ 1424 /* `noaccess' & `put'. We position the parser right */ 1425 /* before the next `dup', if any. */ 1426 T1_Skip_PS_Token( parser ); /* `NP' or `|' or `noaccess' */ 1427 if ( parser->root.error ) 1428 return; 1429 T1_Skip_Spaces ( parser ); 1430 1431 if ( parser->root.cursor + 4 < parser->root.limit && 1432 ft_strncmp( (char*)parser->root.cursor, "put", 3 ) == 0 ) 1433 { 1434 T1_Skip_PS_Token( parser ); /* skip `put' */ 1435 T1_Skip_Spaces ( parser ); 1436 } 1437 1438 /* with synthetic fonts it is possible we get here twice */ 1439 if ( loader->num_subrs ) 1440 continue; 1441 1442 /* some fonts use a value of -1 for lenIV to indicate that */ 1443 /* the charstrings are unencoded */ 1444 /* */ 1445 /* thanks to Tom Kacvinsky for pointing this out */ 1446 /* */ 1447 if ( face->type1.private_dict.lenIV >= 0 ) 1448 { 1449 FT_Byte* temp; 1450 1451 1452 /* some fonts define empty subr records -- this is not totally */ 1453 /* compliant to the specification (which says they should at */ 1454 /* least contain a `return'), but we support them anyway */ 1455 if ( size < face->type1.private_dict.lenIV ) 1456 { 1457 error = FT_THROW( Invalid_File_Format ); 1458 goto Fail; 1459 } 1460 1461 /* t1_decrypt() shouldn't write to base -- make temporary copy */ 1462 if ( FT_ALLOC( temp, size ) ) 1463 goto Fail; 1464 FT_MEM_COPY( temp, base, size ); 1465 psaux->t1_decrypt( temp, size, 4330 ); 1466 size -= face->type1.private_dict.lenIV; 1467 error = T1_Add_Table( table, (FT_Int)idx, 1468 temp + face->type1.private_dict.lenIV, size ); 1469 FT_FREE( temp ); 1470 } 1471 else 1472 error = T1_Add_Table( table, (FT_Int)idx, base, size ); 1473 if ( error ) 1474 goto Fail; 1475 } 1476 1477 if ( !loader->num_subrs ) 1478 loader->num_subrs = num_subrs; 1479 1480 return; 1481 1482 Fail: 1483 parser->root.error = error; 1484 } 1485 1486 1487 #define TABLE_EXTEND 5 1488 1489 1490 static void 1491 parse_charstrings( T1_Face face, 1492 T1_Loader loader ) 1493 { 1494 T1_Parser parser = &loader->parser; 1495 PS_Table code_table = &loader->charstrings; 1496 PS_Table name_table = &loader->glyph_names; 1497 PS_Table swap_table = &loader->swap_table; 1498 FT_Memory memory = parser->root.memory; 1499 FT_Error error; 1500 1501 PSAux_Service psaux = (PSAux_Service)face->psaux; 1502 1503 FT_Byte* cur; 1504 FT_Byte* limit = parser->root.limit; 1505 FT_Int n, num_glyphs; 1506 FT_UInt notdef_index = 0; 1507 FT_Byte notdef_found = 0; 1508 1509 1510 num_glyphs = (FT_Int)T1_ToInt( parser ); 1511 if ( num_glyphs < 0 ) 1512 { 1513 error = FT_THROW( Invalid_File_Format ); 1514 goto Fail; 1515 } 1516 1517 /* some fonts like Optima-Oblique not only define the /CharStrings */ 1518 /* array but access it also */ 1519 if ( num_glyphs == 0 || parser->root.error ) 1520 return; 1521 1522 /* initialize tables, leaving space for addition of .notdef, */ 1523 /* if necessary, and a few other glyphs to handle buggy */ 1524 /* fonts which have more glyphs than specified. */ 1525 1526 /* for some non-standard fonts like `Optima' which provides */ 1527 /* different outlines depending on the resolution it is */ 1528 /* possible to get here twice */ 1529 if ( !loader->num_glyphs ) 1530 { 1531 error = psaux->ps_table_funcs->init( 1532 code_table, num_glyphs + 1 + TABLE_EXTEND, memory ); 1533 if ( error ) 1534 goto Fail; 1535 1536 error = psaux->ps_table_funcs->init( 1537 name_table, num_glyphs + 1 + TABLE_EXTEND, memory ); 1538 if ( error ) 1539 goto Fail; 1540 1541 /* Initialize table for swapping index notdef_index and */ 1542 /* index 0 names and codes (if necessary). */ 1543 1544 error = psaux->ps_table_funcs->init( swap_table, 4, memory ); 1545 if ( error ) 1546 goto Fail; 1547 } 1548 1549 n = 0; 1550 1551 for (;;) 1552 { 1553 FT_Long size; 1554 FT_Byte* base; 1555 1556 1557 /* the format is simple: */ 1558 /* `/glyphname' + binary data */ 1559 1560 T1_Skip_Spaces( parser ); 1561 1562 cur = parser->root.cursor; 1563 if ( cur >= limit ) 1564 break; 1565 1566 /* we stop when we find a `def' or `end' keyword */ 1567 if ( cur + 3 < limit && IS_PS_DELIM( cur[3] ) ) 1568 { 1569 if ( cur[0] == 'd' && 1570 cur[1] == 'e' && 1571 cur[2] == 'f' ) 1572 { 1573 /* There are fonts which have this: */ 1574 /* */ 1575 /* /CharStrings 118 dict def */ 1576 /* Private begin */ 1577 /* CharStrings begin */ 1578 /* ... */ 1579 /* */ 1580 /* To catch this we ignore `def' if */ 1581 /* no charstring has actually been */ 1582 /* seen. */ 1583 if ( n ) 1584 break; 1585 } 1586 1587 if ( cur[0] == 'e' && 1588 cur[1] == 'n' && 1589 cur[2] == 'd' ) 1590 break; 1591 } 1592 1593 T1_Skip_PS_Token( parser ); 1594 if ( parser->root.error ) 1595 return; 1596 1597 if ( *cur == '/' ) 1598 { 1599 FT_PtrDist len; 1600 1601 1602 if ( cur + 1 >= limit ) 1603 { 1604 error = FT_THROW( Invalid_File_Format ); 1605 goto Fail; 1606 } 1607 1608 cur++; /* skip `/' */ 1609 len = parser->root.cursor - cur; 1610 1611 if ( !read_binary_data( parser, &size, &base, IS_INCREMENTAL ) ) 1612 return; 1613 /* xhl: Add boundary check here. Fix the bug reported by ifilter. */ 1614 /* TESTDOC: bug# 0018509, 45.pdf. */ 1615 if (base + size >= limit) { 1616 error = T1_Err_Invalid_File_Format; 1617 goto Fail; 1618 } 1619 /* for some non-standard fonts like `Optima' which provides */ 1620 /* different outlines depending on the resolution it is */ 1621 /* possible to get here twice */ 1622 if ( loader->num_glyphs ) 1623 continue; 1624 1625 error = T1_Add_Table( name_table, n, cur, len + 1 ); 1626 if ( error ) 1627 goto Fail; 1628 1629 /* add a trailing zero to the name table */ 1630 name_table->elements[n][len] = '\0'; 1631 1632 /* record index of /.notdef */ 1633 if ( *cur == '.' && 1634 ft_strcmp( ".notdef", 1635 (const char*)(name_table->elements[n]) ) == 0 ) 1636 { 1637 notdef_index = n; 1638 notdef_found = 1; 1639 } 1640 1641 if ( face->type1.private_dict.lenIV >= 0 && 1642 n < num_glyphs + TABLE_EXTEND ) 1643 { 1644 FT_Byte* temp; 1645 1646 1647 if ( size <= face->type1.private_dict.lenIV ) 1648 { 1649 error = FT_THROW( Invalid_File_Format ); 1650 goto Fail; 1651 } 1652 1653 /* t1_decrypt() shouldn't write to base -- make temporary copy */ 1654 if ( FT_ALLOC( temp, size ) ) 1655 goto Fail; 1656 FT_MEM_COPY( temp, base, size ); 1657 psaux->t1_decrypt( temp, size, 4330 ); 1658 size -= face->type1.private_dict.lenIV; 1659 error = T1_Add_Table( code_table, n, 1660 temp + face->type1.private_dict.lenIV, size ); 1661 FT_FREE( temp ); 1662 } 1663 else 1664 error = T1_Add_Table( code_table, n, base, size ); 1665 if ( error ) 1666 goto Fail; 1667 1668 n++; 1669 } 1670 } 1671 1672 loader->num_glyphs = n; 1673 1674 /* if /.notdef is found but does not occupy index 0, do our magic. */ 1675 if ( notdef_found && 1676 ft_strcmp( ".notdef", (const char*)name_table->elements[0] ) ) 1677 { 1678 /* Swap glyph in index 0 with /.notdef glyph. First, add index 0 */ 1679 /* name and code entries to swap_table. Then place notdef_index */ 1680 /* name and code entries into swap_table. Then swap name and code */ 1681 /* entries at indices notdef_index and 0 using values stored in */ 1682 /* swap_table. */ 1683 1684 /* Index 0 name */ 1685 error = T1_Add_Table( swap_table, 0, 1686 name_table->elements[0], 1687 name_table->lengths [0] ); 1688 if ( error ) 1689 goto Fail; 1690 1691 /* Index 0 code */ 1692 error = T1_Add_Table( swap_table, 1, 1693 code_table->elements[0], 1694 code_table->lengths [0] ); 1695 if ( error ) 1696 goto Fail; 1697 1698 /* Index notdef_index name */ 1699 error = T1_Add_Table( swap_table, 2, 1700 name_table->elements[notdef_index], 1701 name_table->lengths [notdef_index] ); 1702 if ( error ) 1703 goto Fail; 1704 1705 /* Index notdef_index code */ 1706 error = T1_Add_Table( swap_table, 3, 1707 code_table->elements[notdef_index], 1708 code_table->lengths [notdef_index] ); 1709 if ( error ) 1710 goto Fail; 1711 1712 error = T1_Add_Table( name_table, notdef_index, 1713 swap_table->elements[0], 1714 swap_table->lengths [0] ); 1715 if ( error ) 1716 goto Fail; 1717 1718 error = T1_Add_Table( code_table, notdef_index, 1719 swap_table->elements[1], 1720 swap_table->lengths [1] ); 1721 if ( error ) 1722 goto Fail; 1723 1724 error = T1_Add_Table( name_table, 0, 1725 swap_table->elements[2], 1726 swap_table->lengths [2] ); 1727 if ( error ) 1728 goto Fail; 1729 1730 error = T1_Add_Table( code_table, 0, 1731 swap_table->elements[3], 1732 swap_table->lengths [3] ); 1733 if ( error ) 1734 goto Fail; 1735 1736 } 1737 else if ( !notdef_found ) 1738 { 1739 /* notdef_index is already 0, or /.notdef is undefined in */ 1740 /* charstrings dictionary. Worry about /.notdef undefined. */ 1741 /* We take index 0 and add it to the end of the table(s) */ 1742 /* and add our own /.notdef glyph to index 0. */ 1743 1744 /* 0 333 hsbw endchar */ 1745 FT_Byte notdef_glyph[] = { 0x8B, 0xF7, 0xE1, 0x0D, 0x0E }; 1746 char* notdef_name = (char *)".notdef"; 1747 1748 1749 error = T1_Add_Table( swap_table, 0, 1750 name_table->elements[0], 1751 name_table->lengths [0] ); 1752 if ( error ) 1753 goto Fail; 1754 1755 error = T1_Add_Table( swap_table, 1, 1756 code_table->elements[0], 1757 code_table->lengths [0] ); 1758 if ( error ) 1759 goto Fail; 1760 1761 error = T1_Add_Table( name_table, 0, notdef_name, 8 ); 1762 if ( error ) 1763 goto Fail; 1764 1765 error = T1_Add_Table( code_table, 0, notdef_glyph, 5 ); 1766 1767 if ( error ) 1768 goto Fail; 1769 1770 error = T1_Add_Table( name_table, n, 1771 swap_table->elements[0], 1772 swap_table->lengths [0] ); 1773 if ( error ) 1774 goto Fail; 1775 1776 error = T1_Add_Table( code_table, n, 1777 swap_table->elements[1], 1778 swap_table->lengths [1] ); 1779 if ( error ) 1780 goto Fail; 1781 1782 /* we added a glyph. */ 1783 loader->num_glyphs += 1; 1784 } 1785 1786 return; 1787 1788 Fail: 1789 parser->root.error = error; 1790 } 1791 1792 1793 /*************************************************************************/ 1794 /* */ 1795 /* Define the token field static variables. This is a set of */ 1796 /* T1_FieldRec variables. */ 1797 /* */ 1798 /*************************************************************************/ 1799 1800 1801 static 1802 const T1_FieldRec t1_keywords[] = 1803 { 1804 1805 #include "t1tokens.h" 1806 1807 /* now add the special functions... */ 1808 T1_FIELD_CALLBACK( "FontMatrix", t1_parse_font_matrix, 1809 T1_FIELD_DICT_FONTDICT ) 1810 T1_FIELD_CALLBACK( "Encoding", parse_encoding, 1811 T1_FIELD_DICT_FONTDICT ) 1812 T1_FIELD_CALLBACK( "Subrs", parse_subrs, 1813 T1_FIELD_DICT_PRIVATE ) 1814 T1_FIELD_CALLBACK( "CharStrings", parse_charstrings, 1815 T1_FIELD_DICT_PRIVATE ) 1816 T1_FIELD_CALLBACK( "Private", parse_private, 1817 T1_FIELD_DICT_FONTDICT ) 1818 1819 #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT 1820 T1_FIELD_CALLBACK( "BlendDesignPositions", parse_blend_design_positions, 1821 T1_FIELD_DICT_FONTDICT ) 1822 T1_FIELD_CALLBACK( "BlendDesignMap", parse_blend_design_map, 1823 T1_FIELD_DICT_FONTDICT ) 1824 T1_FIELD_CALLBACK( "BlendAxisTypes", parse_blend_axis_types, 1825 T1_FIELD_DICT_FONTDICT ) 1826 T1_FIELD_CALLBACK( "WeightVector", parse_weight_vector, 1827 T1_FIELD_DICT_FONTDICT ) 1828 T1_FIELD_CALLBACK( "BuildCharArray", parse_buildchar, 1829 T1_FIELD_DICT_PRIVATE ) 1830 #endif 1831 1832 { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0, 0 } 1833 }; 1834 1835 1836 #define T1_FIELD_COUNT \ 1837 ( sizeof ( t1_keywords ) / sizeof ( t1_keywords[0] ) ) 1838 1839 1840 static FT_Error 1841 parse_dict( T1_Face face, 1842 T1_Loader loader, 1843 FT_Byte* base, 1844 FT_Long size ) 1845 { 1846 T1_Parser parser = &loader->parser; 1847 FT_Byte *limit, *start_binary = NULL; 1848 FT_Bool have_integer = 0; 1849 1850 1851 parser->root.cursor = base; 1852 parser->root.limit = base + size; 1853 parser->root.error = FT_Err_Ok; 1854 1855 limit = parser->root.limit; 1856 1857 T1_Skip_Spaces( parser ); 1858 1859 while ( parser->root.cursor < limit ) 1860 { 1861 FT_Byte* cur; 1862 1863 1864 cur = parser->root.cursor; 1865 1866 /* look for `eexec' */ 1867 if ( IS_PS_TOKEN( cur, limit, "eexec" ) ) 1868 break; 1869 1870 /* look for `closefile' which ends the eexec section */ 1871 else if ( IS_PS_TOKEN( cur, limit, "closefile" ) ) 1872 break; 1873 1874 /* in a synthetic font the base font starts after a */ 1875 /* `FontDictionary' token that is placed after a Private dict */ 1876 else if ( IS_PS_TOKEN( cur, limit, "FontDirectory" ) ) 1877 { 1878 if ( loader->keywords_encountered & T1_PRIVATE ) 1879 loader->keywords_encountered |= 1880 T1_FONTDIR_AFTER_PRIVATE; 1881 parser->root.cursor += 13; 1882 } 1883 1884 /* check whether we have an integer */ 1885 else if ( ft_isdigit( *cur ) ) 1886 { 1887 start_binary = cur; 1888 T1_Skip_PS_Token( parser ); 1889 if ( parser->root.error ) 1890 goto Exit; 1891 have_integer = 1; 1892 } 1893 1894 /* in valid Type 1 fonts we don't see `RD' or `-|' directly */ 1895 /* since those tokens are handled by parse_subrs and */ 1896 /* parse_charstrings */ 1897 else if ( *cur == 'R' && cur + 6 < limit && *(cur + 1) == 'D' && 1898 have_integer ) 1899 { 1900 FT_Long s; 1901 FT_Byte* b; 1902 1903 1904 parser->root.cursor = start_binary; 1905 if ( !read_binary_data( parser, &s, &b, IS_INCREMENTAL ) ) 1906 return FT_THROW( Invalid_File_Format ); 1907 have_integer = 0; 1908 } 1909 1910 else if ( *cur == '-' && cur + 6 < limit && *(cur + 1) == '|' && 1911 have_integer ) 1912 { 1913 FT_Long s; 1914 FT_Byte* b; 1915 1916 1917 parser->root.cursor = start_binary; 1918 if ( !read_binary_data( parser, &s, &b, IS_INCREMENTAL ) ) 1919 return FT_THROW( Invalid_File_Format ); 1920 have_integer = 0; 1921 } 1922 1923 /* look for immediates */ 1924 else if ( *cur == '/' && cur + 2 < limit ) 1925 { 1926 FT_PtrDist len; 1927 1928 1929 cur++; 1930 1931 parser->root.cursor = cur; 1932 T1_Skip_PS_Token( parser ); 1933 if ( parser->root.error ) 1934 goto Exit; 1935 1936 len = parser->root.cursor - cur; 1937 1938 if ( len > 0 && len < 22 && parser->root.cursor < limit ) 1939 { 1940 /* now compare the immediate name to the keyword table */ 1941 T1_Field keyword = (T1_Field)t1_keywords; 1942 1943 1944 for (;;) 1945 { 1946 FT_Byte* name; 1947 1948 1949 name = (FT_Byte*)keyword->ident; 1950 if ( !name ) 1951 break; 1952 1953 if ( cur[0] == name[0] && 1954 len == (FT_PtrDist)ft_strlen( (const char *)name ) && 1955 ft_memcmp( cur, name, len ) == 0 ) 1956 { 1957 /* We found it -- run the parsing callback! */ 1958 /* We record every instance of every field */ 1959 /* (until we reach the base font of a */ 1960 /* synthetic font) to deal adequately with */ 1961 /* multiple master fonts; this is also */ 1962 /* necessary because later PostScript */ 1963 /* definitions override earlier ones. */ 1964 1965 /* Once we encounter `FontDirectory' after */ 1966 /* `/Private', we know that this is a synthetic */ 1967 /* font; except for `/CharStrings' we are not */ 1968 /* interested in anything that follows this */ 1969 /* `FontDirectory'. */ 1970 1971 /* MM fonts have more than one /Private token at */ 1972 /* the top level; let's hope that all the junk */ 1973 /* that follows the first /Private token is not */ 1974 /* interesting to us. */ 1975 1976 /* According to Adobe Tech Note #5175 (CID-Keyed */ 1977 /* Font Installation for ATM Software) a `begin' */ 1978 /* must be followed by exactly one `end', and */ 1979 /* `begin' -- `end' pairs must be accurately */ 1980 /* paired. We could use this to distinguish */ 1981 /* between the global Private and the Private */ 1982 /* dict that is a member of the Blend dict. */ 1983 1984 const FT_UInt dict = 1985 ( loader->keywords_encountered & T1_PRIVATE ) 1986 ? T1_FIELD_DICT_PRIVATE 1987 : T1_FIELD_DICT_FONTDICT; 1988 1989 if ( !( dict & keyword->dict ) ) 1990 { 1991 FT_TRACE1(( "parse_dict: found `%s' but ignoring it" 1992 " since it is in the wrong dictionary\n", 1993 keyword->ident )); 1994 break; 1995 } 1996 1997 if ( !( loader->keywords_encountered & 1998 T1_FONTDIR_AFTER_PRIVATE ) || 1999 ft_strcmp( (const char*)name, "CharStrings" ) == 0 ) 2000 { 2001 parser->root.error = t1_load_keyword( face, 2002 loader, 2003 keyword ); 2004 if ( parser->root.error != FT_Err_Ok ) 2005 { 2006 if ( FT_ERR_EQ( parser->root.error, Ignore ) ) 2007 parser->root.error = FT_Err_Ok; 2008 else 2009 return parser->root.error; 2010 } 2011 } 2012 break; 2013 } 2014 2015 keyword++; 2016 } 2017 } 2018 2019 have_integer = 0; 2020 } 2021 else 2022 { 2023 T1_Skip_PS_Token( parser ); 2024 if ( parser->root.error ) 2025 goto Exit; 2026 have_integer = 0; 2027 } 2028 2029 T1_Skip_Spaces( parser ); 2030 } 2031 2032 Exit: 2033 return parser->root.error; 2034 } 2035 2036 2037 static void 2038 t1_init_loader( T1_Loader loader, 2039 T1_Face face ) 2040 { 2041 FT_UNUSED( face ); 2042 2043 FT_MEM_ZERO( loader, sizeof ( *loader ) ); 2044 loader->num_glyphs = 0; 2045 loader->num_chars = 0; 2046 2047 /* initialize the tables -- simply set their `init' field to 0 */ 2048 loader->encoding_table.init = 0; 2049 loader->charstrings.init = 0; 2050 loader->glyph_names.init = 0; 2051 loader->subrs.init = 0; 2052 loader->swap_table.init = 0; 2053 loader->fontdata = 0; 2054 loader->keywords_encountered = 0; 2055 } 2056 2057 2058 static void 2059 t1_done_loader( T1_Loader loader ) 2060 { 2061 T1_Parser parser = &loader->parser; 2062 2063 2064 /* finalize tables */ 2065 T1_Release_Table( &loader->encoding_table ); 2066 T1_Release_Table( &loader->charstrings ); 2067 T1_Release_Table( &loader->glyph_names ); 2068 T1_Release_Table( &loader->swap_table ); 2069 T1_Release_Table( &loader->subrs ); 2070 2071 /* finalize parser */ 2072 T1_Finalize_Parser( parser ); 2073 } 2074 2075 2076 FT_LOCAL_DEF( FT_Error ) 2077 T1_Open_Face( T1_Face face ) 2078 { 2079 T1_LoaderRec loader; 2080 T1_Parser parser; 2081 T1_Font type1 = &face->type1; 2082 PS_Private priv = &type1->private_dict; 2083 FT_Error error; 2084 2085 PSAux_Service psaux = (PSAux_Service)face->psaux; 2086 2087 2088 t1_init_loader( &loader, face ); 2089 2090 /* default values */ 2091 face->ndv_idx = -1; 2092 face->cdv_idx = -1; 2093 face->len_buildchar = 0; 2094 2095 priv->blue_shift = 7; 2096 priv->blue_fuzz = 1; 2097 priv->lenIV = 4; 2098 priv->expansion_factor = (FT_Fixed)( 0.06 * 0x10000L ); 2099 priv->blue_scale = (FT_Fixed)( 0.039625 * 0x10000L * 1000 ); 2100 2101 parser = &loader.parser; 2102 error = T1_New_Parser( parser, 2103 face->root.stream, 2104 face->root.memory, 2105 psaux ); 2106 if ( error ) 2107 goto Exit; 2108 2109 error = parse_dict( face, &loader, 2110 parser->base_dict, parser->base_len ); 2111 if ( error ) 2112 goto Exit; 2113 2114 error = T1_Get_Private_Dict( parser, psaux ); 2115 if ( error ) 2116 goto Exit; 2117 2118 error = parse_dict( face, &loader, 2119 parser->private_dict, parser->private_len ); 2120 if ( error ) 2121 goto Exit; 2122 2123 /* ensure even-ness of `num_blue_values' */ 2124 priv->num_blue_values &= ~1; 2125 2126 #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT 2127 2128 if ( face->blend && 2129 face->blend->num_default_design_vector != 0 && 2130 face->blend->num_default_design_vector != face->blend->num_axis ) 2131 { 2132 /* we don't use it currently so just warn, reset, and ignore */ 2133 FT_ERROR(( "T1_Open_Face(): /DesignVector contains %u entries " 2134 "while there are %u axes.\n", 2135 face->blend->num_default_design_vector, 2136 face->blend->num_axis )); 2137 2138 face->blend->num_default_design_vector = 0; 2139 } 2140 2141 /* the following can happen for MM instances; we then treat the */ 2142 /* font as a normal PS font */ 2143 if ( face->blend && 2144 ( !face->blend->num_designs || !face->blend->num_axis ) ) 2145 T1_Done_Blend( face ); 2146 2147 /* another safety check */ 2148 if ( face->blend ) 2149 { 2150 FT_UInt i; 2151 2152 2153 for ( i = 0; i < face->blend->num_axis; i++ ) 2154 if ( !face->blend->design_map[i].num_points ) 2155 { 2156 T1_Done_Blend( face ); 2157 break; 2158 } 2159 } 2160 2161 if ( face->blend ) 2162 { 2163 if ( face->len_buildchar > 0 ) 2164 { 2165 FT_Memory memory = face->root.memory; 2166 2167 2168 if ( FT_NEW_ARRAY( face->buildchar, face->len_buildchar ) ) 2169 { 2170 FT_ERROR(( "T1_Open_Face: cannot allocate BuildCharArray\n" )); 2171 face->len_buildchar = 0; 2172 goto Exit; 2173 } 2174 } 2175 } 2176 else 2177 face->len_buildchar = 0; 2178 2179 #endif /* !T1_CONFIG_OPTION_NO_MM_SUPPORT */ 2180 2181 /* now, propagate the subrs, charstrings, and glyphnames tables */ 2182 /* to the Type1 data */ 2183 type1->num_glyphs = loader.num_glyphs; 2184 2185 if ( loader.subrs.init ) 2186 { 2187 loader.subrs.init = 0; 2188 type1->num_subrs = loader.num_subrs; 2189 type1->subrs_block = loader.subrs.block; 2190 type1->subrs = loader.subrs.elements; 2191 type1->subrs_len = loader.subrs.lengths; 2192 } 2193 2194 if ( !IS_INCREMENTAL ) 2195 if ( !loader.charstrings.init ) 2196 { 2197 FT_ERROR(( "T1_Open_Face: no `/CharStrings' array in face\n" )); 2198 error = FT_THROW( Invalid_File_Format ); 2199 } 2200 2201 loader.charstrings.init = 0; 2202 type1->charstrings_block = loader.charstrings.block; 2203 type1->charstrings = loader.charstrings.elements; 2204 type1->charstrings_len = loader.charstrings.lengths; 2205 2206 /* we copy the glyph names `block' and `elements' fields; */ 2207 /* the `lengths' field must be released later */ 2208 type1->glyph_names_block = loader.glyph_names.block; 2209 type1->glyph_names = (FT_String**)loader.glyph_names.elements; 2210 loader.glyph_names.block = 0; 2211 loader.glyph_names.elements = 0; 2212 2213 /* we must now build type1.encoding when we have a custom array */ 2214 if ( type1->encoding_type == T1_ENCODING_TYPE_ARRAY ) 2215 { 2216 FT_Int charcode, idx, min_char, max_char; 2217 FT_Byte* char_name; 2218 FT_Byte* glyph_name; 2219 2220 2221 /* OK, we do the following: for each element in the encoding */ 2222 /* table, look up the index of the glyph having the same name */ 2223 /* the index is then stored in type1.encoding.char_index, and */ 2224 /* the name to type1.encoding.char_name */ 2225 2226 min_char = 0; 2227 max_char = 0; 2228 2229 charcode = 0; 2230 for ( ; charcode < loader.encoding_table.max_elems; charcode++ ) 2231 { 2232 type1->encoding.char_index[charcode] = 0; 2233 type1->encoding.char_name [charcode] = (char *)".notdef"; 2234 2235 char_name = loader.encoding_table.elements[charcode]; 2236 if ( char_name ) 2237 for ( idx = 0; idx < type1->num_glyphs; idx++ ) 2238 { 2239 glyph_name = (FT_Byte*)type1->glyph_names[idx]; 2240 if ( ft_strcmp( (const char*)char_name, 2241 (const char*)glyph_name ) == 0 ) 2242 { 2243 type1->encoding.char_index[charcode] = (FT_UShort)idx; 2244 type1->encoding.char_name [charcode] = (char*)glyph_name; 2245 2246 /* Change min/max encoded char only if glyph name is */ 2247 /* not /.notdef */ 2248 if ( ft_strcmp( (const char*)".notdef", 2249 (const char*)glyph_name ) != 0 ) 2250 { 2251 if ( charcode < min_char ) 2252 min_char = charcode; 2253 if ( charcode >= max_char ) 2254 max_char = charcode + 1; 2255 } 2256 break; 2257 } 2258 } 2259 } 2260 2261 type1->encoding.code_first = min_char; 2262 type1->encoding.code_last = max_char; 2263 type1->encoding.num_chars = loader.num_chars; 2264 } 2265 2266 Exit: 2267 t1_done_loader( &loader ); 2268 return error; 2269 } 2270 2271 2272 /* END */ 2273