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