Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenpsobjs.c
Go to the documentation of this file.
00001 /***************************************************************************/ 00002 /* */ 00003 /* psobjs.c */ 00004 /* */ 00005 /* Auxiliary functions for PostScript fonts (body). */ 00006 /* */ 00007 /* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, */ 00008 /* 2010 by */ 00009 /* David Turner, Robert Wilhelm, and Werner Lemberg. */ 00010 /* */ 00011 /* This file is part of the FreeType project, and may only be used, */ 00012 /* modified, and distributed under the terms of the FreeType project */ 00013 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ 00014 /* this file you indicate that you have read the license and */ 00015 /* understand and accept it fully. */ 00016 /* */ 00017 /***************************************************************************/ 00018 00019 00020 #include <ft2build.h> 00021 #include FT_INTERNAL_POSTSCRIPT_AUX_H 00022 #include FT_INTERNAL_DEBUG_H 00023 #include FT_INTERNAL_CALC_H 00024 00025 #include "psobjs.h" 00026 #include "psconv.h" 00027 00028 #include "psauxerr.h" 00029 00030 00031 /*************************************************************************/ 00032 /* */ 00033 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 00034 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 00035 /* messages during execution. */ 00036 /* */ 00037 #undef FT_COMPONENT 00038 #define FT_COMPONENT trace_psobjs 00039 00040 00041 /*************************************************************************/ 00042 /*************************************************************************/ 00043 /***** *****/ 00044 /***** PS_TABLE *****/ 00045 /***** *****/ 00046 /*************************************************************************/ 00047 /*************************************************************************/ 00048 00049 /*************************************************************************/ 00050 /* */ 00051 /* <Function> */ 00052 /* ps_table_new */ 00053 /* */ 00054 /* <Description> */ 00055 /* Initializes a PS_Table. */ 00056 /* */ 00057 /* <InOut> */ 00058 /* table :: The address of the target table. */ 00059 /* */ 00060 /* <Input> */ 00061 /* count :: The table size = the maximum number of elements. */ 00062 /* */ 00063 /* memory :: The memory object to use for all subsequent */ 00064 /* reallocations. */ 00065 /* */ 00066 /* <Return> */ 00067 /* FreeType error code. 0 means success. */ 00068 /* */ 00069 FT_LOCAL_DEF( FT_Error ) 00070 ps_table_new( PS_Table table, 00071 FT_Int count, 00072 FT_Memory memory ) 00073 { 00074 FT_Error error; 00075 00076 00077 table->memory = memory; 00078 if ( FT_NEW_ARRAY( table->elements, count ) || 00079 FT_NEW_ARRAY( table->lengths, count ) ) 00080 goto Exit; 00081 00082 table->max_elems = count; 00083 table->init = 0xDEADBEEFUL; 00084 table->num_elems = 0; 00085 table->block = 0; 00086 table->capacity = 0; 00087 table->cursor = 0; 00088 00089 *(PS_Table_FuncsRec*)&table->funcs = ps_table_funcs; 00090 00091 Exit: 00092 if ( error ) 00093 FT_FREE( table->elements ); 00094 00095 return error; 00096 } 00097 00098 00099 static void 00100 shift_elements( PS_Table table, 00101 FT_Byte* old_base ) 00102 { 00103 FT_PtrDist delta = table->block - old_base; 00104 FT_Byte** offset = table->elements; 00105 FT_Byte** limit = offset + table->max_elems; 00106 00107 00108 for ( ; offset < limit; offset++ ) 00109 { 00110 if ( offset[0] ) 00111 offset[0] += delta; 00112 } 00113 } 00114 00115 00116 static FT_Error 00117 reallocate_t1_table( PS_Table table, 00118 FT_Long new_size ) 00119 { 00120 FT_Memory memory = table->memory; 00121 FT_Byte* old_base = table->block; 00122 FT_Error error; 00123 00124 00125 /* allocate new base block */ 00126 if ( FT_ALLOC( table->block, new_size ) ) 00127 { 00128 table->block = old_base; 00129 return error; 00130 } 00131 00132 /* copy elements and shift offsets */ 00133 if ( old_base ) 00134 { 00135 FT_MEM_COPY( table->block, old_base, table->capacity ); 00136 shift_elements( table, old_base ); 00137 FT_FREE( old_base ); 00138 } 00139 00140 table->capacity = new_size; 00141 00142 return PSaux_Err_Ok; 00143 } 00144 00145 00146 /*************************************************************************/ 00147 /* */ 00148 /* <Function> */ 00149 /* ps_table_add */ 00150 /* */ 00151 /* <Description> */ 00152 /* Adds an object to a PS_Table, possibly growing its memory block. */ 00153 /* */ 00154 /* <InOut> */ 00155 /* table :: The target table. */ 00156 /* */ 00157 /* <Input> */ 00158 /* idx :: The index of the object in the table. */ 00159 /* */ 00160 /* object :: The address of the object to copy in memory. */ 00161 /* */ 00162 /* length :: The length in bytes of the source object. */ 00163 /* */ 00164 /* <Return> */ 00165 /* FreeType error code. 0 means success. An error is returned if a */ 00166 /* reallocation fails. */ 00167 /* */ 00168 FT_LOCAL_DEF( FT_Error ) 00169 ps_table_add( PS_Table table, 00170 FT_Int idx, 00171 void* object, 00172 FT_PtrDist length ) 00173 { 00174 if ( idx < 0 || idx >= table->max_elems ) 00175 { 00176 FT_ERROR(( "ps_table_add: invalid index\n" )); 00177 return PSaux_Err_Invalid_Argument; 00178 } 00179 00180 if ( length < 0 ) 00181 { 00182 FT_ERROR(( "ps_table_add: invalid length\n" )); 00183 return PSaux_Err_Invalid_Argument; 00184 } 00185 00186 /* grow the base block if needed */ 00187 if ( table->cursor + length > table->capacity ) 00188 { 00189 FT_Error error; 00190 FT_Offset new_size = table->capacity; 00191 FT_Long in_offset; 00192 00193 00194 in_offset = (FT_Long)((FT_Byte*)object - table->block); 00195 if ( (FT_ULong)in_offset >= table->capacity ) 00196 in_offset = -1; 00197 00198 while ( new_size < table->cursor + length ) 00199 { 00200 /* increase size by 25% and round up to the nearest multiple 00201 of 1024 */ 00202 new_size += ( new_size >> 2 ) + 1; 00203 new_size = FT_PAD_CEIL( new_size, 1024 ); 00204 } 00205 00206 error = reallocate_t1_table( table, new_size ); 00207 if ( error ) 00208 return error; 00209 00210 if ( in_offset >= 0 ) 00211 object = table->block + in_offset; 00212 } 00213 00214 /* add the object to the base block and adjust offset */ 00215 table->elements[idx] = table->block + table->cursor; 00216 table->lengths [idx] = length; 00217 FT_MEM_COPY( table->block + table->cursor, object, length ); 00218 00219 table->cursor += length; 00220 return PSaux_Err_Ok; 00221 } 00222 00223 00224 /*************************************************************************/ 00225 /* */ 00226 /* <Function> */ 00227 /* ps_table_done */ 00228 /* */ 00229 /* <Description> */ 00230 /* Finalizes a PS_TableRec (i.e., reallocate it to its current */ 00231 /* cursor). */ 00232 /* */ 00233 /* <InOut> */ 00234 /* table :: The target table. */ 00235 /* */ 00236 /* <Note> */ 00237 /* This function does NOT release the heap's memory block. It is up */ 00238 /* to the caller to clean it, or reference it in its own structures. */ 00239 /* */ 00240 FT_LOCAL_DEF( void ) 00241 ps_table_done( PS_Table table ) 00242 { 00243 FT_Memory memory = table->memory; 00244 FT_Error error; 00245 FT_Byte* old_base = table->block; 00246 00247 00248 /* should never fail, because rec.cursor <= rec.size */ 00249 if ( !old_base ) 00250 return; 00251 00252 if ( FT_ALLOC( table->block, table->cursor ) ) 00253 return; 00254 FT_MEM_COPY( table->block, old_base, table->cursor ); 00255 shift_elements( table, old_base ); 00256 00257 table->capacity = table->cursor; 00258 FT_FREE( old_base ); 00259 00260 FT_UNUSED( error ); 00261 } 00262 00263 00264 FT_LOCAL_DEF( void ) 00265 ps_table_release( PS_Table table ) 00266 { 00267 FT_Memory memory = table->memory; 00268 00269 00270 if ( (FT_ULong)table->init == 0xDEADBEEFUL ) 00271 { 00272 FT_FREE( table->block ); 00273 FT_FREE( table->elements ); 00274 FT_FREE( table->lengths ); 00275 table->init = 0; 00276 } 00277 } 00278 00279 00280 /*************************************************************************/ 00281 /*************************************************************************/ 00282 /***** *****/ 00283 /***** T1 PARSER *****/ 00284 /***** *****/ 00285 /*************************************************************************/ 00286 /*************************************************************************/ 00287 00288 00289 /* first character must be already part of the comment */ 00290 00291 static void 00292 skip_comment( FT_Byte* *acur, 00293 FT_Byte* limit ) 00294 { 00295 FT_Byte* cur = *acur; 00296 00297 00298 while ( cur < limit ) 00299 { 00300 if ( IS_PS_NEWLINE( *cur ) ) 00301 break; 00302 cur++; 00303 } 00304 00305 *acur = cur; 00306 } 00307 00308 00309 static void 00310 skip_spaces( FT_Byte* *acur, 00311 FT_Byte* limit ) 00312 { 00313 FT_Byte* cur = *acur; 00314 00315 00316 while ( cur < limit ) 00317 { 00318 if ( !IS_PS_SPACE( *cur ) ) 00319 { 00320 if ( *cur == '%' ) 00321 /* According to the PLRM, a comment is equal to a space. */ 00322 skip_comment( &cur, limit ); 00323 else 00324 break; 00325 } 00326 cur++; 00327 } 00328 00329 *acur = cur; 00330 } 00331 00332 00333 #define IS_OCTAL_DIGIT( c ) ( '0' <= (c) && (c) <= '7' ) 00334 00335 00336 /* first character must be `('; */ 00337 /* *acur is positioned at the character after the closing `)' */ 00338 00339 static FT_Error 00340 skip_literal_string( FT_Byte* *acur, 00341 FT_Byte* limit ) 00342 { 00343 FT_Byte* cur = *acur; 00344 FT_Int embed = 0; 00345 FT_Error error = PSaux_Err_Invalid_File_Format; 00346 unsigned int i; 00347 00348 00349 while ( cur < limit ) 00350 { 00351 FT_Byte c = *cur; 00352 00353 00354 ++cur; 00355 00356 if ( c == '\\' ) 00357 { 00358 /* Red Book 3rd ed., section `Literal Text Strings', p. 29: */ 00359 /* A backslash can introduce three different types */ 00360 /* of escape sequences: */ 00361 /* - a special escaped char like \r, \n, etc. */ 00362 /* - a one-, two-, or three-digit octal number */ 00363 /* - none of the above in which case the backslash is ignored */ 00364 00365 if ( cur == limit ) 00366 /* error (or to be ignored?) */ 00367 break; 00368 00369 switch ( *cur ) 00370 { 00371 /* skip `special' escape */ 00372 case 'n': 00373 case 'r': 00374 case 't': 00375 case 'b': 00376 case 'f': 00377 case '\\': 00378 case '(': 00379 case ')': 00380 ++cur; 00381 break; 00382 00383 default: 00384 /* skip octal escape or ignore backslash */ 00385 for ( i = 0; i < 3 && cur < limit; ++i ) 00386 { 00387 if ( !IS_OCTAL_DIGIT( *cur ) ) 00388 break; 00389 00390 ++cur; 00391 } 00392 } 00393 } 00394 else if ( c == '(' ) 00395 embed++; 00396 else if ( c == ')' ) 00397 { 00398 embed--; 00399 if ( embed == 0 ) 00400 { 00401 error = PSaux_Err_Ok; 00402 break; 00403 } 00404 } 00405 } 00406 00407 *acur = cur; 00408 00409 return error; 00410 } 00411 00412 00413 /* first character must be `<' */ 00414 00415 static FT_Error 00416 skip_string( FT_Byte* *acur, 00417 FT_Byte* limit ) 00418 { 00419 FT_Byte* cur = *acur; 00420 FT_Error err = PSaux_Err_Ok; 00421 00422 00423 while ( ++cur < limit ) 00424 { 00425 /* All whitespace characters are ignored. */ 00426 skip_spaces( &cur, limit ); 00427 if ( cur >= limit ) 00428 break; 00429 00430 if ( !IS_PS_XDIGIT( *cur ) ) 00431 break; 00432 } 00433 00434 if ( cur < limit && *cur != '>' ) 00435 { 00436 FT_ERROR(( "skip_string: missing closing delimiter `>'\n" )); 00437 err = PSaux_Err_Invalid_File_Format; 00438 } 00439 else 00440 cur++; 00441 00442 *acur = cur; 00443 return err; 00444 } 00445 00446 00447 /* first character must be the opening brace that */ 00448 /* starts the procedure */ 00449 00450 /* NB: [ and ] need not match: */ 00451 /* `/foo {[} def' is a valid PostScript fragment, */ 00452 /* even within a Type1 font */ 00453 00454 static FT_Error 00455 skip_procedure( FT_Byte* *acur, 00456 FT_Byte* limit ) 00457 { 00458 FT_Byte* cur; 00459 FT_Int embed = 0; 00460 FT_Error error = PSaux_Err_Ok; 00461 00462 00463 FT_ASSERT( **acur == '{' ); 00464 00465 for ( cur = *acur; cur < limit && error == PSaux_Err_Ok; ++cur ) 00466 { 00467 switch ( *cur ) 00468 { 00469 case '{': 00470 ++embed; 00471 break; 00472 00473 case '}': 00474 --embed; 00475 if ( embed == 0 ) 00476 { 00477 ++cur; 00478 goto end; 00479 } 00480 break; 00481 00482 case '(': 00483 error = skip_literal_string( &cur, limit ); 00484 break; 00485 00486 case '<': 00487 error = skip_string( &cur, limit ); 00488 break; 00489 00490 case '%': 00491 skip_comment( &cur, limit ); 00492 break; 00493 } 00494 } 00495 00496 end: 00497 if ( embed != 0 ) 00498 error = PSaux_Err_Invalid_File_Format; 00499 00500 *acur = cur; 00501 00502 return error; 00503 } 00504 00505 00506 /***********************************************************************/ 00507 /* */ 00508 /* All exported parsing routines handle leading whitespace and stop at */ 00509 /* the first character which isn't part of the just handled token. */ 00510 /* */ 00511 /***********************************************************************/ 00512 00513 00514 FT_LOCAL_DEF( void ) 00515 ps_parser_skip_PS_token( PS_Parser parser ) 00516 { 00517 /* Note: PostScript allows any non-delimiting, non-whitespace */ 00518 /* character in a name (PS Ref Manual, 3rd ed, p31). */ 00519 /* PostScript delimiters are (, ), <, >, [, ], {, }, /, and %. */ 00520 00521 FT_Byte* cur = parser->cursor; 00522 FT_Byte* limit = parser->limit; 00523 FT_Error error = PSaux_Err_Ok; 00524 00525 00526 skip_spaces( &cur, limit ); /* this also skips comments */ 00527 if ( cur >= limit ) 00528 goto Exit; 00529 00530 /* self-delimiting, single-character tokens */ 00531 if ( *cur == '[' || *cur == ']' ) 00532 { 00533 cur++; 00534 goto Exit; 00535 } 00536 00537 /* skip balanced expressions (procedures and strings) */ 00538 00539 if ( *cur == '{' ) /* {...} */ 00540 { 00541 error = skip_procedure( &cur, limit ); 00542 goto Exit; 00543 } 00544 00545 if ( *cur == '(' ) /* (...) */ 00546 { 00547 error = skip_literal_string( &cur, limit ); 00548 goto Exit; 00549 } 00550 00551 if ( *cur == '<' ) /* <...> */ 00552 { 00553 if ( cur + 1 < limit && *(cur + 1) == '<' ) /* << */ 00554 { 00555 cur++; 00556 cur++; 00557 } 00558 else 00559 error = skip_string( &cur, limit ); 00560 00561 goto Exit; 00562 } 00563 00564 if ( *cur == '>' ) 00565 { 00566 cur++; 00567 if ( cur >= limit || *cur != '>' ) /* >> */ 00568 { 00569 FT_ERROR(( "ps_parser_skip_PS_token:" 00570 " unexpected closing delimiter `>'\n" )); 00571 error = PSaux_Err_Invalid_File_Format; 00572 goto Exit; 00573 } 00574 cur++; 00575 goto Exit; 00576 } 00577 00578 if ( *cur == '/' ) 00579 cur++; 00580 00581 /* anything else */ 00582 while ( cur < limit ) 00583 { 00584 /* *cur might be invalid (e.g., ')' or '}'), but this */ 00585 /* is handled by the test `cur == parser->cursor' below */ 00586 if ( IS_PS_DELIM( *cur ) ) 00587 break; 00588 00589 cur++; 00590 } 00591 00592 Exit: 00593 if ( cur == parser->cursor ) 00594 { 00595 FT_ERROR(( "ps_parser_skip_PS_token:" 00596 " current token is `%c' which is self-delimiting\n" 00597 " " 00598 " but invalid at this point\n", 00599 *cur )); 00600 00601 error = PSaux_Err_Invalid_File_Format; 00602 } 00603 00604 parser->error = error; 00605 parser->cursor = cur; 00606 } 00607 00608 00609 FT_LOCAL_DEF( void ) 00610 ps_parser_skip_spaces( PS_Parser parser ) 00611 { 00612 skip_spaces( &parser->cursor, parser->limit ); 00613 } 00614 00615 00616 /* `token' here means either something between balanced delimiters */ 00617 /* or the next token; the delimiters are not removed. */ 00618 00619 FT_LOCAL_DEF( void ) 00620 ps_parser_to_token( PS_Parser parser, 00621 T1_Token token ) 00622 { 00623 FT_Byte* cur; 00624 FT_Byte* limit; 00625 FT_Int embed; 00626 00627 00628 token->type = T1_TOKEN_TYPE_NONE; 00629 token->start = 0; 00630 token->limit = 0; 00631 00632 /* first of all, skip leading whitespace */ 00633 ps_parser_skip_spaces( parser ); 00634 00635 cur = parser->cursor; 00636 limit = parser->limit; 00637 00638 if ( cur >= limit ) 00639 return; 00640 00641 switch ( *cur ) 00642 { 00643 /************* check for literal string *****************/ 00644 case '(': 00645 token->type = T1_TOKEN_TYPE_STRING; 00646 token->start = cur; 00647 00648 if ( skip_literal_string( &cur, limit ) == PSaux_Err_Ok ) 00649 token->limit = cur; 00650 break; 00651 00652 /************* check for programs/array *****************/ 00653 case '{': 00654 token->type = T1_TOKEN_TYPE_ARRAY; 00655 token->start = cur; 00656 00657 if ( skip_procedure( &cur, limit ) == PSaux_Err_Ok ) 00658 token->limit = cur; 00659 break; 00660 00661 /************* check for table/array ********************/ 00662 /* XXX: in theory we should also look for "<<" */ 00663 /* since this is semantically equivalent to "["; */ 00664 /* in practice it doesn't matter (?) */ 00665 case '[': 00666 token->type = T1_TOKEN_TYPE_ARRAY; 00667 embed = 1; 00668 token->start = cur++; 00669 00670 /* we need this to catch `[ ]' */ 00671 parser->cursor = cur; 00672 ps_parser_skip_spaces( parser ); 00673 cur = parser->cursor; 00674 00675 while ( cur < limit && !parser->error ) 00676 { 00677 /* XXX: this is wrong because it does not */ 00678 /* skip comments, procedures, and strings */ 00679 if ( *cur == '[' ) 00680 embed++; 00681 else if ( *cur == ']' ) 00682 { 00683 embed--; 00684 if ( embed <= 0 ) 00685 { 00686 token->limit = ++cur; 00687 break; 00688 } 00689 } 00690 00691 parser->cursor = cur; 00692 ps_parser_skip_PS_token( parser ); 00693 /* we need this to catch `[XXX ]' */ 00694 ps_parser_skip_spaces ( parser ); 00695 cur = parser->cursor; 00696 } 00697 break; 00698 00699 /* ************ otherwise, it is any token **************/ 00700 default: 00701 token->start = cur; 00702 token->type = ( *cur == '/' ? T1_TOKEN_TYPE_KEY : T1_TOKEN_TYPE_ANY ); 00703 ps_parser_skip_PS_token( parser ); 00704 cur = parser->cursor; 00705 if ( !parser->error ) 00706 token->limit = cur; 00707 } 00708 00709 if ( !token->limit ) 00710 { 00711 token->start = 0; 00712 token->type = T1_TOKEN_TYPE_NONE; 00713 } 00714 00715 parser->cursor = cur; 00716 } 00717 00718 00719 /* NB: `tokens' can be NULL if we only want to count */ 00720 /* the number of array elements */ 00721 00722 FT_LOCAL_DEF( void ) 00723 ps_parser_to_token_array( PS_Parser parser, 00724 T1_Token tokens, 00725 FT_UInt max_tokens, 00726 FT_Int* pnum_tokens ) 00727 { 00728 T1_TokenRec master; 00729 00730 00731 *pnum_tokens = -1; 00732 00733 /* this also handles leading whitespace */ 00734 ps_parser_to_token( parser, &master ); 00735 00736 if ( master.type == T1_TOKEN_TYPE_ARRAY ) 00737 { 00738 FT_Byte* old_cursor = parser->cursor; 00739 FT_Byte* old_limit = parser->limit; 00740 T1_Token cur = tokens; 00741 T1_Token limit = cur + max_tokens; 00742 00743 00744 /* don't include outermost delimiters */ 00745 parser->cursor = master.start + 1; 00746 parser->limit = master.limit - 1; 00747 00748 while ( parser->cursor < parser->limit ) 00749 { 00750 T1_TokenRec token; 00751 00752 00753 ps_parser_to_token( parser, &token ); 00754 if ( !token.type ) 00755 break; 00756 00757 if ( tokens != NULL && cur < limit ) 00758 *cur = token; 00759 00760 cur++; 00761 } 00762 00763 *pnum_tokens = (FT_Int)( cur - tokens ); 00764 00765 parser->cursor = old_cursor; 00766 parser->limit = old_limit; 00767 } 00768 } 00769 00770 00771 /* first character must be a delimiter or a part of a number */ 00772 /* NB: `coords' can be NULL if we just want to skip the */ 00773 /* array; in this case we ignore `max_coords' */ 00774 00775 static FT_Int 00776 ps_tocoordarray( FT_Byte* *acur, 00777 FT_Byte* limit, 00778 FT_Int max_coords, 00779 FT_Short* coords ) 00780 { 00781 FT_Byte* cur = *acur; 00782 FT_Int count = 0; 00783 FT_Byte c, ender; 00784 00785 00786 if ( cur >= limit ) 00787 goto Exit; 00788 00789 /* check for the beginning of an array; otherwise, only one number */ 00790 /* will be read */ 00791 c = *cur; 00792 ender = 0; 00793 00794 if ( c == '[' ) 00795 ender = ']'; 00796 else if ( c == '{' ) 00797 ender = '}'; 00798 00799 if ( ender ) 00800 cur++; 00801 00802 /* now, read the coordinates */ 00803 while ( cur < limit ) 00804 { 00805 FT_Short dummy; 00806 FT_Byte* old_cur; 00807 00808 00809 /* skip whitespace in front of data */ 00810 skip_spaces( &cur, limit ); 00811 if ( cur >= limit ) 00812 goto Exit; 00813 00814 if ( *cur == ender ) 00815 { 00816 cur++; 00817 break; 00818 } 00819 00820 old_cur = cur; 00821 00822 if ( coords != NULL && count >= max_coords ) 00823 break; 00824 00825 /* call PS_Conv_ToFixed() even if coords == NULL */ 00826 /* to properly parse number at `cur' */ 00827 *( coords != NULL ? &coords[count] : &dummy ) = 00828 (FT_Short)( PS_Conv_ToFixed( &cur, limit, 0 ) >> 16 ); 00829 00830 if ( old_cur == cur ) 00831 { 00832 count = -1; 00833 goto Exit; 00834 } 00835 else 00836 count++; 00837 00838 if ( !ender ) 00839 break; 00840 } 00841 00842 Exit: 00843 *acur = cur; 00844 return count; 00845 } 00846 00847 00848 /* first character must be a delimiter or a part of a number */ 00849 /* NB: `values' can be NULL if we just want to skip the */ 00850 /* array; in this case we ignore `max_values' */ 00851 00852 static FT_Int 00853 ps_tofixedarray( FT_Byte* *acur, 00854 FT_Byte* limit, 00855 FT_Int max_values, 00856 FT_Fixed* values, 00857 FT_Int power_ten ) 00858 { 00859 FT_Byte* cur = *acur; 00860 FT_Int count = 0; 00861 FT_Byte c, ender; 00862 00863 00864 if ( cur >= limit ) 00865 goto Exit; 00866 00867 /* Check for the beginning of an array. Otherwise, only one number */ 00868 /* will be read. */ 00869 c = *cur; 00870 ender = 0; 00871 00872 if ( c == '[' ) 00873 ender = ']'; 00874 else if ( c == '{' ) 00875 ender = '}'; 00876 00877 if ( ender ) 00878 cur++; 00879 00880 /* now, read the values */ 00881 while ( cur < limit ) 00882 { 00883 FT_Fixed dummy; 00884 FT_Byte* old_cur; 00885 00886 00887 /* skip whitespace in front of data */ 00888 skip_spaces( &cur, limit ); 00889 if ( cur >= limit ) 00890 goto Exit; 00891 00892 if ( *cur == ender ) 00893 { 00894 cur++; 00895 break; 00896 } 00897 00898 old_cur = cur; 00899 00900 if ( values != NULL && count >= max_values ) 00901 break; 00902 00903 /* call PS_Conv_ToFixed() even if coords == NULL */ 00904 /* to properly parse number at `cur' */ 00905 *( values != NULL ? &values[count] : &dummy ) = 00906 PS_Conv_ToFixed( &cur, limit, power_ten ); 00907 00908 if ( old_cur == cur ) 00909 { 00910 count = -1; 00911 goto Exit; 00912 } 00913 else 00914 count++; 00915 00916 if ( !ender ) 00917 break; 00918 } 00919 00920 Exit: 00921 *acur = cur; 00922 return count; 00923 } 00924 00925 00926 #if 0 00927 00928 static FT_String* 00929 ps_tostring( FT_Byte** cursor, 00930 FT_Byte* limit, 00931 FT_Memory memory ) 00932 { 00933 FT_Byte* cur = *cursor; 00934 FT_PtrDist len = 0; 00935 FT_Int count; 00936 FT_String* result; 00937 FT_Error error; 00938 00939 00940 /* XXX: some stupid fonts have a `Notice' or `Copyright' string */ 00941 /* that simply doesn't begin with an opening parenthesis, even */ 00942 /* though they have a closing one! E.g. "amuncial.pfb" */ 00943 /* */ 00944 /* We must deal with these ill-fated cases there. Note that */ 00945 /* these fonts didn't work with the old Type 1 driver as the */ 00946 /* notice/copyright was not recognized as a valid string token */ 00947 /* and made the old token parser commit errors. */ 00948 00949 while ( cur < limit && ( *cur == ' ' || *cur == '\t' ) ) 00950 cur++; 00951 if ( cur + 1 >= limit ) 00952 return 0; 00953 00954 if ( *cur == '(' ) 00955 cur++; /* skip the opening parenthesis, if there is one */ 00956 00957 *cursor = cur; 00958 count = 0; 00959 00960 /* then, count its length */ 00961 for ( ; cur < limit; cur++ ) 00962 { 00963 if ( *cur == '(' ) 00964 count++; 00965 00966 else if ( *cur == ')' ) 00967 { 00968 count--; 00969 if ( count < 0 ) 00970 break; 00971 } 00972 } 00973 00974 len = cur - *cursor; 00975 if ( cur >= limit || FT_ALLOC( result, len + 1 ) ) 00976 return 0; 00977 00978 /* now copy the string */ 00979 FT_MEM_COPY( result, *cursor, len ); 00980 result[len] = '\0'; 00981 *cursor = cur; 00982 return result; 00983 } 00984 00985 #endif /* 0 */ 00986 00987 00988 static int 00989 ps_tobool( FT_Byte* *acur, 00990 FT_Byte* limit ) 00991 { 00992 FT_Byte* cur = *acur; 00993 FT_Bool result = 0; 00994 00995 00996 /* return 1 if we find `true', 0 otherwise */ 00997 if ( cur + 3 < limit && 00998 cur[0] == 't' && 00999 cur[1] == 'r' && 01000 cur[2] == 'u' && 01001 cur[3] == 'e' ) 01002 { 01003 result = 1; 01004 cur += 5; 01005 } 01006 else if ( cur + 4 < limit && 01007 cur[0] == 'f' && 01008 cur[1] == 'a' && 01009 cur[2] == 'l' && 01010 cur[3] == 's' && 01011 cur[4] == 'e' ) 01012 { 01013 result = 0; 01014 cur += 6; 01015 } 01016 01017 *acur = cur; 01018 return result; 01019 } 01020 01021 01022 /* load a simple field (i.e. non-table) into the current list of objects */ 01023 01024 FT_LOCAL_DEF( FT_Error ) 01025 ps_parser_load_field( PS_Parser parser, 01026 const T1_Field field, 01027 void** objects, 01028 FT_UInt max_objects, 01029 FT_ULong* pflags ) 01030 { 01031 T1_TokenRec token; 01032 FT_Byte* cur; 01033 FT_Byte* limit; 01034 FT_UInt count; 01035 FT_UInt idx; 01036 FT_Error error; 01037 01038 01039 /* this also skips leading whitespace */ 01040 ps_parser_to_token( parser, &token ); 01041 if ( !token.type ) 01042 goto Fail; 01043 01044 count = 1; 01045 idx = 0; 01046 cur = token.start; 01047 limit = token.limit; 01048 01049 /* we must detect arrays in /FontBBox */ 01050 if ( field->type == T1_FIELD_TYPE_BBOX ) 01051 { 01052 T1_TokenRec token2; 01053 FT_Byte* old_cur = parser->cursor; 01054 FT_Byte* old_limit = parser->limit; 01055 01056 01057 /* don't include delimiters */ 01058 parser->cursor = token.start + 1; 01059 parser->limit = token.limit - 1; 01060 01061 ps_parser_to_token( parser, &token2 ); 01062 parser->cursor = old_cur; 01063 parser->limit = old_limit; 01064 01065 if ( token2.type == T1_TOKEN_TYPE_ARRAY ) 01066 goto FieldArray; 01067 } 01068 else if ( token.type == T1_TOKEN_TYPE_ARRAY ) 01069 { 01070 FieldArray: 01071 /* if this is an array and we have no blend, an error occurs */ 01072 if ( max_objects == 0 ) 01073 goto Fail; 01074 01075 count = max_objects; 01076 idx = 1; 01077 01078 /* don't include delimiters */ 01079 cur++; 01080 limit--; 01081 } 01082 01083 for ( ; count > 0; count--, idx++ ) 01084 { 01085 FT_Byte* q = (FT_Byte*)objects[idx] + field->offset; 01086 FT_Long val; 01087 FT_String* string; 01088 01089 01090 skip_spaces( &cur, limit ); 01091 01092 switch ( field->type ) 01093 { 01094 case T1_FIELD_TYPE_BOOL: 01095 val = ps_tobool( &cur, limit ); 01096 goto Store_Integer; 01097 01098 case T1_FIELD_TYPE_FIXED: 01099 val = PS_Conv_ToFixed( &cur, limit, 0 ); 01100 goto Store_Integer; 01101 01102 case T1_FIELD_TYPE_FIXED_1000: 01103 val = PS_Conv_ToFixed( &cur, limit, 3 ); 01104 goto Store_Integer; 01105 01106 case T1_FIELD_TYPE_INTEGER: 01107 val = PS_Conv_ToInt( &cur, limit ); 01108 /* fall through */ 01109 01110 Store_Integer: 01111 switch ( field->size ) 01112 { 01113 case (8 / FT_CHAR_BIT): 01114 *(FT_Byte*)q = (FT_Byte)val; 01115 break; 01116 01117 case (16 / FT_CHAR_BIT): 01118 *(FT_UShort*)q = (FT_UShort)val; 01119 break; 01120 01121 case (32 / FT_CHAR_BIT): 01122 *(FT_UInt32*)q = (FT_UInt32)val; 01123 break; 01124 01125 default: /* for 64-bit systems */ 01126 *(FT_Long*)q = val; 01127 } 01128 break; 01129 01130 case T1_FIELD_TYPE_STRING: 01131 case T1_FIELD_TYPE_KEY: 01132 { 01133 FT_Memory memory = parser->memory; 01134 FT_UInt len = (FT_UInt)( limit - cur ); 01135 01136 01137 if ( cur >= limit ) 01138 break; 01139 01140 /* we allow both a string or a name */ 01141 /* for cases like /FontName (foo) def */ 01142 if ( token.type == T1_TOKEN_TYPE_KEY ) 01143 { 01144 /* don't include leading `/' */ 01145 len--; 01146 cur++; 01147 } 01148 else if ( token.type == T1_TOKEN_TYPE_STRING ) 01149 { 01150 /* don't include delimiting parentheses */ 01151 /* XXX we don't handle <<...>> here */ 01152 /* XXX should we convert octal escapes? */ 01153 /* if so, what encoding should we use? */ 01154 cur++; 01155 len -= 2; 01156 } 01157 else 01158 { 01159 FT_ERROR(( "ps_parser_load_field:" 01160 " expected a name or string\n" 01161 " " 01162 " but found token of type %d instead\n", 01163 token.type )); 01164 error = PSaux_Err_Invalid_File_Format; 01165 goto Exit; 01166 } 01167 01168 /* for this to work (FT_String**)q must have been */ 01169 /* initialized to NULL */ 01170 if ( *(FT_String**)q != NULL ) 01171 { 01172 FT_TRACE0(( "ps_parser_load_field: overwriting field %s\n", 01173 field->ident )); 01174 FT_FREE( *(FT_String**)q ); 01175 *(FT_String**)q = NULL; 01176 } 01177 01178 if ( FT_ALLOC( string, len + 1 ) ) 01179 goto Exit; 01180 01181 FT_MEM_COPY( string, cur, len ); 01182 string[len] = 0; 01183 01184 *(FT_String**)q = string; 01185 } 01186 break; 01187 01188 case T1_FIELD_TYPE_BBOX: 01189 { 01190 FT_Fixed temp[4]; 01191 FT_BBox* bbox = (FT_BBox*)q; 01192 FT_Int result; 01193 01194 01195 result = ps_tofixedarray( &cur, limit, 4, temp, 0 ); 01196 01197 if ( result < 0 ) 01198 { 01199 FT_ERROR(( "ps_parser_load_field:" 01200 " expected four integers in bounding box\n" )); 01201 error = PSaux_Err_Invalid_File_Format; 01202 goto Exit; 01203 } 01204 01205 bbox->xMin = FT_RoundFix( temp[0] ); 01206 bbox->yMin = FT_RoundFix( temp[1] ); 01207 bbox->xMax = FT_RoundFix( temp[2] ); 01208 bbox->yMax = FT_RoundFix( temp[3] ); 01209 } 01210 break; 01211 01212 default: 01213 /* an error occurred */ 01214 goto Fail; 01215 } 01216 } 01217 01218 #if 0 /* obsolete -- keep for reference */ 01219 if ( pflags ) 01220 *pflags |= 1L << field->flag_bit; 01221 #else 01222 FT_UNUSED( pflags ); 01223 #endif 01224 01225 error = PSaux_Err_Ok; 01226 01227 Exit: 01228 return error; 01229 01230 Fail: 01231 error = PSaux_Err_Invalid_File_Format; 01232 goto Exit; 01233 } 01234 01235 01236 #define T1_MAX_TABLE_ELEMENTS 32 01237 01238 01239 FT_LOCAL_DEF( FT_Error ) 01240 ps_parser_load_field_table( PS_Parser parser, 01241 const T1_Field field, 01242 void** objects, 01243 FT_UInt max_objects, 01244 FT_ULong* pflags ) 01245 { 01246 T1_TokenRec elements[T1_MAX_TABLE_ELEMENTS]; 01247 T1_Token token; 01248 FT_Int num_elements; 01249 FT_Error error = PSaux_Err_Ok; 01250 FT_Byte* old_cursor; 01251 FT_Byte* old_limit; 01252 T1_FieldRec fieldrec = *(T1_Field)field; 01253 01254 01255 fieldrec.type = T1_FIELD_TYPE_INTEGER; 01256 if ( field->type == T1_FIELD_TYPE_FIXED_ARRAY || 01257 field->type == T1_FIELD_TYPE_BBOX ) 01258 fieldrec.type = T1_FIELD_TYPE_FIXED; 01259 01260 ps_parser_to_token_array( parser, elements, 01261 T1_MAX_TABLE_ELEMENTS, &num_elements ); 01262 if ( num_elements < 0 ) 01263 { 01264 error = PSaux_Err_Ignore; 01265 goto Exit; 01266 } 01267 if ( (FT_UInt)num_elements > field->array_max ) 01268 num_elements = field->array_max; 01269 01270 old_cursor = parser->cursor; 01271 old_limit = parser->limit; 01272 01273 /* we store the elements count if necessary; */ 01274 /* we further assume that `count_offset' can't be zero */ 01275 if ( field->type != T1_FIELD_TYPE_BBOX && field->count_offset != 0 ) 01276 *(FT_Byte*)( (FT_Byte*)objects[0] + field->count_offset ) = 01277 (FT_Byte)num_elements; 01278 01279 /* we now load each element, adjusting the field.offset on each one */ 01280 token = elements; 01281 for ( ; num_elements > 0; num_elements--, token++ ) 01282 { 01283 parser->cursor = token->start; 01284 parser->limit = token->limit; 01285 ps_parser_load_field( parser, &fieldrec, objects, max_objects, 0 ); 01286 fieldrec.offset += fieldrec.size; 01287 } 01288 01289 #if 0 /* obsolete -- keep for reference */ 01290 if ( pflags ) 01291 *pflags |= 1L << field->flag_bit; 01292 #else 01293 FT_UNUSED( pflags ); 01294 #endif 01295 01296 parser->cursor = old_cursor; 01297 parser->limit = old_limit; 01298 01299 Exit: 01300 return error; 01301 } 01302 01303 01304 FT_LOCAL_DEF( FT_Long ) 01305 ps_parser_to_int( PS_Parser parser ) 01306 { 01307 ps_parser_skip_spaces( parser ); 01308 return PS_Conv_ToInt( &parser->cursor, parser->limit ); 01309 } 01310 01311 01312 /* first character must be `<' if `delimiters' is non-zero */ 01313 01314 FT_LOCAL_DEF( FT_Error ) 01315 ps_parser_to_bytes( PS_Parser parser, 01316 FT_Byte* bytes, 01317 FT_Offset max_bytes, 01318 FT_Long* pnum_bytes, 01319 FT_Bool delimiters ) 01320 { 01321 FT_Error error = PSaux_Err_Ok; 01322 FT_Byte* cur; 01323 01324 01325 ps_parser_skip_spaces( parser ); 01326 cur = parser->cursor; 01327 01328 if ( cur >= parser->limit ) 01329 goto Exit; 01330 01331 if ( delimiters ) 01332 { 01333 if ( *cur != '<' ) 01334 { 01335 FT_ERROR(( "ps_parser_to_bytes: Missing starting delimiter `<'\n" )); 01336 error = PSaux_Err_Invalid_File_Format; 01337 goto Exit; 01338 } 01339 01340 cur++; 01341 } 01342 01343 *pnum_bytes = PS_Conv_ASCIIHexDecode( &cur, 01344 parser->limit, 01345 bytes, 01346 max_bytes ); 01347 01348 if ( delimiters ) 01349 { 01350 if ( cur < parser->limit && *cur != '>' ) 01351 { 01352 FT_ERROR(( "ps_parser_to_bytes: Missing closing delimiter `>'\n" )); 01353 error = PSaux_Err_Invalid_File_Format; 01354 goto Exit; 01355 } 01356 01357 cur++; 01358 } 01359 01360 parser->cursor = cur; 01361 01362 Exit: 01363 return error; 01364 } 01365 01366 01367 FT_LOCAL_DEF( FT_Fixed ) 01368 ps_parser_to_fixed( PS_Parser parser, 01369 FT_Int power_ten ) 01370 { 01371 ps_parser_skip_spaces( parser ); 01372 return PS_Conv_ToFixed( &parser->cursor, parser->limit, power_ten ); 01373 } 01374 01375 01376 FT_LOCAL_DEF( FT_Int ) 01377 ps_parser_to_coord_array( PS_Parser parser, 01378 FT_Int max_coords, 01379 FT_Short* coords ) 01380 { 01381 ps_parser_skip_spaces( parser ); 01382 return ps_tocoordarray( &parser->cursor, parser->limit, 01383 max_coords, coords ); 01384 } 01385 01386 01387 FT_LOCAL_DEF( FT_Int ) 01388 ps_parser_to_fixed_array( PS_Parser parser, 01389 FT_Int max_values, 01390 FT_Fixed* values, 01391 FT_Int power_ten ) 01392 { 01393 ps_parser_skip_spaces( parser ); 01394 return ps_tofixedarray( &parser->cursor, parser->limit, 01395 max_values, values, power_ten ); 01396 } 01397 01398 01399 #if 0 01400 01401 FT_LOCAL_DEF( FT_String* ) 01402 T1_ToString( PS_Parser parser ) 01403 { 01404 return ps_tostring( &parser->cursor, parser->limit, parser->memory ); 01405 } 01406 01407 01408 FT_LOCAL_DEF( FT_Bool ) 01409 T1_ToBool( PS_Parser parser ) 01410 { 01411 return ps_tobool( &parser->cursor, parser->limit ); 01412 } 01413 01414 #endif /* 0 */ 01415 01416 01417 FT_LOCAL_DEF( void ) 01418 ps_parser_init( PS_Parser parser, 01419 FT_Byte* base, 01420 FT_Byte* limit, 01421 FT_Memory memory ) 01422 { 01423 parser->error = PSaux_Err_Ok; 01424 parser->base = base; 01425 parser->limit = limit; 01426 parser->cursor = base; 01427 parser->memory = memory; 01428 parser->funcs = ps_parser_funcs; 01429 } 01430 01431 01432 FT_LOCAL_DEF( void ) 01433 ps_parser_done( PS_Parser parser ) 01434 { 01435 FT_UNUSED( parser ); 01436 } 01437 01438 01439 /*************************************************************************/ 01440 /*************************************************************************/ 01441 /***** *****/ 01442 /***** T1 BUILDER *****/ 01443 /***** *****/ 01444 /*************************************************************************/ 01445 /*************************************************************************/ 01446 01447 /*************************************************************************/ 01448 /* */ 01449 /* <Function> */ 01450 /* t1_builder_init */ 01451 /* */ 01452 /* <Description> */ 01453 /* Initializes a given glyph builder. */ 01454 /* */ 01455 /* <InOut> */ 01456 /* builder :: A pointer to the glyph builder to initialize. */ 01457 /* */ 01458 /* <Input> */ 01459 /* face :: The current face object. */ 01460 /* */ 01461 /* size :: The current size object. */ 01462 /* */ 01463 /* glyph :: The current glyph object. */ 01464 /* */ 01465 /* hinting :: Whether hinting should be applied. */ 01466 /* */ 01467 FT_LOCAL_DEF( void ) 01468 t1_builder_init( T1_Builder builder, 01469 FT_Face face, 01470 FT_Size size, 01471 FT_GlyphSlot glyph, 01472 FT_Bool hinting ) 01473 { 01474 builder->parse_state = T1_Parse_Start; 01475 builder->load_points = 1; 01476 01477 builder->face = face; 01478 builder->glyph = glyph; 01479 builder->memory = face->memory; 01480 01481 if ( glyph ) 01482 { 01483 FT_GlyphLoader loader = glyph->internal->loader; 01484 01485 01486 builder->loader = loader; 01487 builder->base = &loader->base.outline; 01488 builder->current = &loader->current.outline; 01489 FT_GlyphLoader_Rewind( loader ); 01490 01491 builder->hints_globals = size->internal; 01492 builder->hints_funcs = 0; 01493 01494 if ( hinting ) 01495 builder->hints_funcs = glyph->internal->glyph_hints; 01496 } 01497 01498 builder->pos_x = 0; 01499 builder->pos_y = 0; 01500 01501 builder->left_bearing.x = 0; 01502 builder->left_bearing.y = 0; 01503 builder->advance.x = 0; 01504 builder->advance.y = 0; 01505 01506 builder->funcs = t1_builder_funcs; 01507 } 01508 01509 01510 /*************************************************************************/ 01511 /* */ 01512 /* <Function> */ 01513 /* t1_builder_done */ 01514 /* */ 01515 /* <Description> */ 01516 /* Finalizes a given glyph builder. Its contents can still be used */ 01517 /* after the call, but the function saves important information */ 01518 /* within the corresponding glyph slot. */ 01519 /* */ 01520 /* <Input> */ 01521 /* builder :: A pointer to the glyph builder to finalize. */ 01522 /* */ 01523 FT_LOCAL_DEF( void ) 01524 t1_builder_done( T1_Builder builder ) 01525 { 01526 FT_GlyphSlot glyph = builder->glyph; 01527 01528 01529 if ( glyph ) 01530 glyph->outline = *builder->base; 01531 } 01532 01533 01534 /* check that there is enough space for `count' more points */ 01535 FT_LOCAL_DEF( FT_Error ) 01536 t1_builder_check_points( T1_Builder builder, 01537 FT_Int count ) 01538 { 01539 return FT_GLYPHLOADER_CHECK_POINTS( builder->loader, count, 0 ); 01540 } 01541 01542 01543 /* add a new point, do not check space */ 01544 FT_LOCAL_DEF( void ) 01545 t1_builder_add_point( T1_Builder builder, 01546 FT_Pos x, 01547 FT_Pos y, 01548 FT_Byte flag ) 01549 { 01550 FT_Outline* outline = builder->current; 01551 01552 01553 if ( builder->load_points ) 01554 { 01555 FT_Vector* point = outline->points + outline->n_points; 01556 FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points; 01557 01558 01559 point->x = FIXED_TO_INT( x ); 01560 point->y = FIXED_TO_INT( y ); 01561 *control = (FT_Byte)( flag ? FT_CURVE_TAG_ON : FT_CURVE_TAG_CUBIC ); 01562 } 01563 outline->n_points++; 01564 } 01565 01566 01567 /* check space for a new on-curve point, then add it */ 01568 FT_LOCAL_DEF( FT_Error ) 01569 t1_builder_add_point1( T1_Builder builder, 01570 FT_Pos x, 01571 FT_Pos y ) 01572 { 01573 FT_Error error; 01574 01575 01576 error = t1_builder_check_points( builder, 1 ); 01577 if ( !error ) 01578 t1_builder_add_point( builder, x, y, 1 ); 01579 01580 return error; 01581 } 01582 01583 01584 /* check space for a new contour, then add it */ 01585 FT_LOCAL_DEF( FT_Error ) 01586 t1_builder_add_contour( T1_Builder builder ) 01587 { 01588 FT_Outline* outline = builder->current; 01589 FT_Error error; 01590 01591 01592 /* this might happen in invalid fonts */ 01593 if ( !outline ) 01594 { 01595 FT_ERROR(( "t1_builder_add_contour: no outline to add points to\n" )); 01596 return PSaux_Err_Invalid_File_Format; 01597 } 01598 01599 if ( !builder->load_points ) 01600 { 01601 outline->n_contours++; 01602 return PSaux_Err_Ok; 01603 } 01604 01605 error = FT_GLYPHLOADER_CHECK_POINTS( builder->loader, 0, 1 ); 01606 if ( !error ) 01607 { 01608 if ( outline->n_contours > 0 ) 01609 outline->contours[outline->n_contours - 1] = 01610 (short)( outline->n_points - 1 ); 01611 01612 outline->n_contours++; 01613 } 01614 01615 return error; 01616 } 01617 01618 01619 /* if a path was begun, add its first on-curve point */ 01620 FT_LOCAL_DEF( FT_Error ) 01621 t1_builder_start_point( T1_Builder builder, 01622 FT_Pos x, 01623 FT_Pos y ) 01624 { 01625 FT_Error error = PSaux_Err_Invalid_File_Format; 01626 01627 01628 /* test whether we are building a new contour */ 01629 01630 if ( builder->parse_state == T1_Parse_Have_Path ) 01631 error = PSaux_Err_Ok; 01632 else 01633 { 01634 builder->parse_state = T1_Parse_Have_Path; 01635 error = t1_builder_add_contour( builder ); 01636 if ( !error ) 01637 error = t1_builder_add_point1( builder, x, y ); 01638 } 01639 01640 return error; 01641 } 01642 01643 01644 /* close the current contour */ 01645 FT_LOCAL_DEF( void ) 01646 t1_builder_close_contour( T1_Builder builder ) 01647 { 01648 FT_Outline* outline = builder->current; 01649 FT_Int first; 01650 01651 01652 if ( !outline ) 01653 return; 01654 01655 first = outline->n_contours <= 1 01656 ? 0 : outline->contours[outline->n_contours - 2] + 1; 01657 01658 /* We must not include the last point in the path if it */ 01659 /* is located on the first point. */ 01660 if ( outline->n_points > 1 ) 01661 { 01662 FT_Vector* p1 = outline->points + first; 01663 FT_Vector* p2 = outline->points + outline->n_points - 1; 01664 FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points - 1; 01665 01666 01667 /* `delete' last point only if it coincides with the first */ 01668 /* point and it is not a control point (which can happen). */ 01669 if ( p1->x == p2->x && p1->y == p2->y ) 01670 if ( *control == FT_CURVE_TAG_ON ) 01671 outline->n_points--; 01672 } 01673 01674 if ( outline->n_contours > 0 ) 01675 { 01676 /* Don't add contours only consisting of one point, i.e., */ 01677 /* check whether the first and the last point is the same. */ 01678 if ( first == outline->n_points - 1 ) 01679 { 01680 outline->n_contours--; 01681 outline->n_points--; 01682 } 01683 else 01684 outline->contours[outline->n_contours - 1] = 01685 (short)( outline->n_points - 1 ); 01686 } 01687 } 01688 01689 01690 /*************************************************************************/ 01691 /*************************************************************************/ 01692 /***** *****/ 01693 /***** OTHER *****/ 01694 /***** *****/ 01695 /*************************************************************************/ 01696 /*************************************************************************/ 01697 01698 FT_LOCAL_DEF( void ) 01699 t1_decrypt( FT_Byte* buffer, 01700 FT_Offset length, 01701 FT_UShort seed ) 01702 { 01703 PS_Conv_EexecDecode( &buffer, 01704 buffer + length, 01705 buffer, 01706 length, 01707 &seed ); 01708 } 01709 01710 01711 /* END */ Generated on Mon May 28 2012 04:33:45 for ReactOS by
1.7.6.1
|