Home | History | Annotate | Download | only in base
      1 /***************************************************************************/
      2 /*                                                                         */
      3 /*  ftobjs.c                                                               */
      4 /*                                                                         */
      5 /*    The FreeType private base classes (body).                            */
      6 /*                                                                         */
      7 /*  Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,   */
      8 /*            2010 by                                                      */
      9 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
     10 /*                                                                         */
     11 /*  This file is part of the FreeType project, and may only be used,       */
     12 /*  modified, and distributed under the terms of the FreeType project      */
     13 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
     14 /*  this file you indicate that you have read the license and              */
     15 /*  understand and accept it fully.                                        */
     16 /*                                                                         */
     17 /***************************************************************************/
     18 
     19 
     20 #include <ft2build.h>
     21 #include FT_LIST_H
     22 #include FT_OUTLINE_H
     23 #include FT_INTERNAL_VALIDATE_H
     24 #include FT_INTERNAL_OBJECTS_H
     25 #include FT_INTERNAL_DEBUG_H
     26 #include FT_INTERNAL_RFORK_H
     27 #include FT_INTERNAL_STREAM_H
     28 #include FT_INTERNAL_SFNT_H    /* for SFNT_Load_Table_Func */
     29 #include FT_TRUETYPE_TABLES_H
     30 #include FT_TRUETYPE_TAGS_H
     31 #include FT_TRUETYPE_IDS_H
     32 #include FT_OUTLINE_H
     33 
     34 #include FT_SERVICE_SFNT_H
     35 #include FT_SERVICE_POSTSCRIPT_NAME_H
     36 #include FT_SERVICE_GLYPH_DICT_H
     37 #include FT_SERVICE_TT_CMAP_H
     38 #include FT_SERVICE_KERNING_H
     39 #include FT_SERVICE_TRUETYPE_ENGINE_H
     40 
     41 #ifdef FT_CONFIG_OPTION_MAC_FONTS
     42 #include "ftbase.h"
     43 #endif
     44 
     45 #define GRID_FIT_METRICS
     46 
     47 
     48   FT_BASE_DEF( FT_Pointer )
     49   ft_service_list_lookup( FT_ServiceDesc  service_descriptors,
     50                           const char*     service_id )
     51   {
     52     FT_Pointer      result = NULL;
     53     FT_ServiceDesc  desc   = service_descriptors;
     54 
     55 
     56     if ( desc && service_id )
     57     {
     58       for ( ; desc->serv_id != NULL; desc++ )
     59       {
     60         if ( ft_strcmp( desc->serv_id, service_id ) == 0 )
     61         {
     62           result = (FT_Pointer)desc->serv_data;
     63           break;
     64         }
     65       }
     66     }
     67 
     68     return result;
     69   }
     70 
     71 
     72   FT_BASE_DEF( void )
     73   ft_validator_init( FT_Validator        valid,
     74                      const FT_Byte*      base,
     75                      const FT_Byte*      limit,
     76                      FT_ValidationLevel  level )
     77   {
     78     valid->base  = base;
     79     valid->limit = limit;
     80     valid->level = level;
     81     valid->error = FT_Err_Ok;
     82   }
     83 
     84 
     85   FT_BASE_DEF( FT_Int )
     86   ft_validator_run( FT_Validator  valid )
     87   {
     88     /* This function doesn't work!  None should call it. */
     89     FT_UNUSED( valid );
     90 
     91     return -1;
     92   }
     93 
     94 
     95   FT_BASE_DEF( void )
     96   ft_validator_error( FT_Validator  valid,
     97                       FT_Error      error )
     98   {
     99     /* since the cast below also disables the compiler's */
    100     /* type check, we introduce a dummy variable, which  */
    101     /* will be optimized away                            */
    102     volatile ft_jmp_buf* jump_buffer = &valid->jump_buffer;
    103 
    104 
    105     valid->error = error;
    106 
    107     /* throw away volatileness; use `jump_buffer' or the  */
    108     /* compiler may warn about an unused local variable   */
    109     ft_longjmp( *(ft_jmp_buf*) jump_buffer, 1 );
    110   }
    111 
    112 
    113   /*************************************************************************/
    114   /*************************************************************************/
    115   /*************************************************************************/
    116   /****                                                                 ****/
    117   /****                                                                 ****/
    118   /****                           S T R E A M                           ****/
    119   /****                                                                 ****/
    120   /****                                                                 ****/
    121   /*************************************************************************/
    122   /*************************************************************************/
    123   /*************************************************************************/
    124 
    125 
    126   /* create a new input stream from an FT_Open_Args structure */
    127   /*                                                          */
    128   FT_BASE_DEF( FT_Error )
    129   FT_Stream_New( FT_Library           library,
    130                  const FT_Open_Args*  args,
    131                  FT_Stream           *astream )
    132   {
    133     FT_Error   error;
    134     FT_Memory  memory;
    135     FT_Stream  stream;
    136 
    137 
    138     *astream = 0;
    139 
    140     if ( !library )
    141       return FT_Err_Invalid_Library_Handle;
    142 
    143     if ( !args )
    144       return FT_Err_Invalid_Argument;
    145 
    146     memory   = library->memory;
    147 
    148     if ( FT_NEW( stream ) )
    149       goto Exit;
    150 
    151     stream->memory = memory;
    152 
    153     if ( args->flags & FT_OPEN_MEMORY )
    154     {
    155       /* create a memory-based stream */
    156       FT_Stream_OpenMemory( stream,
    157                             (const FT_Byte*)args->memory_base,
    158                             args->memory_size );
    159     }
    160     else if ( args->flags & FT_OPEN_PATHNAME )
    161     {
    162       /* create a normal system stream */
    163       error = FT_Stream_Open( stream, args->pathname );
    164       stream->pathname.pointer = args->pathname;
    165     }
    166     else if ( ( args->flags & FT_OPEN_STREAM ) && args->stream )
    167     {
    168       /* use an existing, user-provided stream */
    169 
    170       /* in this case, we do not need to allocate a new stream object */
    171       /* since the caller is responsible for closing it himself       */
    172       FT_FREE( stream );
    173       stream = args->stream;
    174     }
    175     else
    176       error = FT_Err_Invalid_Argument;
    177 
    178     if ( error )
    179       FT_FREE( stream );
    180     else
    181       stream->memory = memory;  /* just to be certain */
    182 
    183     *astream = stream;
    184 
    185   Exit:
    186     return error;
    187   }
    188 
    189 
    190   FT_BASE_DEF( void )
    191   FT_Stream_Free( FT_Stream  stream,
    192                   FT_Int     external )
    193   {
    194     if ( stream )
    195     {
    196       FT_Memory  memory = stream->memory;
    197 
    198 
    199       FT_Stream_Close( stream );
    200 
    201       if ( !external )
    202         FT_FREE( stream );
    203     }
    204   }
    205 
    206 
    207   /*************************************************************************/
    208   /*                                                                       */
    209   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
    210   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
    211   /* messages during execution.                                            */
    212   /*                                                                       */
    213 #undef  FT_COMPONENT
    214 #define FT_COMPONENT  trace_objs
    215 
    216 
    217   /*************************************************************************/
    218   /*************************************************************************/
    219   /*************************************************************************/
    220   /****                                                                 ****/
    221   /****                                                                 ****/
    222   /****               FACE, SIZE & GLYPH SLOT OBJECTS                   ****/
    223   /****                                                                 ****/
    224   /****                                                                 ****/
    225   /*************************************************************************/
    226   /*************************************************************************/
    227   /*************************************************************************/
    228 
    229 
    230   static FT_Error
    231   ft_glyphslot_init( FT_GlyphSlot  slot )
    232   {
    233     FT_Driver         driver = slot->face->driver;
    234     FT_Driver_Class   clazz  = driver->clazz;
    235     FT_Memory         memory = driver->root.memory;
    236     FT_Error          error  = FT_Err_Ok;
    237     FT_Slot_Internal  internal;
    238 
    239 
    240     slot->library = driver->root.library;
    241 
    242     if ( FT_NEW( internal ) )
    243       goto Exit;
    244 
    245     slot->internal = internal;
    246 
    247     if ( FT_DRIVER_USES_OUTLINES( driver ) )
    248       error = FT_GlyphLoader_New( memory, &internal->loader );
    249 
    250     if ( !error && clazz->init_slot )
    251       error = clazz->init_slot( slot );
    252 
    253   Exit:
    254     return error;
    255   }
    256 
    257 
    258   FT_BASE_DEF( void )
    259   ft_glyphslot_free_bitmap( FT_GlyphSlot  slot )
    260   {
    261     if ( slot->internal && ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) )
    262     {
    263       FT_Memory  memory = FT_FACE_MEMORY( slot->face );
    264 
    265 
    266       FT_FREE( slot->bitmap.buffer );
    267       slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
    268     }
    269     else
    270     {
    271       /* assume that the bitmap buffer was stolen or not */
    272       /* allocated from the heap                         */
    273       slot->bitmap.buffer = NULL;
    274     }
    275   }
    276 
    277 
    278   FT_BASE_DEF( void )
    279   ft_glyphslot_set_bitmap( FT_GlyphSlot  slot,
    280                            FT_Byte*      buffer )
    281   {
    282     ft_glyphslot_free_bitmap( slot );
    283 
    284     slot->bitmap.buffer = buffer;
    285 
    286     FT_ASSERT( (slot->internal->flags & FT_GLYPH_OWN_BITMAP) == 0 );
    287   }
    288 
    289 
    290   FT_BASE_DEF( FT_Error )
    291   ft_glyphslot_alloc_bitmap( FT_GlyphSlot  slot,
    292                              FT_ULong      size )
    293   {
    294     FT_Memory  memory = FT_FACE_MEMORY( slot->face );
    295     FT_Error   error;
    296 
    297 
    298     if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
    299       FT_FREE( slot->bitmap.buffer );
    300     else
    301       slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
    302 
    303     (void)FT_ALLOC( slot->bitmap.buffer, size );
    304     return error;
    305   }
    306 
    307 
    308   static void
    309   ft_glyphslot_clear( FT_GlyphSlot  slot )
    310   {
    311     /* free bitmap if needed */
    312     ft_glyphslot_free_bitmap( slot );
    313 
    314     /* clear all public fields in the glyph slot */
    315     FT_ZERO( &slot->metrics );
    316     FT_ZERO( &slot->outline );
    317 
    318     slot->bitmap.width      = 0;
    319     slot->bitmap.rows       = 0;
    320     slot->bitmap.pitch      = 0;
    321     slot->bitmap.pixel_mode = 0;
    322     /* `slot->bitmap.buffer' has been handled by ft_glyphslot_free_bitmap */
    323 
    324     slot->bitmap_left   = 0;
    325     slot->bitmap_top    = 0;
    326     slot->num_subglyphs = 0;
    327     slot->subglyphs     = 0;
    328     slot->control_data  = 0;
    329     slot->control_len   = 0;
    330     slot->other         = 0;
    331     slot->format        = FT_GLYPH_FORMAT_NONE;
    332 
    333     slot->linearHoriAdvance = 0;
    334     slot->linearVertAdvance = 0;
    335     slot->lsb_delta         = 0;
    336     slot->rsb_delta         = 0;
    337   }
    338 
    339 
    340   static void
    341   ft_glyphslot_done( FT_GlyphSlot  slot )
    342   {
    343     FT_Driver        driver = slot->face->driver;
    344     FT_Driver_Class  clazz  = driver->clazz;
    345     FT_Memory        memory = driver->root.memory;
    346 
    347 
    348     if ( clazz->done_slot )
    349       clazz->done_slot( slot );
    350 
    351     /* free bitmap buffer if needed */
    352     ft_glyphslot_free_bitmap( slot );
    353 
    354     /* slot->internal might be NULL in out-of-memory situations */
    355     if ( slot->internal )
    356     {
    357     /* free glyph loader */
    358     if ( FT_DRIVER_USES_OUTLINES( driver ) )
    359     {
    360       FT_GlyphLoader_Done( slot->internal->loader );
    361       slot->internal->loader = 0;
    362     }
    363 
    364     FT_FREE( slot->internal );
    365     }
    366   }
    367 
    368 
    369   /* documentation is in ftobjs.h */
    370 
    371   FT_BASE_DEF( FT_Error )
    372   FT_New_GlyphSlot( FT_Face        face,
    373                     FT_GlyphSlot  *aslot )
    374   {
    375     FT_Error         error;
    376     FT_Driver        driver;
    377     FT_Driver_Class  clazz;
    378     FT_Memory        memory;
    379     FT_GlyphSlot     slot;
    380 
    381 
    382     if ( !face || !face->driver )
    383       return FT_Err_Invalid_Argument;
    384 
    385     driver = face->driver;
    386     clazz  = driver->clazz;
    387     memory = driver->root.memory;
    388 
    389     FT_TRACE4(( "FT_New_GlyphSlot: Creating new slot object\n" ));
    390     if ( !FT_ALLOC( slot, clazz->slot_object_size ) )
    391     {
    392       slot->face = face;
    393 
    394       error = ft_glyphslot_init( slot );
    395       if ( error )
    396       {
    397         ft_glyphslot_done( slot );
    398         FT_FREE( slot );
    399         goto Exit;
    400       }
    401 
    402       slot->next  = face->glyph;
    403       face->glyph = slot;
    404 
    405       if ( aslot )
    406         *aslot = slot;
    407     }
    408     else if ( aslot )
    409       *aslot = 0;
    410 
    411 
    412   Exit:
    413     FT_TRACE4(( "FT_New_GlyphSlot: Return %d\n", error ));
    414     return error;
    415   }
    416 
    417 
    418   /* documentation is in ftobjs.h */
    419 
    420   FT_BASE_DEF( void )
    421   FT_Done_GlyphSlot( FT_GlyphSlot  slot )
    422   {
    423     if ( slot )
    424     {
    425       FT_Driver     driver = slot->face->driver;
    426       FT_Memory     memory = driver->root.memory;
    427       FT_GlyphSlot  prev;
    428       FT_GlyphSlot  cur;
    429 
    430 
    431       /* Remove slot from its parent face's list */
    432       prev = NULL;
    433       cur  = slot->face->glyph;
    434 
    435       while ( cur )
    436       {
    437         if ( cur == slot )
    438         {
    439           if ( !prev )
    440             slot->face->glyph = cur->next;
    441           else
    442             prev->next = cur->next;
    443 
    444           ft_glyphslot_done( slot );
    445           FT_FREE( slot );
    446           break;
    447         }
    448         prev = cur;
    449         cur  = cur->next;
    450       }
    451     }
    452   }
    453 
    454 
    455   /* documentation is in freetype.h */
    456 
    457   FT_EXPORT_DEF( void )
    458   FT_Set_Transform( FT_Face     face,
    459                     FT_Matrix*  matrix,
    460                     FT_Vector*  delta )
    461   {
    462     FT_Face_Internal  internal;
    463 
    464 
    465     if ( !face )
    466       return;
    467 
    468     internal = face->internal;
    469 
    470     internal->transform_flags = 0;
    471 
    472     if ( !matrix )
    473     {
    474       internal->transform_matrix.xx = 0x10000L;
    475       internal->transform_matrix.xy = 0;
    476       internal->transform_matrix.yx = 0;
    477       internal->transform_matrix.yy = 0x10000L;
    478       matrix = &internal->transform_matrix;
    479     }
    480     else
    481       internal->transform_matrix = *matrix;
    482 
    483     /* set transform_flags bit flag 0 if `matrix' isn't the identity */
    484     if ( ( matrix->xy | matrix->yx ) ||
    485          matrix->xx != 0x10000L      ||
    486          matrix->yy != 0x10000L      )
    487       internal->transform_flags |= 1;
    488 
    489     if ( !delta )
    490     {
    491       internal->transform_delta.x = 0;
    492       internal->transform_delta.y = 0;
    493       delta = &internal->transform_delta;
    494     }
    495     else
    496       internal->transform_delta = *delta;
    497 
    498     /* set transform_flags bit flag 1 if `delta' isn't the null vector */
    499     if ( delta->x | delta->y )
    500       internal->transform_flags |= 2;
    501   }
    502 
    503 
    504   static FT_Renderer
    505   ft_lookup_glyph_renderer( FT_GlyphSlot  slot );
    506 
    507 
    508 #ifdef GRID_FIT_METRICS
    509   static void
    510   ft_glyphslot_grid_fit_metrics( FT_GlyphSlot  slot,
    511                                  FT_Bool       vertical )
    512   {
    513     FT_Glyph_Metrics*  metrics = &slot->metrics;
    514     FT_Pos             right, bottom;
    515 
    516 
    517     if ( vertical )
    518     {
    519       metrics->horiBearingX = FT_PIX_FLOOR( metrics->horiBearingX );
    520       metrics->horiBearingY = FT_PIX_CEIL ( metrics->horiBearingY );
    521 
    522       right  = FT_PIX_CEIL( metrics->vertBearingX + metrics->width );
    523       bottom = FT_PIX_CEIL( metrics->vertBearingY + metrics->height );
    524 
    525       metrics->vertBearingX = FT_PIX_FLOOR( metrics->vertBearingX );
    526       metrics->vertBearingY = FT_PIX_FLOOR( metrics->vertBearingY );
    527 
    528       metrics->width  = right - metrics->vertBearingX;
    529       metrics->height = bottom - metrics->vertBearingY;
    530     }
    531     else
    532     {
    533       metrics->vertBearingX = FT_PIX_FLOOR( metrics->vertBearingX );
    534       metrics->vertBearingY = FT_PIX_FLOOR( metrics->vertBearingY );
    535 
    536       right  = FT_PIX_CEIL ( metrics->horiBearingX + metrics->width );
    537       bottom = FT_PIX_FLOOR( metrics->horiBearingY - metrics->height );
    538 
    539       metrics->horiBearingX = FT_PIX_FLOOR( metrics->horiBearingX );
    540       metrics->horiBearingY = FT_PIX_CEIL ( metrics->horiBearingY );
    541 
    542       metrics->width  = right - metrics->horiBearingX;
    543       metrics->height = metrics->horiBearingY - bottom;
    544     }
    545 
    546     metrics->horiAdvance = FT_PIX_ROUND( metrics->horiAdvance );
    547     metrics->vertAdvance = FT_PIX_ROUND( metrics->vertAdvance );
    548   }
    549 #endif /* GRID_FIT_METRICS */
    550 
    551 
    552   /* documentation is in freetype.h */
    553 
    554   FT_EXPORT_DEF( FT_Error )
    555   FT_Load_Glyph( FT_Face   face,
    556                  FT_UInt   glyph_index,
    557                  FT_Int32  load_flags )
    558   {
    559     FT_Error      error;
    560     FT_Driver     driver;
    561     FT_GlyphSlot  slot;
    562     FT_Library    library;
    563     FT_Bool       autohint = FALSE;
    564     FT_Module     hinter;
    565 
    566 
    567     if ( !face || !face->size || !face->glyph )
    568       return FT_Err_Invalid_Face_Handle;
    569 
    570     /* The validity test for `glyph_index' is performed by the */
    571     /* font drivers.                                           */
    572 
    573     slot = face->glyph;
    574     ft_glyphslot_clear( slot );
    575 
    576     driver  = face->driver;
    577     library = driver->root.library;
    578     hinter  = library->auto_hinter;
    579 
    580     /* resolve load flags dependencies */
    581 
    582     if ( load_flags & FT_LOAD_NO_RECURSE )
    583       load_flags |= FT_LOAD_NO_SCALE         |
    584                     FT_LOAD_IGNORE_TRANSFORM;
    585 
    586     if ( load_flags & FT_LOAD_NO_SCALE )
    587     {
    588       load_flags |= FT_LOAD_NO_HINTING |
    589                     FT_LOAD_NO_BITMAP;
    590 
    591       load_flags &= ~FT_LOAD_RENDER;
    592     }
    593 
    594     /*
    595      * Determine whether we need to auto-hint or not.
    596      * The general rules are:
    597      *
    598      * - Do only auto-hinting if we have a hinter module, a scalable font
    599      *   format dealing with outlines, and no transforms except simple
    600      *   slants and/or rotations by integer multiples of 90 degrees.
    601      *
    602      * - Then, auto-hint if FT_LOAD_FORCE_AUTOHINT is set or if we don't
    603      *   have a native font hinter.
    604      *
    605      * - Otherwise, auto-hint for LIGHT hinting mode.
    606      *
    607      * - Exception: The font is `tricky' and requires the native hinter to
    608      *   load properly.
    609      */
    610 
    611     if ( hinter                                   &&
    612          !( load_flags & FT_LOAD_NO_HINTING )     &&
    613          !( load_flags & FT_LOAD_NO_AUTOHINT )    &&
    614          FT_DRIVER_IS_SCALABLE( driver )          &&
    615          FT_DRIVER_USES_OUTLINES( driver )        &&
    616          !FT_IS_TRICKY( face )                    &&
    617          ( ( face->internal->transform_matrix.yx == 0 &&
    618              face->internal->transform_matrix.xx != 0 ) ||
    619            ( face->internal->transform_matrix.xx == 0 &&
    620              face->internal->transform_matrix.yx != 0 ) ) )
    621     {
    622       if ( ( load_flags & FT_LOAD_FORCE_AUTOHINT ) ||
    623            !FT_DRIVER_HAS_HINTER( driver )         )
    624         autohint = TRUE;
    625       else
    626       {
    627         FT_Render_Mode  mode = FT_LOAD_TARGET_MODE( load_flags );
    628 
    629 
    630         if ( mode == FT_RENDER_MODE_LIGHT             ||
    631              face->internal->ignore_unpatented_hinter )
    632           autohint = TRUE;
    633       }
    634     }
    635 
    636     if ( autohint )
    637     {
    638       FT_AutoHinter_Service  hinting;
    639 
    640 
    641       /* try to load embedded bitmaps first if available            */
    642       /*                                                            */
    643       /* XXX: This is really a temporary hack that should disappear */
    644       /*      promptly with FreeType 2.1!                           */
    645       /*                                                            */
    646       if ( FT_HAS_FIXED_SIZES( face )             &&
    647           ( load_flags & FT_LOAD_NO_BITMAP ) == 0 )
    648       {
    649         error = driver->clazz->load_glyph( slot, face->size,
    650                                            glyph_index,
    651                                            load_flags | FT_LOAD_SBITS_ONLY );
    652 
    653         if ( !error && slot->format == FT_GLYPH_FORMAT_BITMAP )
    654           goto Load_Ok;
    655       }
    656 
    657       {
    658         FT_Face_Internal  internal        = face->internal;
    659         FT_Int            transform_flags = internal->transform_flags;
    660 
    661 
    662         /* since the auto-hinter calls FT_Load_Glyph by itself, */
    663         /* make sure that glyphs aren't transformed             */
    664         internal->transform_flags = 0;
    665 
    666         /* load auto-hinted outline */
    667         hinting = (FT_AutoHinter_Service)hinter->clazz->module_interface;
    668 
    669         error   = hinting->load_glyph( (FT_AutoHinter)hinter,
    670                                        slot, face->size,
    671                                        glyph_index, load_flags );
    672 
    673         internal->transform_flags = transform_flags;
    674       }
    675     }
    676     else
    677     {
    678       error = driver->clazz->load_glyph( slot,
    679                                          face->size,
    680                                          glyph_index,
    681                                          load_flags );
    682       if ( error )
    683         goto Exit;
    684 
    685       if ( slot->format == FT_GLYPH_FORMAT_OUTLINE )
    686       {
    687         /* check that the loaded outline is correct */
    688         error = FT_Outline_Check( &slot->outline );
    689         if ( error )
    690           goto Exit;
    691 
    692 #ifdef GRID_FIT_METRICS
    693         if ( !( load_flags & FT_LOAD_NO_HINTING ) )
    694           ft_glyphslot_grid_fit_metrics( slot,
    695               FT_BOOL( load_flags & FT_LOAD_VERTICAL_LAYOUT ) );
    696 #endif
    697       }
    698     }
    699 
    700   Load_Ok:
    701     /* compute the advance */
    702     if ( load_flags & FT_LOAD_VERTICAL_LAYOUT )
    703     {
    704       slot->advance.x = 0;
    705       slot->advance.y = slot->metrics.vertAdvance;
    706     }
    707     else
    708     {
    709       slot->advance.x = slot->metrics.horiAdvance;
    710       slot->advance.y = 0;
    711     }
    712 
    713     /* compute the linear advance in 16.16 pixels */
    714     if ( ( load_flags & FT_LOAD_LINEAR_DESIGN ) == 0  &&
    715          ( FT_IS_SCALABLE( face ) )                   )
    716     {
    717       FT_Size_Metrics*  metrics = &face->size->metrics;
    718 
    719 
    720       /* it's tricky! */
    721       slot->linearHoriAdvance = FT_MulDiv( slot->linearHoriAdvance,
    722                                            metrics->x_scale, 64 );
    723 
    724       slot->linearVertAdvance = FT_MulDiv( slot->linearVertAdvance,
    725                                            metrics->y_scale, 64 );
    726     }
    727 
    728     if ( ( load_flags & FT_LOAD_IGNORE_TRANSFORM ) == 0 )
    729     {
    730       FT_Face_Internal  internal = face->internal;
    731 
    732 
    733       /* now, transform the glyph image if needed */
    734       if ( internal->transform_flags )
    735       {
    736         /* get renderer */
    737         FT_Renderer  renderer = ft_lookup_glyph_renderer( slot );
    738 
    739 
    740         if ( renderer )
    741           error = renderer->clazz->transform_glyph(
    742                                      renderer, slot,
    743                                      &internal->transform_matrix,
    744                                      &internal->transform_delta );
    745         else if ( slot->format == FT_GLYPH_FORMAT_OUTLINE )
    746         {
    747           /* apply `standard' transformation if no renderer is available */
    748           if ( &internal->transform_matrix )
    749             FT_Outline_Transform( &slot->outline,
    750                                   &internal->transform_matrix );
    751 
    752           if ( &internal->transform_delta )
    753             FT_Outline_Translate( &slot->outline,
    754                                   internal->transform_delta.x,
    755                                   internal->transform_delta.y );
    756         }
    757 
    758         /* transform advance */
    759         FT_Vector_Transform( &slot->advance, &internal->transform_matrix );
    760       }
    761     }
    762 
    763     FT_TRACE5(( "  x advance: %d\n" , slot->advance.x ));
    764     FT_TRACE5(( "  y advance: %d\n" , slot->advance.y ));
    765 
    766     FT_TRACE5(( "  linear x advance: %d\n" , slot->linearHoriAdvance ));
    767     FT_TRACE5(( "  linear y advance: %d\n" , slot->linearVertAdvance ));
    768 
    769     /* do we need to render the image now? */
    770     if ( !error                                    &&
    771          slot->format != FT_GLYPH_FORMAT_BITMAP    &&
    772          slot->format != FT_GLYPH_FORMAT_COMPOSITE &&
    773          load_flags & FT_LOAD_RENDER )
    774     {
    775       FT_Render_Mode  mode = FT_LOAD_TARGET_MODE( load_flags );
    776 
    777 
    778       if ( mode == FT_RENDER_MODE_NORMAL      &&
    779            (load_flags & FT_LOAD_MONOCHROME ) )
    780         mode = FT_RENDER_MODE_MONO;
    781 
    782       error = FT_Render_Glyph( slot, mode );
    783     }
    784 
    785   Exit:
    786     return error;
    787   }
    788 
    789 
    790   /* documentation is in freetype.h */
    791 
    792   FT_EXPORT_DEF( FT_Error )
    793   FT_Load_Char( FT_Face   face,
    794                 FT_ULong  char_code,
    795                 FT_Int32  load_flags )
    796   {
    797     FT_UInt  glyph_index;
    798 
    799 
    800     if ( !face )
    801       return FT_Err_Invalid_Face_Handle;
    802 
    803     glyph_index = (FT_UInt)char_code;
    804     if ( face->charmap )
    805       glyph_index = FT_Get_Char_Index( face, char_code );
    806 
    807     return FT_Load_Glyph( face, glyph_index, load_flags );
    808   }
    809 
    810 
    811   /* destructor for sizes list */
    812   static void
    813   destroy_size( FT_Memory  memory,
    814                 FT_Size    size,
    815                 FT_Driver  driver )
    816   {
    817     /* finalize client-specific data */
    818     if ( size->generic.finalizer )
    819       size->generic.finalizer( size );
    820 
    821     /* finalize format-specific stuff */
    822     if ( driver->clazz->done_size )
    823       driver->clazz->done_size( size );
    824 
    825     FT_FREE( size->internal );
    826     FT_FREE( size );
    827   }
    828 
    829 
    830   static void
    831   ft_cmap_done_internal( FT_CMap  cmap );
    832 
    833 
    834   static void
    835   destroy_charmaps( FT_Face    face,
    836                     FT_Memory  memory )
    837   {
    838     FT_Int  n;
    839 
    840 
    841     if ( !face )
    842       return;
    843 
    844     for ( n = 0; n < face->num_charmaps; n++ )
    845     {
    846       FT_CMap  cmap = FT_CMAP( face->charmaps[n] );
    847 
    848 
    849       ft_cmap_done_internal( cmap );
    850 
    851       face->charmaps[n] = NULL;
    852     }
    853 
    854     FT_FREE( face->charmaps );
    855     face->num_charmaps = 0;
    856   }
    857 
    858 
    859   /* destructor for faces list */
    860   static void
    861   destroy_face( FT_Memory  memory,
    862                 FT_Face    face,
    863                 FT_Driver  driver )
    864   {
    865     FT_Driver_Class  clazz = driver->clazz;
    866 
    867 
    868     /* discard auto-hinting data */
    869     if ( face->autohint.finalizer )
    870       face->autohint.finalizer( face->autohint.data );
    871 
    872     /* Discard glyph slots for this face.                           */
    873     /* Beware!  FT_Done_GlyphSlot() changes the field `face->glyph' */
    874     while ( face->glyph )
    875       FT_Done_GlyphSlot( face->glyph );
    876 
    877     /* discard all sizes for this face */
    878     FT_List_Finalize( &face->sizes_list,
    879                       (FT_List_Destructor)destroy_size,
    880                       memory,
    881                       driver );
    882     face->size = 0;
    883 
    884     /* now discard client data */
    885     if ( face->generic.finalizer )
    886       face->generic.finalizer( face );
    887 
    888     /* discard charmaps */
    889     destroy_charmaps( face, memory );
    890 
    891     /* finalize format-specific stuff */
    892     if ( clazz->done_face )
    893       clazz->done_face( face );
    894 
    895     /* close the stream for this face if needed */
    896     FT_Stream_Free(
    897       face->stream,
    898       ( face->face_flags & FT_FACE_FLAG_EXTERNAL_STREAM ) != 0 );
    899 
    900     face->stream = 0;
    901 
    902     /* get rid of it */
    903     if ( face->internal )
    904     {
    905       FT_FREE( face->internal );
    906     }
    907     FT_FREE( face );
    908   }
    909 
    910 
    911   static void
    912   Destroy_Driver( FT_Driver  driver )
    913   {
    914     FT_List_Finalize( &driver->faces_list,
    915                       (FT_List_Destructor)destroy_face,
    916                       driver->root.memory,
    917                       driver );
    918 
    919     /* check whether we need to drop the driver's glyph loader */
    920     if ( FT_DRIVER_USES_OUTLINES( driver ) )
    921       FT_GlyphLoader_Done( driver->glyph_loader );
    922   }
    923 
    924 
    925   /*************************************************************************/
    926   /*                                                                       */
    927   /* <Function>                                                            */
    928   /*    find_unicode_charmap                                               */
    929   /*                                                                       */
    930   /* <Description>                                                         */
    931   /*    This function finds a Unicode charmap, if there is one.            */
    932   /*    And if there is more than one, it tries to favour the more         */
    933   /*    extensive one, i.e., one that supports UCS-4 against those which   */
    934   /*    are limited to the BMP (said UCS-2 encoding.)                      */
    935   /*                                                                       */
    936   /*    This function is called from open_face() (just below), and also    */
    937   /*    from FT_Select_Charmap( ..., FT_ENCODING_UNICODE ).                */
    938   /*                                                                       */
    939   static FT_Error
    940   find_unicode_charmap( FT_Face  face )
    941   {
    942     FT_CharMap*  first;
    943     FT_CharMap*  cur;
    944 
    945 
    946     /* caller should have already checked that `face' is valid */
    947     FT_ASSERT( face );
    948 
    949     first = face->charmaps;
    950 
    951     if ( !first )
    952       return FT_Err_Invalid_CharMap_Handle;
    953 
    954     /*
    955      *  The original TrueType specification(s) only specified charmap
    956      *  formats that are capable of mapping 8 or 16 bit character codes to
    957      *  glyph indices.
    958      *
    959      *  However, recent updates to the Apple and OpenType specifications
    960      *  introduced new formats that are capable of mapping 32-bit character
    961      *  codes as well.  And these are already used on some fonts, mainly to
    962      *  map non-BMP Asian ideographs as defined in Unicode.
    963      *
    964      *  For compatibility purposes, these fonts generally come with
    965      *  *several* Unicode charmaps:
    966      *
    967      *   - One of them in the "old" 16-bit format, that cannot access
    968      *     all glyphs in the font.
    969      *
    970      *   - Another one in the "new" 32-bit format, that can access all
    971      *     the glyphs.
    972      *
    973      *  This function has been written to always favor a 32-bit charmap
    974      *  when found.  Otherwise, a 16-bit one is returned when found.
    975      */
    976 
    977     /* Since the `interesting' table, with IDs (3,10), is normally the */
    978     /* last one, we loop backwards.  This loses with type1 fonts with  */
    979     /* non-BMP characters (<.0001%), this wins with .ttf with non-BMP  */
    980     /* chars (.01% ?), and this is the same about 99.99% of the time!  */
    981 
    982     cur = first + face->num_charmaps;  /* points after the last one */
    983 
    984     for ( ; --cur >= first; )
    985     {
    986       if ( cur[0]->encoding == FT_ENCODING_UNICODE )
    987       {
    988         /* XXX If some new encodings to represent UCS-4 are added, */
    989         /*     they should be added here.                          */
    990         if ( ( cur[0]->platform_id == TT_PLATFORM_MICROSOFT &&
    991                cur[0]->encoding_id == TT_MS_ID_UCS_4        )     ||
    992              ( cur[0]->platform_id == TT_PLATFORM_APPLE_UNICODE &&
    993                cur[0]->encoding_id == TT_APPLE_ID_UNICODE_32    ) )
    994         {
    995           face->charmap = cur[0];
    996           return FT_Err_Ok;
    997         }
    998       }
    999     }
   1000 
   1001     /* We do not have any UCS-4 charmap.                */
   1002     /* Do the loop again and search for UCS-2 charmaps. */
   1003     cur = first + face->num_charmaps;
   1004 
   1005     for ( ; --cur >= first; )
   1006     {
   1007       if ( cur[0]->encoding == FT_ENCODING_UNICODE )
   1008       {
   1009         face->charmap = cur[0];
   1010         return FT_Err_Ok;
   1011       }
   1012     }
   1013 
   1014     return FT_Err_Invalid_CharMap_Handle;
   1015   }
   1016 
   1017 
   1018   /*************************************************************************/
   1019   /*                                                                       */
   1020   /* <Function>                                                            */
   1021   /*    find_variant_selector_charmap                                      */
   1022   /*                                                                       */
   1023   /* <Description>                                                         */
   1024   /*    This function finds the variant selector charmap, if there is one. */
   1025   /*    There can only be one (platform=0, specific=5, format=14).         */
   1026   /*                                                                       */
   1027   static FT_CharMap
   1028   find_variant_selector_charmap( FT_Face  face )
   1029   {
   1030     FT_CharMap*  first;
   1031     FT_CharMap*  end;
   1032     FT_CharMap*  cur;
   1033 
   1034 
   1035     /* caller should have already checked that `face' is valid */
   1036     FT_ASSERT( face );
   1037 
   1038     first = face->charmaps;
   1039 
   1040     if ( !first )
   1041       return NULL;
   1042 
   1043     end = first + face->num_charmaps;  /* points after the last one */
   1044 
   1045     for ( cur = first; cur < end; ++cur )
   1046     {
   1047       if ( cur[0]->platform_id == TT_PLATFORM_APPLE_UNICODE    &&
   1048            cur[0]->encoding_id == TT_APPLE_ID_VARIANT_SELECTOR &&
   1049            FT_Get_CMap_Format( cur[0] ) == 14                  )
   1050         return cur[0];
   1051     }
   1052 
   1053     return NULL;
   1054   }
   1055 
   1056 
   1057   /*************************************************************************/
   1058   /*                                                                       */
   1059   /* <Function>                                                            */
   1060   /*    open_face                                                          */
   1061   /*                                                                       */
   1062   /* <Description>                                                         */
   1063   /*    This function does some work for FT_Open_Face().                   */
   1064   /*                                                                       */
   1065   static FT_Error
   1066   open_face( FT_Driver      driver,
   1067              FT_Stream      stream,
   1068              FT_Long        face_index,
   1069              FT_Int         num_params,
   1070              FT_Parameter*  params,
   1071              FT_Face       *aface )
   1072   {
   1073     FT_Memory         memory;
   1074     FT_Driver_Class   clazz;
   1075     FT_Face           face = 0;
   1076     FT_Error          error, error2;
   1077     FT_Face_Internal  internal = NULL;
   1078 
   1079 
   1080     clazz  = driver->clazz;
   1081     memory = driver->root.memory;
   1082 
   1083     /* allocate the face object and perform basic initialization */
   1084     if ( FT_ALLOC( face, clazz->face_object_size ) )
   1085       goto Fail;
   1086 
   1087     if ( FT_NEW( internal ) )
   1088       goto Fail;
   1089 
   1090     face->internal = internal;
   1091 
   1092     face->driver   = driver;
   1093     face->memory   = memory;
   1094     face->stream   = stream;
   1095 
   1096 #ifdef FT_CONFIG_OPTION_INCREMENTAL
   1097     {
   1098       int  i;
   1099 
   1100 
   1101       face->internal->incremental_interface = 0;
   1102       for ( i = 0; i < num_params && !face->internal->incremental_interface;
   1103             i++ )
   1104         if ( params[i].tag == FT_PARAM_TAG_INCREMENTAL )
   1105           face->internal->incremental_interface =
   1106             (FT_Incremental_Interface)params[i].data;
   1107     }
   1108 #endif
   1109 
   1110     if ( clazz->init_face )
   1111       error = clazz->init_face( stream,
   1112                                 face,
   1113                                 (FT_Int)face_index,
   1114                                 num_params,
   1115                                 params );
   1116     if ( error )
   1117       goto Fail;
   1118 
   1119     /* select Unicode charmap by default */
   1120     error2 = find_unicode_charmap( face );
   1121 
   1122     /* if no Unicode charmap can be found, FT_Err_Invalid_CharMap_Handle */
   1123     /* is returned.                                                      */
   1124 
   1125     /* no error should happen, but we want to play safe */
   1126     if ( error2 && error2 != FT_Err_Invalid_CharMap_Handle )
   1127     {
   1128       error = error2;
   1129       goto Fail;
   1130     }
   1131 
   1132     *aface = face;
   1133 
   1134   Fail:
   1135     if ( error )
   1136     {
   1137       destroy_charmaps( face, memory );
   1138       if ( clazz->done_face )
   1139         clazz->done_face( face );
   1140       FT_FREE( internal );
   1141       FT_FREE( face );
   1142       *aface = 0;
   1143     }
   1144 
   1145     return error;
   1146   }
   1147 
   1148 
   1149   /* there's a Mac-specific extended implementation of FT_New_Face() */
   1150   /* in src/base/ftmac.c                                             */
   1151 
   1152 #if !defined( FT_MACINTOSH ) || defined( DARWIN_NO_CARBON )
   1153 
   1154   /* documentation is in freetype.h */
   1155 
   1156   FT_EXPORT_DEF( FT_Error )
   1157   FT_New_Face( FT_Library   library,
   1158                const char*  pathname,
   1159                FT_Long      face_index,
   1160                FT_Face     *aface )
   1161   {
   1162     FT_Open_Args  args;
   1163 
   1164 
   1165     /* test for valid `library' and `aface' delayed to FT_Open_Face() */
   1166     if ( !pathname )
   1167       return FT_Err_Invalid_Argument;
   1168 
   1169     args.flags    = FT_OPEN_PATHNAME;
   1170     args.pathname = (char*)pathname;
   1171     args.stream   = NULL;
   1172 
   1173     return FT_Open_Face( library, &args, face_index, aface );
   1174   }
   1175 
   1176 #endif  /* defined( FT_MACINTOSH ) && !defined( DARWIN_NO_CARBON ) */
   1177 
   1178 
   1179   /* documentation is in freetype.h */
   1180 
   1181   FT_EXPORT_DEF( FT_Error )
   1182   FT_New_Memory_Face( FT_Library      library,
   1183                       const FT_Byte*  file_base,
   1184                       FT_Long         file_size,
   1185                       FT_Long         face_index,
   1186                       FT_Face        *aface )
   1187   {
   1188     FT_Open_Args  args;
   1189 
   1190 
   1191     /* test for valid `library' and `face' delayed to FT_Open_Face() */
   1192     if ( !file_base )
   1193       return FT_Err_Invalid_Argument;
   1194 
   1195     args.flags       = FT_OPEN_MEMORY;
   1196     args.memory_base = file_base;
   1197     args.memory_size = file_size;
   1198     args.stream      = NULL;
   1199 
   1200     return FT_Open_Face( library, &args, face_index, aface );
   1201   }
   1202 
   1203 
   1204 #ifdef FT_CONFIG_OPTION_MAC_FONTS
   1205 
   1206   /* The behavior here is very similar to that in base/ftmac.c, but it     */
   1207   /* is designed to work on non-mac systems, so no mac specific calls.     */
   1208   /*                                                                       */
   1209   /* We look at the file and determine if it is a mac dfont file or a mac  */
   1210   /* resource file, or a macbinary file containing a mac resource file.    */
   1211   /*                                                                       */
   1212   /* Unlike ftmac I'm not going to look at a `FOND'.  I don't really see   */
   1213   /* the point, especially since there may be multiple `FOND' resources.   */
   1214   /* Instead I'll just look for `sfnt' and `POST' resources, ordered as    */
   1215   /* they occur in the file.                                               */
   1216   /*                                                                       */
   1217   /* Note that multiple `POST' resources do not mean multiple postscript   */
   1218   /* fonts; they all get jammed together to make what is essentially a     */
   1219   /* pfb file.                                                             */
   1220   /*                                                                       */
   1221   /* We aren't interested in `NFNT' or `FONT' bitmap resources.            */
   1222   /*                                                                       */
   1223   /* As soon as we get an `sfnt' load it into memory and pass it off to    */
   1224   /* FT_Open_Face.                                                         */
   1225   /*                                                                       */
   1226   /* If we have a (set of) `POST' resources, massage them into a (memory)  */
   1227   /* pfb file and pass that to FT_Open_Face.  (As with ftmac.c I'm not     */
   1228   /* going to try to save the kerning info.  After all that lives in the   */
   1229   /* `FOND' which isn't in the file containing the `POST' resources so     */
   1230   /* we don't really have access to it.                                    */
   1231 
   1232 
   1233   /* Finalizer for a memory stream; gets called by FT_Done_Face(). */
   1234   /* It frees the memory it uses.                                  */
   1235   /* From ftmac.c.                                                 */
   1236   static void
   1237   memory_stream_close( FT_Stream  stream )
   1238   {
   1239     FT_Memory  memory = stream->memory;
   1240 
   1241 
   1242     FT_FREE( stream->base );
   1243 
   1244     stream->size  = 0;
   1245     stream->base  = 0;
   1246     stream->close = 0;
   1247   }
   1248 
   1249 
   1250   /* Create a new memory stream from a buffer and a size. */
   1251   /* From ftmac.c.                                        */
   1252   static FT_Error
   1253   new_memory_stream( FT_Library           library,
   1254                      FT_Byte*             base,
   1255                      FT_ULong             size,
   1256                      FT_Stream_CloseFunc  close,
   1257                      FT_Stream           *astream )
   1258   {
   1259     FT_Error   error;
   1260     FT_Memory  memory;
   1261     FT_Stream  stream;
   1262 
   1263 
   1264     if ( !library )
   1265       return FT_Err_Invalid_Library_Handle;
   1266 
   1267     if ( !base )
   1268       return FT_Err_Invalid_Argument;
   1269 
   1270     *astream = 0;
   1271     memory = library->memory;
   1272     if ( FT_NEW( stream ) )
   1273       goto Exit;
   1274 
   1275     FT_Stream_OpenMemory( stream, base, size );
   1276 
   1277     stream->close = close;
   1278 
   1279     *astream = stream;
   1280 
   1281   Exit:
   1282     return error;
   1283   }
   1284 
   1285 
   1286   /* Create a new FT_Face given a buffer and a driver name. */
   1287   /* from ftmac.c */
   1288   FT_LOCAL_DEF( FT_Error )
   1289   open_face_from_buffer( FT_Library   library,
   1290                          FT_Byte*     base,
   1291                          FT_ULong     size,
   1292                          FT_Long      face_index,
   1293                          const char*  driver_name,
   1294                          FT_Face     *aface )
   1295   {
   1296     FT_Open_Args  args;
   1297     FT_Error      error;
   1298     FT_Stream     stream = NULL;
   1299     FT_Memory     memory = library->memory;
   1300 
   1301 
   1302     error = new_memory_stream( library,
   1303                                base,
   1304                                size,
   1305                                memory_stream_close,
   1306                                &stream );
   1307     if ( error )
   1308     {
   1309       FT_FREE( base );
   1310       return error;
   1311     }
   1312 
   1313     args.flags = FT_OPEN_STREAM;
   1314     args.stream = stream;
   1315     if ( driver_name )
   1316     {
   1317       args.flags = args.flags | FT_OPEN_DRIVER;
   1318       args.driver = FT_Get_Module( library, driver_name );
   1319     }
   1320 
   1321 #ifdef FT_MACINTOSH
   1322     /* At this point, face_index has served its purpose;      */
   1323     /* whoever calls this function has already used it to     */
   1324     /* locate the correct font data.  We should not propagate */
   1325     /* this index to FT_Open_Face() (unless it is negative).  */
   1326 
   1327     if ( face_index > 0 )
   1328       face_index = 0;
   1329 #endif
   1330 
   1331     error = FT_Open_Face( library, &args, face_index, aface );
   1332 
   1333     if ( error == FT_Err_Ok )
   1334       (*aface)->face_flags &= ~FT_FACE_FLAG_EXTERNAL_STREAM;
   1335     else
   1336 #ifdef FT_MACINTOSH
   1337       FT_Stream_Free( stream, 0 );
   1338 #else
   1339     {
   1340       FT_Stream_Close( stream );
   1341       FT_FREE( stream );
   1342     }
   1343 #endif
   1344 
   1345     return error;
   1346   }
   1347 
   1348 
   1349   /* Look up `TYP1' or `CID ' table from sfnt table directory.       */
   1350   /* `offset' and `length' must exclude the binary header in tables. */
   1351 
   1352   /* Type 1 and CID-keyed font drivers should recognize sfnt-wrapped */
   1353   /* format too.  Here, since we can't expect that the TrueType font */
   1354   /* driver is loaded unconditially, we must parse the font by       */
   1355   /* ourselves.  We are only interested in the name of the table and */
   1356   /* the offset.                                                     */
   1357 
   1358   static FT_Error
   1359   ft_lookup_PS_in_sfnt_stream( FT_Stream  stream,
   1360                                FT_Long    face_index,
   1361                                FT_ULong*  offset,
   1362                                FT_ULong*  length,
   1363                                FT_Bool*   is_sfnt_cid )
   1364   {
   1365     FT_Error   error;
   1366     FT_UShort  numTables;
   1367     FT_Long    pstable_index;
   1368     FT_ULong   tag;
   1369     int        i;
   1370 
   1371 
   1372     *offset = 0;
   1373     *length = 0;
   1374     *is_sfnt_cid = FALSE;
   1375 
   1376     /* TODO: support for sfnt-wrapped PS/CID in TTC format */
   1377 
   1378     /* version check for 'typ1' (should be ignored?) */
   1379     if ( FT_READ_ULONG( tag ) )
   1380       return error;
   1381     if ( tag != TTAG_typ1 )
   1382       return FT_Err_Unknown_File_Format;
   1383 
   1384     if ( FT_READ_USHORT( numTables ) )
   1385       return error;
   1386     if ( FT_STREAM_SKIP( 2 * 3 ) ) /* skip binary search header */
   1387       return error;
   1388 
   1389     pstable_index = -1;
   1390     *is_sfnt_cid  = FALSE;
   1391 
   1392     for ( i = 0; i < numTables; i++ )
   1393     {
   1394       if ( FT_READ_ULONG( tag )     || FT_STREAM_SKIP( 4 )      ||
   1395            FT_READ_ULONG( *offset ) || FT_READ_ULONG( *length ) )
   1396         return error;
   1397 
   1398       if ( tag == TTAG_CID )
   1399       {
   1400         pstable_index++;
   1401         *offset += 22;
   1402         *length -= 22;
   1403         *is_sfnt_cid = TRUE;
   1404         if ( face_index < 0 )
   1405           return FT_Err_Ok;
   1406       }
   1407       else if ( tag == TTAG_TYP1 )
   1408       {
   1409         pstable_index++;
   1410         *offset += 24;
   1411         *length -= 24;
   1412         *is_sfnt_cid = FALSE;
   1413         if ( face_index < 0 )
   1414           return FT_Err_Ok;
   1415       }
   1416       if ( face_index >= 0 && pstable_index == face_index )
   1417         return FT_Err_Ok;
   1418     }
   1419     return FT_Err_Table_Missing;
   1420   }
   1421 
   1422 
   1423   FT_LOCAL_DEF( FT_Error )
   1424   open_face_PS_from_sfnt_stream( FT_Library     library,
   1425                                  FT_Stream      stream,
   1426                                  FT_Long        face_index,
   1427                                  FT_Int         num_params,
   1428                                  FT_Parameter  *params,
   1429                                  FT_Face       *aface )
   1430   {
   1431     FT_Error   error;
   1432     FT_Memory  memory = library->memory;
   1433     FT_ULong   offset, length;
   1434     FT_Long    pos;
   1435     FT_Bool    is_sfnt_cid;
   1436     FT_Byte*   sfnt_ps;
   1437 
   1438     FT_UNUSED( num_params );
   1439     FT_UNUSED( params );
   1440 
   1441 
   1442     pos = FT_Stream_Pos( stream );
   1443 
   1444     error = ft_lookup_PS_in_sfnt_stream( stream,
   1445                                          face_index,
   1446                                          &offset,
   1447                                          &length,
   1448                                          &is_sfnt_cid );
   1449     if ( error )
   1450       goto Exit;
   1451 
   1452     if ( FT_Stream_Seek( stream, pos + offset ) )
   1453       goto Exit;
   1454 
   1455     if ( FT_ALLOC( sfnt_ps, (FT_Long)length ) )
   1456       goto Exit;
   1457 
   1458     error = FT_Stream_Read( stream, (FT_Byte *)sfnt_ps, length );
   1459     if ( error )
   1460       goto Exit;
   1461 
   1462     error = open_face_from_buffer( library,
   1463                                    sfnt_ps,
   1464                                    length,
   1465                                    face_index < 0 ? face_index : 0,
   1466                                    is_sfnt_cid ? "cid" : "type1",
   1467                                    aface );
   1468   Exit:
   1469     {
   1470       FT_Error  error1;
   1471 
   1472 
   1473       if ( error == FT_Err_Unknown_File_Format )
   1474       {
   1475         error1 = FT_Stream_Seek( stream, pos );
   1476         if ( error1 )
   1477           return error1;
   1478       }
   1479 
   1480       return error;
   1481     }
   1482   }
   1483 
   1484 
   1485 #if !defined( FT_MACINTOSH ) || defined( DARWIN_NO_CARBON )
   1486 
   1487   /* The resource header says we've got resource_cnt `POST' (type1) */
   1488   /* resources in this file.  They all need to be coalesced into    */
   1489   /* one lump which gets passed on to the type1 driver.             */
   1490   /* Here can be only one PostScript font in a file so face_index   */
   1491   /* must be 0 (or -1).                                             */
   1492   /*                                                                */
   1493   static FT_Error
   1494   Mac_Read_POST_Resource( FT_Library  library,
   1495                           FT_Stream   stream,
   1496                           FT_Long    *offsets,
   1497                           FT_Long     resource_cnt,
   1498                           FT_Long     face_index,
   1499                           FT_Face    *aface )
   1500   {
   1501     FT_Error   error  = FT_Err_Cannot_Open_Resource;
   1502     FT_Memory  memory = library->memory;
   1503     FT_Byte*   pfb_data;
   1504     int        i, type, flags;
   1505     FT_Long    len;
   1506     FT_Long    pfb_len, pfb_pos, pfb_lenpos;
   1507     FT_Long    rlen, temp;
   1508 
   1509 
   1510     if ( face_index == -1 )
   1511       face_index = 0;
   1512     if ( face_index != 0 )
   1513       return error;
   1514 
   1515     /* Find the length of all the POST resources, concatenated.  Assume */
   1516     /* worst case (each resource in its own section).                   */
   1517     pfb_len = 0;
   1518     for ( i = 0; i < resource_cnt; ++i )
   1519     {
   1520       error = FT_Stream_Seek( stream, offsets[i] );
   1521       if ( error )
   1522         goto Exit;
   1523       if ( FT_READ_LONG( temp ) )
   1524         goto Exit;
   1525       pfb_len += temp + 6;
   1526     }
   1527 
   1528     if ( FT_ALLOC( pfb_data, (FT_Long)pfb_len + 2 ) )
   1529       goto Exit;
   1530 
   1531     pfb_data[0] = 0x80;
   1532     pfb_data[1] = 1;            /* Ascii section */
   1533     pfb_data[2] = 0;            /* 4-byte length, fill in later */
   1534     pfb_data[3] = 0;
   1535     pfb_data[4] = 0;
   1536     pfb_data[5] = 0;
   1537     pfb_pos     = 6;
   1538     pfb_lenpos  = 2;
   1539 
   1540     len = 0;
   1541     type = 1;
   1542     for ( i = 0; i < resource_cnt; ++i )
   1543     {
   1544       error = FT_Stream_Seek( stream, offsets[i] );
   1545       if ( error )
   1546         goto Exit2;
   1547       if ( FT_READ_LONG( rlen ) )
   1548         goto Exit;
   1549       if ( FT_READ_USHORT( flags ) )
   1550         goto Exit;
   1551       rlen -= 2;                    /* the flags are part of the resource */
   1552       if ( ( flags >> 8 ) == type )
   1553         len += rlen;
   1554       else
   1555       {
   1556         pfb_data[pfb_lenpos    ] = (FT_Byte)( len );
   1557         pfb_data[pfb_lenpos + 1] = (FT_Byte)( len >> 8 );
   1558         pfb_data[pfb_lenpos + 2] = (FT_Byte)( len >> 16 );
   1559         pfb_data[pfb_lenpos + 3] = (FT_Byte)( len >> 24 );
   1560 
   1561         if ( ( flags >> 8 ) == 5 )      /* End of font mark */
   1562           break;
   1563 
   1564         pfb_data[pfb_pos++] = 0x80;
   1565 
   1566         type = flags >> 8;
   1567         len = rlen;
   1568 
   1569         pfb_data[pfb_pos++] = (FT_Byte)type;
   1570         pfb_lenpos          = pfb_pos;
   1571         pfb_data[pfb_pos++] = 0;        /* 4-byte length, fill in later */
   1572         pfb_data[pfb_pos++] = 0;
   1573         pfb_data[pfb_pos++] = 0;
   1574         pfb_data[pfb_pos++] = 0;
   1575       }
   1576 
   1577       error = FT_Stream_Read( stream, (FT_Byte *)pfb_data + pfb_pos, rlen );
   1578       pfb_pos += rlen;
   1579     }
   1580 
   1581     pfb_data[pfb_pos++] = 0x80;
   1582     pfb_data[pfb_pos++] = 3;
   1583 
   1584     pfb_data[pfb_lenpos    ] = (FT_Byte)( len );
   1585     pfb_data[pfb_lenpos + 1] = (FT_Byte)( len >> 8 );
   1586     pfb_data[pfb_lenpos + 2] = (FT_Byte)( len >> 16 );
   1587     pfb_data[pfb_lenpos + 3] = (FT_Byte)( len >> 24 );
   1588 
   1589     return open_face_from_buffer( library,
   1590                                   pfb_data,
   1591                                   pfb_pos,
   1592                                   face_index,
   1593                                   "type1",
   1594                                   aface );
   1595 
   1596   Exit2:
   1597     FT_FREE( pfb_data );
   1598 
   1599   Exit:
   1600     return error;
   1601   }
   1602 
   1603 
   1604   /* The resource header says we've got resource_cnt `sfnt'      */
   1605   /* (TrueType/OpenType) resources in this file.  Look through   */
   1606   /* them for the one indicated by face_index, load it into mem, */
   1607   /* pass it on the the truetype driver and return it.           */
   1608   /*                                                             */
   1609   static FT_Error
   1610   Mac_Read_sfnt_Resource( FT_Library  library,
   1611                           FT_Stream   stream,
   1612                           FT_Long    *offsets,
   1613                           FT_Long     resource_cnt,
   1614                           FT_Long     face_index,
   1615                           FT_Face    *aface )
   1616   {
   1617     FT_Memory  memory = library->memory;
   1618     FT_Byte*   sfnt_data;
   1619     FT_Error   error;
   1620     FT_Long    flag_offset;
   1621     FT_Long    rlen;
   1622     int        is_cff;
   1623     FT_Long    face_index_in_resource = 0;
   1624 
   1625 
   1626     if ( face_index == -1 )
   1627       face_index = 0;
   1628     if ( face_index >= resource_cnt )
   1629       return FT_Err_Cannot_Open_Resource;
   1630 
   1631     flag_offset = offsets[face_index];
   1632     error = FT_Stream_Seek( stream, flag_offset );
   1633     if ( error )
   1634       goto Exit;
   1635 
   1636     if ( FT_READ_LONG( rlen ) )
   1637       goto Exit;
   1638     if ( rlen == -1 )
   1639       return FT_Err_Cannot_Open_Resource;
   1640 
   1641     error = open_face_PS_from_sfnt_stream( library,
   1642                                            stream,
   1643                                            face_index,
   1644                                            0, NULL,
   1645                                            aface );
   1646     if ( !error )
   1647       goto Exit;
   1648 
   1649     /* rewind sfnt stream before open_face_PS_from_sfnt_stream() */
   1650     if ( FT_Stream_Seek( stream, flag_offset + 4 ) )
   1651       goto Exit;
   1652 
   1653     if ( FT_ALLOC( sfnt_data, (FT_Long)rlen ) )
   1654       return error;
   1655     error = FT_Stream_Read( stream, (FT_Byte *)sfnt_data, rlen );
   1656     if ( error )
   1657       goto Exit;
   1658 
   1659     is_cff = rlen > 4 && !ft_memcmp( sfnt_data, "OTTO", 4 );
   1660     error = open_face_from_buffer( library,
   1661                                    sfnt_data,
   1662                                    rlen,
   1663                                    face_index_in_resource,
   1664                                    is_cff ? "cff" : "truetype",
   1665                                    aface );
   1666 
   1667   Exit:
   1668     return error;
   1669   }
   1670 
   1671 
   1672   /* Check for a valid resource fork header, or a valid dfont    */
   1673   /* header.  In a resource fork the first 16 bytes are repeated */
   1674   /* at the location specified by bytes 4-7.  In a dfont bytes   */
   1675   /* 4-7 point to 16 bytes of zeroes instead.                    */
   1676   /*                                                             */
   1677   static FT_Error
   1678   IsMacResource( FT_Library  library,
   1679                  FT_Stream   stream,
   1680                  FT_Long     resource_offset,
   1681                  FT_Long     face_index,
   1682                  FT_Face    *aface )
   1683   {
   1684     FT_Memory  memory = library->memory;
   1685     FT_Error   error;
   1686     FT_Long    map_offset, rdara_pos;
   1687     FT_Long    *data_offsets;
   1688     FT_Long    count;
   1689 
   1690 
   1691     error = FT_Raccess_Get_HeaderInfo( library, stream, resource_offset,
   1692                                        &map_offset, &rdara_pos );
   1693     if ( error )
   1694       return error;
   1695 
   1696     error = FT_Raccess_Get_DataOffsets( library, stream,
   1697                                         map_offset, rdara_pos,
   1698                                         TTAG_POST,
   1699                                         &data_offsets, &count );
   1700     if ( !error )
   1701     {
   1702       error = Mac_Read_POST_Resource( library, stream, data_offsets, count,
   1703                                       face_index, aface );
   1704       FT_FREE( data_offsets );
   1705       /* POST exists in an LWFN providing a single face */
   1706       if ( !error )
   1707         (*aface)->num_faces = 1;
   1708       return error;
   1709     }
   1710 
   1711     error = FT_Raccess_Get_DataOffsets( library, stream,
   1712                                         map_offset, rdara_pos,
   1713                                         TTAG_sfnt,
   1714                                         &data_offsets, &count );
   1715     if ( !error )
   1716     {
   1717       FT_Long  face_index_internal = face_index % count;
   1718 
   1719 
   1720       error = Mac_Read_sfnt_Resource( library, stream, data_offsets, count,
   1721                                       face_index_internal, aface );
   1722       FT_FREE( data_offsets );
   1723       if ( !error )
   1724         (*aface)->num_faces = count;
   1725     }
   1726 
   1727     return error;
   1728   }
   1729 
   1730 
   1731   /* Check for a valid macbinary header, and if we find one   */
   1732   /* check that the (flattened) resource fork in it is valid. */
   1733   /*                                                          */
   1734   static FT_Error
   1735   IsMacBinary( FT_Library  library,
   1736                FT_Stream   stream,
   1737                FT_Long     face_index,
   1738                FT_Face    *aface )
   1739   {
   1740     unsigned char  header[128];
   1741     FT_Error       error;
   1742     FT_Long        dlen, offset;
   1743 
   1744 
   1745     if ( NULL == stream )
   1746       return FT_Err_Invalid_Stream_Operation;
   1747 
   1748     error = FT_Stream_Seek( stream, 0 );
   1749     if ( error )
   1750       goto Exit;
   1751 
   1752     error = FT_Stream_Read( stream, (FT_Byte*)header, 128 );
   1753     if ( error )
   1754       goto Exit;
   1755 
   1756     if (            header[ 0] !=  0 ||
   1757                     header[74] !=  0 ||
   1758                     header[82] !=  0 ||
   1759                     header[ 1] ==  0 ||
   1760                     header[ 1] >  33 ||
   1761                     header[63] !=  0 ||
   1762          header[2 + header[1]] !=  0 )
   1763       return FT_Err_Unknown_File_Format;
   1764 
   1765     dlen = ( header[0x53] << 24 ) |
   1766            ( header[0x54] << 16 ) |
   1767            ( header[0x55] <<  8 ) |
   1768              header[0x56];
   1769 #if 0
   1770     rlen = ( header[0x57] << 24 ) |
   1771            ( header[0x58] << 16 ) |
   1772            ( header[0x59] <<  8 ) |
   1773              header[0x5a];
   1774 #endif /* 0 */
   1775     offset = 128 + ( ( dlen + 127 ) & ~127 );
   1776 
   1777     return IsMacResource( library, stream, offset, face_index, aface );
   1778 
   1779   Exit:
   1780     return error;
   1781   }
   1782 
   1783 
   1784   static FT_Error
   1785   load_face_in_embedded_rfork( FT_Library           library,
   1786                                FT_Stream            stream,
   1787                                FT_Long              face_index,
   1788                                FT_Face             *aface,
   1789                                const FT_Open_Args  *args )
   1790   {
   1791 
   1792 #undef  FT_COMPONENT
   1793 #define FT_COMPONENT  trace_raccess
   1794 
   1795     FT_Memory  memory = library->memory;
   1796     FT_Error   error  = FT_Err_Unknown_File_Format;
   1797     int        i;
   1798 
   1799     char *     file_names[FT_RACCESS_N_RULES];
   1800     FT_Long    offsets[FT_RACCESS_N_RULES];
   1801     FT_Error   errors[FT_RACCESS_N_RULES];
   1802 
   1803     FT_Open_Args  args2;
   1804     FT_Stream     stream2 = 0;
   1805 
   1806 
   1807     FT_Raccess_Guess( library, stream,
   1808                       args->pathname, file_names, offsets, errors );
   1809 
   1810     for ( i = 0; i < FT_RACCESS_N_RULES; i++ )
   1811     {
   1812       if ( errors[i] )
   1813       {
   1814         FT_TRACE3(( "Error[%d] has occurred in rule %d\n", errors[i], i ));
   1815         continue;
   1816       }
   1817 
   1818       args2.flags    = FT_OPEN_PATHNAME;
   1819       args2.pathname = file_names[i] ? file_names[i] : args->pathname;
   1820 
   1821       FT_TRACE3(( "Try rule %d: %s (offset=%d) ...",
   1822                   i, args2.pathname, offsets[i] ));
   1823 
   1824       error = FT_Stream_New( library, &args2, &stream2 );
   1825       if ( error )
   1826       {
   1827         FT_TRACE3(( "failed\n" ));
   1828         continue;
   1829       }
   1830 
   1831       error = IsMacResource( library, stream2, offsets[i],
   1832                              face_index, aface );
   1833       FT_Stream_Free( stream2, 0 );
   1834 
   1835       FT_TRACE3(( "%s\n", error ? "failed": "successful" ));
   1836 
   1837       if ( !error )
   1838           break;
   1839     }
   1840 
   1841     for (i = 0; i < FT_RACCESS_N_RULES; i++)
   1842     {
   1843       if ( file_names[i] )
   1844         FT_FREE( file_names[i] );
   1845     }
   1846 
   1847     /* Caller (load_mac_face) requires FT_Err_Unknown_File_Format. */
   1848     if ( error )
   1849       error = FT_Err_Unknown_File_Format;
   1850 
   1851     return error;
   1852 
   1853 #undef  FT_COMPONENT
   1854 #define FT_COMPONENT  trace_objs
   1855 
   1856   }
   1857 
   1858 
   1859   /* Check for some macintosh formats without Carbon framework.    */
   1860   /* Is this a macbinary file?  If so look at the resource fork.   */
   1861   /* Is this a mac dfont file?                                     */
   1862   /* Is this an old style resource fork? (in data)                 */
   1863   /* Else call load_face_in_embedded_rfork to try extra rules      */
   1864   /* (defined in `ftrfork.c').                                     */
   1865   /*                                                               */
   1866   static FT_Error
   1867   load_mac_face( FT_Library           library,
   1868                  FT_Stream            stream,
   1869                  FT_Long              face_index,
   1870                  FT_Face             *aface,
   1871                  const FT_Open_Args  *args )
   1872   {
   1873     FT_Error error;
   1874     FT_UNUSED( args );
   1875 
   1876 
   1877     error = IsMacBinary( library, stream, face_index, aface );
   1878     if ( FT_ERROR_BASE( error ) == FT_Err_Unknown_File_Format )
   1879     {
   1880 
   1881 #undef  FT_COMPONENT
   1882 #define FT_COMPONENT  trace_raccess
   1883 
   1884       FT_TRACE3(( "Try as dfont: %s ...", args->pathname ));
   1885 
   1886       error = IsMacResource( library, stream, 0, face_index, aface );
   1887 
   1888       FT_TRACE3(( "%s\n", error ? "failed" : "successful" ));
   1889 
   1890 #undef  FT_COMPONENT
   1891 #define FT_COMPONENT  trace_objs
   1892 
   1893     }
   1894 
   1895     if ( ( FT_ERROR_BASE( error ) == FT_Err_Unknown_File_Format      ||
   1896            FT_ERROR_BASE( error ) == FT_Err_Invalid_Stream_Operation ) &&
   1897          ( args->flags & FT_OPEN_PATHNAME )                            )
   1898       error = load_face_in_embedded_rfork( library, stream,
   1899                                            face_index, aface, args );
   1900     return error;
   1901   }
   1902 #endif
   1903 
   1904 #endif  /* !FT_MACINTOSH && FT_CONFIG_OPTION_MAC_FONTS */
   1905 
   1906 
   1907   /* documentation is in freetype.h */
   1908 
   1909   FT_EXPORT_DEF( FT_Error )
   1910   FT_Open_Face( FT_Library           library,
   1911                 const FT_Open_Args*  args,
   1912                 FT_Long              face_index,
   1913                 FT_Face             *aface )
   1914   {
   1915     FT_Error     error;
   1916     FT_Driver    driver;
   1917     FT_Memory    memory;
   1918     FT_Stream    stream = 0;
   1919     FT_Face      face = 0;
   1920     FT_ListNode  node = 0;
   1921     FT_Bool      external_stream;
   1922     FT_Module*   cur;
   1923     FT_Module*   limit;
   1924 
   1925 
   1926     /* test for valid `library' delayed to */
   1927     /* FT_Stream_New()                     */
   1928 
   1929     if ( ( !aface && face_index >= 0 ) || !args )
   1930       return FT_Err_Invalid_Argument;
   1931 
   1932     external_stream = FT_BOOL( ( args->flags & FT_OPEN_STREAM ) &&
   1933                                args->stream                     );
   1934 
   1935     /* create input stream */
   1936     error = FT_Stream_New( library, args, &stream );
   1937     if ( error )
   1938       goto Fail3;
   1939 
   1940     memory = library->memory;
   1941 
   1942     /* If the font driver is specified in the `args' structure, use */
   1943     /* it.  Otherwise, we scan the list of registered drivers.      */
   1944     if ( ( args->flags & FT_OPEN_DRIVER ) && args->driver )
   1945     {
   1946       driver = FT_DRIVER( args->driver );
   1947 
   1948       /* not all modules are drivers, so check... */
   1949       if ( FT_MODULE_IS_DRIVER( driver ) )
   1950       {
   1951         FT_Int         num_params = 0;
   1952         FT_Parameter*  params     = 0;
   1953 
   1954 
   1955         if ( args->flags & FT_OPEN_PARAMS )
   1956         {
   1957           num_params = args->num_params;
   1958           params     = args->params;
   1959         }
   1960 
   1961         error = open_face( driver, stream, face_index,
   1962                            num_params, params, &face );
   1963         if ( !error )
   1964           goto Success;
   1965       }
   1966       else
   1967         error = FT_Err_Invalid_Handle;
   1968 
   1969       FT_Stream_Free( stream, external_stream );
   1970       goto Fail;
   1971     }
   1972     else
   1973     {
   1974       /* check each font driver for an appropriate format */
   1975       cur   = library->modules;
   1976       limit = cur + library->num_modules;
   1977 
   1978 
   1979       for ( ; cur < limit; cur++ )
   1980       {
   1981         /* not all modules are font drivers, so check... */
   1982         if ( FT_MODULE_IS_DRIVER( cur[0] ) )
   1983         {
   1984           FT_Int         num_params = 0;
   1985           FT_Parameter*  params     = 0;
   1986 
   1987 
   1988           driver = FT_DRIVER( cur[0] );
   1989 
   1990           if ( args->flags & FT_OPEN_PARAMS )
   1991           {
   1992             num_params = args->num_params;
   1993             params     = args->params;
   1994           }
   1995 
   1996           error = open_face( driver, stream, face_index,
   1997                              num_params, params, &face );
   1998           if ( !error )
   1999             goto Success;
   2000 
   2001 #ifdef FT_CONFIG_OPTION_MAC_FONTS
   2002           if ( ft_strcmp( cur[0]->clazz->module_name, "truetype" ) == 0 &&
   2003                FT_ERROR_BASE( error ) == FT_Err_Table_Missing           )
   2004           {
   2005             /* TrueType but essential tables are missing */
   2006             if ( FT_Stream_Seek( stream, 0 ) )
   2007               break;
   2008 
   2009             error = open_face_PS_from_sfnt_stream( library,
   2010                                                    stream,
   2011                                                    face_index,
   2012                                                    num_params,
   2013                                                    params,
   2014                                                    aface );
   2015             if ( !error )
   2016             {
   2017               FT_Stream_Free( stream, external_stream );
   2018               return error;
   2019             }
   2020           }
   2021 #endif
   2022 
   2023           if ( FT_ERROR_BASE( error ) != FT_Err_Unknown_File_Format )
   2024             goto Fail3;
   2025         }
   2026       }
   2027 
   2028   Fail3:
   2029     /* If we are on the mac, and we get an FT_Err_Invalid_Stream_Operation */
   2030     /* it may be because we have an empty data fork, so we need to check   */
   2031     /* the resource fork.                                                  */
   2032     if ( FT_ERROR_BASE( error ) != FT_Err_Cannot_Open_Stream       &&
   2033          FT_ERROR_BASE( error ) != FT_Err_Unknown_File_Format      &&
   2034          FT_ERROR_BASE( error ) != FT_Err_Invalid_Stream_Operation )
   2035       goto Fail2;
   2036 
   2037 #if !defined( FT_MACINTOSH ) && defined( FT_CONFIG_OPTION_MAC_FONTS )
   2038     error = load_mac_face( library, stream, face_index, aface, args );
   2039     if ( !error )
   2040     {
   2041       /* We don't want to go to Success here.  We've already done that. */
   2042       /* On the other hand, if we succeeded we still need to close this */
   2043       /* stream (we opened a different stream which extracted the       */
   2044       /* interesting information out of this stream here.  That stream  */
   2045       /* will still be open and the face will point to it).             */
   2046       FT_Stream_Free( stream, external_stream );
   2047       return error;
   2048     }
   2049 
   2050     if ( FT_ERROR_BASE( error ) != FT_Err_Unknown_File_Format )
   2051       goto Fail2;
   2052 #endif  /* !FT_MACINTOSH && FT_CONFIG_OPTION_MAC_FONTS */
   2053 
   2054       /* no driver is able to handle this format */
   2055       error = FT_Err_Unknown_File_Format;
   2056 
   2057   Fail2:
   2058       FT_Stream_Free( stream, external_stream );
   2059       goto Fail;
   2060     }
   2061 
   2062   Success:
   2063     FT_TRACE4(( "FT_Open_Face: New face object, adding to list\n" ));
   2064 
   2065     /* set the FT_FACE_FLAG_EXTERNAL_STREAM bit for FT_Done_Face */
   2066     if ( external_stream )
   2067       face->face_flags |= FT_FACE_FLAG_EXTERNAL_STREAM;
   2068 
   2069     /* add the face object to its driver's list */
   2070     if ( FT_NEW( node ) )
   2071       goto Fail;
   2072 
   2073     node->data = face;
   2074     /* don't assume driver is the same as face->driver, so use */
   2075     /* face->driver instead.                                   */
   2076     FT_List_Add( &face->driver->faces_list, node );
   2077 
   2078     /* now allocate a glyph slot object for the face */
   2079     FT_TRACE4(( "FT_Open_Face: Creating glyph slot\n" ));
   2080 
   2081     if ( face_index >= 0 )
   2082     {
   2083       error = FT_New_GlyphSlot( face, NULL );
   2084       if ( error )
   2085         goto Fail;
   2086 
   2087       /* finally, allocate a size object for the face */
   2088       {
   2089         FT_Size  size;
   2090 
   2091 
   2092         FT_TRACE4(( "FT_Open_Face: Creating size object\n" ));
   2093 
   2094         error = FT_New_Size( face, &size );
   2095         if ( error )
   2096           goto Fail;
   2097 
   2098         face->size = size;
   2099       }
   2100     }
   2101 
   2102     /* some checks */
   2103 
   2104     if ( FT_IS_SCALABLE( face ) )
   2105     {
   2106       if ( face->height < 0 )
   2107         face->height = (FT_Short)-face->height;
   2108 
   2109       if ( !FT_HAS_VERTICAL( face ) )
   2110         face->max_advance_height = (FT_Short)face->height;
   2111     }
   2112 
   2113     if ( FT_HAS_FIXED_SIZES( face ) )
   2114     {
   2115       FT_Int  i;
   2116 
   2117 
   2118       for ( i = 0; i < face->num_fixed_sizes; i++ )
   2119       {
   2120         FT_Bitmap_Size*  bsize = face->available_sizes + i;
   2121 
   2122 
   2123         if ( bsize->height < 0 )
   2124           bsize->height = (FT_Short)-bsize->height;
   2125         if ( bsize->x_ppem < 0 )
   2126           bsize->x_ppem = (FT_Short)-bsize->x_ppem;
   2127         if ( bsize->y_ppem < 0 )
   2128           bsize->y_ppem = -bsize->y_ppem;
   2129       }
   2130     }
   2131 
   2132     /* initialize internal face data */
   2133     {
   2134       FT_Face_Internal  internal = face->internal;
   2135 
   2136 
   2137       internal->transform_matrix.xx = 0x10000L;
   2138       internal->transform_matrix.xy = 0;
   2139       internal->transform_matrix.yx = 0;
   2140       internal->transform_matrix.yy = 0x10000L;
   2141 
   2142       internal->transform_delta.x = 0;
   2143       internal->transform_delta.y = 0;
   2144     }
   2145 
   2146     if ( aface )
   2147       *aface = face;
   2148     else
   2149       FT_Done_Face( face );
   2150 
   2151     goto Exit;
   2152 
   2153   Fail:
   2154     FT_Done_Face( face );
   2155 
   2156   Exit:
   2157     FT_TRACE4(( "FT_Open_Face: Return %d\n", error ));
   2158 
   2159     return error;
   2160   }
   2161 
   2162 
   2163   /* documentation is in freetype.h */
   2164 
   2165   FT_EXPORT_DEF( FT_Error )
   2166   FT_Attach_File( FT_Face      face,
   2167                   const char*  filepathname )
   2168   {
   2169     FT_Open_Args  open;
   2170 
   2171 
   2172     /* test for valid `face' delayed to FT_Attach_Stream() */
   2173 
   2174     if ( !filepathname )
   2175       return FT_Err_Invalid_Argument;
   2176 
   2177     open.stream   = NULL;
   2178     open.flags    = FT_OPEN_PATHNAME;
   2179     open.pathname = (char*)filepathname;
   2180 
   2181     return FT_Attach_Stream( face, &open );
   2182   }
   2183 
   2184 
   2185   /* documentation is in freetype.h */
   2186 
   2187   FT_EXPORT_DEF( FT_Error )
   2188   FT_Attach_Stream( FT_Face        face,
   2189                     FT_Open_Args*  parameters )
   2190   {
   2191     FT_Stream  stream;
   2192     FT_Error   error;
   2193     FT_Driver  driver;
   2194 
   2195     FT_Driver_Class  clazz;
   2196 
   2197 
   2198     /* test for valid `parameters' delayed to FT_Stream_New() */
   2199 
   2200     if ( !face )
   2201       return FT_Err_Invalid_Face_Handle;
   2202 
   2203     driver = face->driver;
   2204     if ( !driver )
   2205       return FT_Err_Invalid_Driver_Handle;
   2206 
   2207     error = FT_Stream_New( driver->root.library, parameters, &stream );
   2208     if ( error )
   2209       goto Exit;
   2210 
   2211     /* we implement FT_Attach_Stream in each driver through the */
   2212     /* `attach_file' interface                                  */
   2213 
   2214     error = FT_Err_Unimplemented_Feature;
   2215     clazz = driver->clazz;
   2216     if ( clazz->attach_file )
   2217       error = clazz->attach_file( face, stream );
   2218 
   2219     /* close the attached stream */
   2220     FT_Stream_Free( stream,
   2221                     (FT_Bool)( parameters->stream &&
   2222                                ( parameters->flags & FT_OPEN_STREAM ) ) );
   2223 
   2224   Exit:
   2225     return error;
   2226   }
   2227 
   2228 
   2229   /* documentation is in freetype.h */
   2230 
   2231   FT_EXPORT_DEF( FT_Error )
   2232   FT_Done_Face( FT_Face  face )
   2233   {
   2234     FT_Error     error;
   2235     FT_Driver    driver;
   2236     FT_Memory    memory;
   2237     FT_ListNode  node;
   2238 
   2239 
   2240     error = FT_Err_Invalid_Face_Handle;
   2241     if ( face && face->driver )
   2242     {
   2243       driver = face->driver;
   2244       memory = driver->root.memory;
   2245 
   2246       /* find face in driver's list */
   2247       node = FT_List_Find( &driver->faces_list, face );
   2248       if ( node )
   2249       {
   2250         /* remove face object from the driver's list */
   2251         FT_List_Remove( &driver->faces_list, node );
   2252         FT_FREE( node );
   2253 
   2254         /* now destroy the object proper */
   2255         destroy_face( memory, face, driver );
   2256         error = FT_Err_Ok;
   2257       }
   2258     }
   2259     return error;
   2260   }
   2261 
   2262 
   2263   /* documentation is in ftobjs.h */
   2264 
   2265   FT_EXPORT_DEF( FT_Error )
   2266   FT_New_Size( FT_Face   face,
   2267                FT_Size  *asize )
   2268   {
   2269     FT_Error         error;
   2270     FT_Memory        memory;
   2271     FT_Driver        driver;
   2272     FT_Driver_Class  clazz;
   2273 
   2274     FT_Size          size = 0;
   2275     FT_ListNode      node = 0;
   2276 
   2277 
   2278     if ( !face )
   2279       return FT_Err_Invalid_Face_Handle;
   2280 
   2281     if ( !asize )
   2282       return FT_Err_Invalid_Size_Handle;
   2283 
   2284     if ( !face->driver )
   2285       return FT_Err_Invalid_Driver_Handle;
   2286 
   2287     *asize = 0;
   2288 
   2289     driver = face->driver;
   2290     clazz  = driver->clazz;
   2291     memory = face->memory;
   2292 
   2293     /* Allocate new size object and perform basic initialisation */
   2294     if ( FT_ALLOC( size, clazz->size_object_size ) || FT_NEW( node ) )
   2295       goto Exit;
   2296 
   2297     size->face = face;
   2298 
   2299     /* for now, do not use any internal fields in size objects */
   2300     size->internal = 0;
   2301 
   2302     if ( clazz->init_size )
   2303       error = clazz->init_size( size );
   2304 
   2305     /* in case of success, add to the face's list */
   2306     if ( !error )
   2307     {
   2308       *asize     = size;
   2309       node->data = size;
   2310       FT_List_Add( &face->sizes_list, node );
   2311     }
   2312 
   2313   Exit:
   2314     if ( error )
   2315     {
   2316       FT_FREE( node );
   2317       FT_FREE( size );
   2318     }
   2319 
   2320     return error;
   2321   }
   2322 
   2323 
   2324   /* documentation is in ftobjs.h */
   2325 
   2326   FT_EXPORT_DEF( FT_Error )
   2327   FT_Done_Size( FT_Size  size )
   2328   {
   2329     FT_Error     error;
   2330     FT_Driver    driver;
   2331     FT_Memory    memory;
   2332     FT_Face      face;
   2333     FT_ListNode  node;
   2334 
   2335 
   2336     if ( !size )
   2337       return FT_Err_Invalid_Size_Handle;
   2338 
   2339     face = size->face;
   2340     if ( !face )
   2341       return FT_Err_Invalid_Face_Handle;
   2342 
   2343     driver = face->driver;
   2344     if ( !driver )
   2345       return FT_Err_Invalid_Driver_Handle;
   2346 
   2347     memory = driver->root.memory;
   2348 
   2349     error = FT_Err_Ok;
   2350     node  = FT_List_Find( &face->sizes_list, size );
   2351     if ( node )
   2352     {
   2353       FT_List_Remove( &face->sizes_list, node );
   2354       FT_FREE( node );
   2355 
   2356       if ( face->size == size )
   2357       {
   2358         face->size = 0;
   2359         if ( face->sizes_list.head )
   2360           face->size = (FT_Size)(face->sizes_list.head->data);
   2361       }
   2362 
   2363       destroy_size( memory, size, driver );
   2364     }
   2365     else
   2366       error = FT_Err_Invalid_Size_Handle;
   2367 
   2368     return error;
   2369   }
   2370 
   2371 
   2372   /* documentation is in ftobjs.h */
   2373 
   2374   FT_BASE_DEF( FT_Error )
   2375   FT_Match_Size( FT_Face          face,
   2376                  FT_Size_Request  req,
   2377                  FT_Bool          ignore_width,
   2378                  FT_ULong*        size_index )
   2379   {
   2380     FT_Int   i;
   2381     FT_Long  w, h;
   2382 
   2383 
   2384     if ( !FT_HAS_FIXED_SIZES( face ) )
   2385       return FT_Err_Invalid_Face_Handle;
   2386 
   2387     /* FT_Bitmap_Size doesn't provide enough info... */
   2388     if ( req->type != FT_SIZE_REQUEST_TYPE_NOMINAL )
   2389       return FT_Err_Unimplemented_Feature;
   2390 
   2391     w = FT_REQUEST_WIDTH ( req );
   2392     h = FT_REQUEST_HEIGHT( req );
   2393 
   2394     if ( req->width && !req->height )
   2395       h = w;
   2396     else if ( !req->width && req->height )
   2397       w = h;
   2398 
   2399     w = FT_PIX_ROUND( w );
   2400     h = FT_PIX_ROUND( h );
   2401 
   2402     for ( i = 0; i < face->num_fixed_sizes; i++ )
   2403     {
   2404       FT_Bitmap_Size*  bsize = face->available_sizes + i;
   2405 
   2406 
   2407       if ( h != FT_PIX_ROUND( bsize->y_ppem ) )
   2408         continue;
   2409 
   2410       if ( w == FT_PIX_ROUND( bsize->x_ppem ) || ignore_width )
   2411       {
   2412         if ( size_index )
   2413           *size_index = (FT_ULong)i;
   2414 
   2415         return FT_Err_Ok;
   2416       }
   2417     }
   2418 
   2419     return FT_Err_Invalid_Pixel_Size;
   2420   }
   2421 
   2422 
   2423   /* documentation is in ftobjs.h */
   2424 
   2425   FT_BASE_DEF( void )
   2426   ft_synthesize_vertical_metrics( FT_Glyph_Metrics*  metrics,
   2427                                   FT_Pos             advance )
   2428   {
   2429     FT_Pos  height = metrics->height;
   2430 
   2431 
   2432     /* compensate for glyph with bbox above/below the baseline */
   2433     if ( metrics->horiBearingY < 0 )
   2434     {
   2435       if ( height < metrics->horiBearingY )
   2436         height = metrics->horiBearingY;
   2437     }
   2438     else if ( metrics->horiBearingY > 0 )
   2439       height -= metrics->horiBearingY;
   2440 
   2441     /* the factor 1.2 is a heuristical value */
   2442     if ( !advance )
   2443       advance = height * 12 / 10;
   2444 
   2445     metrics->vertBearingX = metrics->horiBearingX - metrics->horiAdvance / 2;
   2446     metrics->vertBearingY = ( advance - height ) / 2;
   2447     metrics->vertAdvance  = advance;
   2448   }
   2449 
   2450 
   2451   static void
   2452   ft_recompute_scaled_metrics( FT_Face           face,
   2453                                FT_Size_Metrics*  metrics )
   2454   {
   2455     /* Compute root ascender, descender, test height, and max_advance */
   2456 
   2457 #ifdef GRID_FIT_METRICS
   2458     metrics->ascender    = FT_PIX_CEIL( FT_MulFix( face->ascender,
   2459                                                    metrics->y_scale ) );
   2460 
   2461     metrics->descender   = FT_PIX_FLOOR( FT_MulFix( face->descender,
   2462                                                     metrics->y_scale ) );
   2463 
   2464     metrics->height      = FT_PIX_ROUND( FT_MulFix( face->height,
   2465                                                     metrics->y_scale ) );
   2466 
   2467     metrics->max_advance = FT_PIX_ROUND( FT_MulFix( face->max_advance_width,
   2468                                                     metrics->x_scale ) );
   2469 #else /* !GRID_FIT_METRICS */
   2470     metrics->ascender    = FT_MulFix( face->ascender,
   2471                                       metrics->y_scale );
   2472 
   2473     metrics->descender   = FT_MulFix( face->descender,
   2474                                       metrics->y_scale );
   2475 
   2476     metrics->height      = FT_MulFix( face->height,
   2477                                       metrics->y_scale );
   2478 
   2479     metrics->max_advance = FT_MulFix( face->max_advance_width,
   2480                                       metrics->x_scale );
   2481 #endif /* !GRID_FIT_METRICS */
   2482   }
   2483 
   2484 
   2485   FT_BASE_DEF( void )
   2486   FT_Select_Metrics( FT_Face   face,
   2487                      FT_ULong  strike_index )
   2488   {
   2489     FT_Size_Metrics*  metrics;
   2490     FT_Bitmap_Size*   bsize;
   2491 
   2492 
   2493     metrics = &face->size->metrics;
   2494     bsize   = face->available_sizes + strike_index;
   2495 
   2496     metrics->x_ppem = (FT_UShort)( ( bsize->x_ppem + 32 ) >> 6 );
   2497     metrics->y_ppem = (FT_UShort)( ( bsize->y_ppem + 32 ) >> 6 );
   2498 
   2499     if ( FT_IS_SCALABLE( face ) )
   2500     {
   2501       metrics->x_scale = FT_DivFix( bsize->x_ppem,
   2502                                     face->units_per_EM );
   2503       metrics->y_scale = FT_DivFix( bsize->y_ppem,
   2504                                     face->units_per_EM );
   2505 
   2506       ft_recompute_scaled_metrics( face, metrics );
   2507     }
   2508     else
   2509     {
   2510       metrics->x_scale     = 1L << 16;
   2511       metrics->y_scale     = 1L << 16;
   2512       metrics->ascender    = bsize->y_ppem;
   2513       metrics->descender   = 0;
   2514       metrics->height      = bsize->height << 6;
   2515       metrics->max_advance = bsize->x_ppem;
   2516     }
   2517   }
   2518 
   2519 
   2520   FT_BASE_DEF( void )
   2521   FT_Request_Metrics( FT_Face          face,
   2522                       FT_Size_Request  req )
   2523   {
   2524     FT_Size_Metrics*  metrics;
   2525 
   2526 
   2527     metrics = &face->size->metrics;
   2528 
   2529     if ( FT_IS_SCALABLE( face ) )
   2530     {
   2531       FT_Long  w = 0, h = 0, scaled_w = 0, scaled_h = 0;
   2532 
   2533 
   2534       switch ( req->type )
   2535       {
   2536       case FT_SIZE_REQUEST_TYPE_NOMINAL:
   2537         w = h = face->units_per_EM;
   2538         break;
   2539 
   2540       case FT_SIZE_REQUEST_TYPE_REAL_DIM:
   2541         w = h = face->ascender - face->descender;
   2542         break;
   2543 
   2544       case FT_SIZE_REQUEST_TYPE_BBOX:
   2545         w = face->bbox.xMax - face->bbox.xMin;
   2546         h = face->bbox.yMax - face->bbox.yMin;
   2547         break;
   2548 
   2549       case FT_SIZE_REQUEST_TYPE_CELL:
   2550         w = face->max_advance_width;
   2551         h = face->ascender - face->descender;
   2552         break;
   2553 
   2554       case FT_SIZE_REQUEST_TYPE_SCALES:
   2555         metrics->x_scale = (FT_Fixed)req->width;
   2556         metrics->y_scale = (FT_Fixed)req->height;
   2557         if ( !metrics->x_scale )
   2558           metrics->x_scale = metrics->y_scale;
   2559         else if ( !metrics->y_scale )
   2560           metrics->y_scale = metrics->x_scale;
   2561         goto Calculate_Ppem;
   2562 
   2563       case FT_SIZE_REQUEST_TYPE_MAX:
   2564         break;
   2565       }
   2566 
   2567       /* to be on the safe side */
   2568       if ( w < 0 )
   2569         w = -w;
   2570 
   2571       if ( h < 0 )
   2572         h = -h;
   2573 
   2574       scaled_w = FT_REQUEST_WIDTH ( req );
   2575       scaled_h = FT_REQUEST_HEIGHT( req );
   2576 
   2577       /* determine scales */
   2578       if ( req->width )
   2579       {
   2580         metrics->x_scale = FT_DivFix( scaled_w, w );
   2581 
   2582         if ( req->height )
   2583         {
   2584           metrics->y_scale = FT_DivFix( scaled_h, h );
   2585 
   2586           if ( req->type == FT_SIZE_REQUEST_TYPE_CELL )
   2587           {
   2588             if ( metrics->y_scale > metrics->x_scale )
   2589               metrics->y_scale = metrics->x_scale;
   2590             else
   2591               metrics->x_scale = metrics->y_scale;
   2592           }
   2593         }
   2594         else
   2595         {
   2596           metrics->y_scale = metrics->x_scale;
   2597           scaled_h = FT_MulDiv( scaled_w, h, w );
   2598         }
   2599       }
   2600       else
   2601       {
   2602         metrics->x_scale = metrics->y_scale = FT_DivFix( scaled_h, h );
   2603         scaled_w = FT_MulDiv( scaled_h, w, h );
   2604       }
   2605 
   2606   Calculate_Ppem:
   2607       /* calculate the ppems */
   2608       if ( req->type != FT_SIZE_REQUEST_TYPE_NOMINAL )
   2609       {
   2610         scaled_w = FT_MulFix( face->units_per_EM, metrics->x_scale );
   2611         scaled_h = FT_MulFix( face->units_per_EM, metrics->y_scale );
   2612       }
   2613 
   2614       metrics->x_ppem = (FT_UShort)( ( scaled_w + 32 ) >> 6 );
   2615       metrics->y_ppem = (FT_UShort)( ( scaled_h + 32 ) >> 6 );
   2616 
   2617       ft_recompute_scaled_metrics( face, metrics );
   2618     }
   2619     else
   2620     {
   2621       FT_ZERO( metrics );
   2622       metrics->x_scale = 1L << 16;
   2623       metrics->y_scale = 1L << 16;
   2624     }
   2625   }
   2626 
   2627 
   2628   /* documentation is in freetype.h */
   2629 
   2630   FT_EXPORT_DEF( FT_Error )
   2631   FT_Select_Size( FT_Face  face,
   2632                   FT_Int   strike_index )
   2633   {
   2634     FT_Driver_Class  clazz;
   2635 
   2636 
   2637     if ( !face || !FT_HAS_FIXED_SIZES( face ) )
   2638       return FT_Err_Invalid_Face_Handle;
   2639 
   2640     if ( strike_index < 0 || strike_index >= face->num_fixed_sizes )
   2641       return FT_Err_Invalid_Argument;
   2642 
   2643     clazz = face->driver->clazz;
   2644 
   2645     if ( clazz->select_size )
   2646       return clazz->select_size( face->size, (FT_ULong)strike_index );
   2647 
   2648     FT_Select_Metrics( face, (FT_ULong)strike_index );
   2649 
   2650     return FT_Err_Ok;
   2651   }
   2652 
   2653 
   2654   /* documentation is in freetype.h */
   2655 
   2656   FT_EXPORT_DEF( FT_Error )
   2657   FT_Request_Size( FT_Face          face,
   2658                    FT_Size_Request  req )
   2659   {
   2660     FT_Driver_Class  clazz;
   2661     FT_ULong         strike_index;
   2662 
   2663 
   2664     if ( !face )
   2665       return FT_Err_Invalid_Face_Handle;
   2666 
   2667     if ( !req || req->width < 0 || req->height < 0 ||
   2668          req->type >= FT_SIZE_REQUEST_TYPE_MAX )
   2669       return FT_Err_Invalid_Argument;
   2670 
   2671     clazz = face->driver->clazz;
   2672 
   2673     if ( clazz->request_size )
   2674       return clazz->request_size( face->size, req );
   2675 
   2676     /*
   2677      * The reason that a driver doesn't have `request_size' defined is
   2678      * either that the scaling here suffices or that the supported formats
   2679      * are bitmap-only and size matching is not implemented.
   2680      *
   2681      * In the latter case, a simple size matching is done.
   2682      */
   2683     if ( !FT_IS_SCALABLE( face ) && FT_HAS_FIXED_SIZES( face ) )
   2684     {
   2685       FT_Error  error;
   2686 
   2687 
   2688       error = FT_Match_Size( face, req, 0, &strike_index );
   2689       if ( error )
   2690         return error;
   2691 
   2692       FT_TRACE3(( "FT_Request_Size: bitmap strike %lu matched\n",
   2693                   strike_index ));
   2694 
   2695       return FT_Select_Size( face, (FT_Int)strike_index );
   2696     }
   2697 
   2698     FT_Request_Metrics( face, req );
   2699 
   2700     return FT_Err_Ok;
   2701   }
   2702 
   2703 
   2704   /* documentation is in freetype.h */
   2705 
   2706   FT_EXPORT_DEF( FT_Error )
   2707   FT_Set_Char_Size( FT_Face     face,
   2708                     FT_F26Dot6  char_width,
   2709                     FT_F26Dot6  char_height,
   2710                     FT_UInt     horz_resolution,
   2711                     FT_UInt     vert_resolution )
   2712   {
   2713     FT_Size_RequestRec  req;
   2714 
   2715 
   2716     if ( !char_width )
   2717       char_width = char_height;
   2718     else if ( !char_height )
   2719       char_height = char_width;
   2720 
   2721     if ( !horz_resolution )
   2722       horz_resolution = vert_resolution;
   2723     else if ( !vert_resolution )
   2724       vert_resolution = horz_resolution;
   2725 
   2726     if ( char_width  < 1 * 64 )
   2727       char_width  = 1 * 64;
   2728     if ( char_height < 1 * 64 )
   2729       char_height = 1 * 64;
   2730 
   2731     if ( !horz_resolution )
   2732       horz_resolution = vert_resolution = 72;
   2733 
   2734     req.type           = FT_SIZE_REQUEST_TYPE_NOMINAL;
   2735     req.width          = char_width;
   2736     req.height         = char_height;
   2737     req.horiResolution = horz_resolution;
   2738     req.vertResolution = vert_resolution;
   2739 
   2740     return FT_Request_Size( face, &req );
   2741   }
   2742 
   2743 
   2744   /* documentation is in freetype.h */
   2745 
   2746   FT_EXPORT_DEF( FT_Error )
   2747   FT_Set_Pixel_Sizes( FT_Face  face,
   2748                       FT_UInt  pixel_width,
   2749                       FT_UInt  pixel_height )
   2750   {
   2751     FT_Size_RequestRec  req;
   2752 
   2753 
   2754     if ( pixel_width == 0 )
   2755       pixel_width = pixel_height;
   2756     else if ( pixel_height == 0 )
   2757       pixel_height = pixel_width;
   2758 
   2759     if ( pixel_width  < 1 )
   2760       pixel_width  = 1;
   2761     if ( pixel_height < 1 )
   2762       pixel_height = 1;
   2763 
   2764     /* use `>=' to avoid potential compiler warning on 16bit platforms */
   2765     if ( pixel_width  >= 0xFFFFU )
   2766       pixel_width  = 0xFFFFU;
   2767     if ( pixel_height >= 0xFFFFU )
   2768       pixel_height = 0xFFFFU;
   2769 
   2770     req.type           = FT_SIZE_REQUEST_TYPE_NOMINAL;
   2771     req.width          = pixel_width << 6;
   2772     req.height         = pixel_height << 6;
   2773     req.horiResolution = 0;
   2774     req.vertResolution = 0;
   2775 
   2776     return FT_Request_Size( face, &req );
   2777   }
   2778 
   2779 
   2780   /* documentation is in freetype.h */
   2781 
   2782   FT_EXPORT_DEF( FT_Error )
   2783   FT_Get_Kerning( FT_Face     face,
   2784                   FT_UInt     left_glyph,
   2785                   FT_UInt     right_glyph,
   2786                   FT_UInt     kern_mode,
   2787                   FT_Vector  *akerning )
   2788   {
   2789     FT_Error   error = FT_Err_Ok;
   2790     FT_Driver  driver;
   2791 
   2792 
   2793     if ( !face )
   2794       return FT_Err_Invalid_Face_Handle;
   2795 
   2796     if ( !akerning )
   2797       return FT_Err_Invalid_Argument;
   2798 
   2799     driver = face->driver;
   2800 
   2801     akerning->x = 0;
   2802     akerning->y = 0;
   2803 
   2804     if ( driver->clazz->get_kerning )
   2805     {
   2806       error = driver->clazz->get_kerning( face,
   2807                                           left_glyph,
   2808                                           right_glyph,
   2809                                           akerning );
   2810       if ( !error )
   2811       {
   2812         if ( kern_mode != FT_KERNING_UNSCALED )
   2813         {
   2814           akerning->x = FT_MulFix( akerning->x, face->size->metrics.x_scale );
   2815           akerning->y = FT_MulFix( akerning->y, face->size->metrics.y_scale );
   2816 
   2817           if ( kern_mode != FT_KERNING_UNFITTED )
   2818           {
   2819             /* we scale down kerning values for small ppem values */
   2820             /* to avoid that rounding makes them too big.         */
   2821             /* `25' has been determined heuristically.            */
   2822             if ( face->size->metrics.x_ppem < 25 )
   2823               akerning->x = FT_MulDiv( akerning->x,
   2824                                        face->size->metrics.x_ppem, 25 );
   2825             if ( face->size->metrics.y_ppem < 25 )
   2826               akerning->y = FT_MulDiv( akerning->y,
   2827                                        face->size->metrics.y_ppem, 25 );
   2828 
   2829             akerning->x = FT_PIX_ROUND( akerning->x );
   2830             akerning->y = FT_PIX_ROUND( akerning->y );
   2831           }
   2832         }
   2833       }
   2834     }
   2835 
   2836     return error;
   2837   }
   2838 
   2839 
   2840   /* documentation is in freetype.h */
   2841 
   2842   FT_EXPORT_DEF( FT_Error )
   2843   FT_Get_Track_Kerning( FT_Face    face,
   2844                         FT_Fixed   point_size,
   2845                         FT_Int     degree,
   2846                         FT_Fixed*  akerning )
   2847   {
   2848     FT_Service_Kerning  service;
   2849     FT_Error            error = FT_Err_Ok;
   2850 
   2851 
   2852     if ( !face )
   2853       return FT_Err_Invalid_Face_Handle;
   2854 
   2855     if ( !akerning )
   2856       return FT_Err_Invalid_Argument;
   2857 
   2858     FT_FACE_FIND_SERVICE( face, service, KERNING );
   2859     if ( !service )
   2860       return FT_Err_Unimplemented_Feature;
   2861 
   2862     error = service->get_track( face,
   2863                                 point_size,
   2864                                 degree,
   2865                                 akerning );
   2866 
   2867     return error;
   2868   }
   2869 
   2870 
   2871   /* documentation is in freetype.h */
   2872 
   2873   FT_EXPORT_DEF( FT_Error )
   2874   FT_Select_Charmap( FT_Face      face,
   2875                      FT_Encoding  encoding )
   2876   {
   2877     FT_CharMap*  cur;
   2878     FT_CharMap*  limit;
   2879 
   2880 
   2881     if ( !face )
   2882       return FT_Err_Invalid_Face_Handle;
   2883 
   2884     if ( encoding == FT_ENCODING_NONE )
   2885       return FT_Err_Invalid_Argument;
   2886 
   2887     /* FT_ENCODING_UNICODE is special.  We try to find the `best' Unicode */
   2888     /* charmap available, i.e., one with UCS-4 characters, if possible.   */
   2889     /*                                                                    */
   2890     /* This is done by find_unicode_charmap() above, to share code.       */
   2891     if ( encoding == FT_ENCODING_UNICODE )
   2892       return find_unicode_charmap( face );
   2893 
   2894     cur = face->charmaps;
   2895     if ( !cur )
   2896       return FT_Err_Invalid_CharMap_Handle;
   2897 
   2898     limit = cur + face->num_charmaps;
   2899 
   2900     for ( ; cur < limit; cur++ )
   2901     {
   2902       if ( cur[0]->encoding == encoding )
   2903       {
   2904         face->charmap = cur[0];
   2905         return 0;
   2906       }
   2907     }
   2908 
   2909     return FT_Err_Invalid_Argument;
   2910   }
   2911 
   2912 
   2913   /* documentation is in freetype.h */
   2914 
   2915   FT_EXPORT_DEF( FT_Error )
   2916   FT_Set_Charmap( FT_Face     face,
   2917                   FT_CharMap  charmap )
   2918   {
   2919     FT_CharMap*  cur;
   2920     FT_CharMap*  limit;
   2921 
   2922 
   2923     if ( !face )
   2924       return FT_Err_Invalid_Face_Handle;
   2925 
   2926     cur = face->charmaps;
   2927     if ( !cur )
   2928       return FT_Err_Invalid_CharMap_Handle;
   2929     if ( FT_Get_CMap_Format( charmap ) == 14 )
   2930       return FT_Err_Invalid_Argument;
   2931 
   2932     limit = cur + face->num_charmaps;
   2933 
   2934     for ( ; cur < limit; cur++ )
   2935     {
   2936       if ( cur[0] == charmap )
   2937       {
   2938         face->charmap = cur[0];
   2939         return 0;
   2940       }
   2941     }
   2942     return FT_Err_Invalid_Argument;
   2943   }
   2944 
   2945 
   2946   /* documentation is in freetype.h */
   2947 
   2948   FT_EXPORT_DEF( FT_Int )
   2949   FT_Get_Charmap_Index( FT_CharMap  charmap )
   2950   {
   2951     FT_Int  i;
   2952 
   2953 
   2954     for ( i = 0; i < charmap->face->num_charmaps; i++ )
   2955       if ( charmap->face->charmaps[i] == charmap )
   2956         break;
   2957 
   2958     FT_ASSERT( i < charmap->face->num_charmaps );
   2959 
   2960     return i;
   2961   }
   2962 
   2963 
   2964   static void
   2965   ft_cmap_done_internal( FT_CMap  cmap )
   2966   {
   2967     FT_CMap_Class  clazz  = cmap->clazz;
   2968     FT_Face        face   = cmap->charmap.face;
   2969     FT_Memory      memory = FT_FACE_MEMORY(face);
   2970 
   2971 
   2972     if ( clazz->done )
   2973       clazz->done( cmap );
   2974 
   2975     FT_FREE( cmap );
   2976   }
   2977 
   2978 
   2979   FT_BASE_DEF( void )
   2980   FT_CMap_Done( FT_CMap  cmap )
   2981   {
   2982     if ( cmap )
   2983     {
   2984       FT_Face    face   = cmap->charmap.face;
   2985       FT_Memory  memory = FT_FACE_MEMORY( face );
   2986       FT_Error   error;
   2987       FT_Int     i, j;
   2988 
   2989 
   2990       for ( i = 0; i < face->num_charmaps; i++ )
   2991       {
   2992         if ( (FT_CMap)face->charmaps[i] == cmap )
   2993         {
   2994           FT_CharMap  last_charmap = face->charmaps[face->num_charmaps - 1];
   2995 
   2996 
   2997           if ( FT_RENEW_ARRAY( face->charmaps,
   2998                                face->num_charmaps,
   2999                                face->num_charmaps - 1 ) )
   3000             return;
   3001 
   3002           /* remove it from our list of charmaps */
   3003           for ( j = i + 1; j < face->num_charmaps; j++ )
   3004           {
   3005             if ( j == face->num_charmaps - 1 )
   3006               face->charmaps[j - 1] = last_charmap;
   3007             else
   3008               face->charmaps[j - 1] = face->charmaps[j];
   3009           }
   3010 
   3011           face->num_charmaps--;
   3012 
   3013           if ( (FT_CMap)face->charmap == cmap )
   3014             face->charmap = NULL;
   3015 
   3016           ft_cmap_done_internal( cmap );
   3017 
   3018           break;
   3019         }
   3020       }
   3021     }
   3022   }
   3023 
   3024 
   3025   FT_BASE_DEF( FT_Error )
   3026   FT_CMap_New( FT_CMap_Class  clazz,
   3027                FT_Pointer     init_data,
   3028                FT_CharMap     charmap,
   3029                FT_CMap       *acmap )
   3030   {
   3031     FT_Error   error = FT_Err_Ok;
   3032     FT_Face    face;
   3033     FT_Memory  memory;
   3034     FT_CMap    cmap;
   3035 
   3036 
   3037     if ( clazz == NULL || charmap == NULL || charmap->face == NULL )
   3038       return FT_Err_Invalid_Argument;
   3039 
   3040     face   = charmap->face;
   3041     memory = FT_FACE_MEMORY( face );
   3042 
   3043     if ( !FT_ALLOC( cmap, clazz->size ) )
   3044     {
   3045       cmap->charmap = *charmap;
   3046       cmap->clazz   = clazz;
   3047 
   3048       if ( clazz->init )
   3049       {
   3050         error = clazz->init( cmap, init_data );
   3051         if ( error )
   3052           goto Fail;
   3053       }
   3054 
   3055       /* add it to our list of charmaps */
   3056       if ( FT_RENEW_ARRAY( face->charmaps,
   3057                            face->num_charmaps,
   3058                            face->num_charmaps + 1 ) )
   3059         goto Fail;
   3060 
   3061       face->charmaps[face->num_charmaps++] = (FT_CharMap)cmap;
   3062     }
   3063 
   3064   Exit:
   3065     if ( acmap )
   3066       *acmap = cmap;
   3067 
   3068     return error;
   3069 
   3070   Fail:
   3071     ft_cmap_done_internal( cmap );
   3072     cmap = NULL;
   3073     goto Exit;
   3074   }
   3075 
   3076 
   3077   /* documentation is in freetype.h */
   3078 
   3079   FT_EXPORT_DEF( FT_UInt )
   3080   FT_Get_Char_Index( FT_Face   face,
   3081                      FT_ULong  charcode )
   3082   {
   3083     FT_UInt  result = 0;
   3084 
   3085 
   3086     if ( face && face->charmap )
   3087     {
   3088       FT_CMap  cmap = FT_CMAP( face->charmap );
   3089 
   3090 
   3091       if ( charcode > 0xFFFFFFFFUL )
   3092       {
   3093         FT_TRACE1(( "FT_Get_Char_Index: too large charcode" ));
   3094         FT_TRACE1(( " 0x%x is truncated\n", charcode ));
   3095       }
   3096       result = cmap->clazz->char_index( cmap, (FT_UInt32)charcode );
   3097     }
   3098     return  result;
   3099   }
   3100 
   3101 
   3102   /* documentation is in freetype.h */
   3103 
   3104   FT_EXPORT_DEF( FT_ULong )
   3105   FT_Get_First_Char( FT_Face   face,
   3106                      FT_UInt  *agindex )
   3107   {
   3108     FT_ULong  result = 0;
   3109     FT_UInt   gindex = 0;
   3110 
   3111 
   3112     if ( face && face->charmap )
   3113     {
   3114       gindex = FT_Get_Char_Index( face, 0 );
   3115       if ( gindex == 0 )
   3116         result = FT_Get_Next_Char( face, 0, &gindex );
   3117     }
   3118 
   3119     if ( agindex  )
   3120       *agindex = gindex;
   3121 
   3122     return result;
   3123   }
   3124 
   3125 
   3126   /* documentation is in freetype.h */
   3127 
   3128   FT_EXPORT_DEF( FT_ULong )
   3129   FT_Get_Next_Char( FT_Face   face,
   3130                     FT_ULong  charcode,
   3131                     FT_UInt  *agindex )
   3132   {
   3133     FT_ULong  result = 0;
   3134     FT_UInt   gindex = 0;
   3135 
   3136 
   3137     if ( face && face->charmap )
   3138     {
   3139       FT_UInt32  code = (FT_UInt32)charcode;
   3140       FT_CMap    cmap = FT_CMAP( face->charmap );
   3141 
   3142 
   3143       gindex = cmap->clazz->char_next( cmap, &code );
   3144       result = ( gindex == 0 ) ? 0 : code;
   3145     }
   3146 
   3147     if ( agindex )
   3148       *agindex = gindex;
   3149 
   3150     return result;
   3151   }
   3152 
   3153 
   3154   /* documentation is in freetype.h */
   3155 
   3156   FT_EXPORT_DEF( FT_UInt )
   3157   FT_Face_GetCharVariantIndex( FT_Face   face,
   3158                                FT_ULong  charcode,
   3159                                FT_ULong  variantSelector )
   3160   {
   3161     FT_UInt  result = 0;
   3162 
   3163 
   3164     if ( face && face->charmap &&
   3165         face->charmap->encoding == FT_ENCODING_UNICODE )
   3166     {
   3167       FT_CharMap  charmap = find_variant_selector_charmap( face );
   3168       FT_CMap     ucmap = FT_CMAP( face->charmap );
   3169 
   3170 
   3171       if ( charmap != NULL )
   3172       {
   3173         FT_CMap  vcmap = FT_CMAP( charmap );
   3174 
   3175 
   3176         if ( charcode > 0xFFFFFFFFUL )
   3177         {
   3178           FT_TRACE1(( "FT_Get_Char_Index: too large charcode" ));
   3179           FT_TRACE1(( " 0x%x is truncated\n", charcode ));
   3180         }
   3181         if ( variantSelector > 0xFFFFFFFFUL )
   3182         {
   3183           FT_TRACE1(( "FT_Get_Char_Index: too large variantSelector" ));
   3184           FT_TRACE1(( " 0x%x is truncated\n", variantSelector ));
   3185         }
   3186 
   3187         result = vcmap->clazz->char_var_index( vcmap, ucmap,
   3188                                                (FT_UInt32)charcode,
   3189                                                (FT_UInt32)variantSelector );
   3190       }
   3191     }
   3192 
   3193     return result;
   3194   }
   3195 
   3196 
   3197   /* documentation is in freetype.h */
   3198 
   3199   FT_EXPORT_DEF( FT_Int )
   3200   FT_Face_GetCharVariantIsDefault( FT_Face   face,
   3201                                    FT_ULong  charcode,
   3202                                    FT_ULong  variantSelector )
   3203   {
   3204     FT_Int  result = -1;
   3205 
   3206 
   3207     if ( face )
   3208     {
   3209       FT_CharMap  charmap = find_variant_selector_charmap( face );
   3210 
   3211 
   3212       if ( charmap != NULL )
   3213       {
   3214         FT_CMap  vcmap = FT_CMAP( charmap );
   3215 
   3216 
   3217         if ( charcode > 0xFFFFFFFFUL )
   3218         {
   3219           FT_TRACE1(( "FT_Get_Char_Index: too large charcode" ));
   3220           FT_TRACE1(( " 0x%x is truncated\n", charcode ));
   3221         }
   3222         if ( variantSelector > 0xFFFFFFFFUL )
   3223         {
   3224           FT_TRACE1(( "FT_Get_Char_Index: too large variantSelector" ));
   3225           FT_TRACE1(( " 0x%x is truncated\n", variantSelector ));
   3226         }
   3227 
   3228         result = vcmap->clazz->char_var_default( vcmap,
   3229                                                  (FT_UInt32)charcode,
   3230                                                  (FT_UInt32)variantSelector );
   3231       }
   3232     }
   3233 
   3234     return result;
   3235   }
   3236 
   3237 
   3238   /* documentation is in freetype.h */
   3239 
   3240   FT_EXPORT_DEF( FT_UInt32* )
   3241   FT_Face_GetVariantSelectors( FT_Face  face )
   3242   {
   3243     FT_UInt32  *result = NULL;
   3244 
   3245 
   3246     if ( face )
   3247     {
   3248       FT_CharMap  charmap = find_variant_selector_charmap( face );
   3249 
   3250 
   3251       if ( charmap != NULL )
   3252       {
   3253         FT_CMap    vcmap  = FT_CMAP( charmap );
   3254         FT_Memory  memory = FT_FACE_MEMORY( face );
   3255 
   3256 
   3257         result = vcmap->clazz->variant_list( vcmap, memory );
   3258       }
   3259     }
   3260 
   3261     return result;
   3262   }
   3263 
   3264 
   3265   /* documentation is in freetype.h */
   3266 
   3267   FT_EXPORT_DEF( FT_UInt32* )
   3268   FT_Face_GetVariantsOfChar( FT_Face   face,
   3269                              FT_ULong  charcode )
   3270   {
   3271     FT_UInt32  *result = NULL;
   3272 
   3273 
   3274     if ( face )
   3275     {
   3276       FT_CharMap  charmap = find_variant_selector_charmap( face );
   3277 
   3278 
   3279       if ( charmap != NULL )
   3280       {
   3281         FT_CMap    vcmap  = FT_CMAP( charmap );
   3282         FT_Memory  memory = FT_FACE_MEMORY( face );
   3283 
   3284 
   3285         if ( charcode > 0xFFFFFFFFUL )
   3286         {
   3287           FT_TRACE1(( "FT_Get_Char_Index: too large charcode" ));
   3288           FT_TRACE1(( " 0x%x is truncated\n", charcode ));
   3289         }
   3290 
   3291         result = vcmap->clazz->charvariant_list( vcmap, memory,
   3292                                                  (FT_UInt32)charcode );
   3293       }
   3294     }
   3295     return result;
   3296   }
   3297 
   3298 
   3299   /* documentation is in freetype.h */
   3300 
   3301   FT_EXPORT_DEF( FT_UInt32* )
   3302   FT_Face_GetCharsOfVariant( FT_Face   face,
   3303                              FT_ULong  variantSelector )
   3304   {
   3305     FT_UInt32  *result = NULL;
   3306 
   3307 
   3308     if ( face )
   3309     {
   3310       FT_CharMap  charmap = find_variant_selector_charmap( face );
   3311 
   3312 
   3313       if ( charmap != NULL )
   3314       {
   3315         FT_CMap    vcmap  = FT_CMAP( charmap );
   3316         FT_Memory  memory = FT_FACE_MEMORY( face );
   3317 
   3318 
   3319         if ( variantSelector > 0xFFFFFFFFUL )
   3320         {
   3321           FT_TRACE1(( "FT_Get_Char_Index: too large variantSelector" ));
   3322           FT_TRACE1(( " 0x%x is truncated\n", variantSelector ));
   3323         }
   3324 
   3325         result = vcmap->clazz->variantchar_list( vcmap, memory,
   3326                                                  (FT_UInt32)variantSelector );
   3327       }
   3328     }
   3329 
   3330     return result;
   3331   }
   3332 
   3333 
   3334   /* documentation is in freetype.h */
   3335 
   3336   FT_EXPORT_DEF( FT_UInt )
   3337   FT_Get_Name_Index( FT_Face     face,
   3338                      FT_String*  glyph_name )
   3339   {
   3340     FT_UInt  result = 0;
   3341 
   3342 
   3343     if ( face && FT_HAS_GLYPH_NAMES( face ) )
   3344     {
   3345       FT_Service_GlyphDict  service;
   3346 
   3347 
   3348       FT_FACE_LOOKUP_SERVICE( face,
   3349                               service,
   3350                               GLYPH_DICT );
   3351 
   3352       if ( service && service->name_index )
   3353         result = service->name_index( face, glyph_name );
   3354     }
   3355 
   3356     return result;
   3357   }
   3358 
   3359 
   3360   /* documentation is in freetype.h */
   3361 
   3362   FT_EXPORT_DEF( FT_Error )
   3363   FT_Get_Glyph_Name( FT_Face     face,
   3364                      FT_UInt     glyph_index,
   3365                      FT_Pointer  buffer,
   3366                      FT_UInt     buffer_max )
   3367   {
   3368     FT_Error  error = FT_Err_Invalid_Argument;
   3369 
   3370 
   3371     /* clean up buffer */
   3372     if ( buffer && buffer_max > 0 )
   3373       ((FT_Byte*)buffer)[0] = 0;
   3374 
   3375     if ( face                                     &&
   3376          (FT_Long)glyph_index <= face->num_glyphs &&
   3377          FT_HAS_GLYPH_NAMES( face )               )
   3378     {
   3379       FT_Service_GlyphDict  service;
   3380 
   3381 
   3382       FT_FACE_LOOKUP_SERVICE( face,
   3383                               service,
   3384                               GLYPH_DICT );
   3385 
   3386       if ( service && service->get_name )
   3387         error = service->get_name( face, glyph_index, buffer, buffer_max );
   3388     }
   3389 
   3390     return error;
   3391   }
   3392 
   3393 
   3394   /* documentation is in freetype.h */
   3395 
   3396   FT_EXPORT_DEF( const char* )
   3397   FT_Get_Postscript_Name( FT_Face  face )
   3398   {
   3399     const char*  result = NULL;
   3400 
   3401 
   3402     if ( !face )
   3403       goto Exit;
   3404 
   3405     if ( !result )
   3406     {
   3407       FT_Service_PsFontName  service;
   3408 
   3409 
   3410       FT_FACE_LOOKUP_SERVICE( face,
   3411                               service,
   3412                               POSTSCRIPT_FONT_NAME );
   3413 
   3414       if ( service && service->get_ps_font_name )
   3415         result = service->get_ps_font_name( face );
   3416     }
   3417 
   3418   Exit:
   3419     return result;
   3420   }
   3421 
   3422 
   3423   /* documentation is in tttables.h */
   3424 
   3425   FT_EXPORT_DEF( void* )
   3426   FT_Get_Sfnt_Table( FT_Face      face,
   3427                      FT_Sfnt_Tag  tag )
   3428   {
   3429     void*                  table = 0;
   3430     FT_Service_SFNT_Table  service;
   3431 
   3432 
   3433     if ( face && FT_IS_SFNT( face ) )
   3434     {
   3435       FT_FACE_FIND_SERVICE( face, service, SFNT_TABLE );
   3436       if ( service != NULL )
   3437         table = service->get_table( face, tag );
   3438     }
   3439 
   3440     return table;
   3441   }
   3442 
   3443 
   3444   /* documentation is in tttables.h */
   3445 
   3446   FT_EXPORT_DEF( FT_Error )
   3447   FT_Load_Sfnt_Table( FT_Face    face,
   3448                       FT_ULong   tag,
   3449                       FT_Long    offset,
   3450                       FT_Byte*   buffer,
   3451                       FT_ULong*  length )
   3452   {
   3453     FT_Service_SFNT_Table  service;
   3454 
   3455 
   3456     if ( !face || !FT_IS_SFNT( face ) )
   3457       return FT_Err_Invalid_Face_Handle;
   3458 
   3459     FT_FACE_FIND_SERVICE( face, service, SFNT_TABLE );
   3460     if ( service == NULL )
   3461       return FT_Err_Unimplemented_Feature;
   3462 
   3463     return service->load_table( face, tag, offset, buffer, length );
   3464   }
   3465 
   3466 
   3467   /* documentation is in tttables.h */
   3468 
   3469   FT_EXPORT_DEF( FT_Error )
   3470   FT_Sfnt_Table_Info( FT_Face    face,
   3471                       FT_UInt    table_index,
   3472                       FT_ULong  *tag,
   3473                       FT_ULong  *length )
   3474   {
   3475     FT_Service_SFNT_Table  service;
   3476     FT_ULong               offset;
   3477 
   3478 
   3479     if ( !face || !FT_IS_SFNT( face ) )
   3480       return FT_Err_Invalid_Face_Handle;
   3481 
   3482     FT_FACE_FIND_SERVICE( face, service, SFNT_TABLE );
   3483     if ( service == NULL )
   3484       return FT_Err_Unimplemented_Feature;
   3485 
   3486     return service->table_info( face, table_index, tag, &offset, length );
   3487   }
   3488 
   3489 
   3490   /* documentation is in tttables.h */
   3491 
   3492   FT_EXPORT_DEF( FT_ULong )
   3493   FT_Get_CMap_Language_ID( FT_CharMap  charmap )
   3494   {
   3495     FT_Service_TTCMaps  service;
   3496     FT_Face             face;
   3497     TT_CMapInfo         cmap_info;
   3498 
   3499 
   3500     if ( !charmap || !charmap->face )
   3501       return 0;
   3502 
   3503     face = charmap->face;
   3504     FT_FACE_FIND_SERVICE( face, service, TT_CMAP );
   3505     if ( service == NULL )
   3506       return 0;
   3507     if ( service->get_cmap_info( charmap, &cmap_info ))
   3508       return 0;
   3509 
   3510     return cmap_info.language;
   3511   }
   3512 
   3513 
   3514   /* documentation is in tttables.h */
   3515 
   3516   FT_EXPORT_DEF( FT_Long )
   3517   FT_Get_CMap_Format( FT_CharMap  charmap )
   3518   {
   3519     FT_Service_TTCMaps  service;
   3520     FT_Face             face;
   3521     TT_CMapInfo         cmap_info;
   3522 
   3523 
   3524     if ( !charmap || !charmap->face )
   3525       return -1;
   3526 
   3527     face = charmap->face;
   3528     FT_FACE_FIND_SERVICE( face, service, TT_CMAP );
   3529     if ( service == NULL )
   3530       return -1;
   3531     if ( service->get_cmap_info( charmap, &cmap_info ))
   3532       return -1;
   3533 
   3534     return cmap_info.format;
   3535   }
   3536 
   3537 
   3538   /* documentation is in ftsizes.h */
   3539 
   3540   FT_EXPORT_DEF( FT_Error )
   3541   FT_Activate_Size( FT_Size  size )
   3542   {
   3543     FT_Face  face;
   3544 
   3545 
   3546     if ( size == NULL )
   3547       return FT_Err_Invalid_Argument;
   3548 
   3549     face = size->face;
   3550     if ( face == NULL || face->driver == NULL )
   3551       return FT_Err_Invalid_Argument;
   3552 
   3553     /* we don't need anything more complex than that; all size objects */
   3554     /* are already listed by the face                                  */
   3555     face->size = size;
   3556 
   3557     return FT_Err_Ok;
   3558   }
   3559 
   3560 
   3561   /*************************************************************************/
   3562   /*************************************************************************/
   3563   /*************************************************************************/
   3564   /****                                                                 ****/
   3565   /****                                                                 ****/
   3566   /****                        R E N D E R E R S                        ****/
   3567   /****                                                                 ****/
   3568   /****                                                                 ****/
   3569   /*************************************************************************/
   3570   /*************************************************************************/
   3571   /*************************************************************************/
   3572 
   3573   /* lookup a renderer by glyph format in the library's list */
   3574   FT_BASE_DEF( FT_Renderer )
   3575   FT_Lookup_Renderer( FT_Library       library,
   3576                       FT_Glyph_Format  format,
   3577                       FT_ListNode*     node )
   3578   {
   3579     FT_ListNode  cur;
   3580     FT_Renderer  result = 0;
   3581 
   3582 
   3583     if ( !library )
   3584       goto Exit;
   3585 
   3586     cur = library->renderers.head;
   3587 
   3588     if ( node )
   3589     {
   3590       if ( *node )
   3591         cur = (*node)->next;
   3592       *node = 0;
   3593     }
   3594 
   3595     while ( cur )
   3596     {
   3597       FT_Renderer  renderer = FT_RENDERER( cur->data );
   3598 
   3599 
   3600       if ( renderer->glyph_format == format )
   3601       {
   3602         if ( node )
   3603           *node = cur;
   3604 
   3605         result = renderer;
   3606         break;
   3607       }
   3608       cur = cur->next;
   3609     }
   3610 
   3611   Exit:
   3612     return result;
   3613   }
   3614 
   3615 
   3616   static FT_Renderer
   3617   ft_lookup_glyph_renderer( FT_GlyphSlot  slot )
   3618   {
   3619     FT_Face      face    = slot->face;
   3620     FT_Library   library = FT_FACE_LIBRARY( face );
   3621     FT_Renderer  result  = library->cur_renderer;
   3622 
   3623 
   3624     if ( !result || result->glyph_format != slot->format )
   3625       result = FT_Lookup_Renderer( library, slot->format, 0 );
   3626 
   3627     return result;
   3628   }
   3629 
   3630 
   3631   static void
   3632   ft_set_current_renderer( FT_Library  library )
   3633   {
   3634     FT_Renderer  renderer;
   3635 
   3636 
   3637     renderer = FT_Lookup_Renderer( library, FT_GLYPH_FORMAT_OUTLINE, 0 );
   3638     library->cur_renderer = renderer;
   3639   }
   3640 
   3641 
   3642   static FT_Error
   3643   ft_add_renderer( FT_Module  module )
   3644   {
   3645     FT_Library   library = module->library;
   3646     FT_Memory    memory  = library->memory;
   3647     FT_Error     error;
   3648     FT_ListNode  node;
   3649 
   3650 
   3651     if ( FT_NEW( node ) )
   3652       goto Exit;
   3653 
   3654     {
   3655       FT_Renderer         render = FT_RENDERER( module );
   3656       FT_Renderer_Class*  clazz  = (FT_Renderer_Class*)module->clazz;
   3657 
   3658 
   3659       render->clazz        = clazz;
   3660       render->glyph_format = clazz->glyph_format;
   3661 
   3662       /* allocate raster object if needed */
   3663       if ( clazz->glyph_format == FT_GLYPH_FORMAT_OUTLINE &&
   3664            clazz->raster_class->raster_new )
   3665       {
   3666         error = clazz->raster_class->raster_new( memory, &render->raster );
   3667         if ( error )
   3668           goto Fail;
   3669 
   3670         render->raster_render = clazz->raster_class->raster_render;
   3671         render->render        = clazz->render_glyph;
   3672       }
   3673 
   3674       /* add to list */
   3675       node->data = module;
   3676       FT_List_Add( &library->renderers, node );
   3677 
   3678       ft_set_current_renderer( library );
   3679     }
   3680 
   3681   Fail:
   3682     if ( error )
   3683       FT_FREE( node );
   3684 
   3685   Exit:
   3686     return error;
   3687   }
   3688 
   3689 
   3690   static void
   3691   ft_remove_renderer( FT_Module  module )
   3692   {
   3693     FT_Library   library = module->library;
   3694     FT_Memory    memory  = library->memory;
   3695     FT_ListNode  node;
   3696 
   3697 
   3698     node = FT_List_Find( &library->renderers, module );
   3699     if ( node )
   3700     {
   3701       FT_Renderer  render = FT_RENDERER( module );
   3702 
   3703 
   3704       /* release raster object, if any */
   3705       if ( render->raster )
   3706         render->clazz->raster_class->raster_done( render->raster );
   3707 
   3708       /* remove from list */
   3709       FT_List_Remove( &library->renderers, node );
   3710       FT_FREE( node );
   3711 
   3712       ft_set_current_renderer( library );
   3713     }
   3714   }
   3715 
   3716 
   3717   /* documentation is in ftrender.h */
   3718 
   3719   FT_EXPORT_DEF( FT_Renderer )
   3720   FT_Get_Renderer( FT_Library       library,
   3721                    FT_Glyph_Format  format )
   3722   {
   3723     /* test for valid `library' delayed to FT_Lookup_Renderer() */
   3724 
   3725     return FT_Lookup_Renderer( library, format, 0 );
   3726   }
   3727 
   3728 
   3729   /* documentation is in ftrender.h */
   3730 
   3731   FT_EXPORT_DEF( FT_Error )
   3732   FT_Set_Renderer( FT_Library     library,
   3733                    FT_Renderer    renderer,
   3734                    FT_UInt        num_params,
   3735                    FT_Parameter*  parameters )
   3736   {
   3737     FT_ListNode  node;
   3738     FT_Error     error = FT_Err_Ok;
   3739 
   3740 
   3741     if ( !library )
   3742       return FT_Err_Invalid_Library_Handle;
   3743 
   3744     if ( !renderer )
   3745       return FT_Err_Invalid_Argument;
   3746 
   3747     node = FT_List_Find( &library->renderers, renderer );
   3748     if ( !node )
   3749     {
   3750       error = FT_Err_Invalid_Argument;
   3751       goto Exit;
   3752     }
   3753 
   3754     FT_List_Up( &library->renderers, node );
   3755 
   3756     if ( renderer->glyph_format == FT_GLYPH_FORMAT_OUTLINE )
   3757       library->cur_renderer = renderer;
   3758 
   3759     if ( num_params > 0 )
   3760     {
   3761       FT_Renderer_SetModeFunc  set_mode = renderer->clazz->set_mode;
   3762 
   3763 
   3764       for ( ; num_params > 0; num_params-- )
   3765       {
   3766         error = set_mode( renderer, parameters->tag, parameters->data );
   3767         if ( error )
   3768           break;
   3769       }
   3770     }
   3771 
   3772   Exit:
   3773     return error;
   3774   }
   3775 
   3776 
   3777   FT_BASE_DEF( FT_Error )
   3778   FT_Render_Glyph_Internal( FT_Library      library,
   3779                             FT_GlyphSlot    slot,
   3780                             FT_Render_Mode  render_mode )
   3781   {
   3782     FT_Error     error = FT_Err_Ok;
   3783     FT_Renderer  renderer;
   3784 
   3785 
   3786     /* if it is already a bitmap, no need to do anything */
   3787     switch ( slot->format )
   3788     {
   3789     case FT_GLYPH_FORMAT_BITMAP:   /* already a bitmap, don't do anything */
   3790       break;
   3791 
   3792     default:
   3793       {
   3794         FT_ListNode  node   = 0;
   3795         FT_Bool      update = 0;
   3796 
   3797 
   3798         /* small shortcut for the very common case */
   3799         if ( slot->format == FT_GLYPH_FORMAT_OUTLINE )
   3800         {
   3801           renderer = library->cur_renderer;
   3802           node     = library->renderers.head;
   3803         }
   3804         else
   3805           renderer = FT_Lookup_Renderer( library, slot->format, &node );
   3806 
   3807         error = FT_Err_Unimplemented_Feature;
   3808         while ( renderer )
   3809         {
   3810           error = renderer->render( renderer, slot, render_mode, NULL );
   3811           if ( !error ||
   3812                FT_ERROR_BASE( error ) != FT_Err_Cannot_Render_Glyph )
   3813             break;
   3814 
   3815           /* FT_Err_Cannot_Render_Glyph is returned if the render mode   */
   3816           /* is unsupported by the current renderer for this glyph image */
   3817           /* format.                                                     */
   3818 
   3819           /* now, look for another renderer that supports the same */
   3820           /* format.                                               */
   3821           renderer = FT_Lookup_Renderer( library, slot->format, &node );
   3822           update   = 1;
   3823         }
   3824 
   3825         /* if we changed the current renderer for the glyph image format */
   3826         /* we need to select it as the next current one                  */
   3827         if ( !error && update && renderer )
   3828           FT_Set_Renderer( library, renderer, 0, 0 );
   3829       }
   3830     }
   3831 
   3832     return error;
   3833   }
   3834 
   3835 
   3836   /* documentation is in freetype.h */
   3837 
   3838   FT_EXPORT_DEF( FT_Error )
   3839   FT_Render_Glyph( FT_GlyphSlot    slot,
   3840                    FT_Render_Mode  render_mode )
   3841   {
   3842     FT_Library  library;
   3843 
   3844 
   3845     if ( !slot )
   3846       return FT_Err_Invalid_Argument;
   3847 
   3848     library = FT_FACE_LIBRARY( slot->face );
   3849 
   3850     return FT_Render_Glyph_Internal( library, slot, render_mode );
   3851   }
   3852 
   3853 
   3854   /*************************************************************************/
   3855   /*************************************************************************/
   3856   /*************************************************************************/
   3857   /****                                                                 ****/
   3858   /****                                                                 ****/
   3859   /****                         M O D U L E S                           ****/
   3860   /****                                                                 ****/
   3861   /****                                                                 ****/
   3862   /*************************************************************************/
   3863   /*************************************************************************/
   3864   /*************************************************************************/
   3865 
   3866 
   3867   /*************************************************************************/
   3868   /*                                                                       */
   3869   /* <Function>                                                            */
   3870   /*    Destroy_Module                                                     */
   3871   /*                                                                       */
   3872   /* <Description>                                                         */
   3873   /*    Destroys a given module object.  For drivers, this also destroys   */
   3874   /*    all child faces.                                                   */
   3875   /*                                                                       */
   3876   /* <InOut>                                                               */
   3877   /*     module :: A handle to the target driver object.                   */
   3878   /*                                                                       */
   3879   /* <Note>                                                                */
   3880   /*     The driver _must_ be LOCKED!                                      */
   3881   /*                                                                       */
   3882   static void
   3883   Destroy_Module( FT_Module  module )
   3884   {
   3885     FT_Memory         memory  = module->memory;
   3886     FT_Module_Class*  clazz   = module->clazz;
   3887     FT_Library        library = module->library;
   3888 
   3889 
   3890     /* finalize client-data - before anything else */
   3891     if ( module->generic.finalizer )
   3892       module->generic.finalizer( module );
   3893 
   3894     if ( library && library->auto_hinter == module )
   3895       library->auto_hinter = 0;
   3896 
   3897     /* if the module is a renderer */
   3898     if ( FT_MODULE_IS_RENDERER( module ) )
   3899       ft_remove_renderer( module );
   3900 
   3901     /* if the module is a font driver, add some steps */
   3902     if ( FT_MODULE_IS_DRIVER( module ) )
   3903       Destroy_Driver( FT_DRIVER( module ) );
   3904 
   3905     /* finalize the module object */
   3906     if ( clazz->module_done )
   3907       clazz->module_done( module );
   3908 
   3909     /* discard it */
   3910     FT_FREE( module );
   3911   }
   3912 
   3913 
   3914   /* documentation is in ftmodapi.h */
   3915 
   3916   FT_EXPORT_DEF( FT_Error )
   3917   FT_Add_Module( FT_Library              library,
   3918                  const FT_Module_Class*  clazz )
   3919   {
   3920     FT_Error   error;
   3921     FT_Memory  memory;
   3922     FT_Module  module;
   3923     FT_UInt    nn;
   3924 
   3925 
   3926 #define FREETYPE_VER_FIXED  ( ( (FT_Long)FREETYPE_MAJOR << 16 ) | \
   3927                                 FREETYPE_MINOR                  )
   3928 
   3929     if ( !library )
   3930       return FT_Err_Invalid_Library_Handle;
   3931 
   3932     if ( !clazz )
   3933       return FT_Err_Invalid_Argument;
   3934 
   3935     /* check freetype version */
   3936     if ( clazz->module_requires > FREETYPE_VER_FIXED )
   3937       return FT_Err_Invalid_Version;
   3938 
   3939     /* look for a module with the same name in the library's table */
   3940     for ( nn = 0; nn < library->num_modules; nn++ )
   3941     {
   3942       module = library->modules[nn];
   3943       if ( ft_strcmp( module->clazz->module_name, clazz->module_name ) == 0 )
   3944       {
   3945         /* this installed module has the same name, compare their versions */
   3946         if ( clazz->module_version <= module->clazz->module_version )
   3947           return FT_Err_Lower_Module_Version;
   3948 
   3949         /* remove the module from our list, then exit the loop to replace */
   3950         /* it by our new version..                                        */
   3951         FT_Remove_Module( library, module );
   3952         break;
   3953       }
   3954     }
   3955 
   3956     memory = library->memory;
   3957     error  = FT_Err_Ok;
   3958 
   3959     if ( library->num_modules >= FT_MAX_MODULES )
   3960     {
   3961       error = FT_Err_Too_Many_Drivers;
   3962       goto Exit;
   3963     }
   3964 
   3965     /* allocate module object */
   3966     if ( FT_ALLOC( module, clazz->module_size ) )
   3967       goto Exit;
   3968 
   3969     /* base initialization */
   3970     module->library = library;
   3971     module->memory  = memory;
   3972     module->clazz   = (FT_Module_Class*)clazz;
   3973 
   3974     /* check whether the module is a renderer - this must be performed */
   3975     /* before the normal module initialization                         */
   3976     if ( FT_MODULE_IS_RENDERER( module ) )
   3977     {
   3978       /* add to the renderers list */
   3979       error = ft_add_renderer( module );
   3980       if ( error )
   3981         goto Fail;
   3982     }
   3983 
   3984     /* is the module a auto-hinter? */
   3985     if ( FT_MODULE_IS_HINTER( module ) )
   3986       library->auto_hinter = module;
   3987 
   3988     /* if the module is a font driver */
   3989     if ( FT_MODULE_IS_DRIVER( module ) )
   3990     {
   3991       /* allocate glyph loader if needed */
   3992       FT_Driver  driver = FT_DRIVER( module );
   3993 
   3994 
   3995       driver->clazz = (FT_Driver_Class)module->clazz;
   3996       if ( FT_DRIVER_USES_OUTLINES( driver ) )
   3997       {
   3998         error = FT_GlyphLoader_New( memory, &driver->glyph_loader );
   3999         if ( error )
   4000           goto Fail;
   4001       }
   4002     }
   4003 
   4004     if ( clazz->module_init )
   4005     {
   4006       error = clazz->module_init( module );
   4007       if ( error )
   4008         goto Fail;
   4009     }
   4010 
   4011     /* add module to the library's table */
   4012     library->modules[library->num_modules++] = module;
   4013 
   4014   Exit:
   4015     return error;
   4016 
   4017   Fail:
   4018     if ( FT_MODULE_IS_DRIVER( module ) )
   4019     {
   4020       FT_Driver  driver = FT_DRIVER( module );
   4021 
   4022 
   4023       if ( FT_DRIVER_USES_OUTLINES( driver ) )
   4024         FT_GlyphLoader_Done( driver->glyph_loader );
   4025     }
   4026 
   4027     if ( FT_MODULE_IS_RENDERER( module ) )
   4028     {
   4029       FT_Renderer  renderer = FT_RENDERER( module );
   4030 
   4031 
   4032       if ( renderer->raster )
   4033         renderer->clazz->raster_class->raster_done( renderer->raster );
   4034     }
   4035 
   4036     FT_FREE( module );
   4037     goto Exit;
   4038   }
   4039 
   4040 
   4041   /* documentation is in ftmodapi.h */
   4042 
   4043   FT_EXPORT_DEF( FT_Module )
   4044   FT_Get_Module( FT_Library   library,
   4045                  const char*  module_name )
   4046   {
   4047     FT_Module   result = 0;
   4048     FT_Module*  cur;
   4049     FT_Module*  limit;
   4050 
   4051 
   4052     if ( !library || !module_name )
   4053       return result;
   4054 
   4055     cur   = library->modules;
   4056     limit = cur + library->num_modules;
   4057 
   4058     for ( ; cur < limit; cur++ )
   4059       if ( ft_strcmp( cur[0]->clazz->module_name, module_name ) == 0 )
   4060       {
   4061         result = cur[0];
   4062         break;
   4063       }
   4064 
   4065     return result;
   4066   }
   4067 
   4068 
   4069   /* documentation is in ftobjs.h */
   4070 
   4071   FT_BASE_DEF( const void* )
   4072   FT_Get_Module_Interface( FT_Library   library,
   4073                            const char*  mod_name )
   4074   {
   4075     FT_Module  module;
   4076 
   4077 
   4078     /* test for valid `library' delayed to FT_Get_Module() */
   4079 
   4080     module = FT_Get_Module( library, mod_name );
   4081 
   4082     return module ? module->clazz->module_interface : 0;
   4083   }
   4084 
   4085 
   4086   FT_BASE_DEF( FT_Pointer )
   4087   ft_module_get_service( FT_Module    module,
   4088                          const char*  service_id )
   4089   {
   4090     FT_Pointer  result = NULL;
   4091 
   4092     if ( module )
   4093     {
   4094       FT_ASSERT( module->clazz && module->clazz->get_interface );
   4095 
   4096      /* first, look for the service in the module
   4097       */
   4098       if ( module->clazz->get_interface )
   4099         result = module->clazz->get_interface( module, service_id );
   4100 
   4101       if ( result == NULL )
   4102       {
   4103        /* we didn't find it, look in all other modules then
   4104         */
   4105         FT_Library  library = module->library;
   4106         FT_Module*  cur     = library->modules;
   4107         FT_Module*  limit   = cur + library->num_modules;
   4108 
   4109         for ( ; cur < limit; cur++ )
   4110         {
   4111           if ( cur[0] != module )
   4112           {
   4113             FT_ASSERT( cur[0]->clazz );
   4114 
   4115             if ( cur[0]->clazz->get_interface )
   4116             {
   4117               result = cur[0]->clazz->get_interface( cur[0], service_id );
   4118               if ( result != NULL )
   4119                 break;
   4120             }
   4121           }
   4122         }
   4123       }
   4124     }
   4125 
   4126     return result;
   4127   }
   4128 
   4129 
   4130   /* documentation is in ftmodapi.h */
   4131 
   4132   FT_EXPORT_DEF( FT_Error )
   4133   FT_Remove_Module( FT_Library  library,
   4134                     FT_Module   module )
   4135   {
   4136     /* try to find the module from the table, then remove it from there */
   4137 
   4138     if ( !library )
   4139       return FT_Err_Invalid_Library_Handle;
   4140 
   4141     if ( module )
   4142     {
   4143       FT_Module*  cur   = library->modules;
   4144       FT_Module*  limit = cur + library->num_modules;
   4145 
   4146 
   4147       for ( ; cur < limit; cur++ )
   4148       {
   4149         if ( cur[0] == module )
   4150         {
   4151           /* remove it from the table */
   4152           library->num_modules--;
   4153           limit--;
   4154           while ( cur < limit )
   4155           {
   4156             cur[0] = cur[1];
   4157             cur++;
   4158           }
   4159           limit[0] = 0;
   4160 
   4161           /* destroy the module */
   4162           Destroy_Module( module );
   4163 
   4164           return FT_Err_Ok;
   4165         }
   4166       }
   4167     }
   4168     return FT_Err_Invalid_Driver_Handle;
   4169   }
   4170 
   4171 
   4172   /*************************************************************************/
   4173   /*************************************************************************/
   4174   /*************************************************************************/
   4175   /****                                                                 ****/
   4176   /****                                                                 ****/
   4177   /****                         L I B R A R Y                           ****/
   4178   /****                                                                 ****/
   4179   /****                                                                 ****/
   4180   /*************************************************************************/
   4181   /*************************************************************************/
   4182   /*************************************************************************/
   4183 
   4184 
   4185   /* documentation is in ftmodapi.h */
   4186 
   4187   FT_EXPORT_DEF( FT_Error )
   4188   FT_New_Library( FT_Memory    memory,
   4189                   FT_Library  *alibrary )
   4190   {
   4191     FT_Library  library = 0;
   4192     FT_Error    error;
   4193 
   4194 
   4195     if ( !memory )
   4196       return FT_Err_Invalid_Argument;
   4197 
   4198 #ifdef FT_DEBUG_LEVEL_ERROR
   4199     /* init debugging support */
   4200     ft_debug_init();
   4201 #endif
   4202 
   4203     /* first of all, allocate the library object */
   4204     if ( FT_NEW( library ) )
   4205       return error;
   4206 
   4207     library->memory = memory;
   4208 
   4209 #ifdef FT_CONFIG_OPTION_PIC
   4210     /* initialize position independent code containers */
   4211     error = ft_pic_container_init( library );
   4212     if ( error )
   4213       goto Fail;
   4214 #endif
   4215 
   4216     /* allocate the render pool */
   4217     library->raster_pool_size = FT_RENDER_POOL_SIZE;
   4218 #if FT_RENDER_POOL_SIZE > 0
   4219     if ( FT_ALLOC( library->raster_pool, FT_RENDER_POOL_SIZE ) )
   4220       goto Fail;
   4221 #endif
   4222 
   4223     library->version_major = FREETYPE_MAJOR;
   4224     library->version_minor = FREETYPE_MINOR;
   4225     library->version_patch = FREETYPE_PATCH;
   4226 
   4227     /* That's ok now */
   4228     *alibrary = library;
   4229 
   4230     return FT_Err_Ok;
   4231 
   4232   Fail:
   4233 #ifdef FT_CONFIG_OPTION_PIC
   4234     ft_pic_container_destroy( library );
   4235 #endif
   4236     FT_FREE( library );
   4237     return error;
   4238   }
   4239 
   4240 
   4241   /* documentation is in freetype.h */
   4242 
   4243   FT_EXPORT_DEF( void )
   4244   FT_Library_Version( FT_Library   library,
   4245                       FT_Int      *amajor,
   4246                       FT_Int      *aminor,
   4247                       FT_Int      *apatch )
   4248   {
   4249     FT_Int  major = 0;
   4250     FT_Int  minor = 0;
   4251     FT_Int  patch = 0;
   4252 
   4253 
   4254     if ( library )
   4255     {
   4256       major = library->version_major;
   4257       minor = library->version_minor;
   4258       patch = library->version_patch;
   4259     }
   4260 
   4261     if ( amajor )
   4262       *amajor = major;
   4263 
   4264     if ( aminor )
   4265       *aminor = minor;
   4266 
   4267     if ( apatch )
   4268       *apatch = patch;
   4269   }
   4270 
   4271 
   4272   /* documentation is in ftmodapi.h */
   4273 
   4274   FT_EXPORT_DEF( FT_Error )
   4275   FT_Done_Library( FT_Library  library )
   4276   {
   4277     FT_Memory  memory;
   4278 
   4279 
   4280     if ( !library )
   4281       return FT_Err_Invalid_Library_Handle;
   4282 
   4283     memory = library->memory;
   4284 
   4285     /* Discard client-data */
   4286     if ( library->generic.finalizer )
   4287       library->generic.finalizer( library );
   4288 
   4289     /* Close all faces in the library.  If we don't do
   4290      * this, we can have some subtle memory leaks.
   4291      * Example:
   4292      *
   4293      *  - the cff font driver uses the pshinter module in cff_size_done
   4294      *  - if the pshinter module is destroyed before the cff font driver,
   4295      *    opened FT_Face objects managed by the driver are not properly
   4296      *    destroyed, resulting in a memory leak
   4297      */
   4298     {
   4299       FT_UInt  n;
   4300 
   4301 
   4302       for ( n = 0; n < library->num_modules; n++ )
   4303       {
   4304         FT_Module  module = library->modules[n];
   4305         FT_List    faces;
   4306 
   4307 
   4308         if ( ( module->clazz->module_flags & FT_MODULE_FONT_DRIVER ) == 0 )
   4309           continue;
   4310 
   4311         faces = &FT_DRIVER(module)->faces_list;
   4312         while ( faces->head )
   4313         {
   4314           FT_Done_Face( FT_FACE( faces->head->data ) );
   4315           if ( faces->head )
   4316             FT_TRACE0(( "FT_Done_Library: failed to free some faces\n" ));
   4317         }
   4318       }
   4319     }
   4320 
   4321     /* Close all other modules in the library */
   4322 #if 1
   4323     /* XXX Modules are removed in the reversed order so that  */
   4324     /* type42 module is removed before truetype module.  This */
   4325     /* avoids double free in some occasions.  It is a hack.   */
   4326     while ( library->num_modules > 0 )
   4327       FT_Remove_Module( library,
   4328                         library->modules[library->num_modules - 1] );
   4329 #else
   4330     {
   4331       FT_UInt  n;
   4332 
   4333 
   4334       for ( n = 0; n < library->num_modules; n++ )
   4335       {
   4336         FT_Module  module = library->modules[n];
   4337 
   4338 
   4339         if ( module )
   4340         {
   4341           Destroy_Module( module );
   4342           library->modules[n] = 0;
   4343         }
   4344       }
   4345     }
   4346 #endif
   4347 
   4348     /* Destroy raster objects */
   4349     FT_FREE( library->raster_pool );
   4350     library->raster_pool_size = 0;
   4351 
   4352 #ifdef FT_CONFIG_OPTION_PIC
   4353     /* Destroy pic container contents */
   4354     ft_pic_container_destroy( library );
   4355 #endif
   4356 
   4357     FT_FREE( library );
   4358     return FT_Err_Ok;
   4359   }
   4360 
   4361 
   4362   /* documentation is in ftmodapi.h */
   4363 
   4364   FT_EXPORT_DEF( void )
   4365   FT_Set_Debug_Hook( FT_Library         library,
   4366                      FT_UInt            hook_index,
   4367                      FT_DebugHook_Func  debug_hook )
   4368   {
   4369     if ( library && debug_hook &&
   4370          hook_index <
   4371            ( sizeof ( library->debug_hooks ) / sizeof ( void* ) ) )
   4372       library->debug_hooks[hook_index] = debug_hook;
   4373   }
   4374 
   4375 
   4376   /* documentation is in ftmodapi.h */
   4377 
   4378   FT_EXPORT_DEF( FT_TrueTypeEngineType )
   4379   FT_Get_TrueType_Engine_Type( FT_Library  library )
   4380   {
   4381     FT_TrueTypeEngineType  result = FT_TRUETYPE_ENGINE_TYPE_NONE;
   4382 
   4383 
   4384     if ( library )
   4385     {
   4386       FT_Module  module = FT_Get_Module( library, "truetype" );
   4387 
   4388 
   4389       if ( module )
   4390       {
   4391         FT_Service_TrueTypeEngine  service;
   4392 
   4393 
   4394         service = (FT_Service_TrueTypeEngine)
   4395                     ft_module_get_service( module,
   4396                                            FT_SERVICE_ID_TRUETYPE_ENGINE );
   4397         if ( service )
   4398           result = service->engine_type;
   4399       }
   4400     }
   4401 
   4402     return result;
   4403   }
   4404 
   4405 
   4406 #ifdef FT_CONFIG_OPTION_OLD_INTERNALS
   4407 
   4408   FT_BASE_DEF( FT_Error )
   4409   ft_stub_set_char_sizes( FT_Size     size,
   4410                           FT_F26Dot6  width,
   4411                           FT_F26Dot6  height,
   4412                           FT_UInt     horz_res,
   4413                           FT_UInt     vert_res )
   4414   {
   4415     FT_Size_RequestRec  req;
   4416     FT_Driver           driver = size->face->driver;
   4417 
   4418 
   4419     if ( driver->clazz->request_size )
   4420     {
   4421       req.type   = FT_SIZE_REQUEST_TYPE_NOMINAL;
   4422       req.width  = width;
   4423       req.height = height;
   4424 
   4425       if ( horz_res == 0 )
   4426         horz_res = vert_res;
   4427 
   4428       if ( vert_res == 0 )
   4429         vert_res = horz_res;
   4430 
   4431       if ( horz_res == 0 )
   4432         horz_res = vert_res = 72;
   4433 
   4434       req.horiResolution = horz_res;
   4435       req.vertResolution = vert_res;
   4436 
   4437       return driver->clazz->request_size( size, &req );
   4438     }
   4439 
   4440     return 0;
   4441   }
   4442 
   4443 
   4444   FT_BASE_DEF( FT_Error )
   4445   ft_stub_set_pixel_sizes( FT_Size  size,
   4446                            FT_UInt  width,
   4447                            FT_UInt  height )
   4448   {
   4449     FT_Size_RequestRec  req;
   4450     FT_Driver           driver = size->face->driver;
   4451 
   4452 
   4453     if ( driver->clazz->request_size )
   4454     {
   4455       req.type           = FT_SIZE_REQUEST_TYPE_NOMINAL;
   4456       req.width          = width  << 6;
   4457       req.height         = height << 6;
   4458       req.horiResolution = 0;
   4459       req.vertResolution = 0;
   4460 
   4461       return driver->clazz->request_size( size, &req );
   4462     }
   4463 
   4464     return 0;
   4465   }
   4466 
   4467 #endif /* FT_CONFIG_OPTION_OLD_INTERNALS */
   4468 
   4469 
   4470   FT_EXPORT_DEF( FT_Error )
   4471   FT_Get_SubGlyph_Info( FT_GlyphSlot  glyph,
   4472                         FT_UInt       sub_index,
   4473                         FT_Int       *p_index,
   4474                         FT_UInt      *p_flags,
   4475                         FT_Int       *p_arg1,
   4476                         FT_Int       *p_arg2,
   4477                         FT_Matrix    *p_transform )
   4478   {
   4479     FT_Error  error = FT_Err_Invalid_Argument;
   4480 
   4481 
   4482     if ( glyph != NULL                              &&
   4483          glyph->format == FT_GLYPH_FORMAT_COMPOSITE &&
   4484          sub_index < glyph->num_subglyphs           )
   4485     {
   4486       FT_SubGlyph  subg = glyph->subglyphs + sub_index;
   4487 
   4488 
   4489       *p_index     = subg->index;
   4490       *p_flags     = subg->flags;
   4491       *p_arg1      = subg->arg1;
   4492       *p_arg2      = subg->arg2;
   4493       *p_transform = subg->transform;
   4494     }
   4495 
   4496     return error;
   4497   }
   4498 
   4499 
   4500 /* END */
   4501