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