ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

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,   */
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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.