1 /***************************************************************************/ 2 /* */ 3 /* psobjs.c */ 4 /* */ 5 /* Auxiliary functions for PostScript fonts (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 #include <ft2build.h> 20 #include FT_INTERNAL_POSTSCRIPT_AUX_H 21 #include FT_INTERNAL_DEBUG_H 22 #include FT_INTERNAL_CALC_H 23 24 #include "psobjs.h" 25 #include "psconv.h" 26 27 #include "psauxerr.h" 28 29 30 /*************************************************************************/ 31 /* */ 32 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 33 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 34 /* messages during execution. */ 35 /* */ 36 #undef FT_COMPONENT 37 #define FT_COMPONENT trace_psobjs 38 39 40 /*************************************************************************/ 41 /*************************************************************************/ 42 /***** *****/ 43 /***** PS_TABLE *****/ 44 /***** *****/ 45 /*************************************************************************/ 46 /*************************************************************************/ 47 48 /*************************************************************************/ 49 /* */ 50 /* <Function> */ 51 /* ps_table_new */ 52 /* */ 53 /* <Description> */ 54 /* Initializes a PS_Table. */ 55 /* */ 56 /* <InOut> */ 57 /* table :: The address of the target table. */ 58 /* */ 59 /* <Input> */ 60 /* count :: The table size = the maximum number of elements. */ 61 /* */ 62 /* memory :: The memory object to use for all subsequent */ 63 /* reallocations. */ 64 /* */ 65 /* <Return> */ 66 /* FreeType error code. 0 means success. */ 67 /* */ 68 FT_LOCAL_DEF( FT_Error ) ps_table_new(PS_Table table,FT_Int count,FT_Memory memory)69 ps_table_new( PS_Table table, 70 FT_Int count, 71 FT_Memory memory ) 72 { 73 FT_Error error; 74 75 76 table->memory = memory; 77 if ( FT_NEW_ARRAY( table->elements, count ) || 78 FT_NEW_ARRAY( table->lengths, count ) ) 79 goto Exit; 80 81 table->max_elems = count; 82 table->init = 0xDEADBEEFUL; 83 table->num_elems = 0; 84 table->block = NULL; 85 table->capacity = 0; 86 table->cursor = 0; 87 88 *(PS_Table_FuncsRec*)&table->funcs = ps_table_funcs; 89 90 Exit: 91 if ( error ) 92 FT_FREE( table->elements ); 93 94 return error; 95 } 96 97 98 static void shift_elements(PS_Table table,FT_Byte * old_base)99 shift_elements( PS_Table table, 100 FT_Byte* old_base ) 101 { 102 FT_PtrDist delta = table->block - old_base; 103 FT_Byte** offset = table->elements; 104 FT_Byte** limit = offset + table->max_elems; 105 106 107 for ( ; offset < limit; offset++ ) 108 { 109 if ( offset[0] ) 110 offset[0] += delta; 111 } 112 } 113 114 115 static FT_Error reallocate_t1_table(PS_Table table,FT_Offset new_size)116 reallocate_t1_table( PS_Table table, 117 FT_Offset new_size ) 118 { 119 FT_Memory memory = table->memory; 120 FT_Byte* old_base = table->block; 121 FT_Error error; 122 123 124 /* allocate new base block */ 125 if ( FT_ALLOC( table->block, new_size ) ) 126 { 127 table->block = old_base; 128 return error; 129 } 130 131 /* copy elements and shift offsets */ 132 if ( old_base ) 133 { 134 FT_MEM_COPY( table->block, old_base, table->capacity ); 135 shift_elements( table, old_base ); 136 FT_FREE( old_base ); 137 } 138 139 table->capacity = new_size; 140 141 return FT_Err_Ok; 142 } 143 144 145 /*************************************************************************/ 146 /* */ 147 /* <Function> */ 148 /* ps_table_add */ 149 /* */ 150 /* <Description> */ 151 /* Adds an object to a PS_Table, possibly growing its memory block. */ 152 /* */ 153 /* <InOut> */ 154 /* table :: The target table. */ 155 /* */ 156 /* <Input> */ 157 /* idx :: The index of the object in the table. */ 158 /* */ 159 /* object :: The address of the object to copy in memory. */ 160 /* */ 161 /* length :: The length in bytes of the source object. */ 162 /* */ 163 /* <Return> */ 164 /* FreeType error code. 0 means success. An error is returned if a */ 165 /* reallocation fails. */ 166 /* */ 167 FT_LOCAL_DEF( FT_Error ) ps_table_add(PS_Table table,FT_Int idx,void * object,FT_UInt length)168 ps_table_add( PS_Table table, 169 FT_Int idx, 170 void* object, 171 FT_UInt length ) 172 { 173 if ( idx < 0 || idx >= table->max_elems ) 174 { 175 FT_ERROR(( "ps_table_add: invalid index\n" )); 176 return FT_THROW( Invalid_Argument ); 177 } 178 179 /* grow the base block if needed */ 180 if ( table->cursor + length > table->capacity ) 181 { 182 FT_Error error; 183 FT_Offset new_size = table->capacity; 184 FT_PtrDist in_offset; 185 186 187 in_offset = (FT_Byte*)object - table->block; 188 if ( in_offset < 0 || (FT_Offset)in_offset >= table->capacity ) 189 in_offset = -1; 190 191 while ( new_size < table->cursor + length ) 192 { 193 /* increase size by 25% and round up to the nearest multiple 194 of 1024 */ 195 new_size += ( new_size >> 2 ) + 1; 196 new_size = FT_PAD_CEIL( new_size, 1024 ); 197 } 198 199 error = reallocate_t1_table( table, new_size ); 200 if ( error ) 201 return error; 202 203 if ( in_offset >= 0 ) 204 object = table->block + in_offset; 205 } 206 207 /* add the object to the base block and adjust offset */ 208 table->elements[idx] = table->block + table->cursor; 209 table->lengths [idx] = length; 210 FT_MEM_COPY( table->block + table->cursor, object, length ); 211 212 table->cursor += length; 213 return FT_Err_Ok; 214 } 215 216 217 /*************************************************************************/ 218 /* */ 219 /* <Function> */ 220 /* ps_table_done */ 221 /* */ 222 /* <Description> */ 223 /* Finalizes a PS_TableRec (i.e., reallocate it to its current */ 224 /* cursor). */ 225 /* */ 226 /* <InOut> */ 227 /* table :: The target table. */ 228 /* */ 229 /* <Note> */ 230 /* This function does NOT release the heap's memory block. It is up */ 231 /* to the caller to clean it, or reference it in its own structures. */ 232 /* */ 233 FT_LOCAL_DEF( void ) ps_table_done(PS_Table table)234 ps_table_done( PS_Table table ) 235 { 236 FT_Memory memory = table->memory; 237 FT_Error error; 238 FT_Byte* old_base = table->block; 239 240 241 /* should never fail, because rec.cursor <= rec.size */ 242 if ( !old_base ) 243 return; 244 245 if ( FT_ALLOC( table->block, table->cursor ) ) 246 return; 247 FT_MEM_COPY( table->block, old_base, table->cursor ); 248 shift_elements( table, old_base ); 249 250 table->capacity = table->cursor; 251 FT_FREE( old_base ); 252 253 FT_UNUSED( error ); 254 } 255 256 257 FT_LOCAL_DEF( void ) ps_table_release(PS_Table table)258 ps_table_release( PS_Table table ) 259 { 260 FT_Memory memory = table->memory; 261 262 263 if ( (FT_ULong)table->init == 0xDEADBEEFUL ) 264 { 265 FT_FREE( table->block ); 266 FT_FREE( table->elements ); 267 FT_FREE( table->lengths ); 268 table->init = 0; 269 } 270 } 271 272 273 /*************************************************************************/ 274 /*************************************************************************/ 275 /***** *****/ 276 /***** T1 PARSER *****/ 277 /***** *****/ 278 /*************************************************************************/ 279 /*************************************************************************/ 280 281 282 /* first character must be already part of the comment */ 283 284 static void skip_comment(FT_Byte ** acur,FT_Byte * limit)285 skip_comment( FT_Byte* *acur, 286 FT_Byte* limit ) 287 { 288 FT_Byte* cur = *acur; 289 290 291 while ( cur < limit ) 292 { 293 if ( IS_PS_NEWLINE( *cur ) ) 294 break; 295 cur++; 296 } 297 298 *acur = cur; 299 } 300 301 302 static void skip_spaces(FT_Byte ** acur,FT_Byte * limit)303 skip_spaces( FT_Byte* *acur, 304 FT_Byte* limit ) 305 { 306 FT_Byte* cur = *acur; 307 308 309 while ( cur < limit ) 310 { 311 if ( !IS_PS_SPACE( *cur ) ) 312 { 313 if ( *cur == '%' ) 314 /* According to the PLRM, a comment is equal to a space. */ 315 skip_comment( &cur, limit ); 316 else 317 break; 318 } 319 cur++; 320 } 321 322 *acur = cur; 323 } 324 325 326 #define IS_OCTAL_DIGIT( c ) ( '0' <= (c) && (c) <= '7' ) 327 328 329 /* first character must be `('; */ 330 /* *acur is positioned at the character after the closing `)' */ 331 332 static FT_Error skip_literal_string(FT_Byte ** acur,FT_Byte * limit)333 skip_literal_string( FT_Byte* *acur, 334 FT_Byte* limit ) 335 { 336 FT_Byte* cur = *acur; 337 FT_Int embed = 0; 338 FT_Error error = FT_ERR( Invalid_File_Format ); 339 unsigned int i; 340 341 342 while ( cur < limit ) 343 { 344 FT_Byte c = *cur; 345 346 347 ++cur; 348 349 if ( c == '\\' ) 350 { 351 /* Red Book 3rd ed., section `Literal Text Strings', p. 29: */ 352 /* A backslash can introduce three different types */ 353 /* of escape sequences: */ 354 /* - a special escaped char like \r, \n, etc. */ 355 /* - a one-, two-, or three-digit octal number */ 356 /* - none of the above in which case the backslash is ignored */ 357 358 if ( cur == limit ) 359 /* error (or to be ignored?) */ 360 break; 361 362 switch ( *cur ) 363 { 364 /* skip `special' escape */ 365 case 'n': 366 case 'r': 367 case 't': 368 case 'b': 369 case 'f': 370 case '\\': 371 case '(': 372 case ')': 373 ++cur; 374 break; 375 376 default: 377 /* skip octal escape or ignore backslash */ 378 for ( i = 0; i < 3 && cur < limit; ++i ) 379 { 380 if ( !IS_OCTAL_DIGIT( *cur ) ) 381 break; 382 383 ++cur; 384 } 385 } 386 } 387 else if ( c == '(' ) 388 embed++; 389 else if ( c == ')' ) 390 { 391 embed--; 392 if ( embed == 0 ) 393 { 394 error = FT_Err_Ok; 395 break; 396 } 397 } 398 } 399 400 *acur = cur; 401 402 return error; 403 } 404 405 406 /* first character must be `<' */ 407 408 static FT_Error skip_string(FT_Byte ** acur,FT_Byte * limit)409 skip_string( FT_Byte* *acur, 410 FT_Byte* limit ) 411 { 412 FT_Byte* cur = *acur; 413 FT_Error err = FT_Err_Ok; 414 415 416 while ( ++cur < limit ) 417 { 418 /* All whitespace characters are ignored. */ 419 skip_spaces( &cur, limit ); 420 if ( cur >= limit ) 421 break; 422 423 if ( !IS_PS_XDIGIT( *cur ) ) 424 break; 425 } 426 427 if ( cur < limit && *cur != '>' ) 428 { 429 FT_ERROR(( "skip_string: missing closing delimiter `>'\n" )); 430 err = FT_THROW( Invalid_File_Format ); 431 } 432 else 433 cur++; 434 435 *acur = cur; 436 return err; 437 } 438 439 440 /* first character must be the opening brace that */ 441 /* starts the procedure */ 442 443 /* NB: [ and ] need not match: */ 444 /* `/foo {[} def' is a valid PostScript fragment, */ 445 /* even within a Type1 font */ 446 447 static FT_Error skip_procedure(FT_Byte ** acur,FT_Byte * limit)448 skip_procedure( FT_Byte* *acur, 449 FT_Byte* limit ) 450 { 451 FT_Byte* cur; 452 FT_Int embed = 0; 453 FT_Error error = FT_Err_Ok; 454 455 456 FT_ASSERT( **acur == '{' ); 457 458 for ( cur = *acur; cur < limit && error == FT_Err_Ok; ++cur ) 459 { 460 switch ( *cur ) 461 { 462 case '{': 463 ++embed; 464 break; 465 466 case '}': 467 --embed; 468 if ( embed == 0 ) 469 { 470 ++cur; 471 goto end; 472 } 473 break; 474 475 case '(': 476 error = skip_literal_string( &cur, limit ); 477 break; 478 479 case '<': 480 error = skip_string( &cur, limit ); 481 break; 482 483 case '%': 484 skip_comment( &cur, limit ); 485 break; 486 } 487 } 488 489 end: 490 if ( embed != 0 ) 491 error = FT_THROW( Invalid_File_Format ); 492 493 *acur = cur; 494 495 return error; 496 } 497 498 499 /***********************************************************************/ 500 /* */ 501 /* All exported parsing routines handle leading whitespace and stop at */ 502 /* the first character which isn't part of the just handled token. */ 503 /* */ 504 /***********************************************************************/ 505 506 507 FT_LOCAL_DEF( void ) ps_parser_skip_PS_token(PS_Parser parser)508 ps_parser_skip_PS_token( PS_Parser parser ) 509 { 510 /* Note: PostScript allows any non-delimiting, non-whitespace */ 511 /* character in a name (PS Ref Manual, 3rd ed, p31). */ 512 /* PostScript delimiters are (, ), <, >, [, ], {, }, /, and %. */ 513 514 FT_Byte* cur = parser->cursor; 515 FT_Byte* limit = parser->limit; 516 FT_Error error = FT_Err_Ok; 517 518 519 skip_spaces( &cur, limit ); /* this also skips comments */ 520 if ( cur >= limit ) 521 goto Exit; 522 523 /* self-delimiting, single-character tokens */ 524 if ( *cur == '[' || *cur == ']' ) 525 { 526 cur++; 527 goto Exit; 528 } 529 530 /* skip balanced expressions (procedures and strings) */ 531 532 if ( *cur == '{' ) /* {...} */ 533 { 534 error = skip_procedure( &cur, limit ); 535 goto Exit; 536 } 537 538 if ( *cur == '(' ) /* (...) */ 539 { 540 error = skip_literal_string( &cur, limit ); 541 goto Exit; 542 } 543 544 if ( *cur == '<' ) /* <...> */ 545 { 546 if ( cur + 1 < limit && *(cur + 1) == '<' ) /* << */ 547 { 548 cur++; 549 cur++; 550 } 551 else 552 error = skip_string( &cur, limit ); 553 554 goto Exit; 555 } 556 557 if ( *cur == '>' ) 558 { 559 cur++; 560 if ( cur >= limit || *cur != '>' ) /* >> */ 561 { 562 FT_ERROR(( "ps_parser_skip_PS_token:" 563 " unexpected closing delimiter `>'\n" )); 564 error = FT_THROW( Invalid_File_Format ); 565 goto Exit; 566 } 567 cur++; 568 goto Exit; 569 } 570 571 if ( *cur == '/' ) 572 cur++; 573 574 /* anything else */ 575 while ( cur < limit ) 576 { 577 /* *cur might be invalid (e.g., ')' or '}'), but this */ 578 /* is handled by the test `cur == parser->cursor' below */ 579 if ( IS_PS_DELIM( *cur ) ) 580 break; 581 582 cur++; 583 } 584 585 Exit: 586 if ( cur < limit && cur == parser->cursor ) 587 { 588 FT_ERROR(( "ps_parser_skip_PS_token:" 589 " current token is `%c' which is self-delimiting\n" 590 " " 591 " but invalid at this point\n", 592 *cur )); 593 594 error = FT_THROW( Invalid_File_Format ); 595 } 596 597 parser->error = error; 598 parser->cursor = cur; 599 } 600 601 602 FT_LOCAL_DEF( void ) ps_parser_skip_spaces(PS_Parser parser)603 ps_parser_skip_spaces( PS_Parser parser ) 604 { 605 skip_spaces( &parser->cursor, parser->limit ); 606 } 607 608 609 /* `token' here means either something between balanced delimiters */ 610 /* or the next token; the delimiters are not removed. */ 611 612 FT_LOCAL_DEF( void ) ps_parser_to_token(PS_Parser parser,T1_Token token)613 ps_parser_to_token( PS_Parser parser, 614 T1_Token token ) 615 { 616 FT_Byte* cur; 617 FT_Byte* limit; 618 FT_Int embed; 619 620 621 token->type = T1_TOKEN_TYPE_NONE; 622 token->start = NULL; 623 token->limit = NULL; 624 625 /* first of all, skip leading whitespace */ 626 ps_parser_skip_spaces( parser ); 627 628 cur = parser->cursor; 629 limit = parser->limit; 630 631 if ( cur >= limit ) 632 return; 633 634 switch ( *cur ) 635 { 636 /************* check for literal string *****************/ 637 case '(': 638 token->type = T1_TOKEN_TYPE_STRING; 639 token->start = cur; 640 641 if ( skip_literal_string( &cur, limit ) == FT_Err_Ok ) 642 token->limit = cur; 643 break; 644 645 /************* check for programs/array *****************/ 646 case '{': 647 token->type = T1_TOKEN_TYPE_ARRAY; 648 token->start = cur; 649 650 if ( skip_procedure( &cur, limit ) == FT_Err_Ok ) 651 token->limit = cur; 652 break; 653 654 /************* check for table/array ********************/ 655 /* XXX: in theory we should also look for "<<" */ 656 /* since this is semantically equivalent to "["; */ 657 /* in practice it doesn't matter (?) */ 658 case '[': 659 token->type = T1_TOKEN_TYPE_ARRAY; 660 embed = 1; 661 token->start = cur++; 662 663 /* we need this to catch `[ ]' */ 664 parser->cursor = cur; 665 ps_parser_skip_spaces( parser ); 666 cur = parser->cursor; 667 668 while ( cur < limit && !parser->error ) 669 { 670 /* XXX: this is wrong because it does not */ 671 /* skip comments, procedures, and strings */ 672 if ( *cur == '[' ) 673 embed++; 674 else if ( *cur == ']' ) 675 { 676 embed--; 677 if ( embed <= 0 ) 678 { 679 token->limit = ++cur; 680 break; 681 } 682 } 683 684 parser->cursor = cur; 685 ps_parser_skip_PS_token( parser ); 686 /* we need this to catch `[XXX ]' */ 687 ps_parser_skip_spaces ( parser ); 688 cur = parser->cursor; 689 } 690 break; 691 692 /* ************ otherwise, it is any token **************/ 693 default: 694 token->start = cur; 695 token->type = ( *cur == '/' ? T1_TOKEN_TYPE_KEY : T1_TOKEN_TYPE_ANY ); 696 ps_parser_skip_PS_token( parser ); 697 cur = parser->cursor; 698 if ( !parser->error ) 699 token->limit = cur; 700 } 701 702 if ( !token->limit ) 703 { 704 token->start = NULL; 705 token->type = T1_TOKEN_TYPE_NONE; 706 } 707 708 parser->cursor = cur; 709 } 710 711 712 /* NB: `tokens' can be NULL if we only want to count */ 713 /* the number of array elements */ 714 715 FT_LOCAL_DEF( void ) ps_parser_to_token_array(PS_Parser parser,T1_Token tokens,FT_UInt max_tokens,FT_Int * pnum_tokens)716 ps_parser_to_token_array( PS_Parser parser, 717 T1_Token tokens, 718 FT_UInt max_tokens, 719 FT_Int* pnum_tokens ) 720 { 721 T1_TokenRec master; 722 723 724 *pnum_tokens = -1; 725 726 /* this also handles leading whitespace */ 727 ps_parser_to_token( parser, &master ); 728 729 if ( master.type == T1_TOKEN_TYPE_ARRAY ) 730 { 731 FT_Byte* old_cursor = parser->cursor; 732 FT_Byte* old_limit = parser->limit; 733 T1_Token cur = tokens; 734 T1_Token limit = cur + max_tokens; 735 736 737 /* don't include outermost delimiters */ 738 parser->cursor = master.start + 1; 739 parser->limit = master.limit - 1; 740 741 while ( parser->cursor < parser->limit ) 742 { 743 T1_TokenRec token; 744 745 746 ps_parser_to_token( parser, &token ); 747 if ( !token.type ) 748 break; 749 750 if ( tokens != NULL && cur < limit ) 751 *cur = token; 752 753 cur++; 754 } 755 756 *pnum_tokens = (FT_Int)( cur - tokens ); 757 758 parser->cursor = old_cursor; 759 parser->limit = old_limit; 760 } 761 } 762 763 764 /* first character must be a delimiter or a part of a number */ 765 /* NB: `coords' can be NULL if we just want to skip the */ 766 /* array; in this case we ignore `max_coords' */ 767 768 static FT_Int ps_tocoordarray(FT_Byte ** acur,FT_Byte * limit,FT_Int max_coords,FT_Short * coords)769 ps_tocoordarray( FT_Byte* *acur, 770 FT_Byte* limit, 771 FT_Int max_coords, 772 FT_Short* coords ) 773 { 774 FT_Byte* cur = *acur; 775 FT_Int count = 0; 776 FT_Byte c, ender; 777 778 779 if ( cur >= limit ) 780 goto Exit; 781 782 /* check for the beginning of an array; otherwise, only one number */ 783 /* will be read */ 784 c = *cur; 785 ender = 0; 786 787 if ( c == '[' ) 788 ender = ']'; 789 else if ( c == '{' ) 790 ender = '}'; 791 792 if ( ender ) 793 cur++; 794 795 /* now, read the coordinates */ 796 while ( cur < limit ) 797 { 798 FT_Short dummy; 799 FT_Byte* old_cur; 800 801 802 /* skip whitespace in front of data */ 803 skip_spaces( &cur, limit ); 804 if ( cur >= limit ) 805 goto Exit; 806 807 if ( *cur == ender ) 808 { 809 cur++; 810 break; 811 } 812 813 old_cur = cur; 814 815 if ( coords != NULL && count >= max_coords ) 816 break; 817 818 /* call PS_Conv_ToFixed() even if coords == NULL */ 819 /* to properly parse number at `cur' */ 820 *( coords != NULL ? &coords[count] : &dummy ) = 821 (FT_Short)( PS_Conv_ToFixed( &cur, limit, 0 ) >> 16 ); 822 823 if ( old_cur == cur ) 824 { 825 count = -1; 826 goto Exit; 827 } 828 else 829 count++; 830 831 if ( !ender ) 832 break; 833 } 834 835 Exit: 836 *acur = cur; 837 return count; 838 } 839 840 841 /* first character must be a delimiter or a part of a number */ 842 /* NB: `values' can be NULL if we just want to skip the */ 843 /* array; in this case we ignore `max_values' */ 844 /* */ 845 /* return number of successfully parsed values */ 846 847 static FT_Int ps_tofixedarray(FT_Byte ** acur,FT_Byte * limit,FT_Int max_values,FT_Fixed * values,FT_Int power_ten)848 ps_tofixedarray( FT_Byte* *acur, 849 FT_Byte* limit, 850 FT_Int max_values, 851 FT_Fixed* values, 852 FT_Int power_ten ) 853 { 854 FT_Byte* cur = *acur; 855 FT_Int count = 0; 856 FT_Byte c, ender; 857 858 859 if ( cur >= limit ) 860 goto Exit; 861 862 /* Check for the beginning of an array. Otherwise, only one number */ 863 /* will be read. */ 864 c = *cur; 865 ender = 0; 866 867 if ( c == '[' ) 868 ender = ']'; 869 else if ( c == '{' ) 870 ender = '}'; 871 872 if ( ender ) 873 cur++; 874 875 /* now, read the values */ 876 while ( cur < limit ) 877 { 878 FT_Fixed dummy; 879 FT_Byte* old_cur; 880 881 882 /* skip whitespace in front of data */ 883 skip_spaces( &cur, limit ); 884 if ( cur >= limit ) 885 goto Exit; 886 887 if ( *cur == ender ) 888 { 889 cur++; 890 break; 891 } 892 893 old_cur = cur; 894 895 if ( values != NULL && count >= max_values ) 896 break; 897 898 /* call PS_Conv_ToFixed() even if coords == NULL */ 899 /* to properly parse number at `cur' */ 900 *( values != NULL ? &values[count] : &dummy ) = 901 PS_Conv_ToFixed( &cur, limit, power_ten ); 902 903 if ( old_cur == cur ) 904 { 905 count = -1; 906 goto Exit; 907 } 908 else 909 count++; 910 911 if ( !ender ) 912 break; 913 } 914 915 Exit: 916 *acur = cur; 917 return count; 918 } 919 920 921 #if 0 922 923 static FT_String* 924 ps_tostring( FT_Byte** cursor, 925 FT_Byte* limit, 926 FT_Memory memory ) 927 { 928 FT_Byte* cur = *cursor; 929 FT_UInt len = 0; 930 FT_Int count; 931 FT_String* result; 932 FT_Error error; 933 934 935 /* XXX: some stupid fonts have a `Notice' or `Copyright' string */ 936 /* that simply doesn't begin with an opening parenthesis, even */ 937 /* though they have a closing one! E.g. "amuncial.pfb" */ 938 /* */ 939 /* We must deal with these ill-fated cases there. Note that */ 940 /* these fonts didn't work with the old Type 1 driver as the */ 941 /* notice/copyright was not recognized as a valid string token */ 942 /* and made the old token parser commit errors. */ 943 944 while ( cur < limit && ( *cur == ' ' || *cur == '\t' ) ) 945 cur++; 946 if ( cur + 1 >= limit ) 947 return 0; 948 949 if ( *cur == '(' ) 950 cur++; /* skip the opening parenthesis, if there is one */ 951 952 *cursor = cur; 953 count = 0; 954 955 /* then, count its length */ 956 for ( ; cur < limit; cur++ ) 957 { 958 if ( *cur == '(' ) 959 count++; 960 961 else if ( *cur == ')' ) 962 { 963 count--; 964 if ( count < 0 ) 965 break; 966 } 967 } 968 969 len = (FT_UInt)( cur - *cursor ); 970 if ( cur >= limit || FT_ALLOC( result, len + 1 ) ) 971 return 0; 972 973 /* now copy the string */ 974 FT_MEM_COPY( result, *cursor, len ); 975 result[len] = '\0'; 976 *cursor = cur; 977 return result; 978 } 979 980 #endif /* 0 */ 981 982 983 static int ps_tobool(FT_Byte ** acur,FT_Byte * limit)984 ps_tobool( FT_Byte* *acur, 985 FT_Byte* limit ) 986 { 987 FT_Byte* cur = *acur; 988 FT_Bool result = 0; 989 990 991 /* return 1 if we find `true', 0 otherwise */ 992 if ( cur + 3 < limit && 993 cur[0] == 't' && 994 cur[1] == 'r' && 995 cur[2] == 'u' && 996 cur[3] == 'e' ) 997 { 998 result = 1; 999 cur += 5; 1000 } 1001 else if ( cur + 4 < limit && 1002 cur[0] == 'f' && 1003 cur[1] == 'a' && 1004 cur[2] == 'l' && 1005 cur[3] == 's' && 1006 cur[4] == 'e' ) 1007 { 1008 result = 0; 1009 cur += 6; 1010 } 1011 1012 *acur = cur; 1013 return result; 1014 } 1015 1016 1017 /* load a simple field (i.e. non-table) into the current list of objects */ 1018 1019 FT_LOCAL_DEF( FT_Error ) ps_parser_load_field(PS_Parser parser,const T1_Field field,void ** objects,FT_UInt max_objects,FT_ULong * pflags)1020 ps_parser_load_field( PS_Parser parser, 1021 const T1_Field field, 1022 void** objects, 1023 FT_UInt max_objects, 1024 FT_ULong* pflags ) 1025 { 1026 T1_TokenRec token; 1027 FT_Byte* cur; 1028 FT_Byte* limit; 1029 FT_UInt count; 1030 FT_UInt idx; 1031 FT_Error error; 1032 T1_FieldType type; 1033 1034 1035 /* this also skips leading whitespace */ 1036 ps_parser_to_token( parser, &token ); 1037 if ( !token.type ) 1038 goto Fail; 1039 1040 count = 1; 1041 idx = 0; 1042 cur = token.start; 1043 limit = token.limit; 1044 1045 type = field->type; 1046 1047 /* we must detect arrays in /FontBBox */ 1048 if ( type == T1_FIELD_TYPE_BBOX ) 1049 { 1050 T1_TokenRec token2; 1051 FT_Byte* old_cur = parser->cursor; 1052 FT_Byte* old_limit = parser->limit; 1053 1054 1055 /* don't include delimiters */ 1056 parser->cursor = token.start + 1; 1057 parser->limit = token.limit - 1; 1058 1059 ps_parser_to_token( parser, &token2 ); 1060 parser->cursor = old_cur; 1061 parser->limit = old_limit; 1062 1063 if ( token2.type == T1_TOKEN_TYPE_ARRAY ) 1064 { 1065 type = T1_FIELD_TYPE_MM_BBOX; 1066 goto FieldArray; 1067 } 1068 } 1069 else if ( token.type == T1_TOKEN_TYPE_ARRAY ) 1070 { 1071 count = max_objects; 1072 1073 FieldArray: 1074 /* if this is an array and we have no blend, an error occurs */ 1075 if ( max_objects == 0 ) 1076 goto Fail; 1077 1078 idx = 1; 1079 1080 /* don't include delimiters */ 1081 cur++; 1082 limit--; 1083 } 1084 1085 for ( ; count > 0; count--, idx++ ) 1086 { 1087 FT_Byte* q = (FT_Byte*)objects[idx] + field->offset; 1088 FT_Long val; 1089 FT_String* string; 1090 1091 1092 skip_spaces( &cur, limit ); 1093 1094 switch ( type ) 1095 { 1096 case T1_FIELD_TYPE_BOOL: 1097 val = ps_tobool( &cur, limit ); 1098 goto Store_Integer; 1099 1100 case T1_FIELD_TYPE_FIXED: 1101 val = PS_Conv_ToFixed( &cur, limit, 0 ); 1102 goto Store_Integer; 1103 1104 case T1_FIELD_TYPE_FIXED_1000: 1105 val = PS_Conv_ToFixed( &cur, limit, 3 ); 1106 goto Store_Integer; 1107 1108 case T1_FIELD_TYPE_INTEGER: 1109 val = PS_Conv_ToInt( &cur, limit ); 1110 /* fall through */ 1111 1112 Store_Integer: 1113 switch ( field->size ) 1114 { 1115 case (8 / FT_CHAR_BIT): 1116 *(FT_Byte*)q = (FT_Byte)val; 1117 break; 1118 1119 case (16 / FT_CHAR_BIT): 1120 *(FT_UShort*)q = (FT_UShort)val; 1121 break; 1122 1123 case (32 / FT_CHAR_BIT): 1124 *(FT_UInt32*)q = (FT_UInt32)val; 1125 break; 1126 1127 default: /* for 64-bit systems */ 1128 *(FT_Long*)q = val; 1129 } 1130 break; 1131 1132 case T1_FIELD_TYPE_STRING: 1133 case T1_FIELD_TYPE_KEY: 1134 { 1135 FT_Memory memory = parser->memory; 1136 FT_UInt len = (FT_UInt)( limit - cur ); 1137 1138 1139 if ( cur >= limit ) 1140 break; 1141 1142 /* we allow both a string or a name */ 1143 /* for cases like /FontName (foo) def */ 1144 if ( token.type == T1_TOKEN_TYPE_KEY ) 1145 { 1146 /* don't include leading `/' */ 1147 len--; 1148 cur++; 1149 } 1150 else if ( token.type == T1_TOKEN_TYPE_STRING ) 1151 { 1152 /* don't include delimiting parentheses */ 1153 /* XXX we don't handle <<...>> here */ 1154 /* XXX should we convert octal escapes? */ 1155 /* if so, what encoding should we use? */ 1156 cur++; 1157 len -= 2; 1158 } 1159 else 1160 { 1161 FT_ERROR(( "ps_parser_load_field:" 1162 " expected a name or string\n" 1163 " " 1164 " but found token of type %d instead\n", 1165 token.type )); 1166 error = FT_THROW( Invalid_File_Format ); 1167 goto Exit; 1168 } 1169 1170 /* for this to work (FT_String**)q must have been */ 1171 /* initialized to NULL */ 1172 if ( *(FT_String**)q != NULL ) 1173 { 1174 FT_TRACE0(( "ps_parser_load_field: overwriting field %s\n", 1175 field->ident )); 1176 FT_FREE( *(FT_String**)q ); 1177 *(FT_String**)q = NULL; 1178 } 1179 1180 if ( FT_ALLOC( string, len + 1 ) ) 1181 goto Exit; 1182 1183 FT_MEM_COPY( string, cur, len ); 1184 string[len] = 0; 1185 1186 *(FT_String**)q = string; 1187 } 1188 break; 1189 1190 case T1_FIELD_TYPE_BBOX: 1191 { 1192 FT_Fixed temp[4]; 1193 FT_BBox* bbox = (FT_BBox*)q; 1194 FT_Int result; 1195 1196 1197 result = ps_tofixedarray( &cur, limit, 4, temp, 0 ); 1198 1199 if ( result < 4 ) 1200 { 1201 FT_ERROR(( "ps_parser_load_field:" 1202 " expected four integers in bounding box\n" )); 1203 error = FT_THROW( Invalid_File_Format ); 1204 goto Exit; 1205 } 1206 1207 bbox->xMin = FT_RoundFix( temp[0] ); 1208 bbox->yMin = FT_RoundFix( temp[1] ); 1209 bbox->xMax = FT_RoundFix( temp[2] ); 1210 bbox->yMax = FT_RoundFix( temp[3] ); 1211 } 1212 break; 1213 1214 case T1_FIELD_TYPE_MM_BBOX: 1215 { 1216 FT_Memory memory = parser->memory; 1217 FT_Fixed* temp; 1218 FT_Int result; 1219 FT_UInt i; 1220 1221 1222 if ( FT_NEW_ARRAY( temp, max_objects * 4 ) ) 1223 goto Exit; 1224 1225 for ( i = 0; i < 4; i++ ) 1226 { 1227 result = ps_tofixedarray( &cur, limit, (FT_Int)max_objects, 1228 temp + i * max_objects, 0 ); 1229 if ( result < 0 || (FT_UInt)result < max_objects ) 1230 { 1231 FT_ERROR(( "ps_parser_load_field:" 1232 " expected %d integers in the %s subarray\n" 1233 " " 1234 " of /FontBBox in the /Blend dictionary\n", 1235 max_objects, 1236 i == 0 ? "first" 1237 : ( i == 1 ? "second" 1238 : ( i == 2 ? "third" 1239 : "fourth" ) ) )); 1240 error = FT_THROW( Invalid_File_Format ); 1241 goto Exit; 1242 } 1243 1244 skip_spaces( &cur, limit ); 1245 } 1246 1247 for ( i = 0; i < max_objects; i++ ) 1248 { 1249 FT_BBox* bbox = (FT_BBox*)objects[i]; 1250 1251 1252 bbox->xMin = FT_RoundFix( temp[i ] ); 1253 bbox->yMin = FT_RoundFix( temp[i + max_objects] ); 1254 bbox->xMax = FT_RoundFix( temp[i + 2 * max_objects] ); 1255 bbox->yMax = FT_RoundFix( temp[i + 3 * max_objects] ); 1256 } 1257 1258 FT_FREE( temp ); 1259 } 1260 break; 1261 1262 default: 1263 /* an error occurred */ 1264 goto Fail; 1265 } 1266 } 1267 1268 #if 0 /* obsolete -- keep for reference */ 1269 if ( pflags ) 1270 *pflags |= 1L << field->flag_bit; 1271 #else 1272 FT_UNUSED( pflags ); 1273 #endif 1274 1275 error = FT_Err_Ok; 1276 1277 Exit: 1278 return error; 1279 1280 Fail: 1281 error = FT_THROW( Invalid_File_Format ); 1282 goto Exit; 1283 } 1284 1285 1286 #define T1_MAX_TABLE_ELEMENTS 32 1287 1288 1289 FT_LOCAL_DEF( FT_Error ) ps_parser_load_field_table(PS_Parser parser,const T1_Field field,void ** objects,FT_UInt max_objects,FT_ULong * pflags)1290 ps_parser_load_field_table( PS_Parser parser, 1291 const T1_Field field, 1292 void** objects, 1293 FT_UInt max_objects, 1294 FT_ULong* pflags ) 1295 { 1296 T1_TokenRec elements[T1_MAX_TABLE_ELEMENTS]; 1297 T1_Token token; 1298 FT_Int num_elements; 1299 FT_Error error = FT_Err_Ok; 1300 FT_Byte* old_cursor; 1301 FT_Byte* old_limit; 1302 T1_FieldRec fieldrec = *(T1_Field)field; 1303 1304 1305 fieldrec.type = T1_FIELD_TYPE_INTEGER; 1306 if ( field->type == T1_FIELD_TYPE_FIXED_ARRAY || 1307 field->type == T1_FIELD_TYPE_BBOX ) 1308 fieldrec.type = T1_FIELD_TYPE_FIXED; 1309 1310 ps_parser_to_token_array( parser, elements, 1311 T1_MAX_TABLE_ELEMENTS, &num_elements ); 1312 if ( num_elements < 0 ) 1313 { 1314 error = FT_ERR( Ignore ); 1315 goto Exit; 1316 } 1317 if ( (FT_UInt)num_elements > field->array_max ) 1318 num_elements = (FT_Int)field->array_max; 1319 1320 old_cursor = parser->cursor; 1321 old_limit = parser->limit; 1322 1323 /* we store the elements count if necessary; */ 1324 /* we further assume that `count_offset' can't be zero */ 1325 if ( field->type != T1_FIELD_TYPE_BBOX && field->count_offset != 0 ) 1326 *(FT_Byte*)( (FT_Byte*)objects[0] + field->count_offset ) = 1327 (FT_Byte)num_elements; 1328 1329 /* we now load each element, adjusting the field.offset on each one */ 1330 token = elements; 1331 for ( ; num_elements > 0; num_elements--, token++ ) 1332 { 1333 parser->cursor = token->start; 1334 parser->limit = token->limit; 1335 1336 error = ps_parser_load_field( parser, 1337 &fieldrec, 1338 objects, 1339 max_objects, 1340 0 ); 1341 if ( error ) 1342 break; 1343 1344 fieldrec.offset += fieldrec.size; 1345 } 1346 1347 #if 0 /* obsolete -- keep for reference */ 1348 if ( pflags ) 1349 *pflags |= 1L << field->flag_bit; 1350 #else 1351 FT_UNUSED( pflags ); 1352 #endif 1353 1354 parser->cursor = old_cursor; 1355 parser->limit = old_limit; 1356 1357 Exit: 1358 return error; 1359 } 1360 1361 1362 FT_LOCAL_DEF( FT_Long ) ps_parser_to_int(PS_Parser parser)1363 ps_parser_to_int( PS_Parser parser ) 1364 { 1365 ps_parser_skip_spaces( parser ); 1366 return PS_Conv_ToInt( &parser->cursor, parser->limit ); 1367 } 1368 1369 1370 /* first character must be `<' if `delimiters' is non-zero */ 1371 1372 FT_LOCAL_DEF( FT_Error ) ps_parser_to_bytes(PS_Parser parser,FT_Byte * bytes,FT_Offset max_bytes,FT_ULong * pnum_bytes,FT_Bool delimiters)1373 ps_parser_to_bytes( PS_Parser parser, 1374 FT_Byte* bytes, 1375 FT_Offset max_bytes, 1376 FT_ULong* pnum_bytes, 1377 FT_Bool delimiters ) 1378 { 1379 FT_Error error = FT_Err_Ok; 1380 FT_Byte* cur; 1381 1382 1383 ps_parser_skip_spaces( parser ); 1384 cur = parser->cursor; 1385 1386 if ( cur >= parser->limit ) 1387 goto Exit; 1388 1389 if ( delimiters ) 1390 { 1391 if ( *cur != '<' ) 1392 { 1393 FT_ERROR(( "ps_parser_to_bytes: Missing starting delimiter `<'\n" )); 1394 error = FT_THROW( Invalid_File_Format ); 1395 goto Exit; 1396 } 1397 1398 cur++; 1399 } 1400 1401 *pnum_bytes = PS_Conv_ASCIIHexDecode( &cur, 1402 parser->limit, 1403 bytes, 1404 max_bytes ); 1405 1406 if ( delimiters ) 1407 { 1408 if ( cur < parser->limit && *cur != '>' ) 1409 { 1410 FT_ERROR(( "ps_parser_to_bytes: Missing closing delimiter `>'\n" )); 1411 error = FT_THROW( Invalid_File_Format ); 1412 goto Exit; 1413 } 1414 1415 cur++; 1416 } 1417 1418 parser->cursor = cur; 1419 1420 Exit: 1421 return error; 1422 } 1423 1424 1425 FT_LOCAL_DEF( FT_Fixed ) ps_parser_to_fixed(PS_Parser parser,FT_Int power_ten)1426 ps_parser_to_fixed( PS_Parser parser, 1427 FT_Int power_ten ) 1428 { 1429 ps_parser_skip_spaces( parser ); 1430 return PS_Conv_ToFixed( &parser->cursor, parser->limit, power_ten ); 1431 } 1432 1433 1434 FT_LOCAL_DEF( FT_Int ) ps_parser_to_coord_array(PS_Parser parser,FT_Int max_coords,FT_Short * coords)1435 ps_parser_to_coord_array( PS_Parser parser, 1436 FT_Int max_coords, 1437 FT_Short* coords ) 1438 { 1439 ps_parser_skip_spaces( parser ); 1440 return ps_tocoordarray( &parser->cursor, parser->limit, 1441 max_coords, coords ); 1442 } 1443 1444 1445 FT_LOCAL_DEF( FT_Int ) ps_parser_to_fixed_array(PS_Parser parser,FT_Int max_values,FT_Fixed * values,FT_Int power_ten)1446 ps_parser_to_fixed_array( PS_Parser parser, 1447 FT_Int max_values, 1448 FT_Fixed* values, 1449 FT_Int power_ten ) 1450 { 1451 ps_parser_skip_spaces( parser ); 1452 return ps_tofixedarray( &parser->cursor, parser->limit, 1453 max_values, values, power_ten ); 1454 } 1455 1456 1457 #if 0 1458 1459 FT_LOCAL_DEF( FT_String* ) 1460 T1_ToString( PS_Parser parser ) 1461 { 1462 return ps_tostring( &parser->cursor, parser->limit, parser->memory ); 1463 } 1464 1465 1466 FT_LOCAL_DEF( FT_Bool ) 1467 T1_ToBool( PS_Parser parser ) 1468 { 1469 return ps_tobool( &parser->cursor, parser->limit ); 1470 } 1471 1472 #endif /* 0 */ 1473 1474 1475 FT_LOCAL_DEF( void ) ps_parser_init(PS_Parser parser,FT_Byte * base,FT_Byte * limit,FT_Memory memory)1476 ps_parser_init( PS_Parser parser, 1477 FT_Byte* base, 1478 FT_Byte* limit, 1479 FT_Memory memory ) 1480 { 1481 parser->error = FT_Err_Ok; 1482 parser->base = base; 1483 parser->limit = limit; 1484 parser->cursor = base; 1485 parser->memory = memory; 1486 parser->funcs = ps_parser_funcs; 1487 } 1488 1489 1490 FT_LOCAL_DEF( void ) ps_parser_done(PS_Parser parser)1491 ps_parser_done( PS_Parser parser ) 1492 { 1493 FT_UNUSED( parser ); 1494 } 1495 1496 1497 /*************************************************************************/ 1498 /*************************************************************************/ 1499 /***** *****/ 1500 /***** T1 BUILDER *****/ 1501 /***** *****/ 1502 /*************************************************************************/ 1503 /*************************************************************************/ 1504 1505 /*************************************************************************/ 1506 /* */ 1507 /* <Function> */ 1508 /* t1_builder_init */ 1509 /* */ 1510 /* <Description> */ 1511 /* Initializes a given glyph builder. */ 1512 /* */ 1513 /* <InOut> */ 1514 /* builder :: A pointer to the glyph builder to initialize. */ 1515 /* */ 1516 /* <Input> */ 1517 /* face :: The current face object. */ 1518 /* */ 1519 /* size :: The current size object. */ 1520 /* */ 1521 /* glyph :: The current glyph object. */ 1522 /* */ 1523 /* hinting :: Whether hinting should be applied. */ 1524 /* */ 1525 FT_LOCAL_DEF( void ) t1_builder_init(T1_Builder builder,FT_Face face,FT_Size size,FT_GlyphSlot glyph,FT_Bool hinting)1526 t1_builder_init( T1_Builder builder, 1527 FT_Face face, 1528 FT_Size size, 1529 FT_GlyphSlot glyph, 1530 FT_Bool hinting ) 1531 { 1532 builder->parse_state = T1_Parse_Start; 1533 builder->load_points = 1; 1534 1535 builder->face = face; 1536 builder->glyph = glyph; 1537 builder->memory = face->memory; 1538 1539 if ( glyph ) 1540 { 1541 FT_GlyphLoader loader = glyph->internal->loader; 1542 1543 1544 builder->loader = loader; 1545 builder->base = &loader->base.outline; 1546 builder->current = &loader->current.outline; 1547 FT_GlyphLoader_Rewind( loader ); 1548 1549 builder->hints_globals = size->internal; 1550 builder->hints_funcs = NULL; 1551 1552 if ( hinting ) 1553 builder->hints_funcs = glyph->internal->glyph_hints; 1554 } 1555 1556 builder->pos_x = 0; 1557 builder->pos_y = 0; 1558 1559 builder->left_bearing.x = 0; 1560 builder->left_bearing.y = 0; 1561 builder->advance.x = 0; 1562 builder->advance.y = 0; 1563 1564 builder->funcs = t1_builder_funcs; 1565 } 1566 1567 1568 /*************************************************************************/ 1569 /* */ 1570 /* <Function> */ 1571 /* t1_builder_done */ 1572 /* */ 1573 /* <Description> */ 1574 /* Finalizes a given glyph builder. Its contents can still be used */ 1575 /* after the call, but the function saves important information */ 1576 /* within the corresponding glyph slot. */ 1577 /* */ 1578 /* <Input> */ 1579 /* builder :: A pointer to the glyph builder to finalize. */ 1580 /* */ 1581 FT_LOCAL_DEF( void ) t1_builder_done(T1_Builder builder)1582 t1_builder_done( T1_Builder builder ) 1583 { 1584 FT_GlyphSlot glyph = builder->glyph; 1585 1586 1587 if ( glyph ) 1588 glyph->outline = *builder->base; 1589 } 1590 1591 1592 /* check that there is enough space for `count' more points */ 1593 FT_LOCAL_DEF( FT_Error ) t1_builder_check_points(T1_Builder builder,FT_Int count)1594 t1_builder_check_points( T1_Builder builder, 1595 FT_Int count ) 1596 { 1597 return FT_GLYPHLOADER_CHECK_POINTS( builder->loader, count, 0 ); 1598 } 1599 1600 1601 /* add a new point, do not check space */ 1602 FT_LOCAL_DEF( void ) t1_builder_add_point(T1_Builder builder,FT_Pos x,FT_Pos y,FT_Byte flag)1603 t1_builder_add_point( T1_Builder builder, 1604 FT_Pos x, 1605 FT_Pos y, 1606 FT_Byte flag ) 1607 { 1608 FT_Outline* outline = builder->current; 1609 1610 1611 if ( builder->load_points ) 1612 { 1613 FT_Vector* point = outline->points + outline->n_points; 1614 FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points; 1615 1616 1617 point->x = FIXED_TO_INT( x ); 1618 point->y = FIXED_TO_INT( y ); 1619 *control = (FT_Byte)( flag ? FT_CURVE_TAG_ON : FT_CURVE_TAG_CUBIC ); 1620 } 1621 outline->n_points++; 1622 } 1623 1624 1625 /* check space for a new on-curve point, then add it */ 1626 FT_LOCAL_DEF( FT_Error ) t1_builder_add_point1(T1_Builder builder,FT_Pos x,FT_Pos y)1627 t1_builder_add_point1( T1_Builder builder, 1628 FT_Pos x, 1629 FT_Pos y ) 1630 { 1631 FT_Error error; 1632 1633 1634 error = t1_builder_check_points( builder, 1 ); 1635 if ( !error ) 1636 t1_builder_add_point( builder, x, y, 1 ); 1637 1638 return error; 1639 } 1640 1641 1642 /* check space for a new contour, then add it */ 1643 FT_LOCAL_DEF( FT_Error ) t1_builder_add_contour(T1_Builder builder)1644 t1_builder_add_contour( T1_Builder builder ) 1645 { 1646 FT_Outline* outline = builder->current; 1647 FT_Error error; 1648 1649 1650 /* this might happen in invalid fonts */ 1651 if ( !outline ) 1652 { 1653 FT_ERROR(( "t1_builder_add_contour: no outline to add points to\n" )); 1654 return FT_THROW( Invalid_File_Format ); 1655 } 1656 1657 if ( !builder->load_points ) 1658 { 1659 outline->n_contours++; 1660 return FT_Err_Ok; 1661 } 1662 1663 error = FT_GLYPHLOADER_CHECK_POINTS( builder->loader, 0, 1 ); 1664 if ( !error ) 1665 { 1666 if ( outline->n_contours > 0 ) 1667 outline->contours[outline->n_contours - 1] = 1668 (short)( outline->n_points - 1 ); 1669 1670 outline->n_contours++; 1671 } 1672 1673 return error; 1674 } 1675 1676 1677 /* if a path was begun, add its first on-curve point */ 1678 FT_LOCAL_DEF( FT_Error ) t1_builder_start_point(T1_Builder builder,FT_Pos x,FT_Pos y)1679 t1_builder_start_point( T1_Builder builder, 1680 FT_Pos x, 1681 FT_Pos y ) 1682 { 1683 FT_Error error = FT_ERR( Invalid_File_Format ); 1684 1685 1686 /* test whether we are building a new contour */ 1687 1688 if ( builder->parse_state == T1_Parse_Have_Path ) 1689 error = FT_Err_Ok; 1690 else 1691 { 1692 builder->parse_state = T1_Parse_Have_Path; 1693 error = t1_builder_add_contour( builder ); 1694 if ( !error ) 1695 error = t1_builder_add_point1( builder, x, y ); 1696 } 1697 1698 return error; 1699 } 1700 1701 1702 /* close the current contour */ 1703 FT_LOCAL_DEF( void ) t1_builder_close_contour(T1_Builder builder)1704 t1_builder_close_contour( T1_Builder builder ) 1705 { 1706 FT_Outline* outline = builder->current; 1707 FT_Int first; 1708 1709 1710 if ( !outline ) 1711 return; 1712 1713 first = outline->n_contours <= 1 1714 ? 0 : outline->contours[outline->n_contours - 2] + 1; 1715 1716 /* We must not include the last point in the path if it */ 1717 /* is located on the first point. */ 1718 if ( outline->n_points > 1 ) 1719 { 1720 FT_Vector* p1 = outline->points + first; 1721 FT_Vector* p2 = outline->points + outline->n_points - 1; 1722 FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points - 1; 1723 1724 1725 /* `delete' last point only if it coincides with the first */ 1726 /* point and it is not a control point (which can happen). */ 1727 if ( p1->x == p2->x && p1->y == p2->y ) 1728 if ( *control == FT_CURVE_TAG_ON ) 1729 outline->n_points--; 1730 } 1731 1732 if ( outline->n_contours > 0 ) 1733 { 1734 /* Don't add contours only consisting of one point, i.e., */ 1735 /* check whether the first and the last point is the same. */ 1736 if ( first == outline->n_points - 1 ) 1737 { 1738 outline->n_contours--; 1739 outline->n_points--; 1740 } 1741 else 1742 outline->contours[outline->n_contours - 1] = 1743 (short)( outline->n_points - 1 ); 1744 } 1745 } 1746 1747 1748 /*************************************************************************/ 1749 /*************************************************************************/ 1750 /***** *****/ 1751 /***** OTHER *****/ 1752 /***** *****/ 1753 /*************************************************************************/ 1754 /*************************************************************************/ 1755 1756 FT_LOCAL_DEF( void ) t1_decrypt(FT_Byte * buffer,FT_Offset length,FT_UShort seed)1757 t1_decrypt( FT_Byte* buffer, 1758 FT_Offset length, 1759 FT_UShort seed ) 1760 { 1761 PS_Conv_EexecDecode( &buffer, 1762 buffer + length, 1763 buffer, 1764 length, 1765 &seed ); 1766 } 1767 1768 1769 /* END */ 1770