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

Generated on Tue Jul 5 14:13:50 2011 for ROOT_528-00b_version by  doxygen 1.5.1