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