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