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 if ( cur > limit ) 598 cur = limit; 599 600 parser->error = error; 601 parser->cursor = cur; 602 } 603 604 605 FT_LOCAL_DEF( void ) ps_parser_skip_spaces(PS_Parser parser)606 ps_parser_skip_spaces( PS_Parser parser ) 607 { 608 skip_spaces( &parser->cursor, parser->limit ); 609 } 610 611 612 /* `token' here means either something between balanced delimiters */ 613 /* or the next token; the delimiters are not removed. */ 614 615 FT_LOCAL_DEF( void ) ps_parser_to_token(PS_Parser parser,T1_Token token)616 ps_parser_to_token( PS_Parser parser, 617 T1_Token token ) 618 { 619 FT_Byte* cur; 620 FT_Byte* limit; 621 FT_Int embed; 622 623 624 token->type = T1_TOKEN_TYPE_NONE; 625 token->start = NULL; 626 token->limit = NULL; 627 628 /* first of all, skip leading whitespace */ 629 ps_parser_skip_spaces( parser ); 630 631 cur = parser->cursor; 632 limit = parser->limit; 633 634 if ( cur >= limit ) 635 return; 636 637 switch ( *cur ) 638 { 639 /************* check for literal string *****************/ 640 case '(': 641 token->type = T1_TOKEN_TYPE_STRING; 642 token->start = cur; 643 644 if ( skip_literal_string( &cur, limit ) == FT_Err_Ok ) 645 token->limit = cur; 646 break; 647 648 /************* check for programs/array *****************/ 649 case '{': 650 token->type = T1_TOKEN_TYPE_ARRAY; 651 token->start = cur; 652 653 if ( skip_procedure( &cur, limit ) == FT_Err_Ok ) 654 token->limit = cur; 655 break; 656 657 /************* check for table/array ********************/ 658 /* XXX: in theory we should also look for "<<" */ 659 /* since this is semantically equivalent to "["; */ 660 /* in practice it doesn't matter (?) */ 661 case '[': 662 token->type = T1_TOKEN_TYPE_ARRAY; 663 embed = 1; 664 token->start = cur++; 665 666 /* we need this to catch `[ ]' */ 667 parser->cursor = cur; 668 ps_parser_skip_spaces( parser ); 669 cur = parser->cursor; 670 671 while ( cur < limit && !parser->error ) 672 { 673 /* XXX: this is wrong because it does not */ 674 /* skip comments, procedures, and strings */ 675 if ( *cur == '[' ) 676 embed++; 677 else if ( *cur == ']' ) 678 { 679 embed--; 680 if ( embed <= 0 ) 681 { 682 token->limit = ++cur; 683 break; 684 } 685 } 686 687 parser->cursor = cur; 688 ps_parser_skip_PS_token( parser ); 689 /* we need this to catch `[XXX ]' */ 690 ps_parser_skip_spaces ( parser ); 691 cur = parser->cursor; 692 } 693 break; 694 695 /* ************ otherwise, it is any token **************/ 696 default: 697 token->start = cur; 698 token->type = ( *cur == '/' ? T1_TOKEN_TYPE_KEY : T1_TOKEN_TYPE_ANY ); 699 ps_parser_skip_PS_token( parser ); 700 cur = parser->cursor; 701 if ( !parser->error ) 702 token->limit = cur; 703 } 704 705 if ( !token->limit ) 706 { 707 token->start = NULL; 708 token->type = T1_TOKEN_TYPE_NONE; 709 } 710 711 parser->cursor = cur; 712 } 713 714 715 /* NB: `tokens' can be NULL if we only want to count */ 716 /* the number of array elements */ 717 718 FT_LOCAL_DEF( void ) ps_parser_to_token_array(PS_Parser parser,T1_Token tokens,FT_UInt max_tokens,FT_Int * pnum_tokens)719 ps_parser_to_token_array( PS_Parser parser, 720 T1_Token tokens, 721 FT_UInt max_tokens, 722 FT_Int* pnum_tokens ) 723 { 724 T1_TokenRec master; 725 726 727 *pnum_tokens = -1; 728 729 /* this also handles leading whitespace */ 730 ps_parser_to_token( parser, &master ); 731 732 if ( master.type == T1_TOKEN_TYPE_ARRAY ) 733 { 734 FT_Byte* old_cursor = parser->cursor; 735 FT_Byte* old_limit = parser->limit; 736 T1_Token cur = tokens; 737 T1_Token limit = cur + max_tokens; 738 739 740 /* don't include outermost delimiters */ 741 parser->cursor = master.start + 1; 742 parser->limit = master.limit - 1; 743 744 while ( parser->cursor < parser->limit ) 745 { 746 T1_TokenRec token; 747 748 749 ps_parser_to_token( parser, &token ); 750 if ( !token.type ) 751 break; 752 753 if ( tokens != NULL && cur < limit ) 754 *cur = token; 755 756 cur++; 757 } 758 759 *pnum_tokens = (FT_Int)( cur - tokens ); 760 761 parser->cursor = old_cursor; 762 parser->limit = old_limit; 763 } 764 } 765 766 767 /* first character must be a delimiter or a part of a number */ 768 /* NB: `coords' can be NULL if we just want to skip the */ 769 /* array; in this case we ignore `max_coords' */ 770 771 static FT_Int ps_tocoordarray(FT_Byte ** acur,FT_Byte * limit,FT_Int max_coords,FT_Short * coords)772 ps_tocoordarray( FT_Byte* *acur, 773 FT_Byte* limit, 774 FT_Int max_coords, 775 FT_Short* coords ) 776 { 777 FT_Byte* cur = *acur; 778 FT_Int count = 0; 779 FT_Byte c, ender; 780 781 782 if ( cur >= limit ) 783 goto Exit; 784 785 /* check for the beginning of an array; otherwise, only one number */ 786 /* will be read */ 787 c = *cur; 788 ender = 0; 789 790 if ( c == '[' ) 791 ender = ']'; 792 else if ( c == '{' ) 793 ender = '}'; 794 795 if ( ender ) 796 cur++; 797 798 /* now, read the coordinates */ 799 while ( cur < limit ) 800 { 801 FT_Short dummy; 802 FT_Byte* old_cur; 803 804 805 /* skip whitespace in front of data */ 806 skip_spaces( &cur, limit ); 807 if ( cur >= limit ) 808 goto Exit; 809 810 if ( *cur == ender ) 811 { 812 cur++; 813 break; 814 } 815 816 old_cur = cur; 817 818 if ( coords != NULL && count >= max_coords ) 819 break; 820 821 /* call PS_Conv_ToFixed() even if coords == NULL */ 822 /* to properly parse number at `cur' */ 823 *( coords != NULL ? &coords[count] : &dummy ) = 824 (FT_Short)( PS_Conv_ToFixed( &cur, limit, 0 ) >> 16 ); 825 826 if ( old_cur == cur ) 827 { 828 count = -1; 829 goto Exit; 830 } 831 else 832 count++; 833 834 if ( !ender ) 835 break; 836 } 837 838 Exit: 839 *acur = cur; 840 return count; 841 } 842 843 844 /* first character must be a delimiter or a part of a number */ 845 /* NB: `values' can be NULL if we just want to skip the */ 846 /* array; in this case we ignore `max_values' */ 847 /* */ 848 /* return number of successfully parsed values */ 849 850 static FT_Int ps_tofixedarray(FT_Byte ** acur,FT_Byte * limit,FT_Int max_values,FT_Fixed * values,FT_Int power_ten)851 ps_tofixedarray( FT_Byte* *acur, 852 FT_Byte* limit, 853 FT_Int max_values, 854 FT_Fixed* values, 855 FT_Int power_ten ) 856 { 857 FT_Byte* cur = *acur; 858 FT_Int count = 0; 859 FT_Byte c, ender; 860 861 862 if ( cur >= limit ) 863 goto Exit; 864 865 /* Check for the beginning of an array. Otherwise, only one number */ 866 /* will be read. */ 867 c = *cur; 868 ender = 0; 869 870 if ( c == '[' ) 871 ender = ']'; 872 else if ( c == '{' ) 873 ender = '}'; 874 875 if ( ender ) 876 cur++; 877 878 /* now, read the values */ 879 while ( cur < limit ) 880 { 881 FT_Fixed dummy; 882 FT_Byte* old_cur; 883 884 885 /* skip whitespace in front of data */ 886 skip_spaces( &cur, limit ); 887 if ( cur >= limit ) 888 goto Exit; 889 890 if ( *cur == ender ) 891 { 892 cur++; 893 break; 894 } 895 896 old_cur = cur; 897 898 if ( values != NULL && count >= max_values ) 899 break; 900 901 /* call PS_Conv_ToFixed() even if coords == NULL */ 902 /* to properly parse number at `cur' */ 903 *( values != NULL ? &values[count] : &dummy ) = 904 PS_Conv_ToFixed( &cur, limit, power_ten ); 905 906 if ( old_cur == cur ) 907 { 908 count = -1; 909 goto Exit; 910 } 911 else 912 count++; 913 914 if ( !ender ) 915 break; 916 } 917 918 Exit: 919 *acur = cur; 920 return count; 921 } 922 923 924 #if 0 925 926 static FT_String* 927 ps_tostring( FT_Byte** cursor, 928 FT_Byte* limit, 929 FT_Memory memory ) 930 { 931 FT_Byte* cur = *cursor; 932 FT_UInt len = 0; 933 FT_Int count; 934 FT_String* result; 935 FT_Error error; 936 937 938 /* XXX: some stupid fonts have a `Notice' or `Copyright' string */ 939 /* that simply doesn't begin with an opening parenthesis, even */ 940 /* though they have a closing one! E.g. "amuncial.pfb" */ 941 /* */ 942 /* We must deal with these ill-fated cases there. Note that */ 943 /* these fonts didn't work with the old Type 1 driver as the */ 944 /* notice/copyright was not recognized as a valid string token */ 945 /* and made the old token parser commit errors. */ 946 947 while ( cur < limit && ( *cur == ' ' || *cur == '\t' ) ) 948 cur++; 949 if ( cur + 1 >= limit ) 950 return 0; 951 952 if ( *cur == '(' ) 953 cur++; /* skip the opening parenthesis, if there is one */ 954 955 *cursor = cur; 956 count = 0; 957 958 /* then, count its length */ 959 for ( ; cur < limit; cur++ ) 960 { 961 if ( *cur == '(' ) 962 count++; 963 964 else if ( *cur == ')' ) 965 { 966 count--; 967 if ( count < 0 ) 968 break; 969 } 970 } 971 972 len = (FT_UInt)( cur - *cursor ); 973 if ( cur >= limit || FT_ALLOC( result, len + 1 ) ) 974 return 0; 975 976 /* now copy the string */ 977 FT_MEM_COPY( result, *cursor, len ); 978 result[len] = '\0'; 979 *cursor = cur; 980 return result; 981 } 982 983 #endif /* 0 */ 984 985 986 static int ps_tobool(FT_Byte ** acur,FT_Byte * limit)987 ps_tobool( FT_Byte* *acur, 988 FT_Byte* limit ) 989 { 990 FT_Byte* cur = *acur; 991 FT_Bool result = 0; 992 993 994 /* return 1 if we find `true', 0 otherwise */ 995 if ( cur + 3 < limit && 996 cur[0] == 't' && 997 cur[1] == 'r' && 998 cur[2] == 'u' && 999 cur[3] == 'e' ) 1000 { 1001 result = 1; 1002 cur += 5; 1003 } 1004 else if ( cur + 4 < limit && 1005 cur[0] == 'f' && 1006 cur[1] == 'a' && 1007 cur[2] == 'l' && 1008 cur[3] == 's' && 1009 cur[4] == 'e' ) 1010 { 1011 result = 0; 1012 cur += 6; 1013 } 1014 1015 *acur = cur; 1016 return result; 1017 } 1018 1019 1020 /* load a simple field (i.e. non-table) into the current list of objects */ 1021 1022 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)1023 ps_parser_load_field( PS_Parser parser, 1024 const T1_Field field, 1025 void** objects, 1026 FT_UInt max_objects, 1027 FT_ULong* pflags ) 1028 { 1029 T1_TokenRec token; 1030 FT_Byte* cur; 1031 FT_Byte* limit; 1032 FT_UInt count; 1033 FT_UInt idx; 1034 FT_Error error; 1035 T1_FieldType type; 1036 1037 1038 /* this also skips leading whitespace */ 1039 ps_parser_to_token( parser, &token ); 1040 if ( !token.type ) 1041 goto Fail; 1042 1043 count = 1; 1044 idx = 0; 1045 cur = token.start; 1046 limit = token.limit; 1047 1048 type = field->type; 1049 1050 /* we must detect arrays in /FontBBox */ 1051 if ( type == T1_FIELD_TYPE_BBOX ) 1052 { 1053 T1_TokenRec token2; 1054 FT_Byte* old_cur = parser->cursor; 1055 FT_Byte* old_limit = parser->limit; 1056 1057 1058 /* don't include delimiters */ 1059 parser->cursor = token.start + 1; 1060 parser->limit = token.limit - 1; 1061 1062 ps_parser_to_token( parser, &token2 ); 1063 parser->cursor = old_cur; 1064 parser->limit = old_limit; 1065 1066 if ( token2.type == T1_TOKEN_TYPE_ARRAY ) 1067 { 1068 type = T1_FIELD_TYPE_MM_BBOX; 1069 goto FieldArray; 1070 } 1071 } 1072 else if ( token.type == T1_TOKEN_TYPE_ARRAY ) 1073 { 1074 count = max_objects; 1075 1076 FieldArray: 1077 /* if this is an array and we have no blend, an error occurs */ 1078 if ( max_objects == 0 ) 1079 goto Fail; 1080 1081 idx = 1; 1082 1083 /* don't include delimiters */ 1084 cur++; 1085 limit--; 1086 } 1087 1088 for ( ; count > 0; count--, idx++ ) 1089 { 1090 FT_Byte* q = (FT_Byte*)objects[idx] + field->offset; 1091 FT_Long val; 1092 FT_String* string; 1093 1094 1095 skip_spaces( &cur, limit ); 1096 1097 switch ( type ) 1098 { 1099 case T1_FIELD_TYPE_BOOL: 1100 val = ps_tobool( &cur, limit ); 1101 goto Store_Integer; 1102 1103 case T1_FIELD_TYPE_FIXED: 1104 val = PS_Conv_ToFixed( &cur, limit, 0 ); 1105 goto Store_Integer; 1106 1107 case T1_FIELD_TYPE_FIXED_1000: 1108 val = PS_Conv_ToFixed( &cur, limit, 3 ); 1109 goto Store_Integer; 1110 1111 case T1_FIELD_TYPE_INTEGER: 1112 val = PS_Conv_ToInt( &cur, limit ); 1113 /* fall through */ 1114 1115 Store_Integer: 1116 switch ( field->size ) 1117 { 1118 case (8 / FT_CHAR_BIT): 1119 *(FT_Byte*)q = (FT_Byte)val; 1120 break; 1121 1122 case (16 / FT_CHAR_BIT): 1123 *(FT_UShort*)q = (FT_UShort)val; 1124 break; 1125 1126 case (32 / FT_CHAR_BIT): 1127 *(FT_UInt32*)q = (FT_UInt32)val; 1128 break; 1129 1130 default: /* for 64-bit systems */ 1131 *(FT_Long*)q = val; 1132 } 1133 break; 1134 1135 case T1_FIELD_TYPE_STRING: 1136 case T1_FIELD_TYPE_KEY: 1137 { 1138 FT_Memory memory = parser->memory; 1139 FT_UInt len = (FT_UInt)( limit - cur ); 1140 1141 1142 if ( cur >= limit ) 1143 break; 1144 1145 /* we allow both a string or a name */ 1146 /* for cases like /FontName (foo) def */ 1147 if ( token.type == T1_TOKEN_TYPE_KEY ) 1148 { 1149 /* don't include leading `/' */ 1150 len--; 1151 cur++; 1152 } 1153 else if ( token.type == T1_TOKEN_TYPE_STRING ) 1154 { 1155 /* don't include delimiting parentheses */ 1156 /* XXX we don't handle <<...>> here */ 1157 /* XXX should we convert octal escapes? */ 1158 /* if so, what encoding should we use? */ 1159 cur++; 1160 len -= 2; 1161 } 1162 else 1163 { 1164 FT_ERROR(( "ps_parser_load_field:" 1165 " expected a name or string\n" 1166 " " 1167 " but found token of type %d instead\n", 1168 token.type )); 1169 error = FT_THROW( Invalid_File_Format ); 1170 goto Exit; 1171 } 1172 1173 /* for this to work (FT_String**)q must have been */ 1174 /* initialized to NULL */ 1175 if ( *(FT_String**)q != NULL ) 1176 { 1177 FT_TRACE0(( "ps_parser_load_field: overwriting field %s\n", 1178 field->ident )); 1179 FT_FREE( *(FT_String**)q ); 1180 *(FT_String**)q = NULL; 1181 } 1182 1183 if ( FT_ALLOC( string, len + 1 ) ) 1184 goto Exit; 1185 1186 FT_MEM_COPY( string, cur, len ); 1187 string[len] = 0; 1188 1189 *(FT_String**)q = string; 1190 } 1191 break; 1192 1193 case T1_FIELD_TYPE_BBOX: 1194 { 1195 FT_Fixed temp[4]; 1196 FT_BBox* bbox = (FT_BBox*)q; 1197 FT_Int result; 1198 1199 1200 result = ps_tofixedarray( &cur, limit, 4, temp, 0 ); 1201 1202 if ( result < 4 ) 1203 { 1204 FT_ERROR(( "ps_parser_load_field:" 1205 " expected four integers in bounding box\n" )); 1206 error = FT_THROW( Invalid_File_Format ); 1207 goto Exit; 1208 } 1209 1210 bbox->xMin = FT_RoundFix( temp[0] ); 1211 bbox->yMin = FT_RoundFix( temp[1] ); 1212 bbox->xMax = FT_RoundFix( temp[2] ); 1213 bbox->yMax = FT_RoundFix( temp[3] ); 1214 } 1215 break; 1216 1217 case T1_FIELD_TYPE_MM_BBOX: 1218 { 1219 FT_Memory memory = parser->memory; 1220 FT_Fixed* temp; 1221 FT_Int result; 1222 FT_UInt i; 1223 1224 1225 if ( FT_NEW_ARRAY( temp, max_objects * 4 ) ) 1226 goto Exit; 1227 1228 for ( i = 0; i < 4; i++ ) 1229 { 1230 result = ps_tofixedarray( &cur, limit, (FT_Int)max_objects, 1231 temp + i * max_objects, 0 ); 1232 if ( result < 0 || (FT_UInt)result < max_objects ) 1233 { 1234 FT_ERROR(( "ps_parser_load_field:" 1235 " expected %d integer%s in the %s subarray\n" 1236 " " 1237 " of /FontBBox in the /Blend dictionary\n", 1238 max_objects, max_objects > 1 ? "s" : "", 1239 i == 0 ? "first" 1240 : ( i == 1 ? "second" 1241 : ( i == 2 ? "third" 1242 : "fourth" ) ) )); 1243 error = FT_THROW( Invalid_File_Format ); 1244 1245 FT_FREE( temp ); 1246 goto Exit; 1247 } 1248 1249 skip_spaces( &cur, limit ); 1250 } 1251 1252 for ( i = 0; i < max_objects; i++ ) 1253 { 1254 FT_BBox* bbox = (FT_BBox*)objects[i]; 1255 1256 1257 bbox->xMin = FT_RoundFix( temp[i ] ); 1258 bbox->yMin = FT_RoundFix( temp[i + max_objects] ); 1259 bbox->xMax = FT_RoundFix( temp[i + 2 * max_objects] ); 1260 bbox->yMax = FT_RoundFix( temp[i + 3 * max_objects] ); 1261 } 1262 1263 FT_FREE( temp ); 1264 } 1265 break; 1266 1267 default: 1268 /* an error occurred */ 1269 goto Fail; 1270 } 1271 } 1272 1273 #if 0 /* obsolete -- keep for reference */ 1274 if ( pflags ) 1275 *pflags |= 1L << field->flag_bit; 1276 #else 1277 FT_UNUSED( pflags ); 1278 #endif 1279 1280 error = FT_Err_Ok; 1281 1282 Exit: 1283 return error; 1284 1285 Fail: 1286 error = FT_THROW( Invalid_File_Format ); 1287 goto Exit; 1288 } 1289 1290 1291 #define T1_MAX_TABLE_ELEMENTS 32 1292 1293 1294 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)1295 ps_parser_load_field_table( PS_Parser parser, 1296 const T1_Field field, 1297 void** objects, 1298 FT_UInt max_objects, 1299 FT_ULong* pflags ) 1300 { 1301 T1_TokenRec elements[T1_MAX_TABLE_ELEMENTS]; 1302 T1_Token token; 1303 FT_Int num_elements; 1304 FT_Error error = FT_Err_Ok; 1305 FT_Byte* old_cursor; 1306 FT_Byte* old_limit; 1307 T1_FieldRec fieldrec = *(T1_Field)field; 1308 1309 1310 fieldrec.type = T1_FIELD_TYPE_INTEGER; 1311 if ( field->type == T1_FIELD_TYPE_FIXED_ARRAY || 1312 field->type == T1_FIELD_TYPE_BBOX ) 1313 fieldrec.type = T1_FIELD_TYPE_FIXED; 1314 1315 ps_parser_to_token_array( parser, elements, 1316 T1_MAX_TABLE_ELEMENTS, &num_elements ); 1317 if ( num_elements < 0 ) 1318 { 1319 error = FT_ERR( Ignore ); 1320 goto Exit; 1321 } 1322 if ( (FT_UInt)num_elements > field->array_max ) 1323 num_elements = (FT_Int)field->array_max; 1324 1325 old_cursor = parser->cursor; 1326 old_limit = parser->limit; 1327 1328 /* we store the elements count if necessary; */ 1329 /* we further assume that `count_offset' can't be zero */ 1330 if ( field->type != T1_FIELD_TYPE_BBOX && field->count_offset != 0 ) 1331 *(FT_Byte*)( (FT_Byte*)objects[0] + field->count_offset ) = 1332 (FT_Byte)num_elements; 1333 1334 /* we now load each element, adjusting the field.offset on each one */ 1335 token = elements; 1336 for ( ; num_elements > 0; num_elements--, token++ ) 1337 { 1338 parser->cursor = token->start; 1339 parser->limit = token->limit; 1340 1341 error = ps_parser_load_field( parser, 1342 &fieldrec, 1343 objects, 1344 max_objects, 1345 0 ); 1346 if ( error ) 1347 break; 1348 1349 fieldrec.offset += fieldrec.size; 1350 } 1351 1352 #if 0 /* obsolete -- keep for reference */ 1353 if ( pflags ) 1354 *pflags |= 1L << field->flag_bit; 1355 #else 1356 FT_UNUSED( pflags ); 1357 #endif 1358 1359 parser->cursor = old_cursor; 1360 parser->limit = old_limit; 1361 1362 Exit: 1363 return error; 1364 } 1365 1366 1367 FT_LOCAL_DEF( FT_Long ) ps_parser_to_int(PS_Parser parser)1368 ps_parser_to_int( PS_Parser parser ) 1369 { 1370 ps_parser_skip_spaces( parser ); 1371 return PS_Conv_ToInt( &parser->cursor, parser->limit ); 1372 } 1373 1374 1375 /* first character must be `<' if `delimiters' is non-zero */ 1376 1377 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)1378 ps_parser_to_bytes( PS_Parser parser, 1379 FT_Byte* bytes, 1380 FT_Offset max_bytes, 1381 FT_ULong* pnum_bytes, 1382 FT_Bool delimiters ) 1383 { 1384 FT_Error error = FT_Err_Ok; 1385 FT_Byte* cur; 1386 1387 1388 ps_parser_skip_spaces( parser ); 1389 cur = parser->cursor; 1390 1391 if ( cur >= parser->limit ) 1392 goto Exit; 1393 1394 if ( delimiters ) 1395 { 1396 if ( *cur != '<' ) 1397 { 1398 FT_ERROR(( "ps_parser_to_bytes: Missing starting delimiter `<'\n" )); 1399 error = FT_THROW( Invalid_File_Format ); 1400 goto Exit; 1401 } 1402 1403 cur++; 1404 } 1405 1406 *pnum_bytes = PS_Conv_ASCIIHexDecode( &cur, 1407 parser->limit, 1408 bytes, 1409 max_bytes ); 1410 1411 if ( delimiters ) 1412 { 1413 if ( cur < parser->limit && *cur != '>' ) 1414 { 1415 FT_ERROR(( "ps_parser_to_bytes: Missing closing delimiter `>'\n" )); 1416 error = FT_THROW( Invalid_File_Format ); 1417 goto Exit; 1418 } 1419 1420 cur++; 1421 } 1422 1423 parser->cursor = cur; 1424 1425 Exit: 1426 return error; 1427 } 1428 1429 1430 FT_LOCAL_DEF( FT_Fixed ) ps_parser_to_fixed(PS_Parser parser,FT_Int power_ten)1431 ps_parser_to_fixed( PS_Parser parser, 1432 FT_Int power_ten ) 1433 { 1434 ps_parser_skip_spaces( parser ); 1435 return PS_Conv_ToFixed( &parser->cursor, parser->limit, power_ten ); 1436 } 1437 1438 1439 FT_LOCAL_DEF( FT_Int ) ps_parser_to_coord_array(PS_Parser parser,FT_Int max_coords,FT_Short * coords)1440 ps_parser_to_coord_array( PS_Parser parser, 1441 FT_Int max_coords, 1442 FT_Short* coords ) 1443 { 1444 ps_parser_skip_spaces( parser ); 1445 return ps_tocoordarray( &parser->cursor, parser->limit, 1446 max_coords, coords ); 1447 } 1448 1449 1450 FT_LOCAL_DEF( FT_Int ) ps_parser_to_fixed_array(PS_Parser parser,FT_Int max_values,FT_Fixed * values,FT_Int power_ten)1451 ps_parser_to_fixed_array( PS_Parser parser, 1452 FT_Int max_values, 1453 FT_Fixed* values, 1454 FT_Int power_ten ) 1455 { 1456 ps_parser_skip_spaces( parser ); 1457 return ps_tofixedarray( &parser->cursor, parser->limit, 1458 max_values, values, power_ten ); 1459 } 1460 1461 1462 #if 0 1463 1464 FT_LOCAL_DEF( FT_String* ) 1465 T1_ToString( PS_Parser parser ) 1466 { 1467 return ps_tostring( &parser->cursor, parser->limit, parser->memory ); 1468 } 1469 1470 1471 FT_LOCAL_DEF( FT_Bool ) 1472 T1_ToBool( PS_Parser parser ) 1473 { 1474 return ps_tobool( &parser->cursor, parser->limit ); 1475 } 1476 1477 #endif /* 0 */ 1478 1479 1480 FT_LOCAL_DEF( void ) ps_parser_init(PS_Parser parser,FT_Byte * base,FT_Byte * limit,FT_Memory memory)1481 ps_parser_init( PS_Parser parser, 1482 FT_Byte* base, 1483 FT_Byte* limit, 1484 FT_Memory memory ) 1485 { 1486 parser->error = FT_Err_Ok; 1487 parser->base = base; 1488 parser->limit = limit; 1489 parser->cursor = base; 1490 parser->memory = memory; 1491 parser->funcs = ps_parser_funcs; 1492 } 1493 1494 1495 FT_LOCAL_DEF( void ) ps_parser_done(PS_Parser parser)1496 ps_parser_done( PS_Parser parser ) 1497 { 1498 FT_UNUSED( parser ); 1499 } 1500 1501 1502 /*************************************************************************/ 1503 /*************************************************************************/ 1504 /***** *****/ 1505 /***** T1 BUILDER *****/ 1506 /***** *****/ 1507 /*************************************************************************/ 1508 /*************************************************************************/ 1509 1510 /*************************************************************************/ 1511 /* */ 1512 /* <Function> */ 1513 /* t1_builder_init */ 1514 /* */ 1515 /* <Description> */ 1516 /* Initializes a given glyph builder. */ 1517 /* */ 1518 /* <InOut> */ 1519 /* builder :: A pointer to the glyph builder to initialize. */ 1520 /* */ 1521 /* <Input> */ 1522 /* face :: The current face object. */ 1523 /* */ 1524 /* size :: The current size object. */ 1525 /* */ 1526 /* glyph :: The current glyph object. */ 1527 /* */ 1528 /* hinting :: Whether hinting should be applied. */ 1529 /* */ 1530 FT_LOCAL_DEF( void ) t1_builder_init(T1_Builder builder,FT_Face face,FT_Size size,FT_GlyphSlot glyph,FT_Bool hinting)1531 t1_builder_init( T1_Builder builder, 1532 FT_Face face, 1533 FT_Size size, 1534 FT_GlyphSlot glyph, 1535 FT_Bool hinting ) 1536 { 1537 builder->parse_state = T1_Parse_Start; 1538 builder->load_points = 1; 1539 1540 builder->face = face; 1541 builder->glyph = glyph; 1542 builder->memory = face->memory; 1543 1544 if ( glyph ) 1545 { 1546 FT_GlyphLoader loader = glyph->internal->loader; 1547 1548 1549 builder->loader = loader; 1550 builder->base = &loader->base.outline; 1551 builder->current = &loader->current.outline; 1552 FT_GlyphLoader_Rewind( loader ); 1553 1554 builder->hints_globals = size->internal; 1555 builder->hints_funcs = NULL; 1556 1557 if ( hinting ) 1558 builder->hints_funcs = glyph->internal->glyph_hints; 1559 } 1560 1561 builder->pos_x = 0; 1562 builder->pos_y = 0; 1563 1564 builder->left_bearing.x = 0; 1565 builder->left_bearing.y = 0; 1566 builder->advance.x = 0; 1567 builder->advance.y = 0; 1568 1569 builder->funcs = t1_builder_funcs; 1570 } 1571 1572 1573 /*************************************************************************/ 1574 /* */ 1575 /* <Function> */ 1576 /* t1_builder_done */ 1577 /* */ 1578 /* <Description> */ 1579 /* Finalizes a given glyph builder. Its contents can still be used */ 1580 /* after the call, but the function saves important information */ 1581 /* within the corresponding glyph slot. */ 1582 /* */ 1583 /* <Input> */ 1584 /* builder :: A pointer to the glyph builder to finalize. */ 1585 /* */ 1586 FT_LOCAL_DEF( void ) t1_builder_done(T1_Builder builder)1587 t1_builder_done( T1_Builder builder ) 1588 { 1589 FT_GlyphSlot glyph = builder->glyph; 1590 1591 1592 if ( glyph ) 1593 glyph->outline = *builder->base; 1594 } 1595 1596 1597 /* check that there is enough space for `count' more points */ 1598 FT_LOCAL_DEF( FT_Error ) t1_builder_check_points(T1_Builder builder,FT_Int count)1599 t1_builder_check_points( T1_Builder builder, 1600 FT_Int count ) 1601 { 1602 return FT_GLYPHLOADER_CHECK_POINTS( builder->loader, count, 0 ); 1603 } 1604 1605 1606 /* add a new point, do not check space */ 1607 FT_LOCAL_DEF( void ) t1_builder_add_point(T1_Builder builder,FT_Pos x,FT_Pos y,FT_Byte flag)1608 t1_builder_add_point( T1_Builder builder, 1609 FT_Pos x, 1610 FT_Pos y, 1611 FT_Byte flag ) 1612 { 1613 FT_Outline* outline = builder->current; 1614 1615 1616 if ( builder->load_points ) 1617 { 1618 FT_Vector* point = outline->points + outline->n_points; 1619 FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points; 1620 1621 1622 point->x = FIXED_TO_INT( x ); 1623 point->y = FIXED_TO_INT( y ); 1624 *control = (FT_Byte)( flag ? FT_CURVE_TAG_ON : FT_CURVE_TAG_CUBIC ); 1625 } 1626 outline->n_points++; 1627 } 1628 1629 1630 /* check space for a new on-curve point, then add it */ 1631 FT_LOCAL_DEF( FT_Error ) t1_builder_add_point1(T1_Builder builder,FT_Pos x,FT_Pos y)1632 t1_builder_add_point1( T1_Builder builder, 1633 FT_Pos x, 1634 FT_Pos y ) 1635 { 1636 FT_Error error; 1637 1638 1639 error = t1_builder_check_points( builder, 1 ); 1640 if ( !error ) 1641 t1_builder_add_point( builder, x, y, 1 ); 1642 1643 return error; 1644 } 1645 1646 1647 /* check space for a new contour, then add it */ 1648 FT_LOCAL_DEF( FT_Error ) t1_builder_add_contour(T1_Builder builder)1649 t1_builder_add_contour( T1_Builder builder ) 1650 { 1651 FT_Outline* outline = builder->current; 1652 FT_Error error; 1653 1654 1655 /* this might happen in invalid fonts */ 1656 if ( !outline ) 1657 { 1658 FT_ERROR(( "t1_builder_add_contour: no outline to add points to\n" )); 1659 return FT_THROW( Invalid_File_Format ); 1660 } 1661 1662 if ( !builder->load_points ) 1663 { 1664 outline->n_contours++; 1665 return FT_Err_Ok; 1666 } 1667 1668 error = FT_GLYPHLOADER_CHECK_POINTS( builder->loader, 0, 1 ); 1669 if ( !error ) 1670 { 1671 if ( outline->n_contours > 0 ) 1672 outline->contours[outline->n_contours - 1] = 1673 (short)( outline->n_points - 1 ); 1674 1675 outline->n_contours++; 1676 } 1677 1678 return error; 1679 } 1680 1681 1682 /* if a path was begun, add its first on-curve point */ 1683 FT_LOCAL_DEF( FT_Error ) t1_builder_start_point(T1_Builder builder,FT_Pos x,FT_Pos y)1684 t1_builder_start_point( T1_Builder builder, 1685 FT_Pos x, 1686 FT_Pos y ) 1687 { 1688 FT_Error error = FT_ERR( Invalid_File_Format ); 1689 1690 1691 /* test whether we are building a new contour */ 1692 1693 if ( builder->parse_state == T1_Parse_Have_Path ) 1694 error = FT_Err_Ok; 1695 else 1696 { 1697 builder->parse_state = T1_Parse_Have_Path; 1698 error = t1_builder_add_contour( builder ); 1699 if ( !error ) 1700 error = t1_builder_add_point1( builder, x, y ); 1701 } 1702 1703 return error; 1704 } 1705 1706 1707 /* close the current contour */ 1708 FT_LOCAL_DEF( void ) t1_builder_close_contour(T1_Builder builder)1709 t1_builder_close_contour( T1_Builder builder ) 1710 { 1711 FT_Outline* outline = builder->current; 1712 FT_Int first; 1713 1714 1715 if ( !outline ) 1716 return; 1717 1718 first = outline->n_contours <= 1 1719 ? 0 : outline->contours[outline->n_contours - 2] + 1; 1720 1721 /* We must not include the last point in the path if it */ 1722 /* is located on the first point. */ 1723 if ( outline->n_points > 1 ) 1724 { 1725 FT_Vector* p1 = outline->points + first; 1726 FT_Vector* p2 = outline->points + outline->n_points - 1; 1727 FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points - 1; 1728 1729 1730 /* `delete' last point only if it coincides with the first */ 1731 /* point and it is not a control point (which can happen). */ 1732 if ( p1->x == p2->x && p1->y == p2->y ) 1733 if ( *control == FT_CURVE_TAG_ON ) 1734 outline->n_points--; 1735 } 1736 1737 if ( outline->n_contours > 0 ) 1738 { 1739 /* Don't add contours only consisting of one point, i.e., */ 1740 /* check whether the first and the last point is the same. */ 1741 if ( first == outline->n_points - 1 ) 1742 { 1743 outline->n_contours--; 1744 outline->n_points--; 1745 } 1746 else 1747 outline->contours[outline->n_contours - 1] = 1748 (short)( outline->n_points - 1 ); 1749 } 1750 } 1751 1752 1753 /*************************************************************************/ 1754 /*************************************************************************/ 1755 /***** *****/ 1756 /***** OTHER *****/ 1757 /***** *****/ 1758 /*************************************************************************/ 1759 /*************************************************************************/ 1760 1761 FT_LOCAL_DEF( void ) t1_decrypt(FT_Byte * buffer,FT_Offset length,FT_UShort seed)1762 t1_decrypt( FT_Byte* buffer, 1763 FT_Offset length, 1764 FT_UShort seed ) 1765 { 1766 PS_Conv_EexecDecode( &buffer, 1767 buffer + length, 1768 buffer, 1769 length, 1770 &seed ); 1771 } 1772 1773 1774 /* END */ 1775