1 /***************************************************************************/ 2 /* */ 3 /* t1load.c */ 4 /* */ 5 /* Type 1 font loader (body). */ 6 /* */ 7 /* Copyright 1996-2001, 2002 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. */ 45 /* */ 46 /* This file is included twice here; the first time to generate parsing */ 47 /* callback functions, the second to generate a table of keywords (with */ 48 /* pointers to the associated callback). */ 49 /* */ 50 /* The function `parse_dict' simply scans *linearly* a given dictionary */ 51 /* (either the top-level or private one) and calls the appropriate */ 52 /* callback when it encounters an immediate keyword. */ 53 /* */ 54 /* This is by far the fastest way one can find to parse and read all */ 55 /* data. */ 56 /* */ 57 /* This led to tremendous code size reduction. Note that later, the */ 58 /* glyph loader will also be _greatly_ simplified, and the automatic */ 59 /* hinter will replace the clumsy `t1hinter'. */ 60 /* */ 61 /*************************************************************************/ 62 63 64 #include <ft2build.h> 65 #include FT_INTERNAL_DEBUG_H 66 #include FT_CONFIG_CONFIG_H 67 #include FT_MULTIPLE_MASTERS_H 68 #include FT_INTERNAL_TYPE1_TYPES_H 69 70 #include "t1load.h" 71 #include "t1errors.h" 72 73 74 75 /*************************************************************************/ 76 /* */ 77 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 78 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 79 /* messages during execution. */ 80 /* */ 81 #undef FT_COMPONENT 82 #define FT_COMPONENT trace_t1load 83 84 85 #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT 86 87 88 /*************************************************************************/ 89 /*************************************************************************/ 90 /***** *****/ 91 /***** MULTIPLE MASTERS SUPPORT *****/ 92 /***** *****/ 93 /*************************************************************************/ 94 /*************************************************************************/ 95 96 static FT_Error t1_allocate_blend(T1_Face face,FT_UInt num_designs,FT_UInt num_axis)97 t1_allocate_blend( T1_Face face, 98 FT_UInt num_designs, 99 FT_UInt num_axis ) 100 { 101 PS_Blend blend; 102 FT_Memory memory = face->root.memory; 103 FT_Error error = 0; 104 105 106 blend = face->blend; 107 if ( !blend ) 108 { 109 if ( FT_NEW( blend ) ) 110 goto Exit; 111 112 face->blend = blend; 113 } 114 115 /* allocate design data if needed */ 116 if ( num_designs > 0 ) 117 { 118 if ( blend->num_designs == 0 ) 119 { 120 FT_UInt nn; 121 122 123 /* allocate the blend `private' and `font_info' dictionaries */ 124 if ( FT_NEW_ARRAY( blend->font_infos[1], num_designs ) || 125 FT_NEW_ARRAY( blend->privates[1], num_designs ) || 126 FT_NEW_ARRAY( blend->bboxes[1], num_designs ) || 127 FT_NEW_ARRAY( blend->weight_vector, num_designs * 2 ) ) 128 goto Exit; 129 130 blend->default_weight_vector = blend->weight_vector + num_designs; 131 132 blend->font_infos[0] = &face->type1.font_info; 133 blend->privates [0] = &face->type1.private_dict; 134 blend->bboxes [0] = &face->type1.font_bbox; 135 136 for ( nn = 2; nn <= num_designs; nn++ ) 137 { 138 blend->privates[nn] = blend->privates [nn - 1] + 1; 139 blend->font_infos[nn] = blend->font_infos[nn - 1] + 1; 140 blend->bboxes[nn] = blend->bboxes [nn - 1] + 1; 141 } 142 143 blend->num_designs = num_designs; 144 } 145 else if ( blend->num_designs != num_designs ) 146 goto Fail; 147 } 148 149 /* allocate axis data if needed */ 150 if ( num_axis > 0 ) 151 { 152 if ( blend->num_axis != 0 && blend->num_axis != num_axis ) 153 goto Fail; 154 155 blend->num_axis = num_axis; 156 } 157 158 /* allocate the blend design pos table if needed */ 159 num_designs = blend->num_designs; 160 num_axis = blend->num_axis; 161 if ( num_designs && num_axis && blend->design_pos[0] == 0 ) 162 { 163 FT_UInt n; 164 165 166 if ( FT_NEW_ARRAY( blend->design_pos[0], num_designs * num_axis ) ) 167 goto Exit; 168 169 for ( n = 1; n < num_designs; n++ ) 170 blend->design_pos[n] = blend->design_pos[0] + num_axis * n; 171 } 172 173 Exit: 174 return error; 175 176 Fail: 177 error = -1; 178 goto Exit; 179 } 180 181 182 FT_LOCAL_DEF( FT_Error ) T1_Get_Multi_Master(T1_Face face,FT_Multi_Master * master)183 T1_Get_Multi_Master( T1_Face face, 184 FT_Multi_Master* master ) 185 { 186 PS_Blend blend = face->blend; 187 FT_UInt n; 188 FT_Error error; 189 190 191 error = T1_Err_Invalid_Argument; 192 193 if ( blend ) 194 { 195 master->num_axis = blend->num_axis; 196 master->num_designs = blend->num_designs; 197 198 for ( n = 0; n < blend->num_axis; n++ ) 199 { 200 FT_MM_Axis* axis = master->axis + n; 201 PS_DesignMap map = blend->design_map + n; 202 203 204 axis->name = blend->axis_names[n]; 205 axis->minimum = map->design_points[0]; 206 axis->maximum = map->design_points[map->num_points - 1]; 207 } 208 error = 0; 209 } 210 return error; 211 } 212 213 214 FT_LOCAL_DEF( FT_Error ) T1_Set_MM_Blend(T1_Face face,FT_UInt num_coords,FT_Fixed * coords)215 T1_Set_MM_Blend( T1_Face face, 216 FT_UInt num_coords, 217 FT_Fixed* coords ) 218 { 219 PS_Blend blend = face->blend; 220 FT_Error error; 221 FT_UInt n, m; 222 223 224 error = T1_Err_Invalid_Argument; 225 226 if ( blend && blend->num_axis == num_coords ) 227 { 228 /* recompute the weight vector from the blend coordinates */ 229 error = T1_Err_Ok; 230 231 for ( n = 0; n < blend->num_designs; n++ ) 232 { 233 FT_Fixed result = 0x10000L; /* 1.0 fixed */ 234 235 236 for ( m = 0; m < blend->num_axis; m++ ) 237 { 238 FT_Fixed factor; 239 240 241 /* get current blend axis position */ 242 factor = coords[m]; 243 if ( factor < 0 ) factor = 0; 244 if ( factor > 0x10000L ) factor = 0x10000L; 245 246 if ( ( n & ( 1 << m ) ) == 0 ) 247 factor = 0x10000L - factor; 248 249 result = FT_MulFix( result, factor ); 250 } 251 blend->weight_vector[n] = result; 252 } 253 254 error = T1_Err_Ok; 255 } 256 return error; 257 } 258 259 260 FT_LOCAL_DEF( FT_Error ) T1_Set_MM_Design(T1_Face face,FT_UInt num_coords,FT_Long * coords)261 T1_Set_MM_Design( T1_Face face, 262 FT_UInt num_coords, 263 FT_Long* coords ) 264 { 265 PS_Blend blend = face->blend; 266 FT_Error error; 267 FT_UInt n, p; 268 269 270 error = T1_Err_Invalid_Argument; 271 if ( blend && blend->num_axis == num_coords ) 272 { 273 /* compute the blend coordinates through the blend design map */ 274 FT_Fixed final_blends[T1_MAX_MM_DESIGNS]; 275 276 277 for ( n = 0; n < blend->num_axis; n++ ) 278 { 279 FT_Long design = coords[n]; 280 FT_Fixed the_blend; 281 PS_DesignMap map = blend->design_map + n; 282 FT_Fixed* designs = map->design_points; 283 FT_Fixed* blends = map->blend_points; 284 FT_Int before = -1, after = -1; 285 286 287 for ( p = 0; p < (FT_UInt)map->num_points; p++ ) 288 { 289 FT_Fixed p_design = designs[p]; 290 291 292 /* exact match ? */ 293 if ( design == p_design ) 294 { 295 the_blend = blends[p]; 296 goto Found; 297 } 298 299 if ( design < p_design ) 300 { 301 after = p; 302 break; 303 } 304 305 before = p; 306 } 307 308 /* now, interpolate if needed */ 309 if ( before < 0 ) 310 the_blend = blends[0]; 311 312 else if ( after < 0 ) 313 the_blend = blends[map->num_points - 1]; 314 315 else 316 the_blend = FT_MulDiv( design - designs[before], 317 blends [after] - blends [before], 318 designs[after] - designs[before] ); 319 320 Found: 321 final_blends[n] = the_blend; 322 } 323 324 error = T1_Set_MM_Blend( face, num_coords, final_blends ); 325 } 326 327 return error; 328 } 329 330 331 FT_LOCAL_DEF( void ) T1_Done_Blend(T1_Face face)332 T1_Done_Blend( T1_Face face ) 333 { 334 FT_Memory memory = face->root.memory; 335 PS_Blend blend = face->blend; 336 337 338 if ( blend ) 339 { 340 FT_UInt num_designs = blend->num_designs; 341 FT_UInt num_axis = blend->num_axis; 342 FT_UInt n; 343 344 345 /* release design pos table */ 346 FT_FREE( blend->design_pos[0] ); 347 for ( n = 1; n < num_designs; n++ ) 348 blend->design_pos[n] = 0; 349 350 /* release blend `private' and `font info' dictionaries */ 351 FT_FREE( blend->privates[1] ); 352 FT_FREE( blend->font_infos[1] ); 353 FT_FREE( blend->bboxes[1] ); 354 355 for ( n = 0; n < num_designs; n++ ) 356 { 357 blend->privates [n] = 0; 358 blend->font_infos[n] = 0; 359 blend->bboxes [n] = 0; 360 } 361 362 /* release weight vectors */ 363 FT_FREE( blend->weight_vector ); 364 blend->default_weight_vector = 0; 365 366 /* release axis names */ 367 for ( n = 0; n < num_axis; n++ ) 368 FT_FREE( blend->axis_names[n] ); 369 370 /* release design map */ 371 for ( n = 0; n < num_axis; n++ ) 372 { 373 PS_DesignMap dmap = blend->design_map + n; 374 375 376 FT_FREE( dmap->design_points ); 377 dmap->num_points = 0; 378 } 379 380 FT_FREE( face->blend ); 381 } 382 } 383 384 385 static void parse_blend_axis_types(T1_Face face,T1_Loader loader)386 parse_blend_axis_types( T1_Face face, 387 T1_Loader loader ) 388 { 389 T1_TokenRec axis_tokens[ T1_MAX_MM_AXIS ]; 390 FT_Int n, num_axis; 391 FT_Error error = 0; 392 PS_Blend blend; 393 FT_Memory memory; 394 395 396 /* take an array of objects */ 397 T1_ToTokenArray( &loader->parser, axis_tokens, 398 T1_MAX_MM_AXIS, &num_axis ); 399 if ( num_axis <= 0 || num_axis > T1_MAX_MM_AXIS ) 400 { 401 FT_ERROR(( "parse_blend_axis_types: incorrect number of axes: %d\n", 402 num_axis )); 403 error = T1_Err_Invalid_File_Format; 404 goto Exit; 405 } 406 407 /* allocate blend if necessary */ 408 error = t1_allocate_blend( face, 0, (FT_UInt)num_axis ); 409 if ( error ) 410 goto Exit; 411 412 blend = face->blend; 413 memory = face->root.memory; 414 415 /* each token is an immediate containing the name of the axis */ 416 for ( n = 0; n < num_axis; n++ ) 417 { 418 T1_Token token = axis_tokens + n; 419 FT_Byte* name; 420 FT_PtrDist len; 421 422 423 /* skip first slash, if any */ 424 if ( token->start[0] == '/' ) 425 token->start++; 426 427 len = token->limit - token->start; 428 if ( len <= 0 ) 429 { 430 error = T1_Err_Invalid_File_Format; 431 goto Exit; 432 } 433 434 if ( FT_ALLOC( blend->axis_names[n], len + 1 ) ) 435 goto Exit; 436 437 name = (FT_Byte*)blend->axis_names[n]; 438 FT_MEM_COPY( name, token->start, len ); 439 name[len] = 0; 440 } 441 442 Exit: 443 loader->parser.root.error = error; 444 } 445 446 447 static void parse_blend_design_positions(T1_Face face,T1_Loader loader)448 parse_blend_design_positions( T1_Face face, 449 T1_Loader loader ) 450 { 451 T1_TokenRec design_tokens[ T1_MAX_MM_DESIGNS ]; 452 FT_Int num_designs; 453 FT_Int num_axis; 454 T1_Parser parser = &loader->parser; 455 456 FT_Error error = 0; 457 PS_Blend blend; 458 459 460 /* get the array of design tokens - compute number of designs */ 461 T1_ToTokenArray( parser, design_tokens, T1_MAX_MM_DESIGNS, &num_designs ); 462 if ( num_designs <= 0 || num_designs > T1_MAX_MM_DESIGNS ) 463 { 464 FT_ERROR(( "parse_blend_design_positions:" )); 465 FT_ERROR(( " incorrect number of designs: %d\n", 466 num_designs )); 467 error = T1_Err_Invalid_File_Format; 468 goto Exit; 469 } 470 471 { 472 FT_Byte* old_cursor = parser->root.cursor; 473 FT_Byte* old_limit = parser->root.limit; 474 FT_UInt n; 475 476 477 blend = face->blend; 478 num_axis = 0; /* make compiler happy */ 479 480 for ( n = 0; n < (FT_UInt)num_designs; n++ ) 481 { 482 T1_TokenRec axis_tokens[ T1_MAX_MM_DESIGNS ]; 483 T1_Token token; 484 FT_Int axis, n_axis; 485 486 487 /* read axis/coordinates tokens */ 488 token = design_tokens + n; 489 parser->root.cursor = token->start - 1; 490 parser->root.limit = token->limit + 1; 491 T1_ToTokenArray( parser, axis_tokens, T1_MAX_MM_AXIS, &n_axis ); 492 493 if ( n == 0 ) 494 { 495 num_axis = n_axis; 496 error = t1_allocate_blend( face, num_designs, num_axis ); 497 if ( error ) 498 goto Exit; 499 blend = face->blend; 500 } 501 else if ( n_axis != num_axis ) 502 { 503 FT_ERROR(( "parse_blend_design_positions: incorrect table\n" )); 504 error = T1_Err_Invalid_File_Format; 505 goto Exit; 506 } 507 508 /* now, read each axis token into the design position */ 509 for ( axis = 0; axis < n_axis; axis++ ) 510 { 511 T1_Token token2 = axis_tokens + axis; 512 513 514 parser->root.cursor = token2->start; 515 parser->root.limit = token2->limit; 516 blend->design_pos[n][axis] = T1_ToFixed( parser, 0 ); 517 } 518 } 519 520 loader->parser.root.cursor = old_cursor; 521 loader->parser.root.limit = old_limit; 522 } 523 524 Exit: 525 loader->parser.root.error = error; 526 } 527 528 529 static void parse_blend_design_map(T1_Face face,T1_Loader loader)530 parse_blend_design_map( T1_Face face, 531 T1_Loader loader ) 532 { 533 FT_Error error = 0; 534 T1_Parser parser = &loader->parser; 535 PS_Blend blend; 536 T1_TokenRec axis_tokens[T1_MAX_MM_AXIS]; 537 FT_Int n, num_axis; 538 FT_Byte* old_cursor; 539 FT_Byte* old_limit; 540 FT_Memory memory = face->root.memory; 541 542 543 T1_ToTokenArray( parser, axis_tokens, T1_MAX_MM_AXIS, &num_axis ); 544 if ( num_axis <= 0 || num_axis > T1_MAX_MM_AXIS ) 545 { 546 FT_ERROR(( "parse_blend_design_map: incorrect number of axes: %d\n", 547 num_axis )); 548 error = T1_Err_Invalid_File_Format; 549 goto Exit; 550 } 551 old_cursor = parser->root.cursor; 552 old_limit = parser->root.limit; 553 554 error = t1_allocate_blend( face, 0, num_axis ); 555 if ( error ) 556 goto Exit; 557 blend = face->blend; 558 559 /* now, read each axis design map */ 560 for ( n = 0; n < num_axis; n++ ) 561 { 562 PS_DesignMap map = blend->design_map + n; 563 T1_Token token; 564 FT_Int p, num_points; 565 566 567 token = axis_tokens + n; 568 parser->root.cursor = token->start; 569 parser->root.limit = token->limit; 570 571 /* count the number of map points */ 572 { 573 FT_Byte* ptr = token->start; 574 FT_Byte* limit = token->limit; 575 576 577 num_points = 0; 578 for ( ; ptr < limit; ptr++ ) 579 if ( ptr[0] == '[' ) 580 num_points++; 581 } 582 if ( num_points <= 0 || num_points > T1_MAX_MM_MAP_POINTS ) 583 { 584 FT_ERROR(( "parse_blend_design_map: incorrect table\n" )); 585 error = T1_Err_Invalid_File_Format; 586 goto Exit; 587 } 588 589 /* allocate design map data */ 590 if ( FT_NEW_ARRAY( map->design_points, num_points * 2 ) ) 591 goto Exit; 592 map->blend_points = map->design_points + num_points; 593 map->num_points = (FT_Byte)num_points; 594 595 for ( p = 0; p < num_points; p++ ) 596 { 597 map->design_points[p] = T1_ToInt( parser ); 598 map->blend_points [p] = T1_ToFixed( parser, 0 ); 599 } 600 } 601 602 parser->root.cursor = old_cursor; 603 parser->root.limit = old_limit; 604 605 Exit: 606 parser->root.error = error; 607 } 608 609 610 static void parse_weight_vector(T1_Face face,T1_Loader loader)611 parse_weight_vector( T1_Face face, 612 T1_Loader loader ) 613 { 614 FT_Error error = 0; 615 T1_Parser parser = &loader->parser; 616 PS_Blend blend = face->blend; 617 T1_TokenRec master; 618 FT_UInt n; 619 FT_Byte* old_cursor; 620 FT_Byte* old_limit; 621 622 623 if ( !blend || blend->num_designs == 0 ) 624 { 625 FT_ERROR(( "parse_weight_vector: too early!\n" )); 626 error = T1_Err_Invalid_File_Format; 627 goto Exit; 628 } 629 630 T1_ToToken( parser, &master ); 631 if ( master.type != T1_TOKEN_TYPE_ARRAY ) 632 { 633 FT_ERROR(( "parse_weight_vector: incorrect format!\n" )); 634 error = T1_Err_Invalid_File_Format; 635 goto Exit; 636 } 637 638 old_cursor = parser->root.cursor; 639 old_limit = parser->root.limit; 640 641 parser->root.cursor = master.start; 642 parser->root.limit = master.limit; 643 644 for ( n = 0; n < blend->num_designs; n++ ) 645 { 646 blend->default_weight_vector[n] = 647 blend->weight_vector[n] = T1_ToFixed( parser, 0 ); 648 } 649 650 parser->root.cursor = old_cursor; 651 parser->root.limit = old_limit; 652 653 Exit: 654 parser->root.error = error; 655 } 656 657 658 /* the keyword `/shareddict' appears in some multiple master fonts */ 659 /* with a lot of Postscript garbage behind it (that's completely out */ 660 /* of spec!); we detect it and terminate the parsing */ 661 /* */ 662 static void parse_shared_dict(T1_Face face,T1_Loader loader)663 parse_shared_dict( T1_Face face, 664 T1_Loader loader ) 665 { 666 T1_Parser parser = &loader->parser; 667 668 FT_UNUSED( face ); 669 670 671 parser->root.cursor = parser->root.limit; 672 parser->root.error = 0; 673 } 674 675 #endif /* T1_CONFIG_OPTION_NO_MM_SUPPORT */ 676 677 678 /*************************************************************************/ 679 /*************************************************************************/ 680 /***** *****/ 681 /***** TYPE 1 SYMBOL PARSING *****/ 682 /***** *****/ 683 /*************************************************************************/ 684 /*************************************************************************/ 685 686 687 /*************************************************************************/ 688 /* */ 689 /* First of all, define the token field static variables. This is a set */ 690 /* of T1_FieldRec variables used later. */ 691 /* */ 692 /*************************************************************************/ 693 694 695 static FT_Error t1_load_keyword(T1_Face face,T1_Loader loader,T1_Field field)696 t1_load_keyword( T1_Face face, 697 T1_Loader loader, 698 T1_Field field ) 699 { 700 FT_Error error; 701 void* dummy_object; 702 void** objects; 703 FT_UInt max_objects; 704 PS_Blend blend = face->blend; 705 706 707 /* if the keyword has a dedicated callback, call it */ 708 if ( field->type == T1_FIELD_TYPE_CALLBACK ) 709 { 710 field->reader( (FT_Face)face, loader ); 711 error = loader->parser.root.error; 712 goto Exit; 713 } 714 715 /* now, the keyword is either a simple field, or a table of fields; */ 716 /* we are now going to take care of it */ 717 switch ( field->location ) 718 { 719 case T1_FIELD_LOCATION_FONT_INFO: 720 dummy_object = &face->type1.font_info; 721 objects = &dummy_object; 722 max_objects = 0; 723 724 if ( blend ) 725 { 726 objects = (void**)blend->font_infos; 727 max_objects = blend->num_designs; 728 } 729 break; 730 731 case T1_FIELD_LOCATION_PRIVATE: 732 dummy_object = &face->type1.private_dict; 733 objects = &dummy_object; 734 max_objects = 0; 735 736 if ( blend ) 737 { 738 objects = (void**)blend->privates; 739 max_objects = blend->num_designs; 740 } 741 break; 742 743 case T1_FIELD_LOCATION_BBOX: 744 dummy_object = &face->type1.font_bbox; 745 objects = &dummy_object; 746 max_objects = 0; 747 748 if ( blend ) 749 { 750 objects = (void**)blend->bboxes; 751 max_objects = blend->num_designs; 752 } 753 break; 754 755 default: 756 dummy_object = &face->type1; 757 objects = &dummy_object; 758 max_objects = 0; 759 } 760 761 if ( field->type == T1_FIELD_TYPE_INTEGER_ARRAY || 762 field->type == T1_FIELD_TYPE_FIXED_ARRAY ) 763 error = T1_Load_Field_Table( &loader->parser, field, 764 objects, max_objects, 0 ); 765 else 766 error = T1_Load_Field( &loader->parser, field, 767 objects, max_objects, 0 ); 768 769 Exit: 770 return error; 771 } 772 773 774 static int is_space(FT_Byte c)775 is_space( FT_Byte c ) 776 { 777 return ( c == ' ' || c == '\t' || c == '\r' || c == '\n' ); 778 } 779 780 781 static int is_alpha(FT_Byte c)782 is_alpha( FT_Byte c ) 783 { 784 /* Note: we must accept "+" as a valid character, as it is used in */ 785 /* embedded type1 fonts in PDF documents. */ 786 /* */ 787 return ( ft_isalnum( c ) || 788 c == '.' || 789 c == '_' || 790 c == '-' || 791 c == '+' ); 792 } 793 794 795 static int read_binary_data(T1_Parser parser,FT_Long * size,FT_Byte ** base)796 read_binary_data( T1_Parser parser, 797 FT_Long* size, 798 FT_Byte** base ) 799 { 800 FT_Byte* cur; 801 FT_Byte* limit = parser->root.limit; 802 803 804 /* the binary data has the following format */ 805 /* */ 806 /* `size' [white*] RD white ....... ND */ 807 /* */ 808 809 T1_Skip_Spaces( parser ); 810 cur = parser->root.cursor; 811 812 if ( cur < limit && (FT_Byte)( *cur - '0' ) < 10 ) 813 { 814 *size = T1_ToInt( parser ); 815 816 T1_Skip_Spaces( parser ); 817 T1_Skip_Alpha ( parser ); /* `RD' or `-|' or something else */ 818 819 /* there is only one whitespace char after the */ 820 /* `RD' or `-|' token */ 821 *base = parser->root.cursor + 1; 822 823 parser->root.cursor += *size + 1; 824 return 1; 825 } 826 827 FT_ERROR(( "read_binary_data: invalid size field\n" )); 828 parser->root.error = T1_Err_Invalid_File_Format; 829 return 0; 830 } 831 832 833 /* we will now define the routines used to handle */ 834 /* the `/Encoding', `/Subrs', and `/CharStrings' */ 835 /* dictionaries */ 836 837 static void parse_font_name(T1_Face face,T1_Loader loader)838 parse_font_name( T1_Face face, 839 T1_Loader loader ) 840 { 841 T1_Parser parser = &loader->parser; 842 FT_Error error; 843 FT_Memory memory = parser->root.memory; 844 FT_PtrDist len; 845 FT_Byte* cur; 846 FT_Byte* cur2; 847 FT_Byte* limit; 848 849 850 if ( face->type1.font_name ) 851 /* with synthetic fonts, it's possible we get here twice */ 852 return; 853 854 T1_Skip_Spaces( parser ); 855 856 cur = parser->root.cursor; 857 limit = parser->root.limit; 858 859 if ( cur >= limit - 1 || *cur != '/' ) 860 return; 861 862 cur++; 863 cur2 = cur; 864 while ( cur2 < limit && is_alpha( *cur2 ) ) 865 cur2++; 866 867 len = cur2 - cur; 868 if ( len > 0 ) 869 { 870 if ( FT_ALLOC( face->type1.font_name, len + 1 ) ) 871 { 872 parser->root.error = error; 873 return; 874 } 875 876 FT_MEM_COPY( face->type1.font_name, cur, len ); 877 face->type1.font_name[len] = '\0'; 878 } 879 parser->root.cursor = cur2; 880 } 881 882 883 #if 0 884 static void 885 parse_font_bbox( T1_Face face, 886 T1_Loader loader ) 887 { 888 T1_Parser parser = &loader->parser; 889 FT_Fixed temp[4]; 890 FT_BBox* bbox = &face->type1.font_bbox; 891 892 893 (void)T1_ToFixedArray( parser, 4, temp, 0 ); 894 bbox->xMin = FT_RoundFix( temp[0] ); 895 bbox->yMin = FT_RoundFix( temp[1] ); 896 bbox->xMax = FT_RoundFix( temp[2] ); 897 bbox->yMax = FT_RoundFix( temp[3] ); 898 } 899 #endif 900 901 902 static void parse_font_matrix(T1_Face face,T1_Loader loader)903 parse_font_matrix( T1_Face face, 904 T1_Loader loader ) 905 { 906 T1_Parser parser = &loader->parser; 907 FT_Matrix* matrix = &face->type1.font_matrix; 908 FT_Vector* offset = &face->type1.font_offset; 909 FT_Face root = (FT_Face)&face->root; 910 FT_Fixed temp[6]; 911 FT_Fixed temp_scale; 912 913 914 if ( matrix->xx || matrix->yx ) 915 /* with synthetic fonts, it's possible we get here twice */ 916 return; 917 918 (void)T1_ToFixedArray( parser, 6, temp, 3 ); 919 920 temp_scale = ABS( temp[3] ); 921 922 /* Set Units per EM based on FontMatrix values. We set the value to */ 923 /* 1000 / temp_scale, because temp_scale was already multiplied by */ 924 /* 1000 (in t1_tofixed, from psobjs.c). */ 925 926 root->units_per_EM = (FT_UShort)( FT_DivFix( 1000 * 0x10000L, 927 temp_scale ) >> 16 ); 928 929 /* we need to scale the values by 1.0/temp_scale */ 930 if ( temp_scale != 0x10000L ) 931 { 932 temp[0] = FT_DivFix( temp[0], temp_scale ); 933 temp[1] = FT_DivFix( temp[1], temp_scale ); 934 temp[2] = FT_DivFix( temp[2], temp_scale ); 935 temp[4] = FT_DivFix( temp[4], temp_scale ); 936 temp[5] = FT_DivFix( temp[5], temp_scale ); 937 temp[3] = 0x10000L; 938 } 939 940 matrix->xx = temp[0]; 941 matrix->yx = temp[1]; 942 matrix->xy = temp[2]; 943 matrix->yy = temp[3]; 944 945 /* note that the offsets must be expressed in integer font units */ 946 offset->x = temp[4] >> 16; 947 offset->y = temp[5] >> 16; 948 } 949 950 951 static void parse_encoding(T1_Face face,T1_Loader loader)952 parse_encoding( T1_Face face, 953 T1_Loader loader ) 954 { 955 T1_Parser parser = &loader->parser; 956 FT_Byte* cur = parser->root.cursor; 957 FT_Byte* limit = parser->root.limit; 958 959 PSAux_Service psaux = (PSAux_Service)face->psaux; 960 961 962 /* skip whitespace */ 963 while ( is_space( *cur ) ) 964 { 965 cur++; 966 if ( cur >= limit ) 967 { 968 FT_ERROR(( "parse_encoding: out of bounds!\n" )); 969 parser->root.error = T1_Err_Invalid_File_Format; 970 return; 971 } 972 } 973 974 /* if we have a number, then the encoding is an array, */ 975 /* and we must load it now */ 976 if ( (FT_Byte)( *cur - '0' ) < 10 ) 977 { 978 T1_Encoding encode = &face->type1.encoding; 979 FT_Int count, n; 980 PS_Table char_table = &loader->encoding_table; 981 FT_Memory memory = parser->root.memory; 982 FT_Error error; 983 984 985 if ( encode->char_index ) 986 /* with synthetic fonts, it's possible we get here twice */ 987 return; 988 989 /* read the number of entries in the encoding, should be 256 */ 990 count = (FT_Int)T1_ToInt( parser ); 991 if ( parser->root.error ) 992 return; 993 994 /* we use a T1_Table to store our charnames */ 995 loader->num_chars = encode->num_chars = count; 996 if ( FT_NEW_ARRAY( encode->char_index, count ) || 997 FT_NEW_ARRAY( encode->char_name, count ) || 998 FT_SET_ERROR( psaux->ps_table_funcs->init( 999 char_table, count, memory ) ) ) 1000 { 1001 parser->root.error = error; 1002 return; 1003 } 1004 1005 /* We need to `zero' out encoding_table.elements */ 1006 for ( n = 0; n < count; n++ ) 1007 { 1008 char* notdef = (char *)".notdef"; 1009 1010 1011 T1_Add_Table( char_table, n, notdef, 8 ); 1012 } 1013 1014 /* Now, we will need to read a record of the form */ 1015 /* ... charcode /charname ... for each entry in our table */ 1016 /* */ 1017 /* We simply look for a number followed by an immediate */ 1018 /* name. Note that this ignores correctly the sequence */ 1019 /* that is often seen in type1 fonts: */ 1020 /* */ 1021 /* 0 1 255 { 1 index exch /.notdef put } for dup */ 1022 /* */ 1023 /* used to clean the encoding array before anything else. */ 1024 /* */ 1025 /* We stop when we encounter a `def'. */ 1026 1027 cur = parser->root.cursor; 1028 limit = parser->root.limit; 1029 n = 0; 1030 1031 for ( ; cur < limit; ) 1032 { 1033 FT_Byte c; 1034 1035 1036 c = *cur; 1037 1038 /* we stop when we encounter a `def' */ 1039 if ( c == 'd' && cur + 3 < limit ) 1040 { 1041 if ( cur[1] == 'e' && 1042 cur[2] == 'f' && 1043 is_space( cur[-1] ) && 1044 is_space( cur[3] ) ) 1045 { 1046 FT_TRACE6(( "encoding end\n" )); 1047 break; 1048 } 1049 } 1050 1051 /* otherwise, we must find a number before anything else */ 1052 if ( (FT_Byte)( c - '0' ) < 10 ) 1053 { 1054 FT_Int charcode; 1055 1056 1057 parser->root.cursor = cur; 1058 charcode = (FT_Int)T1_ToInt( parser ); 1059 cur = parser->root.cursor; 1060 1061 /* skip whitespace */ 1062 while ( cur < limit && is_space( *cur ) ) 1063 cur++; 1064 1065 if ( cur < limit && *cur == '/' ) 1066 { 1067 /* bingo, we have an immediate name -- it must be a */ 1068 /* character name */ 1069 FT_Byte* cur2 = cur + 1; 1070 FT_PtrDist len; 1071 1072 1073 while ( cur2 < limit && is_alpha( *cur2 ) ) 1074 cur2++; 1075 1076 len = cur2 - cur - 1; 1077 1078 parser->root.error = T1_Add_Table( char_table, charcode, 1079 cur + 1, len + 1 ); 1080 char_table->elements[charcode][len] = '\0'; 1081 if ( parser->root.error ) 1082 return; 1083 1084 cur = cur2; 1085 } 1086 } 1087 else 1088 cur++; 1089 } 1090 1091 face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY; 1092 parser->root.cursor = cur; 1093 } 1094 /* Otherwise, we should have either `StandardEncoding', */ 1095 /* `ExpertEncoding', or `ISOLatin1Encoding' */ 1096 else 1097 { 1098 if ( cur + 17 < limit && 1099 ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 ) 1100 face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD; 1101 1102 else if ( cur + 15 < limit && 1103 ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 ) 1104 face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT; 1105 1106 else if ( cur + 18 < limit && 1107 ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 ) 1108 face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1; 1109 1110 else 1111 { 1112 FT_ERROR(( "parse_encoding: invalid token!\n" )); 1113 parser->root.error = T1_Err_Invalid_File_Format; 1114 } 1115 } 1116 } 1117 1118 1119 static void parse_subrs(T1_Face face,T1_Loader loader)1120 parse_subrs( T1_Face face, 1121 T1_Loader loader ) 1122 { 1123 T1_Parser parser = &loader->parser; 1124 PS_Table table = &loader->subrs; 1125 FT_Memory memory = parser->root.memory; 1126 FT_Error error; 1127 FT_Int n; 1128 1129 PSAux_Service psaux = (PSAux_Service)face->psaux; 1130 1131 1132 if ( loader->num_subrs ) 1133 /* with synthetic fonts, it's possible we get here twice */ 1134 return; 1135 1136 loader->num_subrs = (FT_Int)T1_ToInt( parser ); 1137 if ( parser->root.error ) 1138 return; 1139 1140 /* position the parser right before the `dup' of the first subr */ 1141 T1_Skip_Spaces( parser ); 1142 T1_Skip_Alpha( parser ); /* `array' */ 1143 T1_Skip_Spaces( parser ); 1144 1145 /* initialize subrs array */ 1146 error = psaux->ps_table_funcs->init( table, loader->num_subrs, memory ); 1147 if ( error ) 1148 goto Fail; 1149 1150 /* the format is simple: */ 1151 /* */ 1152 /* `index' + binary data */ 1153 /* */ 1154 for ( n = 0; n < loader->num_subrs; n++ ) 1155 { 1156 FT_Long idx, size; 1157 FT_Byte* base; 1158 1159 1160 /* If the next token isn't `dup', we are also done. This */ 1161 /* happens when there are `holes' in the Subrs array. */ 1162 if ( ft_strncmp( (char*)parser->root.cursor, "dup", 3 ) != 0 ) 1163 break; 1164 1165 idx = T1_ToInt( parser ); 1166 1167 if ( !read_binary_data( parser, &size, &base ) ) 1168 return; 1169 1170 /* The binary string is followed by one token, e.g. `NP' */ 1171 /* (bound to `noaccess put') or by two separate tokens: */ 1172 /* `noaccess' & `put'. We position the parser right */ 1173 /* before the next `dup', if any. */ 1174 T1_Skip_Spaces( parser ); 1175 T1_Skip_Alpha( parser ); /* `NP' or `I' or `noaccess' */ 1176 T1_Skip_Spaces( parser ); 1177 1178 if ( ft_strncmp( (char*)parser->root.cursor, "put", 3 ) == 0 ) 1179 { 1180 T1_Skip_Alpha( parser ); /* skip `put' */ 1181 T1_Skip_Spaces( parser ); 1182 } 1183 1184 /* some fonts use a value of -1 for lenIV to indicate that */ 1185 /* the charstrings are unencoded */ 1186 /* */ 1187 /* thanks to Tom Kacvinsky for pointing this out */ 1188 /* */ 1189 if ( face->type1.private_dict.lenIV >= 0 ) 1190 { 1191 FT_Byte* temp; 1192 1193 1194 /* t1_decrypt() shouldn't write to base -- make temporary copy */ 1195 if ( FT_ALLOC( temp, size ) ) 1196 goto Fail; 1197 FT_MEM_COPY( temp, base, size ); 1198 psaux->t1_decrypt( temp, size, 4330 ); 1199 size -= face->type1.private_dict.lenIV; 1200 error = T1_Add_Table( table, idx, 1201 temp + face->type1.private_dict.lenIV, size ); 1202 FT_FREE( temp ); 1203 } 1204 else 1205 error = T1_Add_Table( table, idx, base, size ); 1206 if ( error ) 1207 goto Fail; 1208 } 1209 return; 1210 1211 Fail: 1212 parser->root.error = error; 1213 } 1214 1215 1216 static void parse_charstrings(T1_Face face,T1_Loader loader)1217 parse_charstrings( T1_Face face, 1218 T1_Loader loader ) 1219 { 1220 T1_Parser parser = &loader->parser; 1221 PS_Table code_table = &loader->charstrings; 1222 PS_Table name_table = &loader->glyph_names; 1223 PS_Table swap_table = &loader->swap_table; 1224 FT_Memory memory = parser->root.memory; 1225 FT_Error error; 1226 1227 PSAux_Service psaux = (PSAux_Service)face->psaux; 1228 1229 FT_Byte* cur; 1230 FT_Byte* limit = parser->root.limit; 1231 FT_Int n; 1232 FT_UInt notdef_index = 0; 1233 FT_Byte notdef_found = 0; 1234 1235 1236 if ( loader->num_glyphs ) 1237 /* with synthetic fonts, it's possible we get here twice */ 1238 return; 1239 1240 loader->num_glyphs = (FT_Int)T1_ToInt( parser ); 1241 if ( parser->root.error ) 1242 return; 1243 1244 /* initialize tables (leaving room for addition of .notdef, */ 1245 /* if necessary). */ 1246 1247 error = psaux->ps_table_funcs->init( code_table, 1248 loader->num_glyphs + 1, 1249 memory ); 1250 if ( error ) 1251 goto Fail; 1252 1253 error = psaux->ps_table_funcs->init( name_table, 1254 loader->num_glyphs + 1, 1255 memory ); 1256 if ( error ) 1257 goto Fail; 1258 1259 /* Initialize table for swapping index notdef_index and */ 1260 /* index 0 names and codes (if necessary). */ 1261 1262 error = psaux->ps_table_funcs->init( swap_table, 4, memory ); 1263 1264 if ( error ) 1265 goto Fail; 1266 1267 n = 0; 1268 1269 for (;;) 1270 { 1271 FT_Long size; 1272 FT_Byte* base; 1273 1274 1275 /* the format is simple: */ 1276 /* `/glyphname' + binary data */ 1277 /* */ 1278 /* note that we stop when we find a `def' */ 1279 /* */ 1280 T1_Skip_Spaces( parser ); 1281 1282 cur = parser->root.cursor; 1283 if ( cur >= limit ) 1284 break; 1285 1286 /* we stop when we find a `def' or `end' keyword */ 1287 if ( *cur == 'd' && 1288 cur + 3 < limit && 1289 cur[1] == 'e' && 1290 cur[2] == 'f' ) 1291 break; 1292 1293 if ( *cur == 'e' && 1294 cur + 3 < limit && 1295 cur[1] == 'n' && 1296 cur[2] == 'd' ) 1297 break; 1298 1299 if ( *cur != '/' ) 1300 T1_Skip_Alpha( parser ); 1301 else 1302 { 1303 FT_Byte* cur2 = cur + 1; 1304 FT_PtrDist len; 1305 1306 1307 while ( cur2 < limit && is_alpha( *cur2 ) ) 1308 cur2++; 1309 len = cur2 - cur - 1; 1310 1311 error = T1_Add_Table( name_table, n, cur + 1, len + 1 ); 1312 if ( error ) 1313 goto Fail; 1314 1315 /* add a trailing zero to the name table */ 1316 name_table->elements[n][len] = '\0'; 1317 1318 /* record index of /.notdef */ 1319 if ( ft_strcmp( (const char*)".notdef", 1320 (const char*)(name_table->elements[n]) ) == 0 ) 1321 { 1322 notdef_index = n; 1323 notdef_found = 1; 1324 } 1325 1326 parser->root.cursor = cur2; 1327 if ( !read_binary_data( parser, &size, &base ) ) 1328 return; 1329 1330 if ( face->type1.private_dict.lenIV >= 0 ) 1331 { 1332 FT_Byte* temp; 1333 1334 1335 /* t1_decrypt() shouldn't write to base -- make temporary copy */ 1336 if ( FT_ALLOC( temp, size ) ) 1337 goto Fail; 1338 FT_MEM_COPY( temp, base, size ); 1339 psaux->t1_decrypt( temp, size, 4330 ); 1340 size -= face->type1.private_dict.lenIV; 1341 error = T1_Add_Table( code_table, n, 1342 temp + face->type1.private_dict.lenIV, size ); 1343 FT_FREE( temp ); 1344 } 1345 else 1346 error = T1_Add_Table( code_table, n, base, size ); 1347 if ( error ) 1348 goto Fail; 1349 1350 n++; 1351 if ( n >= loader->num_glyphs ) 1352 break; 1353 } 1354 } 1355 1356 loader->num_glyphs = n; 1357 1358 /* if /.notdef is found but does not occupy index 0, do our magic. */ 1359 if ( ft_strcmp( (const char*)".notdef", 1360 (const char*)name_table->elements[0] ) && 1361 notdef_found ) 1362 { 1363 /* Swap glyph in index 0 with /.notdef glyph. First, add index 0 */ 1364 /* name and code entries to swap_table. Then place notdef_index name */ 1365 /* and code entries into swap_table. Then swap name and code */ 1366 /* entries at indices notdef_index and 0 using values stored in */ 1367 /* swap_table. */ 1368 1369 /* Index 0 name */ 1370 error = T1_Add_Table( swap_table, 0, 1371 name_table->elements[0], 1372 name_table->lengths [0] ); 1373 if ( error ) 1374 goto Fail; 1375 1376 /* Index 0 code */ 1377 error = T1_Add_Table( swap_table, 1, 1378 code_table->elements[0], 1379 code_table->lengths [0] ); 1380 if ( error ) 1381 goto Fail; 1382 1383 /* Index notdef_index name */ 1384 error = T1_Add_Table( swap_table, 2, 1385 name_table->elements[notdef_index], 1386 name_table->lengths [notdef_index] ); 1387 if ( error ) 1388 goto Fail; 1389 1390 /* Index notdef_index code */ 1391 error = T1_Add_Table( swap_table, 3, 1392 code_table->elements[notdef_index], 1393 code_table->lengths [notdef_index] ); 1394 if ( error ) 1395 goto Fail; 1396 1397 error = T1_Add_Table( name_table, notdef_index, 1398 swap_table->elements[0], 1399 swap_table->lengths [0] ); 1400 if ( error ) 1401 goto Fail; 1402 1403 error = T1_Add_Table( code_table, notdef_index, 1404 swap_table->elements[1], 1405 swap_table->lengths [1] ); 1406 if ( error ) 1407 goto Fail; 1408 1409 error = T1_Add_Table( name_table, 0, 1410 swap_table->elements[2], 1411 swap_table->lengths [2] ); 1412 if ( error ) 1413 goto Fail; 1414 1415 error = T1_Add_Table( code_table, 0, 1416 swap_table->elements[3], 1417 swap_table->lengths [3] ); 1418 if ( error ) 1419 goto Fail; 1420 1421 } 1422 else if ( !notdef_found ) 1423 { 1424 /* notdef_index is already 0, or /.notdef is undefined in */ 1425 /* charstrings dictionary. Worry about /.notdef undefined. */ 1426 /* We take index 0 and add it to the end of the table(s) */ 1427 /* and add our own /.notdef glyph to index 0. */ 1428 1429 /* 0 333 hsbw endchar */ 1430 FT_Byte notdef_glyph[] = {0x8B, 0xF7, 0xE1, 0x0D, 0x0E}; 1431 char* notdef_name = (char *)".notdef"; 1432 1433 1434 error = T1_Add_Table( swap_table, 0, 1435 name_table->elements[0], 1436 name_table->lengths [0] ); 1437 if ( error ) 1438 goto Fail; 1439 1440 error = T1_Add_Table( swap_table, 1, 1441 code_table->elements[0], 1442 code_table->lengths [0] ); 1443 if ( error ) 1444 goto Fail; 1445 1446 error = T1_Add_Table( name_table, 0, notdef_name, 8 ); 1447 if ( error ) 1448 goto Fail; 1449 1450 error = T1_Add_Table( code_table, 0, notdef_glyph, 5 ); 1451 1452 if ( error ) 1453 goto Fail; 1454 1455 error = T1_Add_Table( name_table, n, 1456 swap_table->elements[0], 1457 swap_table->lengths [0] ); 1458 if ( error ) 1459 goto Fail; 1460 1461 error = T1_Add_Table( code_table, n, 1462 swap_table->elements[1], 1463 swap_table->lengths [1] ); 1464 if ( error ) 1465 goto Fail; 1466 1467 /* we added a glyph. */ 1468 loader->num_glyphs = n + 1; 1469 } 1470 1471 return; 1472 1473 Fail: 1474 parser->root.error = error; 1475 } 1476 1477 1478 static 1479 const T1_FieldRec t1_keywords[] = 1480 { 1481 1482 #include "t1tokens.h" 1483 1484 /* now add the special functions... */ 1485 T1_FIELD_CALLBACK( "FontName", parse_font_name ) 1486 #if 0 1487 T1_FIELD_CALLBACK( "FontBBox", parse_font_bbox ) 1488 #endif 1489 T1_FIELD_CALLBACK( "FontMatrix", parse_font_matrix ) 1490 T1_FIELD_CALLBACK( "Encoding", parse_encoding ) 1491 T1_FIELD_CALLBACK( "Subrs", parse_subrs ) 1492 T1_FIELD_CALLBACK( "CharStrings", parse_charstrings ) 1493 1494 #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT 1495 T1_FIELD_CALLBACK( "BlendDesignPositions", parse_blend_design_positions ) 1496 T1_FIELD_CALLBACK( "BlendDesignMap", parse_blend_design_map ) 1497 T1_FIELD_CALLBACK( "BlendAxisTypes", parse_blend_axis_types ) 1498 T1_FIELD_CALLBACK( "WeightVector", parse_weight_vector ) 1499 T1_FIELD_CALLBACK( "shareddict", parse_shared_dict ) 1500 #endif 1501 1502 { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0 } 1503 }; 1504 1505 1506 static FT_Error parse_dict(T1_Face face,T1_Loader loader,FT_Byte * base,FT_Long size)1507 parse_dict( T1_Face face, 1508 T1_Loader loader, 1509 FT_Byte* base, 1510 FT_Long size ) 1511 { 1512 T1_Parser parser = &loader->parser; 1513 1514 1515 parser->root.cursor = base; 1516 parser->root.limit = base + size; 1517 parser->root.error = 0; 1518 1519 { 1520 FT_Byte* cur = base; 1521 FT_Byte* limit = cur + size; 1522 1523 1524 for ( ; cur < limit; cur++ ) 1525 { 1526 /* look for `FontDirectory', which causes problems on some fonts */ 1527 if ( *cur == 'F' && cur + 25 < limit && 1528 ft_strncmp( (char*)cur, "FontDirectory", 13 ) == 0 ) 1529 { 1530 FT_Byte* cur2; 1531 1532 1533 /* skip the `FontDirectory' keyword */ 1534 cur += 13; 1535 cur2 = cur; 1536 1537 /* lookup the `known' keyword */ 1538 while ( cur < limit && *cur != 'k' && 1539 ft_strncmp( (char*)cur, "known", 5 ) ) 1540 cur++; 1541 1542 if ( cur < limit ) 1543 { 1544 T1_TokenRec token; 1545 1546 1547 /* skip the `known' keyword and the token following it */ 1548 cur += 5; 1549 loader->parser.root.cursor = cur; 1550 T1_ToToken( &loader->parser, &token ); 1551 1552 /* if the last token was an array, skip it! */ 1553 if ( token.type == T1_TOKEN_TYPE_ARRAY ) 1554 cur2 = parser->root.cursor; 1555 } 1556 cur = cur2; 1557 } 1558 /* look for immediates */ 1559 else if ( *cur == '/' && cur + 2 < limit ) 1560 { 1561 FT_Byte* cur2; 1562 FT_PtrDist len; 1563 1564 1565 cur++; 1566 cur2 = cur; 1567 while ( cur2 < limit && is_alpha( *cur2 ) ) 1568 cur2++; 1569 1570 len = cur2 - cur; 1571 if ( len > 0 && len < 22 ) 1572 { 1573 { 1574 /* now, compare the immediate name to the keyword table */ 1575 T1_Field keyword = (T1_Field)t1_keywords; 1576 1577 1578 for (;;) 1579 { 1580 FT_Byte* name; 1581 1582 1583 name = (FT_Byte*)keyword->ident; 1584 if ( !name ) 1585 break; 1586 1587 if ( cur[0] == name[0] && 1588 len == ft_strlen( (const char*)name ) ) 1589 { 1590 FT_PtrDist n; 1591 1592 1593 for ( n = 1; n < len; n++ ) 1594 if ( cur[n] != name[n] ) 1595 break; 1596 1597 if ( n >= len ) 1598 { 1599 /* we found it -- run the parsing callback! */ 1600 parser->root.cursor = cur2; 1601 T1_Skip_Spaces( parser ); 1602 parser->root.error = t1_load_keyword( face, 1603 loader, 1604 keyword ); 1605 if ( parser->root.error ) 1606 return parser->root.error; 1607 1608 cur = parser->root.cursor; 1609 break; 1610 } 1611 } 1612 keyword++; 1613 } 1614 } 1615 } 1616 } 1617 } 1618 } 1619 return parser->root.error; 1620 } 1621 1622 1623 static void t1_init_loader(T1_Loader loader,T1_Face face)1624 t1_init_loader( T1_Loader loader, 1625 T1_Face face ) 1626 { 1627 FT_UNUSED( face ); 1628 1629 FT_MEM_ZERO( loader, sizeof ( *loader ) ); 1630 loader->num_glyphs = 0; 1631 loader->num_chars = 0; 1632 1633 /* initialize the tables -- simply set their `init' field to 0 */ 1634 loader->encoding_table.init = 0; 1635 loader->charstrings.init = 0; 1636 loader->glyph_names.init = 0; 1637 loader->subrs.init = 0; 1638 loader->swap_table.init = 0; 1639 loader->fontdata = 0; 1640 } 1641 1642 1643 static void t1_done_loader(T1_Loader loader)1644 t1_done_loader( T1_Loader loader ) 1645 { 1646 T1_Parser parser = &loader->parser; 1647 1648 1649 /* finalize tables */ 1650 T1_Release_Table( &loader->encoding_table ); 1651 T1_Release_Table( &loader->charstrings ); 1652 T1_Release_Table( &loader->glyph_names ); 1653 T1_Release_Table( &loader->swap_table ); 1654 T1_Release_Table( &loader->subrs ); 1655 1656 /* finalize parser */ 1657 T1_Finalize_Parser( parser ); 1658 } 1659 1660 1661 FT_LOCAL_DEF( FT_Error ) T1_Open_Face(T1_Face face)1662 T1_Open_Face( T1_Face face ) 1663 { 1664 T1_LoaderRec loader; 1665 T1_Parser parser; 1666 T1_Font type1 = &face->type1; 1667 FT_Error error; 1668 1669 PSAux_Service psaux = (PSAux_Service)face->psaux; 1670 1671 1672 t1_init_loader( &loader, face ); 1673 1674 /* default lenIV */ 1675 type1->private_dict.lenIV = 4; 1676 1677 /* default blue fuzz, we put it there since 0 is a valid value */ 1678 type1->private_dict.blue_fuzz = 1; 1679 1680 parser = &loader.parser; 1681 error = T1_New_Parser( parser, 1682 face->root.stream, 1683 face->root.memory, 1684 psaux ); 1685 if ( error ) 1686 goto Exit; 1687 1688 error = parse_dict( face, &loader, parser->base_dict, parser->base_len ); 1689 if ( error ) 1690 goto Exit; 1691 1692 error = T1_Get_Private_Dict( parser, psaux ); 1693 if ( error ) 1694 goto Exit; 1695 1696 error = parse_dict( face, &loader, parser->private_dict, 1697 parser->private_len ); 1698 if ( error ) 1699 goto Exit; 1700 1701 /* now, propagate the subrs, charstrings, and glyphnames tables */ 1702 /* to the Type1 data */ 1703 type1->num_glyphs = loader.num_glyphs; 1704 1705 if ( loader.subrs.init ) 1706 { 1707 loader.subrs.init = 0; 1708 type1->num_subrs = loader.num_subrs; 1709 type1->subrs_block = loader.subrs.block; 1710 type1->subrs = loader.subrs.elements; 1711 type1->subrs_len = loader.subrs.lengths; 1712 } 1713 1714 #ifdef FT_CONFIG_OPTION_INCREMENTAL 1715 if ( !face->root.internal->incremental_interface ) 1716 #endif 1717 if ( !loader.charstrings.init ) 1718 { 1719 FT_ERROR(( "T1_Open_Face: no charstrings array in face!\n" )); 1720 error = T1_Err_Invalid_File_Format; 1721 } 1722 1723 loader.charstrings.init = 0; 1724 type1->charstrings_block = loader.charstrings.block; 1725 type1->charstrings = loader.charstrings.elements; 1726 type1->charstrings_len = loader.charstrings.lengths; 1727 1728 /* we copy the glyph names `block' and `elements' fields; */ 1729 /* the `lengths' field must be released later */ 1730 type1->glyph_names_block = loader.glyph_names.block; 1731 type1->glyph_names = (FT_String**)loader.glyph_names.elements; 1732 loader.glyph_names.block = 0; 1733 loader.glyph_names.elements = 0; 1734 1735 /* we must now build type1.encoding when we have a custom array */ 1736 if ( type1->encoding_type == T1_ENCODING_TYPE_ARRAY ) 1737 { 1738 FT_Int charcode, idx, min_char, max_char; 1739 FT_Byte* char_name; 1740 FT_Byte* glyph_name; 1741 1742 1743 /* OK, we do the following: for each element in the encoding */ 1744 /* table, look up the index of the glyph having the same name */ 1745 /* the index is then stored in type1.encoding.char_index, and */ 1746 /* a the name to type1.encoding.char_name */ 1747 1748 min_char = +32000; 1749 max_char = -32000; 1750 1751 charcode = 0; 1752 for ( ; charcode < loader.encoding_table.max_elems; charcode++ ) 1753 { 1754 type1->encoding.char_index[charcode] = 0; 1755 type1->encoding.char_name [charcode] = (char *)".notdef"; 1756 1757 char_name = loader.encoding_table.elements[charcode]; 1758 if ( char_name ) 1759 for ( idx = 0; idx < type1->num_glyphs; idx++ ) 1760 { 1761 glyph_name = (FT_Byte*)type1->glyph_names[idx]; 1762 if ( ft_strcmp( (const char*)char_name, 1763 (const char*)glyph_name ) == 0 ) 1764 { 1765 type1->encoding.char_index[charcode] = (FT_UShort)idx; 1766 type1->encoding.char_name [charcode] = (char*)glyph_name; 1767 1768 /* Change min/max encoded char only if glyph name is */ 1769 /* not /.notdef */ 1770 if ( ft_strcmp( (const char*)".notdef", 1771 (const char*)glyph_name ) != 0 ) 1772 { 1773 if ( charcode < min_char ) min_char = charcode; 1774 if ( charcode > max_char ) max_char = charcode; 1775 } 1776 break; 1777 } 1778 } 1779 } 1780 type1->encoding.code_first = min_char; 1781 type1->encoding.code_last = max_char; 1782 type1->encoding.num_chars = loader.num_chars; 1783 } 1784 1785 Exit: 1786 t1_done_loader( &loader ); 1787 return error; 1788 } 1789 1790 1791 /* END */ 1792