/src/freetype/src/type1/t1load.c
C | 2243 lines | 1489 code | 446 blank | 308 comment | 327 complexity | 75aa6f88e381913fe040e39a0a1d182e MD5 | raw file
Large files files are truncated, but you can click here to view the full file
1/***************************************************************************/ 2/* */ 3/* t1load.c */ 4/* */ 5/* Type 1 font loader (body). */ 6/* */ 7/* Copyright 1996-2012 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 /*************************************************************************/ 75 /* */ 76 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 77 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 78 /* messages during execution. */ 79 /* */ 80#undef FT_COMPONENT 81#define FT_COMPONENT trace_t1load 82 83 84#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT 85 86 87 /*************************************************************************/ 88 /*************************************************************************/ 89 /***** *****/ 90 /***** MULTIPLE MASTERS SUPPORT *****/ 91 /***** *****/ 92 /*************************************************************************/ 93 /*************************************************************************/ 94 95 static FT_Error 96 t1_allocate_blend( T1_Face face, 97 FT_UInt num_designs, 98 FT_UInt num_axis ) 99 { 100 PS_Blend blend; 101 FT_Memory memory = face->root.memory; 102 FT_Error error = T1_Err_Ok; 103 104 105 blend = face->blend; 106 if ( !blend ) 107 { 108 if ( FT_NEW( blend ) ) 109 goto Exit; 110 111 blend->num_default_design_vector = 0; 112 113 face->blend = blend; 114 } 115 116 /* allocate design data if needed */ 117 if ( num_designs > 0 ) 118 { 119 if ( blend->num_designs == 0 ) 120 { 121 FT_UInt nn; 122 123 124 /* allocate the blend `private' and `font_info' dictionaries */ 125 if ( FT_NEW_ARRAY( blend->font_infos[1], num_designs ) || 126 FT_NEW_ARRAY( blend->privates[1], num_designs ) || 127 FT_NEW_ARRAY( blend->bboxes[1], num_designs ) || 128 FT_NEW_ARRAY( blend->weight_vector, num_designs * 2 ) ) 129 goto Exit; 130 131 blend->default_weight_vector = blend->weight_vector + num_designs; 132 133 blend->font_infos[0] = &face->type1.font_info; 134 blend->privates [0] = &face->type1.private_dict; 135 blend->bboxes [0] = &face->type1.font_bbox; 136 137 for ( nn = 2; nn <= num_designs; nn++ ) 138 { 139 blend->privates[nn] = blend->privates [nn - 1] + 1; 140 blend->font_infos[nn] = blend->font_infos[nn - 1] + 1; 141 blend->bboxes[nn] = blend->bboxes [nn - 1] + 1; 142 } 143 144 blend->num_designs = num_designs; 145 } 146 else if ( blend->num_designs != num_designs ) 147 goto Fail; 148 } 149 150 /* allocate axis data if needed */ 151 if ( num_axis > 0 ) 152 { 153 if ( blend->num_axis != 0 && blend->num_axis != num_axis ) 154 goto Fail; 155 156 blend->num_axis = num_axis; 157 } 158 159 /* allocate the blend design pos table if needed */ 160 num_designs = blend->num_designs; 161 num_axis = blend->num_axis; 162 if ( num_designs && num_axis && blend->design_pos[0] == 0 ) 163 { 164 FT_UInt n; 165 166 167 if ( FT_NEW_ARRAY( blend->design_pos[0], num_designs * num_axis ) ) 168 goto Exit; 169 170 for ( n = 1; n < num_designs; n++ ) 171 blend->design_pos[n] = blend->design_pos[0] + num_axis * n; 172 } 173 174 Exit: 175 return error; 176 177 Fail: 178 error = T1_Err_Invalid_File_Format; 179 goto Exit; 180 } 181 182 183 FT_LOCAL_DEF( FT_Error ) 184 T1_Get_Multi_Master( T1_Face face, 185 FT_Multi_Master* master ) 186 { 187 PS_Blend blend = face->blend; 188 FT_UInt n; 189 FT_Error error; 190 191 192 error = T1_Err_Invalid_Argument; 193 194 if ( blend ) 195 { 196 master->num_axis = blend->num_axis; 197 master->num_designs = blend->num_designs; 198 199 for ( n = 0; n < blend->num_axis; n++ ) 200 { 201 FT_MM_Axis* axis = master->axis + n; 202 PS_DesignMap map = blend->design_map + n; 203 204 205 axis->name = blend->axis_names[n]; 206 axis->minimum = map->design_points[0]; 207 axis->maximum = map->design_points[map->num_points - 1]; 208 } 209 210 error = T1_Err_Ok; 211 } 212 213 return error; 214 } 215 216 217 /*************************************************************************/ 218 /* */ 219 /* Given a normalized (blend) coordinate, figure out the design */ 220 /* coordinate appropriate for that value. */ 221 /* */ 222 FT_LOCAL_DEF( FT_Fixed ) 223 mm_axis_unmap( PS_DesignMap axismap, 224 FT_Fixed ncv ) 225 { 226 int j; 227 228 229 if ( ncv <= axismap->blend_points[0] ) 230 return INT_TO_FIXED( axismap->design_points[0] ); 231 232 for ( j = 1; j < axismap->num_points; ++j ) 233 { 234 if ( ncv <= axismap->blend_points[j] ) 235 { 236 FT_Fixed t = FT_MulDiv( ncv - axismap->blend_points[j - 1], 237 0x10000L, 238 axismap->blend_points[j] - 239 axismap->blend_points[j - 1] ); 240 241 return INT_TO_FIXED( axismap->design_points[j - 1] ) + 242 FT_MulDiv( t, 243 axismap->design_points[j] - 244 axismap->design_points[j - 1], 245 1L ); 246 } 247 } 248 249 return INT_TO_FIXED( axismap->design_points[axismap->num_points - 1] ); 250 } 251 252 253 /*************************************************************************/ 254 /* */ 255 /* Given a vector of weights, one for each design, figure out the */ 256 /* normalized axis coordinates which gave rise to those weights. */ 257 /* */ 258 FT_LOCAL_DEF( void ) 259 mm_weights_unmap( FT_Fixed* weights, 260 FT_Fixed* axiscoords, 261 FT_UInt axis_count ) 262 { 263 FT_ASSERT( axis_count <= T1_MAX_MM_AXIS ); 264 265 if ( axis_count == 1 ) 266 axiscoords[0] = weights[1]; 267 268 else if ( axis_count == 2 ) 269 { 270 axiscoords[0] = weights[3] + weights[1]; 271 axiscoords[1] = weights[3] + weights[2]; 272 } 273 274 else if ( axis_count == 3 ) 275 { 276 axiscoords[0] = weights[7] + weights[5] + weights[3] + weights[1]; 277 axiscoords[1] = weights[7] + weights[6] + weights[3] + weights[2]; 278 axiscoords[2] = weights[7] + weights[6] + weights[5] + weights[4]; 279 } 280 281 else 282 { 283 axiscoords[0] = weights[15] + weights[13] + weights[11] + weights[9] + 284 weights[7] + weights[5] + weights[3] + weights[1]; 285 axiscoords[1] = weights[15] + weights[14] + weights[11] + weights[10] + 286 weights[7] + weights[6] + weights[3] + weights[2]; 287 axiscoords[2] = weights[15] + weights[14] + weights[13] + weights[12] + 288 weights[7] + weights[6] + weights[5] + weights[4]; 289 axiscoords[3] = weights[15] + weights[14] + weights[13] + weights[12] + 290 weights[11] + weights[10] + weights[9] + weights[8]; 291 } 292 } 293 294 295 /*************************************************************************/ 296 /* */ 297 /* Just a wrapper around T1_Get_Multi_Master to support the different */ 298 /* arguments needed by the GX var distortable fonts. */ 299 /* */ 300 FT_LOCAL_DEF( FT_Error ) 301 T1_Get_MM_Var( T1_Face face, 302 FT_MM_Var* *master ) 303 { 304 FT_Memory memory = face->root.memory; 305 FT_MM_Var *mmvar = NULL; 306 FT_Multi_Master mmaster; 307 FT_Error error; 308 FT_UInt i; 309 FT_Fixed axiscoords[T1_MAX_MM_AXIS]; 310 PS_Blend blend = face->blend; 311 312 313 error = T1_Get_Multi_Master( face, &mmaster ); 314 if ( error ) 315 goto Exit; 316 if ( FT_ALLOC( mmvar, 317 sizeof ( FT_MM_Var ) + 318 mmaster.num_axis * sizeof ( FT_Var_Axis ) ) ) 319 goto Exit; 320 321 mmvar->num_axis = mmaster.num_axis; 322 mmvar->num_designs = mmaster.num_designs; 323 mmvar->num_namedstyles = (FT_UInt)-1; /* 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 = (FT_UInt)-1; /* Does not apply */ 337 mmvar->axis[i].tag = (FT_ULong)-1; /* Does not apply */ 338 339 if ( ft_strcmp( mmvar->axis[i].name, "Weight" ) == 0 ) 340 mmvar->axis[i].tag = FT_MAKE_TAG( 'w', 'g', 'h', 't' ); 341 else if ( ft_strcmp( mmvar->axis[i].name, "Width" ) == 0 ) 342 mmvar->axis[i].tag = FT_MAKE_TAG( 'w', 'd', 't', 'h' ); 343 else if ( ft_strcmp( mmvar->axis[i].name, "OpticalSize" ) == 0 ) 344 mmvar->axis[i].tag = FT_MAKE_TAG( 'o', 'p', 's', 'z' ); 345 } 346 347 if ( blend->num_designs == ( 1U << blend->num_axis ) ) 348 { 349 mm_weights_unmap( blend->default_weight_vector, 350 axiscoords, 351 blend->num_axis ); 352 353 for ( i = 0; i < mmaster.num_axis; ++i ) 354 mmvar->axis[i].def = mm_axis_unmap( &blend->design_map[i], 355 axiscoords[i] ); 356 } 357 358 *master = mmvar; 359 360 Exit: 361 return error; 362 } 363 364 365 FT_LOCAL_DEF( FT_Error ) 366 T1_Set_MM_Blend( T1_Face face, 367 FT_UInt num_coords, 368 FT_Fixed* coords ) 369 { 370 PS_Blend blend = face->blend; 371 FT_Error error; 372 FT_UInt n, m; 373 374 375 error = T1_Err_Invalid_Argument; 376 377 if ( blend && blend->num_axis == num_coords ) 378 { 379 /* recompute the weight vector from the blend coordinates */ 380 error = T1_Err_Ok; 381 382 for ( n = 0; n < blend->num_designs; n++ ) 383 { 384 FT_Fixed result = 0x10000L; /* 1.0 fixed */ 385 386 387 for ( m = 0; m < blend->num_axis; m++ ) 388 { 389 FT_Fixed factor; 390 391 392 /* get current blend axis position */ 393 factor = coords[m]; 394 if ( factor < 0 ) factor = 0; 395 if ( factor > 0x10000L ) 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 = T1_Err_Ok; 406 } 407 408 return error; 409 } 410 411 412 FT_LOCAL_DEF( FT_Error ) 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 = T1_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 ) 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 = T1_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 ) 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] = 0; 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] = 0; 537 blend->font_infos[n] = 0; 538 blend->bboxes [n] = 0; 539 } 540 541 /* release weight vectors */ 542 FT_FREE( blend->weight_vector ); 543 blend->default_weight_vector = 0; 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 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 = T1_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 = T1_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 = T1_Err_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 = T1_Err_Invalid_File_Format; 615 goto Exit; 616 } 617 618 if ( FT_ALLOC( blend->axis_names[n], 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 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 = T1_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 = T1_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 = T1_Err_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 = T1_Err_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 = T1_Err_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 729 parse_blend_design_map( T1_Face face, 730 T1_Loader loader ) 731 { 732 FT_Error error = T1_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 = T1_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 = T1_Err_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 = T1_Err_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 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 = T1_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 = T1_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 = T1_Err_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 = T1_Err_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 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 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 ( field->type == T1_FIELD_TYPE_INTEGER_ARRAY || 1008 field->type == T1_FIELD_TYPE_FIXED_ARRAY ) 1009 error = T1_Load_Field_Table( &loader->parser, field, 1010 objects, max_objects, 0 ); 1011 else 1012 error = T1_Load_Field( &loader->parser, field, 1013 objects, max_objects, 0 ); 1014 1015 Exit: 1016 return error; 1017 } 1018 1019 1020 static void 1021 parse_private( T1_Face face, 1022 T1_Loader loader ) 1023 { 1024 FT_UNUSED( face ); 1025 1026 loader->keywords_encountered |= T1_PRIVATE; 1027 } 1028 1029 1030 static int 1031 read_binary_data( T1_Parser parser, 1032 FT_Long* size, 1033 FT_Byte** base ) 1034 { 1035 FT_Byte* cur; 1036 FT_Byte* limit = parser->root.limit; 1037 1038 1039 /* the binary data has one of the following formats */ 1040 /* */ 1041 /* `size' [white*] RD white ....... ND */ 1042 /* `size' [white*] -| white ....... |- */ 1043 /* */ 1044 1045 T1_Skip_Spaces( parser ); 1046 1047 cur = parser->root.cursor; 1048 1049 if ( cur < limit && ft_isdigit( *cur ) ) 1050 { 1051 FT_Long s = T1_ToInt( parser ); 1052 1053 1054 T1_Skip_PS_Token( parser ); /* `RD' or `-|' or something else */ 1055 1056 /* there is only one whitespace char after the */ 1057 /* `RD' or `-|' token */ 1058 *base = parser->root.cursor + 1; 1059 1060 if ( s >= 0 && s < limit - *base ) 1061 { 1062 parser->root.cursor += s + 1; 1063 *size = s; 1064 return !parser->root.error; 1065 } 1066 } 1067 1068 FT_ERROR(( "read_binary_data: invalid size field\n" )); 1069 parser->root.error = T1_Err_Invalid_File_Format; 1070 return 0; 1071 } 1072 1073 1074 /* We now define the routines to handle the `/Encoding', `/Subrs', */ 1075 /* and `/CharStrings' dictionaries. */ 1076 1077 static void 1078 t1_parse_font_matrix( T1_Face face, 1079 T1_Loader loader ) 1080 { 1081 T1_Parser parser = &loader->parser; 1082 FT_Matrix* matrix = &face->type1.font_matrix; 1083 FT_Vector* offset = &face->type1.font_offset; 1084 FT_Face root = (FT_Face)&face->root; 1085 FT_Fixed temp[6]; 1086 FT_Fixed temp_scale; 1087 FT_Int result; 1088 1089 1090 result = T1_ToFixedArray( parser, 6, temp, 3 ); 1091 1092 if ( result < 0 ) 1093 { 1094 parser->root.error = T1_Err_Invalid_File_Format; 1095 return; 1096 } 1097 1098 temp_scale = FT_ABS( temp[3] ); 1099 1100 if ( temp_scale == 0 ) 1101 { 1102 FT_ERROR(( "t1_parse_font_matrix: invalid font matrix\n" )); 1103 parser->root.error = T1_Err_Invalid_File_Format; 1104 return; 1105 } 1106 1107 /* Set Units per EM based on FontMatrix values. We set the value to */ 1108 /* 1000 / temp_scale, because temp_scale was already multiplied by */ 1109 /* 1000 (in t1_tofixed, from psobjs.c). */ 1110 1111 root->units_per_EM = (FT_UShort)( FT_DivFix( 1000 * 0x10000L, 1112 temp_scale ) >> 16 ); 1113 1114 /* we need to scale the values by 1.0/temp_scale */ 1115 if ( temp_scale != 0x10000L ) 1116 { 1117 temp[0] = FT_DivFix( temp[0], temp_scale ); 1118 temp[1] = FT_DivFix( temp[1], temp_scale ); 1119 temp[2] = FT_DivFix( temp[2], temp_scale ); 1120 temp[4] = FT_DivFix( temp[4], temp_scale ); 1121 temp[5] = FT_DivFix( temp[5], temp_scale ); 1122 temp[3] = temp[3] < 0 ? -0x10000L : 0x10000L; 1123 } 1124 1125 matrix->xx = temp[0]; 1126 matrix->yx = temp[1]; 1127 matrix->xy = temp[2]; 1128 matrix->yy = temp[3]; 1129 1130 /* note that the offsets must be expressed in integer font units */ 1131 offset->x = temp[4] >> 16; 1132 offset->y = temp[5] >> 16; 1133 } 1134 1135 1136 static void 1137 parse_encoding( T1_Face face, 1138 T1_Loader loader ) 1139 { 1140 T1_Parser parser = &loader->parser; 1141 FT_Byte* cur; 1142 FT_Byte* limit = parser->root.limit; 1143 1144 PSAux_Service psaux = (PSAux_Service)face->psaux; 1145 1146 1147 T1_Skip_Spaces( parser ); 1148 cur = parser->root.cursor; 1149 if ( cur >= limit ) 1150 { 1151 FT_ERROR(( "parse_encoding: out of bounds\n" )); 1152 parser->root.error = T1_Err_Invalid_File_Format; 1153 return; 1154 } 1155 1156 /* if we have a number or `[', the encoding is an array, */ 1157 /* and we must load it now */ 1158 if ( ft_isdigit( *cur ) || *cur == '[' ) 1159 { 1160 T1_Encoding encode = &face->type1.encoding; 1161 FT_Int count, n; 1162 PS_Table char_table = &loader->encoding_table; 1163 FT_Memory memory = parser->root.memory; 1164 FT_Error error; 1165 FT_Bool only_immediates = 0; 1166 1167 1168 /* read the number of entries in the encoding; should be 256 */ 1169 if ( *cur == '[' ) 1170 { 1171 count = 256; 1172 only_immediates = 1; 1173 parser->root.cursor++; 1174 } 1175 else 1176 count = (FT_Int)T1_ToInt( parser ); 1177 1178 T1_Skip_Spaces( parser ); 1179 if ( parser->root.cursor >= limit ) 1180 return; 1181 1182 /* we use a T1_Table to store our charnames */ 1183 loader->num_chars = encode->num_chars = count; 1184 if ( FT_NEW_ARRAY( encode->char_index, count ) || 1185 FT_NEW_ARRAY( encode->char_name, count ) || 1186 FT_SET_ERROR( psaux->ps_table_funcs->init( 1187 char_table, count, memory ) ) ) 1188 { 1189 parser->root.error = error; 1190 return; 1191 } 1192 1193 /* We need to `zero' out encoding_table.elements */ 1194 for ( n = 0; n < count; n++ ) 1195 { 1196 char* notdef = (char *)".notdef"; 1197 1198 1199 T1_Add_Table( char_table, n, notdef, 8 ); 1200 } 1201 1202 /* Now we need to read records of the form */ 1203 /* */ 1204 /* ... charcode /charname ... */ 1205 /* */ 1206 /* for each entry in our table. */ 1207 /* */ 1208 /* We simply look for a number followed by an immediate */ 1209 /* name. Note that this ignores correctly the sequence */ 1210 /* that is often seen in type1 fonts: */ 1211 /* */ 1212 /* 0 1 255 { 1 index exch /.notdef put } for dup */ 1213 /* */ 1214 /* used to clean the encoding array before anything else. */ 1215 /* */ 1216 /* Alternatively, if the array is directly given as */ 1217 /* */ 1218 /* /Encoding [ ... ] */ 1219 /* */ 1220 /* we only read immediates. */ 1221 1222 n = 0; 1223 T1_Skip_Spaces( parser ); 1224 1225 while ( parser->root.cursor < limit ) 1226 { 1227 cur = parser->root.cursor; 1228 1229 /* we stop when we encounter a `def' or `]' */ 1230 if ( *cur == 'd' && cur + 3 < limit ) 1231 { 1232 if ( cur[1] == 'e' && 1233 cur[2] == 'f' && 1234 IS_PS_DELIM( cur[3] ) ) 1235 { 1236 FT_TRACE6(( "encoding end\n" )); 1237 cur += 3; 1238 break; 1239 } 1240 } 1241 if ( *cur == ']' ) 1242 { 1243 FT_TRACE6(( "encoding end\n" )); 1244 cur++; 1245 break; 1246 } 1247 1248 /* check whether we've found an entry */ 1249 if ( ft_isdigit( *cur ) || only_immediates ) 1250 { 1251 FT_Int charcode; 1252 1253 1254 if ( only_immediates ) 1255 charcode = n; 1256 else 1257 { 1258 charcode = (FT_Int)T1_ToInt( parser ); 1259 T1_Skip_Spaces( parser ); 1260 } 1261 1262 cur = parser->root.cursor; 1263 1264 if ( *cur == '/' && cur + 2 < limit && n < count ) 1265 { 1266 FT_PtrDist len; 1267 1268 1269 cur++; 1270 1271 parser->root.cursor = cur; 1272 T1_Skip_PS_Token( parser ); 1273 if ( parser->root.error ) 1274 return; 1275 1276 len = parser->root.cursor - cur; 1277 1278 parser->root.error = T1_Add_Table( char_table, charcode, 1279 cur, len + 1 ); 1280 if ( parser->root.error ) 1281 return; 1282 char_table->elements[charcode][len] = '\0'; 1283 1284 n++; 1285 } 1286 else if ( only_immediates ) 1287 { 1288 /* Since the current position is not updated for */ 1289 /* immediates-only mode we would get an infinite loop if */ 1290 /* we don't do anything here. */ 1291 /* */ 1292 /* This encoding array is not valid according to the type1 */ 1293 /* specification (it might be an encoding for a CID type1 */ 1294 /* font, however), so we conclude that this font is NOT a */ 1295 /* type1 font. */ 1296 parser->root.error = FT_Err_Unknown_File_Format; 1297 return; 1298 } 1299 } 1300 else 1301 { 1302 T1_Skip_PS_Token( parser ); 1303 if ( parser->root.error ) 1304 return; 1305 } 1306 1307 T1_Skip_Spaces( parser ); 1308 } 1309 1310 face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY; 1311 parser->root.cursor = cur; 1312 } 1313 1314 /* Otherwise, we should have either `StandardEncoding', */ 1315 /* `ExpertEncoding', or `ISOLatin1Encoding' */ 1316 else 1317 { 1318 if ( cur + 17 < limit && 1319 ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 ) 1320 face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD; 1321 1322 else if ( cur + 15 < limit && 1323 ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 ) 1324 face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT; 1325 1326 else if ( cur + 18 < limit && 1327 ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 ) 1328 face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1; 1329 1330 else 1331 parser->root.error = T1_Err_Ignore; 1332 } 1333 } 1334 1335 1336 static void 1337 parse_subrs( T1_Face face, 1338 T1_Loader loader ) 1339 { 1340 T1_Parser parser = &loader->parser; 1341 PS_Table table = &loader->subrs; 1342 FT_Memory memory = parser->root.memory; 1343 FT_Error error; 1344 FT_Int num_subrs; 1345 1346 PSAux_Service psaux = (PSAux_Service)face->psaux; 1347 1348 1349 T1_Skip_Spaces( parser ); 1350 1351 /* test for empty array */ 1352 if ( parser->root.cursor < parser->root.limit && 1353 *parser->root.cursor == '[' ) 1354 { 1355 T1_Skip_PS_Token( parser ); 1356 T1_Skip_Spaces ( parser ); 1357 if ( parser->root.cursor >= parser->root.limit || 1358 *parser->root.cursor != ']' ) 1359 parser->root.error = T1_Err_Invalid_File_Format; 1360 return; 1361 } 1362 1363 num_subrs = (FT_Int)T1_ToInt( parser ); 1364 1365 /* position the parser right before the `dup' of the first subr */ 1366 T1_Skip_PS_Token( parser ); /* `array' */ 1367 if ( parser->root.error ) 1368 return; 1369 T1_Skip_Spaces( parser ); 1370 1371 /* initialize subrs array -- with synthetic fonts it is possible */ 1372 /* we get here twice */ 1373 if ( !loader->num_subrs ) 1374 { 1375 error = psaux->ps_table_funcs->init( table, num_subrs, memory ); 1376 if ( error ) 1377 goto Fail; 1378 } 1379 1380 /* the format is simple: */ 1381 /* */ 1382 /* `index' + binary data */ 1383 /* */ 1384 for (;;) 1385 { 1386 FT_Long idx, size; 1387 FT_Byte* base; 1388 1389 1390 /* If the next token isn't `dup' we are done. */ 1391 if ( parser->root.cursor + 4 < parser->root.limit && 1392 ft_strncmp( (char*)parser->root.cursor, "dup", 3 ) != 0 ) 1393 break; 1394 1395 T1_Skip_PS_Token( parser ); /* `dup' */ 1396 1397 idx = T1_ToInt( parser ); 1398 1399 if ( !read_binary_data( parser, &size, &base ) ) 1400 return; 1401 1402 /* The binary string is followed by one token, e.g. `NP' */ 1403 /* (bound to `noaccess put') or by two separate tokens: */ 1404 /* `noaccess' & `put'. We position the parser right */ 1405 /* before the next `dup', if any. */ 1406 T1_Skip_PS_Token( parser ); /* `NP' or `|' or `noaccess' */ 1407 if ( parser->root.error ) 1408 return; 1409 T1_Skip_Spaces ( parser ); 1410 1411 if ( parser->root.cursor + 4 < parser->root.limit && 1412 ft_strncmp( (char*)parser->root.cursor, "put", 3 ) == 0 ) 1413 { 1414 T1_Skip_PS_Token( parser ); /* skip `put' */ 1415 T1_Skip_Spaces ( parser ); 1416 } 1417 1418 /* with synthetic fonts it is possible we get here twice */ 1419 if ( loader->num_subrs ) 1420 continue; 1421 1422 /* some fonts use a value of -1 for lenIV to indicate that */ 1423 /* the charstrings are unencoded */ 1424 /* */ 1425 /* thanks to Tom Kacvinsky for pointing this out */ 1426 /* */ 1427 if ( face->type1.private_dict.lenIV >= 0 ) 1428 { 1429 FT_Byte* temp; 1430 1431 1432 /* some fonts define empty subr records -- this is not totally */ 1433 /* compliant to the specification (which says they should at */ 1434 /* least contain a `return'), but we support them anyway */ 1435 if ( size < face->type1.private_dict.lenIV ) 1436 { 1437 error = T1_Err_Invalid_File_Format; 1438 goto Fail; 1439 } 1440 1441 /* t1_decrypt() shouldn't write to base -- make temporary copy */ 1442 if ( FT_ALLOC( temp, size ) ) 1443 goto Fail; 1444 FT_MEM_COPY( temp, base, size ); 1445 psaux->t1_decrypt( temp, size, 4330 ); 1446 size -= face->type1.private_dict.lenIV; 1447 error = T1_Add_Table( table, (FT_Int)idx, 1448 temp + face->type1.private_dict.lenIV, size ); 1449 FT_FREE( temp ); 1450 } 1451 else 1452 error = T1_Add_Table( table, (FT_Int)idx, base, size ); 1453 if ( error ) 1454 goto Fail; 1455 } 1456 1457 if ( !loader->num_subrs ) 1458 loader->num_subrs = num_subrs; 1459 1460 return; 1461 1462 Fail: 1463 parser->root.error = error; 1464 } 1465 1466 1467#define TABLE_EXTEND 5 1468 1469 1470 static void 1471 parse_charstrings( T1_Face face, 1472 T1_Loader loader ) 1473 { 1474 T1_Parser parser = &loader->parser; 1475 PS_Table code_table = &loader->charstrings; 1476 PS_Table name_table = &loader->glyph_names; 1477 PS_Table swap_table = &loader->swap_table; 1478 FT_Memory memory = parser->root.memory; 1479 FT_Error error; 1480 1481 PSAux_Service psaux = (PSAux_Service)face->psaux; 1482 1483 FT_Byte* cur; 1484 FT_Byte* limit = parser->root.limit; 1485 FT_Int n, num_glyphs; 1486 FT_UInt notdef_index = 0; 1487 FT_Byte notdef_found = 0; 1488 1489 1490 num_glyphs = (FT_Int)T1_ToInt( parser ); 1491 /* some fonts like Optima-Oblique not only define the /CharStrings */ 1492 /* array but access it also */ 1493 if ( num_glyphs == 0 || parser->root.error ) 1494 return; 1495 1496 /* initialize tables, leaving space for addition of .notdef, */ 1497 /* if necessary, and a few other glyphs to handle buggy */ 1498 /* fonts which have more glyphs than specified. */ 1499 1500 /* for some non-standard fonts like `Optima' which provides */ 1501 /* different outlines depending on the resolution it is */ 1502 /* possible to get here twice */ 1503 if ( !loader->num_glyphs ) 1504 { 1505 error = psaux->ps_table_funcs->init( 1506 code_table, num_glyphs + 1 + TABLE_EXTEND, memory ); 1507 if ( error ) 1508 goto Fail; 1509 1510 error = psaux->ps_table_funcs->init( 1511 name_table, num_glyphs + 1 + TABLE_EXTEND, memory ); 1512 if ( error ) 1513 goto Fail; 1514 1515 /* Initialize table for swapping index notdef_index and */ 1516 /* index 0 names and codes (if necessary). */ 1517 1518 error = psaux->ps_table_funcs->init( swap_table, 4, memory ); 1519 if ( error ) 1520 goto Fail; 1521 } 1522 1523 n = 0; 1524 1525 for (;;) 1526 { 1527 FT_Long size; 1528 FT_Byte* base; 1529 1530 1531 /* the format is simple: */ 1532 /* `/glyphname' + binary data */ 1533 1534 T1_Skip_Spaces( parser ); 1535 1536 cur = parser->root.cursor; 1537 if ( cur >= limit ) 1538 break; 1539 1540 /* we stop when we find a `def' or `end' keyword */ 1541 if ( cur + 3 < limit && IS_PS_DELIM( cur[3] ) ) 1542 { 1543 if ( cur[0] == 'd' && 1544 cur[1] == 'e' && 1545 cur[2] == 'f' ) 1546 { 1547 /* There are fonts which have this: */ 1548 /* */ 1549 /* /CharStrings 118 dict def */ 1550 /* Private begin */ 1551 /* CharStrings begin */ 1552 /* ... */ 1553 /* */ 1554 /* To catch this we ignore `def' if */ 1555 /* no charstring has actually been */ 1556 /* seen. */ 1557 if ( n ) 1558 break; 1559 } 1560 1561 if ( cur[0] == 'e' && 1562 cur[1] == 'n' && 1563 cur[2] == 'd' ) 1564 break; 1565 } 1566 1567 T1_Skip_PS_Token( parser ); 1568 if ( parser->root.error ) 1569 return; 1570 1571 if ( *cur == '/' ) 1572 { 1573 FT_PtrDist len; 1574 1575 1576 if ( cur + 1 >= limit ) 1577 { 1578 error = T1_Err_Invalid_File_Format; 1579 goto Fail; 1580 } 1581 1582 cur++; /* skip `/' */ 1583 len = parser->root.cursor - cur; 1584 1585 if ( !read_binary_data( parser, &size, &base ) ) 1586 return; 1587 1588 /* for some non-standard fonts like `Optima' which provides */ 1589 /* different outlines depending on the resolution it is */ 1590 /* possible to get here twice */ 1591 if ( loader->num_glyphs ) 1592 continue; 1593 1594 error = T1_Add_Table( name_table, n, cur, len + 1 ); 1595 if ( error ) 1596 goto Fail; 1597 1598 /* add a trailing zero to the name table */ 1599 name_table->elements[n][len] = '\0'; 1600 1601 /* record index of /.notdef */ 1602 if ( *cur == '.' && 1603 ft_strcmp( ".notdef", 1604 (const char*)(name_table->elements[n]) ) == 0 ) 1605 { 1606 notdef_index = n; 1607 notdef_found = 1; 1608 } 1609…
Large files files are truncated, but you can click here to view the full file