ftobjs.c

Go to the documentation of this file.
00001 /***************************************************************************/
00002 /*                                                                         */
00003 /*  ftobjs.c                                                               */
00004 /*                                                                         */
00005 /*    The FreeType private base classes (body).                            */
00006 /*                                                                         */
00007 /*  Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,   */
00008 /*            2010 by                                                      */
00009 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
00010 /*                                                                         */
00011 /*  This file is part of the FreeType project, and may only be used,       */
00012 /*  modified, and distributed under the terms of the FreeType project      */
00013 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
00014 /*  this file you indicate that you have read the license and              */
00015 /*  understand and accept it fully.                                        */
00016 /*                                                                         */
00017 /***************************************************************************/
00018 
00019 
00020 #include <ft2build.h>
00021 #include FT_LIST_H
00022 #include FT_OUTLINE_H
00023 #include FT_INTERNAL_VALIDATE_H
00024 #include FT_INTERNAL_OBJECTS_H
00025 #include FT_INTERNAL_DEBUG_H
00026 #include FT_INTERNAL_RFORK_H
00027 #include FT_INTERNAL_STREAM_H
00028 #include FT_INTERNAL_SFNT_H    /* for SFNT_Load_Table_Func */
00029 #include FT_TRUETYPE_TABLES_H
00030 #include FT_TRUETYPE_TAGS_H
00031 #include FT_TRUETYPE_IDS_H
00032 #include FT_OUTLINE_H
00033 
00034 #include FT_SERVICE_SFNT_H
00035 #include FT_SERVICE_POSTSCRIPT_NAME_H
00036 #include FT_SERVICE_GLYPH_DICT_H
00037 #include FT_SERVICE_TT_CMAP_H
00038 #include FT_SERVICE_KERNING_H
00039 #include FT_SERVICE_TRUETYPE_ENGINE_H
00040 
00041 #ifdef FT_CONFIG_OPTION_MAC_FONTS
00042 #include "ftbase.h"
00043 #endif
00044 
00045 #define GRID_FIT_METRICS
00046 
00047 
00048   FT_BASE_DEF( FT_Pointer )
00049   ft_service_list_lookup( FT_ServiceDesc  service_descriptors,
00050                           const char*     service_id )
00051   {
00052     FT_Pointer      result = NULL;
00053     FT_ServiceDesc  desc   = service_descriptors;
00054 
00055 
00056     if ( desc && service_id )
00057     {
00058       for ( ; desc->serv_id != NULL; desc++ )
00059       {
00060         if ( ft_strcmp( desc->serv_id, service_id ) == 0 )
00061         {
00062           result = (FT_Pointer)desc->serv_data;
00063           break;
00064         }
00065       }
00066     }
00067 
00068     return result;
00069   }
00070 
00071 
00072   FT_BASE_DEF( void )
00073   ft_validator_init( FT_Validator        valid,
00074                      const FT_Byte*      base,
00075                      const FT_Byte*      limit,
00076                      FT_ValidationLevel  level )
00077   {
00078     valid->base  = base;
00079     valid->limit = limit;
00080     valid->level = level;
00081     valid->error = FT_Err_Ok;
00082   }
00083 
00084 
00085   FT_BASE_DEF( FT_Int )
00086   ft_validator_run( FT_Validator  valid )
00087   {
00088     /* This function doesn't work!  None should call it. */
00089     FT_UNUSED( valid );
00090 
00091     return -1;
00092   }
00093 
00094 
00095   FT_BASE_DEF( void )
00096   ft_validator_error( FT_Validator  valid,
00097                       FT_Error      error )
00098   {
00099     /* since the cast below also disables the compiler's */
00100     /* type check, we introduce a dummy variable, which  */
00101     /* will be optimized away                            */
00102     volatile ft_jmp_buf* jump_buffer = &valid->jump_buffer;
00103 
00104 
00105     valid->error = error;
00106 
00107     /* throw away volatileness; use `jump_buffer' or the  */
00108     /* compiler may warn about an unused local variable   */
00109     ft_longjmp( *(ft_jmp_buf*) jump_buffer, 1 );
00110   }
00111 
00112 
00113   /*************************************************************************/
00114   /*************************************************************************/
00115   /*************************************************************************/
00116   /****                                                                 ****/
00117   /****                                                                 ****/
00118   /****                           S T R E A M                           ****/
00119   /****                                                                 ****/
00120   /****                                                                 ****/
00121   /*************************************************************************/
00122   /*************************************************************************/
00123   /*************************************************************************/
00124 
00125 
00126   /* create a new input stream from an FT_Open_Args structure */
00127   /*                                                          */
00128   FT_BASE_DEF( FT_Error )
00129   FT_Stream_New( FT_Library           library,
00130                  const FT_Open_Args*  args,
00131                  FT_Stream           *astream )
00132   {
00133     FT_Error   error;
00134     FT_Memory  memory;
00135     FT_Stream  stream;
00136 
00137 
00138     *astream = 0;
00139 
00140     if ( !library )
00141       return FT_Err_Invalid_Library_Handle;
00142 
00143     if ( !args )
00144       return FT_Err_Invalid_Argument;
00145 
00146     memory   = library->memory;
00147 
00148     if ( FT_NEW( stream ) )
00149       goto Exit;
00150 
00151     stream->memory = memory;
00152 
00153     if ( args->flags & FT_OPEN_MEMORY )
00154     {
00155       /* create a memory-based stream */
00156       FT_Stream_OpenMemory( stream,
00157                             (const FT_Byte*)args->memory_base,
00158                             args->memory_size );
00159     }
00160     else if ( args->flags & FT_OPEN_PATHNAME )
00161     {
00162       /* create a normal system stream */
00163       error = FT_Stream_Open( stream, args->pathname );
00164       stream->pathname.pointer = args->pathname;
00165     }
00166     else if ( ( args->flags & FT_OPEN_STREAM ) && args->stream )
00167     {
00168       /* use an existing, user-provided stream */
00169 
00170       /* in this case, we do not need to allocate a new stream object */
00171       /* since the caller is responsible for closing it himself       */
00172       FT_FREE( stream );
00173       stream = args->stream;
00174     }
00175     else
00176       error = FT_Err_Invalid_Argument;
00177 
00178     if ( error )
00179       FT_FREE( stream );
00180     else
00181       stream->memory = memory;  /* just to be certain */
00182 
00183     *astream = stream;
00184 
00185   Exit:
00186     return error;
00187   }
00188 
00189 
00190   FT_BASE_DEF( void )
00191   FT_Stream_Free( FT_Stream  stream,
00192                   FT_Int     external )
00193   {
00194     if ( stream )
00195     {
00196       FT_Memory  memory = stream->memory;
00197 
00198 
00199       FT_Stream_Close( stream );
00200 
00201       if ( !external )
00202         FT_FREE( stream );
00203     }
00204   }
00205 
00206 
00207   /*************************************************************************/
00208   /*                                                                       */
00209   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
00210   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
00211   /* messages during execution.                                            */
00212   /*                                                                       */
00213 #undef  FT_COMPONENT
00214 #define FT_COMPONENT  trace_objs
00215 
00216 
00217   /*************************************************************************/
00218   /*************************************************************************/
00219   /*************************************************************************/
00220   /****                                                                 ****/
00221   /****                                                                 ****/
00222   /****               FACE, SIZE & GLYPH SLOT OBJECTS                   ****/
00223   /****                                                                 ****/
00224   /****                                                                 ****/
00225   /*************************************************************************/
00226   /*************************************************************************/
00227   /*************************************************************************/
00228 
00229 
00230   static FT_Error
00231   ft_glyphslot_init( FT_GlyphSlot  slot )
00232   {
00233     FT_Driver         driver = slot->face->driver;
00234     FT_Driver_Class   clazz  = driver->clazz;
00235     FT_Memory         memory = driver->root.memory;
00236     FT_Error          error  = FT_Err_Ok;
00237     FT_Slot_Internal  internal;
00238 
00239 
00240     slot->library = driver->root.library;
00241 
00242     if ( FT_NEW( internal ) )
00243       goto Exit;
00244 
00245     slot->internal = internal;
00246 
00247     if ( FT_DRIVER_USES_OUTLINES( driver ) )
00248       error = FT_GlyphLoader_New( memory, &internal->loader );
00249 
00250     if ( !error && clazz->init_slot )
00251       error = clazz->init_slot( slot );
00252 
00253   Exit:
00254     return error;
00255   }
00256 
00257 
00258   FT_BASE_DEF( void )
00259   ft_glyphslot_free_bitmap( FT_GlyphSlot  slot )
00260   {
00261     if ( slot->internal && ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) )
00262     {
00263       FT_Memory  memory = FT_FACE_MEMORY( slot->face );
00264 
00265 
00266       FT_FREE( slot->bitmap.buffer );
00267       slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
00268     }
00269     else
00270     {
00271       /* assume that the bitmap buffer was stolen or not */
00272       /* allocated from the heap                         */
00273       slot->bitmap.buffer = NULL;
00274     }
00275   }
00276 
00277 
00278   FT_BASE_DEF( void )
00279   ft_glyphslot_set_bitmap( FT_GlyphSlot  slot,
00280                            FT_Byte*      buffer )
00281   {
00282     ft_glyphslot_free_bitmap( slot );
00283 
00284     slot->bitmap.buffer = buffer;
00285 
00286     FT_ASSERT( (slot->internal->flags & FT_GLYPH_OWN_BITMAP) == 0 );
00287   }
00288 
00289 
00290   FT_BASE_DEF( FT_Error )
00291   ft_glyphslot_alloc_bitmap( FT_GlyphSlot  slot,
00292                              FT_ULong      size )
00293   {
00294     FT_Memory  memory = FT_FACE_MEMORY( slot->face );
00295     FT_Error   error;
00296 
00297 
00298     if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
00299       FT_FREE( slot->bitmap.buffer );
00300     else
00301       slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
00302 
00303     (void)FT_ALLOC( slot->bitmap.buffer, size );
00304     return error;
00305   }
00306 
00307 
00308   static void
00309   ft_glyphslot_clear( FT_GlyphSlot  slot )
00310   {
00311     /* free bitmap if needed */
00312     ft_glyphslot_free_bitmap( slot );
00313 
00314     /* clear all public fields in the glyph slot */
00315     FT_ZERO( &slot->metrics );
00316     FT_ZERO( &slot->outline );
00317 
00318     slot->bitmap.width      = 0;
00319     slot->bitmap.rows       = 0;
00320     slot->bitmap.pitch      = 0;
00321     slot->bitmap.pixel_mode = 0;
00322     /* `slot->bitmap.buffer' has been handled by ft_glyphslot_free_bitmap */
00323 
00324     slot->bitmap_left   = 0;
00325     slot->bitmap_top    = 0;
00326     slot->num_subglyphs = 0;
00327     slot->subglyphs     = 0;
00328     slot->control_data  = 0;
00329     slot->control_len   = 0;
00330     slot->other         = 0;
00331     slot->format        = FT_GLYPH_FORMAT_NONE;
00332 
00333     slot->linearHoriAdvance = 0;
00334     slot->linearVertAdvance = 0;
00335     slot->lsb_delta         = 0;
00336     slot->rsb_delta         = 0;
00337   }
00338 
00339 
00340   static void
00341   ft_glyphslot_done( FT_GlyphSlot  slot )
00342   {
00343     FT_Driver        driver = slot->face->driver;
00344     FT_Driver_Class  clazz  = driver->clazz;
00345     FT_Memory        memory = driver->root.memory;
00346 
00347 
00348     if ( clazz->done_slot )
00349       clazz->done_slot( slot );
00350 
00351     /* free bitmap buffer if needed */
00352     ft_glyphslot_free_bitmap( slot );
00353 
00354     /* slot->internal might be NULL in out-of-memory situations */
00355     if ( slot->internal )
00356     {
00357       /* free glyph loader */
00358       if ( FT_DRIVER_USES_OUTLINES( driver ) )
00359       {
00360         FT_GlyphLoader_Done( slot->internal->loader );
00361         slot->internal->loader = 0;
00362       }
00363 
00364       FT_FREE( slot->internal );
00365     }
00366   }
00367 
00368 
00369   /* documentation is in ftobjs.h */
00370 
00371   FT_BASE_DEF( FT_Error )
00372   FT_New_GlyphSlot( FT_Face        face,
00373                     FT_GlyphSlot  *aslot )
00374   {
00375     FT_Error         error;
00376     FT_Driver        driver;
00377     FT_Driver_Class  clazz;
00378     FT_Memory        memory;
00379     FT_GlyphSlot     slot;
00380 
00381 
00382     if ( !face || !face->driver )
00383       return FT_Err_Invalid_Argument;
00384 
00385     driver = face->driver;
00386     clazz  = driver->clazz;
00387     memory = driver->root.memory;
00388 
00389     FT_TRACE4(( "FT_New_GlyphSlot: Creating new slot object\n" ));
00390     if ( !FT_ALLOC( slot, clazz->slot_object_size ) )
00391     {
00392       slot->face = face;
00393 
00394       error = ft_glyphslot_init( slot );
00395       if ( error )
00396       {
00397         ft_glyphslot_done( slot );
00398         FT_FREE( slot );
00399         goto Exit;
00400       }
00401 
00402       slot->next  = face->glyph;
00403       face->glyph = slot;
00404 
00405       if ( aslot )
00406         *aslot = slot;
00407     }
00408     else if ( aslot )
00409       *aslot = 0;
00410 
00411 
00412   Exit:
00413     FT_TRACE4(( "FT_New_GlyphSlot: Return %d\n", error ));
00414     return error;
00415   }
00416 
00417 
00418   /* documentation is in ftobjs.h */
00419 
00420   FT_BASE_DEF( void )
00421   FT_Done_GlyphSlot( FT_GlyphSlot  slot )
00422   {
00423     if ( slot )
00424     {
00425       FT_Driver     driver = slot->face->driver;
00426       FT_Memory     memory = driver->root.memory;
00427       FT_GlyphSlot  prev;
00428       FT_GlyphSlot  cur;
00429 
00430 
00431       /* Remove slot from its parent face's list */
00432       prev = NULL;
00433       cur  = slot->face->glyph;
00434 
00435       while ( cur )
00436       {
00437         if ( cur == slot )
00438         {
00439           if ( !prev )
00440             slot->face->glyph = cur->next;
00441           else
00442             prev->next = cur->next;
00443 
00444           ft_glyphslot_done( slot );
00445           FT_FREE( slot );
00446           break;
00447         }
00448         prev = cur;
00449         cur  = cur->next;
00450       }
00451     }
00452   }
00453 
00454 
00455   /* documentation is in freetype.h */
00456 
00457   FT_EXPORT_DEF( void )
00458   FT_Set_Transform( FT_Face     face,
00459                     FT_Matrix*  matrix,
00460                     FT_Vector*  delta )
00461   {
00462     FT_Face_Internal  internal;
00463 
00464 
00465     if ( !face )
00466       return;
00467 
00468     internal = face->internal;
00469 
00470     internal->transform_flags = 0;
00471 
00472     if ( !matrix )
00473     {
00474       internal->transform_matrix.xx = 0x10000L;
00475       internal->transform_matrix.xy = 0;
00476       internal->transform_matrix.yx = 0;
00477       internal->transform_matrix.yy = 0x10000L;
00478       matrix = &internal->transform_matrix;
00479     }
00480     else
00481       internal->transform_matrix = *matrix;
00482 
00483     /* set transform_flags bit flag 0 if `matrix' isn't the identity */
00484     if ( ( matrix->xy | matrix->yx ) ||
00485          matrix->xx != 0x10000L      ||
00486          matrix->yy != 0x10000L      )
00487       internal->transform_flags |= 1;
00488 
00489     if ( !delta )
00490     {
00491       internal->transform_delta.x = 0;
00492       internal->transform_delta.y = 0;
00493       delta = &internal->transform_delta;
00494     }
00495     else
00496       internal->transform_delta = *delta;
00497 
00498     /* set transform_flags bit flag 1 if `delta' isn't the null vector */
00499     if ( delta->x | delta->y )
00500       internal->transform_flags |= 2;
00501   }
00502 
00503 
00504   static FT_Renderer
00505   ft_lookup_glyph_renderer( FT_GlyphSlot  slot );
00506 
00507 
00508 #ifdef GRID_FIT_METRICS
00509   static void
00510   ft_glyphslot_grid_fit_metrics( FT_GlyphSlot  slot,
00511                                  FT_Bool       vertical )
00512   {
00513     FT_Glyph_Metrics*  metrics = &slot->metrics;
00514     FT_Pos             right, bottom;
00515 
00516 
00517     if ( vertical )
00518     {
00519       metrics->horiBearingX = FT_PIX_FLOOR( metrics->horiBearingX );
00520       metrics->horiBearingY = FT_PIX_CEIL ( metrics->horiBearingY );
00521 
00522       right  = FT_PIX_CEIL( metrics->vertBearingX + metrics->width );
00523       bottom = FT_PIX_CEIL( metrics->vertBearingY + metrics->height );
00524 
00525       metrics->vertBearingX = FT_PIX_FLOOR( metrics->vertBearingX );
00526       metrics->vertBearingY = FT_PIX_FLOOR( metrics->vertBearingY );
00527 
00528       metrics->width  = right - metrics->vertBearingX;
00529       metrics->height = bottom - metrics->vertBearingY;
00530     }
00531     else
00532     {
00533       metrics->vertBearingX = FT_PIX_FLOOR( metrics->vertBearingX );
00534       metrics->vertBearingY = FT_PIX_FLOOR( metrics->vertBearingY );
00535 
00536       right  = FT_PIX_CEIL ( metrics->horiBearingX + metrics->width );
00537       bottom = FT_PIX_FLOOR( metrics->horiBearingY - metrics->height );
00538 
00539       metrics->horiBearingX = FT_PIX_FLOOR( metrics->horiBearingX );
00540       metrics->horiBearingY = FT_PIX_CEIL ( metrics->horiBearingY );
00541 
00542       metrics->width  = right - metrics->horiBearingX;
00543       metrics->height = metrics->horiBearingY - bottom;
00544     }
00545 
00546     metrics->horiAdvance = FT_PIX_ROUND( metrics->horiAdvance );
00547     metrics->vertAdvance = FT_PIX_ROUND( metrics->vertAdvance );
00548   }
00549 #endif /* GRID_FIT_METRICS */
00550 
00551 
00552   /* documentation is in freetype.h */
00553 
00554   FT_EXPORT_DEF( FT_Error )
00555   FT_Load_Glyph( FT_Face   face,
00556                  FT_UInt   glyph_index,
00557                  FT_Int32  load_flags )
00558   {
00559     FT_Error      error;
00560     FT_Driver     driver;
00561     FT_GlyphSlot  slot;
00562     FT_Library    library;
00563     FT_Bool       autohint = FALSE;
00564     FT_Module     hinter;
00565 
00566 
00567     if ( !face || !face->size || !face->glyph )
00568       return FT_Err_Invalid_Face_Handle;
00569 
00570     /* The validity test for `glyph_index' is performed by the */
00571     /* font drivers.                                           */
00572 
00573     slot = face->glyph;
00574     ft_glyphslot_clear( slot );
00575 
00576     driver  = face->driver;
00577     library = driver->root.library;
00578     hinter  = library->auto_hinter;
00579 
00580     /* resolve load flags dependencies */
00581 
00582     if ( load_flags & FT_LOAD_NO_RECURSE )
00583       load_flags |= FT_LOAD_NO_SCALE         |
00584                     FT_LOAD_IGNORE_TRANSFORM;
00585 
00586     if ( load_flags & FT_LOAD_NO_SCALE )
00587     {
00588       load_flags |= FT_LOAD_NO_HINTING |
00589                     FT_LOAD_NO_BITMAP;
00590 
00591       load_flags &= ~FT_LOAD_RENDER;
00592     }
00593 
00594     /*
00595      * Determine whether we need to auto-hint or not.
00596      * The general rules are:
00597      *
00598      * - Do only auto-hinting if we have a hinter module, a scalable font
00599      *   format dealing with outlines, and no transforms except simple
00600      *   slants and/or rotations by integer multiples of 90 degrees.
00601      *
00602      * - Then, auto-hint if FT_LOAD_FORCE_AUTOHINT is set or if we don't
00603      *   have a native font hinter.
00604      *
00605      * - Otherwise, auto-hint for LIGHT hinting mode.
00606      *
00607      * - Exception: The font is `tricky' and requires the native hinter to
00608      *   load properly.
00609      */
00610 
00611     if ( hinter                                           &&
00612          !( load_flags & FT_LOAD_NO_HINTING )             &&
00613          !( load_flags & FT_LOAD_NO_AUTOHINT )            &&
00614          FT_DRIVER_IS_SCALABLE( driver )                  &&
00615          FT_DRIVER_USES_OUTLINES( driver )                &&
00616          !FT_IS_TRICKY( face )                            &&
00617          ( ( face->internal->transform_matrix.yx == 0 &&
00618              face->internal->transform_matrix.xx != 0 ) ||
00619            ( face->internal->transform_matrix.xx == 0 &&
00620              face->internal->transform_matrix.yx != 0 ) ) )
00621     {
00622       if ( ( load_flags & FT_LOAD_FORCE_AUTOHINT ) ||
00623            !FT_DRIVER_HAS_HINTER( driver )         )
00624         autohint = TRUE;
00625       else
00626       {
00627         FT_Render_Mode  mode = FT_LOAD_TARGET_MODE( load_flags );
00628 
00629 
00630         if ( mode == FT_RENDER_MODE_LIGHT             ||
00631              face->internal->ignore_unpatented_hinter )
00632           autohint = TRUE;
00633       }
00634     }
00635 
00636     if ( autohint )
00637     {
00638       FT_AutoHinter_Service  hinting;
00639 
00640 
00641       /* try to load embedded bitmaps first if available            */
00642       /*                                                            */
00643       /* XXX: This is really a temporary hack that should disappear */
00644       /*      promptly with FreeType 2.1!                           */
00645       /*                                                            */
00646       if ( FT_HAS_FIXED_SIZES( face )             &&
00647           ( load_flags & FT_LOAD_NO_BITMAP ) == 0 )
00648       {
00649         error = driver->clazz->load_glyph( slot, face->size,
00650                                            glyph_index,
00651                                            load_flags | FT_LOAD_SBITS_ONLY );
00652 
00653         if ( !error && slot->format == FT_GLYPH_FORMAT_BITMAP )
00654           goto Load_Ok;
00655       }
00656 
00657       {
00658         FT_Face_Internal  internal        = face->internal;
00659         FT_Int            transform_flags = internal->transform_flags;
00660 
00661 
00662         /* since the auto-hinter calls FT_Load_Glyph by itself, */
00663         /* make sure that glyphs aren't transformed             */
00664         internal->transform_flags = 0;
00665 
00666         /* load auto-hinted outline */
00667         hinting = (FT_AutoHinter_Service)hinter->clazz->module_interface;
00668 
00669         error   = hinting->load_glyph( (FT_AutoHinter)hinter,
00670                                        slot, face->size,
00671                                        glyph_index, load_flags );
00672 
00673         internal->transform_flags = transform_flags;
00674       }
00675     }
00676     else
00677     {
00678       error = driver->clazz->load_glyph( slot,
00679                                          face->size,
00680                                          glyph_index,
00681                                          load_flags );
00682       if ( error )
00683         goto Exit;
00684 
00685       if ( slot->format == FT_GLYPH_FORMAT_OUTLINE )
00686       {
00687         /* check that the loaded outline is correct */
00688         error = FT_Outline_Check( &slot->outline );
00689         if ( error )
00690           goto Exit;
00691 
00692 #ifdef GRID_FIT_METRICS
00693         if ( !( load_flags & FT_LOAD_NO_HINTING ) )
00694           ft_glyphslot_grid_fit_metrics( slot,
00695               FT_BOOL( load_flags & FT_LOAD_VERTICAL_LAYOUT ) );
00696 #endif
00697       }
00698     }
00699 
00700   Load_Ok:
00701     /* compute the advance */
00702     if ( load_flags & FT_LOAD_VERTICAL_LAYOUT )
00703     {
00704       slot->advance.x = 0;
00705       slot->advance.y = slot->metrics.vertAdvance;
00706     }
00707     else
00708     {
00709       slot->advance.x = slot->metrics.horiAdvance;
00710       slot->advance.y = 0;
00711     }
00712 
00713     /* compute the linear advance in 16.16 pixels */
00714     if ( ( load_flags & FT_LOAD_LINEAR_DESIGN ) == 0 &&
00715          ( FT_IS_SCALABLE( face ) )                  )
00716     {
00717       FT_Size_Metrics*  metrics = &face->size->metrics;
00718 
00719 
00720       /* it's tricky! */
00721       slot->linearHoriAdvance = FT_MulDiv( slot->linearHoriAdvance,
00722                                            metrics->x_scale, 64 );
00723 
00724       slot->linearVertAdvance = FT_MulDiv( slot->linearVertAdvance,
00725                                            metrics->y_scale, 64 );
00726     }
00727 
00728     if ( ( load_flags & FT_LOAD_IGNORE_TRANSFORM ) == 0 )
00729     {
00730       FT_Face_Internal  internal = face->internal;
00731 
00732 
00733       /* now, transform the glyph image if needed */
00734       if ( internal->transform_flags )
00735       {
00736         /* get renderer */
00737         FT_Renderer  renderer = ft_lookup_glyph_renderer( slot );
00738 
00739 
00740         if ( renderer )
00741           error = renderer->clazz->transform_glyph(
00742                                      renderer, slot,
00743                                      &internal->transform_matrix,
00744                                      &internal->transform_delta );
00745         else if ( slot->format == FT_GLYPH_FORMAT_OUTLINE )
00746         {
00747           /* apply `standard' transformation if no renderer is available */
00748           if ( &internal->transform_matrix )
00749             FT_Outline_Transform( &slot->outline,
00750                                   &internal->transform_matrix );
00751 
00752           if ( &internal->transform_delta )
00753             FT_Outline_Translate( &slot->outline,
00754                                   internal->transform_delta.x,
00755                                   internal->transform_delta.y );
00756         }
00757 
00758         /* transform advance */
00759         FT_Vector_Transform( &slot->advance, &internal->transform_matrix );
00760       }
00761     }
00762 
00763     FT_TRACE5(( "  x advance: %d\n" , slot->advance.x ));
00764     FT_TRACE5(( "  y advance: %d\n" , slot->advance.y ));
00765 
00766     FT_TRACE5(( "  linear x advance: %d\n" , slot->linearHoriAdvance ));
00767     FT_TRACE5(( "  linear y advance: %d\n" , slot->linearVertAdvance ));
00768 
00769     /* do we need to render the image now? */
00770     if ( !error                                    &&
00771          slot->format != FT_GLYPH_FORMAT_BITMAP    &&
00772          slot->format != FT_GLYPH_FORMAT_COMPOSITE &&
00773          load_flags & FT_LOAD_RENDER )
00774     {
00775       FT_Render_Mode  mode = FT_LOAD_TARGET_MODE( load_flags );
00776 
00777 
00778       if ( mode == FT_RENDER_MODE_NORMAL      &&
00779            (load_flags & FT_LOAD_MONOCHROME ) )
00780         mode = FT_RENDER_MODE_MONO;
00781 
00782       error = FT_Render_Glyph( slot, mode );
00783     }
00784 
00785   Exit:
00786     return error;
00787   }
00788 
00789 
00790   /* documentation is in freetype.h */
00791 
00792   FT_EXPORT_DEF( FT_Error )
00793   FT_Load_Char( FT_Face   face,
00794                 FT_ULong  char_code,
00795                 FT_Int32  load_flags )
00796   {
00797     FT_UInt  glyph_index;
00798 
00799 
00800     if ( !face )
00801       return FT_Err_Invalid_Face_Handle;
00802 
00803     glyph_index = (FT_UInt)char_code;
00804     if ( face->charmap )
00805       glyph_index = FT_Get_Char_Index( face, char_code );
00806 
00807     return FT_Load_Glyph( face, glyph_index, load_flags );
00808   }
00809 
00810 
00811   /* destructor for sizes list */
00812   static void
00813   destroy_size( FT_Memory  memory,
00814                 FT_Size    size,
00815                 FT_Driver  driver )
00816   {
00817     /* finalize client-specific data */
00818     if ( size->generic.finalizer )
00819       size->generic.finalizer( size );
00820 
00821     /* finalize format-specific stuff */
00822     if ( driver->clazz->done_size )
00823       driver->clazz->done_size( size );
00824 
00825     FT_FREE( size->internal );
00826     FT_FREE( size );
00827   }
00828 
00829 
00830   static void
00831   ft_cmap_done_internal( FT_CMap  cmap );
00832 
00833 
00834   static void
00835   destroy_charmaps( FT_Face    face,
00836                     FT_Memory  memory )
00837   {
00838     FT_Int  n;
00839 
00840 
00841     if ( !face )
00842       return;
00843 
00844     for ( n = 0; n < face->num_charmaps; n++ )
00845     {
00846       FT_CMap  cmap = FT_CMAP( face->charmaps[n] );
00847 
00848 
00849       ft_cmap_done_internal( cmap );
00850 
00851       face->charmaps[n] = NULL;
00852     }
00853 
00854     FT_FREE( face->charmaps );
00855     face->num_charmaps = 0;
00856   }
00857 
00858 
00859   /* destructor for faces list */
00860   static void
00861   destroy_face( FT_Memory  memory,
00862                 FT_Face    face,
00863                 FT_Driver  driver )
00864   {
00865     FT_Driver_Class  clazz = driver->clazz;
00866 
00867 
00868     /* discard auto-hinting data */
00869     if ( face->autohint.finalizer )
00870       face->autohint.finalizer( face->autohint.data );
00871 
00872     /* Discard glyph slots for this face.                           */
00873     /* Beware!  FT_Done_GlyphSlot() changes the field `face->glyph' */
00874     while ( face->glyph )
00875       FT_Done_GlyphSlot( face->glyph );
00876 
00877     /* discard all sizes for this face */
00878     FT_List_Finalize( &face->sizes_list,
00879                       (FT_List_Destructor)destroy_size,
00880                       memory,
00881                       driver );
00882     face->size = 0;
00883 
00884     /* now discard client data */
00885     if ( face->generic.finalizer )
00886       face->generic.finalizer( face );
00887 
00888     /* discard charmaps */
00889     destroy_charmaps( face, memory );
00890 
00891     /* finalize format-specific stuff */
00892     if ( clazz->done_face )
00893       clazz->done_face( face );
00894 
00895     /* close the stream for this face if needed */
00896     FT_Stream_Free(
00897       face->stream,
00898       ( face->face_flags & FT_FACE_FLAG_EXTERNAL_STREAM ) != 0 );
00899 
00900     face->stream = 0;
00901 
00902     /* get rid of it */
00903     if ( face->internal )
00904     {
00905       FT_FREE( face->internal );
00906     }
00907     FT_FREE( face );
00908   }
00909 
00910 
00911   static void
00912   Destroy_Driver( FT_Driver  driver )
00913   {
00914     FT_List_Finalize( &driver->faces_list,
00915                       (FT_List_Destructor)destroy_face,
00916                       driver->root.memory,
00917                       driver );
00918 
00919     /* check whether we need to drop the driver's glyph loader */
00920     if ( FT_DRIVER_USES_OUTLINES( driver ) )
00921       FT_GlyphLoader_Done( driver->glyph_loader );
00922   }
00923 
00924 
00925   /*************************************************************************/
00926   /*                                                                       */
00927   /* <Function>                                                            */
00928   /*    find_unicode_charmap                                               */
00929   /*                                                                       */
00930   /* <Description>                                                         */
00931   /*    This function finds a Unicode charmap, if there is one.            */
00932   /*    And if there is more than one, it tries to favour the more         */
00933   /*    extensive one, i.e., one that supports UCS-4 against those which   */
00934   /*    are limited to the BMP (said UCS-2 encoding.)                      */
00935   /*                                                                       */
00936   /*    This function is called from open_face() (just below), and also    */
00937   /*    from FT_Select_Charmap( ..., FT_ENCODING_UNICODE ).                */
00938   /*                                                                       */
00939   static FT_Error
00940   find_unicode_charmap( FT_Face  face )
00941   {
00942     FT_CharMap*  first;
00943     FT_CharMap*  cur;
00944 
00945 
00946     /* caller should have already checked that `face' is valid */
00947     FT_ASSERT( face );
00948 
00949     first = face->charmaps;
00950 
00951     if ( !first )
00952       return FT_Err_Invalid_CharMap_Handle;
00953 
00954     /*
00955      *  The original TrueType specification(s) only specified charmap
00956      *  formats that are capable of mapping 8 or 16 bit character codes to
00957      *  glyph indices.
00958      *
00959      *  However, recent updates to the Apple and OpenType specifications
00960      *  introduced new formats that are capable of mapping 32-bit character
00961      *  codes as well.  And these are already used on some fonts, mainly to
00962      *  map non-BMP Asian ideographs as defined in Unicode.
00963      *
00964      *  For compatibility purposes, these fonts generally come with
00965      *  *several* Unicode charmaps:
00966      *
00967      *   - One of them in the "old" 16-bit format, that cannot access
00968      *     all glyphs in the font.
00969      *
00970      *   - Another one in the "new" 32-bit format, that can access all
00971      *     the glyphs.
00972      *
00973      *  This function has been written to always favor a 32-bit charmap
00974      *  when found.  Otherwise, a 16-bit one is returned when found.
00975      */
00976 
00977     /* Since the `interesting' table, with IDs (3,10), is normally the */
00978     /* last one, we loop backwards.  This loses with type1 fonts with  */
00979     /* non-BMP characters (<.0001%), this wins with .ttf with non-BMP  */
00980     /* chars (.01% ?), and this is the same about 99.99% of the time!  */
00981 
00982     cur = first + face->num_charmaps;  /* points after the last one */
00983 
00984     for ( ; --cur >= first; )
00985     {
00986       if ( cur[0]->encoding == FT_ENCODING_UNICODE )
00987       {
00988         /* XXX If some new encodings to represent UCS-4 are added, */
00989         /*     they should be added here.                          */
00990         if ( ( cur[0]->platform_id == TT_PLATFORM_MICROSOFT &&
00991                cur[0]->encoding_id == TT_MS_ID_UCS_4        )     ||
00992              ( cur[0]->platform_id == TT_PLATFORM_APPLE_UNICODE &&
00993                cur[0]->encoding_id == TT_APPLE_ID_UNICODE_32    ) )
00994         {
00995           face->charmap = cur[0];
00996           return FT_Err_Ok;
00997         }
00998       }
00999     }
01000 
01001     /* We do not have any UCS-4 charmap.                */
01002     /* Do the loop again and search for UCS-2 charmaps. */
01003     cur = first + face->num_charmaps;
01004 
01005     for ( ; --cur >= first; )
01006     {
01007       if ( cur[0]->encoding == FT_ENCODING_UNICODE )
01008       {
01009         face->charmap = cur[0];
01010         return FT_Err_Ok;
01011       }
01012     }
01013 
01014     return FT_Err_Invalid_CharMap_Handle;
01015   }
01016 
01017 
01018   /*************************************************************************/
01019   /*                                                                       */
01020   /* <Function>                                                            */
01021   /*    find_variant_selector_charmap                                      */
01022   /*                                                                       */
01023   /* <Description>                                                         */
01024   /*    This function finds the variant selector charmap, if there is one. */
01025   /*    There can only be one (platform=0, specific=5, format=14).         */
01026   /*                                                                       */
01027   static FT_CharMap
01028   find_variant_selector_charmap( FT_Face  face )
01029   {
01030     FT_CharMap*  first;
01031     FT_CharMap*  end;
01032     FT_CharMap*  cur;
01033 
01034 
01035     /* caller should have already checked that `face' is valid */
01036     FT_ASSERT( face );
01037 
01038     first = face->charmaps;
01039 
01040     if ( !first )
01041       return NULL;
01042 
01043     end = first + face->num_charmaps;  /* points after the last one */
01044 
01045     for ( cur = first; cur < end; ++cur )
01046     {
01047       if ( cur[0]->platform_id == TT_PLATFORM_APPLE_UNICODE    &&
01048            cur[0]->encoding_id == TT_APPLE_ID_VARIANT_SELECTOR &&
01049            FT_Get_CMap_Format( cur[0] ) == 14                  )
01050         return cur[0];
01051     }
01052 
01053     return NULL;
01054   }
01055 
01056 
01057   /*************************************************************************/
01058   /*                                                                       */
01059   /* <Function>                                                            */
01060   /*    open_face                                                          */
01061   /*                                                                       */
01062   /* <Description>                                                         */
01063   /*    This function does some work for FT_Open_Face().                   */
01064   /*                                                                       */
01065   static FT_Error
01066   open_face( FT_Driver      driver,
01067              FT_Stream      stream,
01068              FT_Long        face_index,
01069              FT_Int         num_params,
01070              FT_Parameter*  params,
01071              FT_Face       *aface )
01072   {
01073     FT_Memory         memory;
01074     FT_Driver_Class   clazz;
01075     FT_Face           face = 0;
01076     FT_Error          error, error2;
01077     FT_Face_Internal  internal = NULL;
01078 
01079 
01080     clazz  = driver->clazz;
01081     memory = driver->root.memory;
01082 
01083     /* allocate the face object and perform basic initialization */
01084     if ( FT_ALLOC( face, clazz->face_object_size ) )
01085       goto Fail;
01086 
01087     if ( FT_NEW( internal ) )
01088       goto Fail;
01089 
01090     face->internal = internal;
01091 
01092     face->driver   = driver;
01093     face->memory   = memory;
01094     face->stream   = stream;
01095 
01096 #ifdef FT_CONFIG_OPTION_INCREMENTAL
01097     {
01098       int  i;
01099 
01100 
01101       face->internal->incremental_interface = 0;
01102       for ( i = 0; i < num_params && !face->internal->incremental_interface;
01103             i++ )
01104         if ( params[i].tag == FT_PARAM_TAG_INCREMENTAL )
01105           face->internal->incremental_interface =
01106             (FT_Incremental_Interface)params[i].data;
01107     }
01108 #endif
01109 
01110     if ( clazz->init_face )
01111       error = clazz->init_face( stream,
01112                                 face,
01113                                 (FT_Int)face_index,
01114                                 num_params,
01115                                 params );
01116     if ( error )
01117       goto Fail;
01118 
01119     /* select Unicode charmap by default */
01120     error2 = find_unicode_charmap( face );
01121 
01122     /* if no Unicode charmap can be found, FT_Err_Invalid_CharMap_Handle */
01123     /* is returned.                                                      */
01124 
01125     /* no error should happen, but we want to play safe */
01126     if ( error2 && error2 != FT_Err_Invalid_CharMap_Handle )
01127     {
01128       error = error2;
01129       goto Fail;
01130     }
01131 
01132     *aface = face;
01133 
01134   Fail:
01135     if ( error )
01136     {
01137       destroy_charmaps( face, memory );
01138       if ( clazz->done_face )
01139         clazz->done_face( face );
01140       FT_FREE( internal );
01141       FT_FREE( face );
01142       *aface = 0;
01143     }
01144 
01145     return error;
01146   }
01147 
01148 
01149   /* there's a Mac-specific extended implementation of FT_New_Face() */
01150   /* in src/base/ftmac.c                                             */
01151 
01152 #if !defined( FT_MACINTOSH ) || defined( DARWIN_NO_CARBON )
01153 
01154   /* documentation is in freetype.h */
01155 
01156   FT_EXPORT_DEF( FT_Error )
01157   FT_New_Face( FT_Library   library,
01158                const char*  pathname,
01159                FT_Long      face_index,
01160                FT_Face     *aface )
01161   {
01162     FT_Open_Args  args;
01163 
01164 
01165     /* test for valid `library' and `aface' delayed to FT_Open_Face() */
01166     if ( !pathname )
01167       return FT_Err_Invalid_Argument;
01168 
01169     args.flags    = FT_OPEN_PATHNAME;
01170     args.pathname = (char*)pathname;
01171     args.stream   = NULL;
01172 
01173     return FT_Open_Face( library, &args, face_index, aface );
01174   }
01175 
01176 #endif  /* defined( FT_MACINTOSH ) && !defined( DARWIN_NO_CARBON ) */
01177 
01178 
01179   /* documentation is in freetype.h */
01180 
01181   FT_EXPORT_DEF( FT_Error )
01182   FT_New_Memory_Face( FT_Library      library,
01183                       const FT_Byte*  file_base,
01184                       FT_Long         file_size,
01185                       FT_Long         face_index,
01186                       FT_Face        *aface )
01187   {
01188     FT_Open_Args  args;
01189 
01190 
01191     /* test for valid `library' and `face' delayed to FT_Open_Face() */
01192     if ( !file_base )
01193       return FT_Err_Invalid_Argument;
01194 
01195     args.flags       = FT_OPEN_MEMORY;
01196     args.memory_base = file_base;
01197     args.memory_size = file_size;
01198     args.stream      = NULL;
01199 
01200     return FT_Open_Face( library, &args, face_index, aface );
01201   }
01202 
01203 
01204 #ifdef FT_CONFIG_OPTION_MAC_FONTS
01205 
01206   /* The behavior here is very similar to that in base/ftmac.c, but it     */
01207   /* is designed to work on non-mac systems, so no mac specific calls.     */
01208   /*                                                                       */
01209   /* We look at the file and determine if it is a mac dfont file or a mac  */
01210   /* resource file, or a macbinary file containing a mac resource file.    */
01211   /*                                                                       */
01212   /* Unlike ftmac I'm not going to look at a `FOND'.  I don't really see   */
01213   /* the point, especially since there may be multiple `FOND' resources.   */
01214   /* Instead I'll just look for `sfnt' and `POST' resources, ordered as    */
01215   /* they occur in the file.                                               */
01216   /*                                                                       */
01217   /* Note that multiple `POST' resources do not mean multiple postscript   */
01218   /* fonts; they all get jammed together to make what is essentially a     */
01219   /* pfb file.                                                             */
01220   /*                                                                       */
01221   /* We aren't interested in `NFNT' or `FONT' bitmap resources.            */
01222   /*                                                                       */
01223   /* As soon as we get an `sfnt' load it into memory and pass it off to    */
01224   /* FT_Open_Face.                                                         */
01225   /*                                                                       */
01226   /* If we have a (set of) `POST' resources, massage them into a (memory)  */
01227   /* pfb file and pass that to FT_Open_Face.  (As with ftmac.c I'm not     */
01228   /* going to try to save the kerning info.  After all that lives in the   */
01229   /* `FOND' which isn't in the file containing the `POST' resources so     */
01230   /* we don't really have access to it.                                    */
01231 
01232 
01233   /* Finalizer for a memory stream; gets called by FT_Done_Face(). */
01234   /* It frees the memory it uses.                                  */
01235   /* From ftmac.c.                                                 */
01236   static void
01237   memory_stream_close( FT_Stream  stream )
01238   {
01239     FT_Memory  memory = stream->memory;
01240 
01241 
01242     FT_FREE( stream->base );
01243 
01244     stream->size  = 0;
01245     stream->base  = 0;
01246     stream->close = 0;
01247   }
01248 
01249 
01250   /* Create a new memory stream from a buffer and a size. */
01251   /* From ftmac.c.                                        */
01252   static FT_Error
01253   new_memory_stream( FT_Library           library,
01254                      FT_Byte*             base,
01255                      FT_ULong             size,
01256                      FT_Stream_CloseFunc  close,
01257                      FT_Stream           *astream )
01258   {
01259     FT_Error   error;
01260     FT_Memory  memory;
01261     FT_Stream  stream;
01262 
01263 
01264     if ( !library )
01265       return FT_Err_Invalid_Library_Handle;
01266 
01267     if ( !base )
01268       return FT_Err_Invalid_Argument;
01269 
01270     *astream = 0;
01271     memory = library->memory;
01272     if ( FT_NEW( stream ) )
01273       goto Exit;
01274 
01275     FT_Stream_OpenMemory( stream, base, size );
01276 
01277     stream->close = close;
01278 
01279     *astream = stream;
01280 
01281   Exit:
01282     return error;
01283   }
01284 
01285 
01286   /* Create a new FT_Face given a buffer and a driver name. */
01287   /* from ftmac.c */
01288   FT_LOCAL_DEF( FT_Error )
01289   open_face_from_buffer( FT_Library   library,
01290                          FT_Byte*     base,
01291                          FT_ULong     size,
01292                          FT_Long      face_index,
01293                          const char*  driver_name,
01294                          FT_Face     *aface )
01295   {
01296     FT_Open_Args  args;
01297     FT_Error      error;
01298     FT_Stream     stream = NULL;
01299     FT_Memory     memory = library->memory;
01300 
01301 
01302     error = new_memory_stream( library,
01303                                base,
01304                                size,
01305                                memory_stream_close,
01306                                &stream );
01307     if ( error )
01308     {
01309       FT_FREE( base );
01310       return error;
01311     }
01312 
01313     args.flags = FT_OPEN_STREAM;
01314     args.stream = stream;
01315     if ( driver_name )
01316     {
01317       args.flags = args.flags | FT_OPEN_DRIVER;
01318       args.driver = FT_Get_Module( library, driver_name );
01319     }
01320 
01321 #ifdef FT_MACINTOSH
01322     /* At this point, face_index has served its purpose;      */
01323     /* whoever calls this function has already used it to     */
01324     /* locate the correct font data.  We should not propagate */
01325     /* this index to FT_Open_Face() (unless it is negative).  */
01326 
01327     if ( face_index > 0 )
01328       face_index = 0;
01329 #endif
01330 
01331     error = FT_Open_Face( library, &args, face_index, aface );
01332 
01333     if ( error == FT_Err_Ok )
01334       (*aface)->face_flags &= ~FT_FACE_FLAG_EXTERNAL_STREAM;
01335     else
01336 #ifdef FT_MACINTOSH
01337       FT_Stream_Free( stream, 0 );
01338 #else
01339     {
01340       FT_Stream_Close( stream );
01341       FT_FREE( stream );
01342     }
01343 #endif
01344 
01345     return error;
01346   }
01347 
01348 
01349   /* Look up `TYP1' or `CID ' table from sfnt table directory.       */
01350   /* `offset' and `length' must exclude the binary header in tables. */
01351 
01352   /* Type 1 and CID-keyed font drivers should recognize sfnt-wrapped */
01353   /* format too.  Here, since we can't expect that the TrueType font */
01354   /* driver is loaded unconditially, we must parse the font by       */
01355   /* ourselves.  We are only interested in the name of the table and */
01356   /* the offset.                                                     */
01357 
01358   static FT_Error
01359   ft_lookup_PS_in_sfnt_stream( FT_Stream  stream,
01360                                FT_Long    face_index,
01361                                FT_ULong*  offset,
01362                                FT_ULong*  length,
01363                                FT_Bool*   is_sfnt_cid )
01364   {
01365     FT_Error   error;
01366     FT_UShort  numTables;
01367     FT_Long    pstable_index;
01368     FT_ULong   tag;
01369     int        i;
01370 
01371 
01372     *offset = 0;
01373     *length = 0;
01374     *is_sfnt_cid = FALSE;
01375 
01376     /* TODO: support for sfnt-wrapped PS/CID in TTC format */
01377 
01378     /* version check for 'typ1' (should be ignored?) */
01379     if ( FT_READ_ULONG( tag ) )
01380       return error;
01381     if ( tag != TTAG_typ1 )
01382       return FT_Err_Unknown_File_Format;
01383 
01384     if ( FT_READ_USHORT( numTables ) )
01385       return error;
01386     if ( FT_STREAM_SKIP( 2 * 3 ) ) /* skip binary search header */
01387       return error;
01388 
01389     pstable_index = -1;
01390     *is_sfnt_cid  = FALSE;
01391 
01392     for ( i = 0; i < numTables; i++ )
01393     {
01394       if ( FT_READ_ULONG( tag )     || FT_STREAM_SKIP( 4 )      ||
01395            FT_READ_ULONG( *offset ) || FT_READ_ULONG( *length ) )
01396         return error;
01397 
01398       if ( tag == TTAG_CID )
01399       {
01400         pstable_index++;
01401         *offset += 22;
01402         *length -= 22;
01403         *is_sfnt_cid = TRUE;
01404         if ( face_index < 0 )
01405           return FT_Err_Ok;
01406       }
01407       else if ( tag == TTAG_TYP1 )
01408       {
01409         pstable_index++;
01410         *offset += 24;
01411         *length -= 24;
01412         *is_sfnt_cid = FALSE;
01413         if ( face_index < 0 )
01414           return FT_Err_Ok;
01415       }
01416       if ( face_index >= 0 && pstable_index == face_index )
01417         return FT_Err_Ok;
01418     }
01419     return FT_Err_Table_Missing;
01420   }
01421 
01422 
01423   FT_LOCAL_DEF( FT_Error )
01424   open_face_PS_from_sfnt_stream( FT_Library     library,
01425                                  FT_Stream      stream,
01426                                  FT_Long        face_index,
01427                                  FT_Int         num_params,
01428                                  FT_Parameter  *params,
01429                                  FT_Face       *aface )
01430   {
01431     FT_Error   error;
01432     FT_Memory  memory = library->memory;
01433     FT_ULong   offset, length;
01434     FT_Long    pos;
01435     FT_Bool    is_sfnt_cid;
01436     FT_Byte*   sfnt_ps;
01437 
01438     FT_UNUSED( num_params );
01439     FT_UNUSED( params );
01440 
01441 
01442     pos = FT_Stream_Pos( stream );
01443 
01444     error = ft_lookup_PS_in_sfnt_stream( stream,
01445                                          face_index,
01446                                          &offset,
01447                                          &length,
01448                                          &is_sfnt_cid );
01449     if ( error )
01450       goto Exit;
01451 
01452     if ( FT_Stream_Seek( stream, pos + offset ) )
01453       goto Exit;
01454 
01455     if ( FT_ALLOC( sfnt_ps, (FT_Long)length ) )
01456       goto Exit;
01457 
01458     error = FT_Stream_Read( stream, (FT_Byte *)sfnt_ps, length );
01459     if ( error )
01460       goto Exit;
01461 
01462     error = open_face_from_buffer( library,
01463                                    sfnt_ps,
01464                                    length,
01465                                    face_index < 0 ? face_index : 0,
01466                                    is_sfnt_cid ? "cid" : "type1",
01467                                    aface );
01468   Exit:
01469     {
01470       FT_Error  error1;
01471 
01472 
01473       if ( error == FT_Err_Unknown_File_Format )
01474       {
01475         error1 = FT_Stream_Seek( stream, pos );
01476         if ( error1 )
01477           return error1;
01478       }
01479 
01480       return error;
01481     }
01482   }
01483 
01484 
01485 #if !defined( FT_MACINTOSH ) || defined( DARWIN_NO_CARBON )
01486 
01487   /* The resource header says we've got resource_cnt `POST' (type1) */
01488   /* resources in this file.  They all need to be coalesced into    */
01489   /* one lump which gets passed on to the type1 driver.             */
01490   /* Here can be only one PostScript font in a file so face_index   */
01491   /* must be 0 (or -1).                                             */
01492   /*                                                                */
01493   static FT_Error
01494   Mac_Read_POST_Resource( FT_Library  library,
01495                           FT_Stream   stream,
01496                           FT_Long    *offsets,
01497                           FT_Long     resource_cnt,
01498                           FT_Long     face_index,
01499                           FT_Face    *aface )
01500   {
01501     FT_Error   error  = FT_Err_Cannot_Open_Resource;
01502     FT_Memory  memory = library->memory;
01503     FT_Byte*   pfb_data;
01504     int        i, type, flags;
01505     FT_Long    len;
01506     FT_Long    pfb_len, pfb_pos, pfb_lenpos;
01507     FT_Long    rlen, temp;
01508 
01509 
01510     if ( face_index == -1 )
01511       face_index = 0;
01512     if ( face_index != 0 )
01513       return error;
01514 
01515     /* Find the length of all the POST resources, concatenated.  Assume */
01516     /* worst case (each resource in its own section).                   */
01517     pfb_len = 0;
01518     for ( i = 0; i < resource_cnt; ++i )
01519     {
01520       error = FT_Stream_Seek( stream, offsets[i] );
01521       if ( error )
01522         goto Exit;
01523       if ( FT_READ_LONG( temp ) )
01524         goto Exit;
01525       pfb_len += temp + 6;
01526     }
01527 
01528     if ( FT_ALLOC( pfb_data, (FT_Long)pfb_len + 2 ) )
01529       goto Exit;
01530 
01531     pfb_data[0] = 0x80;
01532     pfb_data[1] = 1;            /* Ascii section */
01533     pfb_data[2] = 0;            /* 4-byte length, fill in later */
01534     pfb_data[3] = 0;
01535     pfb_data[4] = 0;
01536     pfb_data[5] = 0;
01537     pfb_pos     = 6;
01538     pfb_lenpos  = 2;
01539 
01540     len = 0;
01541     type = 1;
01542     for ( i = 0; i < resource_cnt; ++i )
01543     {
01544       error = FT_Stream_Seek( stream, offsets[i] );
01545       if ( error )
01546         goto Exit2;
01547       if ( FT_READ_LONG( rlen ) )
01548         goto Exit;
01549       if ( FT_READ_USHORT( flags ) )
01550         goto Exit;
01551       rlen -= 2;                    /* the flags are part of the resource */
01552       if ( ( flags >> 8 ) == type )
01553         len += rlen;
01554       else
01555       {
01556         pfb_data[pfb_lenpos    ] = (FT_Byte)( len );
01557         pfb_data[pfb_lenpos + 1] = (FT_Byte)( len >> 8 );
01558         pfb_data[pfb_lenpos + 2] = (FT_Byte)( len >> 16 );
01559         pfb_data[pfb_lenpos + 3] = (FT_Byte)( len >> 24 );
01560 
01561         if ( ( flags >> 8 ) == 5 )      /* End of font mark */
01562           break;
01563 
01564         pfb_data[pfb_pos++] = 0x80;
01565 
01566         type = flags >> 8;
01567         len = rlen;
01568 
01569         pfb_data[pfb_pos++] = (FT_Byte)type;
01570         pfb_lenpos          = pfb_pos;
01571         pfb_data[pfb_pos++] = 0;        /* 4-byte length, fill in later */
01572         pfb_data[pfb_pos++] = 0;
01573         pfb_data[pfb_pos++] = 0;
01574         pfb_data[pfb_pos++] = 0;
01575       }
01576 
01577       error = FT_Stream_Read( stream, (FT_Byte *)pfb_data + pfb_pos, rlen );
01578       pfb_pos += rlen;
01579     }
01580 
01581     pfb_data[pfb_pos++] = 0x80;
01582     pfb_data[pfb_pos++] = 3;
01583 
01584     pfb_data[pfb_lenpos    ] = (FT_Byte)( len );
01585     pfb_data[pfb_lenpos + 1] = (FT_Byte)( len >> 8 );
01586     pfb_data[pfb_lenpos + 2] = (FT_Byte)( len >> 16 );
01587     pfb_data[pfb_lenpos + 3] = (FT_Byte)( len >> 24 );
01588 
01589     return open_face_from_buffer( library,
01590                                   pfb_data,
01591                                   pfb_pos,
01592                                   face_index,
01593                                   "type1",
01594                                   aface );
01595 
01596   Exit2:
01597     FT_FREE( pfb_data );
01598 
01599   Exit:
01600     return error;
01601   }
01602 
01603 
01604   /* The resource header says we've got resource_cnt `sfnt'      */
01605   /* (TrueType/OpenType) resources in this file.  Look through   */
01606   /* them for the one indicated by face_index, load it into mem, */
01607   /* pass it on the the truetype driver and return it.           */
01608   /*                                                             */
01609   static FT_Error
01610   Mac_Read_sfnt_Resource( FT_Library  library,
01611                           FT_Stream   stream,
01612                           FT_Long    *offsets,
01613                           FT_Long     resource_cnt,
01614                           FT_Long     face_index,
01615                           FT_Face    *aface )
01616   {
01617     FT_Memory  memory = library->memory;
01618     FT_Byte*   sfnt_data;
01619     FT_Error   error;
01620     FT_Long    flag_offset;
01621     FT_Long    rlen;
01622     int        is_cff;
01623     FT_Long    face_index_in_resource = 0;
01624 
01625 
01626     if ( face_index == -1 )
01627       face_index = 0;
01628     if ( face_index >= resource_cnt )
01629       return FT_Err_Cannot_Open_Resource;
01630 
01631     flag_offset = offsets[face_index];
01632     error = FT_Stream_Seek( stream, flag_offset );
01633     if ( error )
01634       goto Exit;
01635 
01636     if ( FT_READ_LONG( rlen ) )
01637       goto Exit;
01638     if ( rlen == -1 )
01639       return FT_Err_Cannot_Open_Resource;
01640 
01641     error = open_face_PS_from_sfnt_stream( library,
01642                                            stream,
01643                                            face_index,
01644                                            0, NULL,
01645                                            aface );
01646     if ( !error )
01647       goto Exit;
01648 
01649     /* rewind sfnt stream before open_face_PS_from_sfnt_stream() */
01650     if ( FT_Stream_Seek( stream, flag_offset + 4 ) )
01651       goto Exit;
01652 
01653     if ( FT_ALLOC( sfnt_data, (FT_Long)rlen ) )
01654       return error;
01655     error = FT_Stream_Read( stream, (FT_Byte *)sfnt_data, rlen );
01656     if ( error )
01657       goto Exit;
01658 
01659     is_cff = rlen > 4 && !ft_memcmp( sfnt_data, "OTTO", 4 );
01660     error = open_face_from_buffer( library,
01661                                    sfnt_data,
01662                                    rlen,
01663                                    face_index_in_resource,
01664                                    is_cff ? "cff" : "truetype",
01665                                    aface );
01666 
01667   Exit:
01668     return error;
01669   }
01670 
01671 
01672   /* Check for a valid resource fork header, or a valid dfont    */
01673   /* header.  In a resource fork the first 16 bytes are repeated */
01674   /* at the location specified by bytes 4-7.  In a dfont bytes   */
01675   /* 4-7 point to 16 bytes of zeroes instead.                    */
01676   /*                                                             */
01677   static FT_Error
01678   IsMacResource( FT_Library  library,
01679                  FT_Stream   stream,
01680                  FT_Long     resource_offset,
01681                  FT_Long     face_index,
01682                  FT_Face    *aface )
01683   {
01684     FT_Memory  memory = library->memory;
01685     FT_Error   error;
01686     FT_Long    map_offset, rdara_pos;
01687     FT_Long    *data_offsets;
01688     FT_Long    count;
01689 
01690 
01691     error = FT_Raccess_Get_HeaderInfo( library, stream, resource_offset,
01692                                        &map_offset, &rdara_pos );
01693     if ( error )
01694       return error;
01695 
01696     error = FT_Raccess_Get_DataOffsets( library, stream,
01697                                         map_offset, rdara_pos,
01698                                         TTAG_POST,
01699                                         &data_offsets, &count );
01700     if ( !error )
01701     {
01702       error = Mac_Read_POST_Resource( library, stream, data_offsets, count,
01703                                       face_index, aface );
01704       FT_FREE( data_offsets );
01705       /* POST exists in an LWFN providing a single face */
01706       if ( !error )
01707         (*aface)->num_faces = 1;
01708       return error;
01709     }
01710 
01711     error = FT_Raccess_Get_DataOffsets( library, stream,
01712                                         map_offset, rdara_pos,
01713                                         TTAG_sfnt,
01714                                         &data_offsets, &count );
01715     if ( !error )
01716     {
01717       FT_Long  face_index_internal = face_index % count;
01718 
01719 
01720       error = Mac_Read_sfnt_Resource( library, stream, data_offsets, count,
01721                                       face_index_internal, aface );
01722       FT_FREE( data_offsets );
01723       if ( !error )
01724         (*aface)->num_faces = count;
01725     }
01726 
01727     return error;
01728   }
01729 
01730 
01731   /* Check for a valid macbinary header, and if we find one   */
01732   /* check that the (flattened) resource fork in it is valid. */
01733   /*                                                          */
01734   static FT_Error
01735   IsMacBinary( FT_Library  library,
01736                FT_Stream   stream,
01737                FT_Long     face_index,
01738                FT_Face    *aface )
01739   {
01740     unsigned char  header[128];
01741     FT_Error       error;
01742     FT_Long        dlen, offset;
01743 
01744 
01745     if ( NULL == stream )
01746       return FT_Err_Invalid_Stream_Operation;
01747 
01748     error = FT_Stream_Seek( stream, 0 );
01749     if ( error )
01750       goto Exit;
01751 
01752     error = FT_Stream_Read( stream, (FT_Byte*)header, 128 );
01753     if ( error )
01754       goto Exit;
01755 
01756     if (            header[ 0] !=  0 ||
01757                     header[74] !=  0 ||
01758                     header[82] !=  0 ||
01759                     header[ 1] ==  0 ||
01760                     header[ 1] >  33 ||
01761                     header[63] !=  0 ||
01762          header[2 + header[1]] !=  0 )
01763       return FT_Err_Unknown_File_Format;
01764 
01765     dlen = ( header[0x53] << 24 ) |
01766            ( header[0x54] << 16 ) |
01767            ( header[0x55] <<  8 ) |
01768              header[0x56];
01769 #if 0
01770     rlen = ( header[0x57] << 24 ) |
01771            ( header[0x58] << 16 ) |
01772            ( header[0x59] <<  8 ) |
01773              header[0x5a];
01774 #endif /* 0 */
01775     offset = 128 + ( ( dlen + 127 ) & ~127 );
01776 
01777     return IsMacResource( library, stream, offset, face_index, aface );
01778 
01779   Exit:
01780     return error;
01781   }
01782 
01783 
01784   static FT_Error
01785   load_face_in_embedded_rfork( FT_Library           library,
01786                                FT_Stream            stream,
01787                                FT_Long              face_index,
01788                                FT_Face             *aface,
01789                                const FT_Open_Args  *args )
01790   {
01791 
01792 #undef  FT_COMPONENT
01793 #define FT_COMPONENT  trace_raccess
01794 
01795     FT_Memory  memory = library->memory;
01796     FT_Error   error  = FT_Err_Unknown_File_Format;
01797     int        i;
01798 
01799     char *     file_names[FT_RACCESS_N_RULES];
01800     FT_Long    offsets[FT_RACCESS_N_RULES];
01801     FT_Error   errors[FT_RACCESS_N_RULES];
01802 
01803     FT_Open_Args  args2;
01804     FT_Stream     stream2 = 0;
01805 
01806 
01807     FT_Raccess_Guess( library, stream,
01808                       args->pathname, file_names, offsets, errors );
01809 
01810     for ( i = 0; i < FT_RACCESS_N_RULES; i++ )
01811     {
01812       if ( errors[i] )
01813       {
01814         FT_TRACE3(( "Error[%d] has occurred in rule %d\n", errors[i], i ));
01815         continue;
01816       }
01817 
01818       args2.flags    = FT_OPEN_PATHNAME;
01819       args2.pathname = file_names[i] ? file_names[i] : args->pathname;
01820 
01821       FT_TRACE3(( "Try rule %d: %s (offset=%d) ...",
01822                   i, args2.pathname, offsets[i] ));
01823 
01824       error = FT_Stream_New( library, &args2, &stream2 );
01825       if ( error )
01826       {
01827         FT_TRACE3(( "failed\n" ));
01828         continue;
01829       }
01830 
01831       error = IsMacResource( library, stream2, offsets[i],
01832                              face_index, aface );
01833       FT_Stream_Free( stream2, 0 );
01834 
01835       FT_TRACE3(( "%s\n", error ? "failed": "successful" ));
01836 
01837       if ( !error )
01838           break;
01839     }
01840 
01841     for (i = 0; i < FT_RACCESS_N_RULES; i++)
01842     {
01843       if ( file_names[i] )
01844         FT_FREE( file_names[i] );
01845     }
01846 
01847     /* Caller (load_mac_face) requires FT_Err_Unknown_File_Format. */
01848     if ( error )
01849       error = FT_Err_Unknown_File_Format;
01850 
01851     return error;
01852 
01853 #undef  FT_COMPONENT
01854 #define FT_COMPONENT  trace_objs
01855 
01856   }
01857 
01858 
01859   /* Check for some macintosh formats without Carbon framework.    */
01860   /* Is this a macbinary file?  If so look at the resource fork.   */
01861   /* Is this a mac dfont file?                                     */
01862   /* Is this an old style resource fork? (in data)                 */
01863   /* Else call load_face_in_embedded_rfork to try extra rules      */
01864   /* (defined in `ftrfork.c').                                     */
01865   /*                                                               */
01866   static FT_Error
01867   load_mac_face( FT_Library           library,
01868                  FT_Stream            stream,
01869                  FT_Long              face_index,
01870                  FT_Face             *aface,
01871                  const FT_Open_Args  *args )
01872   {
01873     FT_Error error;
01874     FT_UNUSED( args );
01875 
01876 
01877     error = IsMacBinary( library, stream, face_index, aface );
01878     if ( FT_ERROR_BASE( error ) == FT_Err_Unknown_File_Format )
01879     {
01880 
01881 #undef  FT_COMPONENT
01882 #define FT_COMPONENT  trace_raccess
01883 
01884       FT_TRACE3(( "Try as dfont: %s ...", args->pathname ));
01885 
01886       error = IsMacResource( library, stream, 0, face_index, aface );
01887 
01888       FT_TRACE3(( "%s\n", error ? "failed" : "successful" ));
01889 
01890 #undef  FT_COMPONENT
01891 #define FT_COMPONENT  trace_objs
01892 
01893     }
01894 
01895     if ( ( FT_ERROR_BASE( error ) == FT_Err_Unknown_File_Format      ||
01896            FT_ERROR_BASE( error ) == FT_Err_Invalid_Stream_Operation ) &&
01897          ( args->flags & FT_OPEN_PATHNAME )                            )
01898       error = load_face_in_embedded_rfork( library, stream,
01899                                            face_index, aface, args );
01900     return error;
01901   }
01902 #endif
01903 
01904 #endif  /* !FT_MACINTOSH && FT_CONFIG_OPTION_MAC_FONTS */
01905 
01906 
01907   /* documentation is in freetype.h */
01908 
01909   FT_EXPORT_DEF( FT_Error )
01910   FT_Open_Face( FT_Library           library,
01911                 const FT_Open_Args*  args,
01912                 FT_Long              face_index,
01913                 FT_Face             *aface )
01914   {
01915     FT_Error     error;
01916     FT_Driver    driver;
01917     FT_Memory    memory;
01918     FT_Stream    stream = 0;
01919     FT_Face      face = 0;
01920     FT_ListNode  node = 0;
01921     FT_Bool      external_stream;
01922     FT_Module*   cur;
01923     FT_Module*   limit;
01924 
01925 
01926     /* test for valid `library' delayed to */
01927     /* FT_Stream_New()                     */
01928 
01929     if ( ( !aface && face_index >= 0 ) || !args )
01930       return FT_Err_Invalid_Argument;
01931 
01932     external_stream = FT_BOOL( ( args->flags & FT_OPEN_STREAM ) &&
01933                                args->stream                     );
01934 
01935     /* create input stream */
01936     error = FT_Stream_New( library, args, &stream );
01937     if ( error )
01938       goto Fail3;
01939 
01940     memory = library->memory;
01941 
01942     /* If the font driver is specified in the `args' structure, use */
01943     /* it.  Otherwise, we scan the list of registered drivers.      */
01944     if ( ( args->flags & FT_OPEN_DRIVER ) && args->driver )
01945     {
01946       driver = FT_DRIVER( args->driver );
01947 
01948       /* not all modules are drivers, so check... */
01949       if ( FT_MODULE_IS_DRIVER( driver ) )
01950       {
01951         FT_Int         num_params = 0;
01952         FT_Parameter*  params     = 0;
01953 
01954 
01955         if ( args->flags & FT_OPEN_PARAMS )
01956         {
01957           num_params = args->num_params;
01958           params     = args->params;
01959         }
01960 
01961         error = open_face( driver, stream, face_index,
01962                            num_params, params, &face );
01963         if ( !error )
01964           goto Success;
01965       }
01966       else
01967         error = FT_Err_Invalid_Handle;
01968 
01969       FT_Stream_Free( stream, external_stream );
01970       goto Fail;
01971     }
01972     else
01973     {
01974       /* check each font driver for an appropriate format */
01975       cur   = library->modules;
01976       limit = cur + library->num_modules;
01977 
01978 
01979       for ( ; cur < limit; cur++ )
01980       {
01981         /* not all modules are font drivers, so check... */
01982         if ( FT_MODULE_IS_DRIVER( cur[0] ) )
01983         {
01984           FT_Int         num_params = 0;
01985           FT_Parameter*  params     = 0;
01986 
01987 
01988           driver = FT_DRIVER( cur[0] );
01989 
01990           if ( args->flags & FT_OPEN_PARAMS )
01991           {
01992             num_params = args->num_params;
01993             params     = args->params;
01994           }
01995 
01996           error = open_face( driver, stream, face_index,
01997                              num_params, params, &face );
01998           if ( !error )
01999             goto Success;
02000 
02001 #ifdef FT_CONFIG_OPTION_MAC_FONTS
02002           if ( ft_strcmp( cur[0]->clazz->module_name, "truetype" ) == 0 &&
02003                FT_ERROR_BASE( error ) == FT_Err_Table_Missing           )
02004           {
02005             /* TrueType but essential tables are missing */
02006             if ( FT_Stream_Seek( stream, 0 ) )
02007               break;
02008 
02009             error = open_face_PS_from_sfnt_stream( library,
02010                                                    stream,
02011                                                    face_index,
02012                                                    num_params,
02013                                                    params,
02014                                                    aface );
02015             if ( !error )
02016             {
02017               FT_Stream_Free( stream, external_stream );
02018               return error;
02019             }
02020           }
02021 #endif
02022 
02023           if ( FT_ERROR_BASE( error ) != FT_Err_Unknown_File_Format )
02024             goto Fail3;
02025         }
02026       }
02027 
02028   Fail3:
02029     /* If we are on the mac, and we get an FT_Err_Invalid_Stream_Operation */
02030     /* it may be because we have an empty data fork, so we need to check   */
02031     /* the resource fork.                                                  */
02032     if ( FT_ERROR_BASE( error ) != FT_Err_Cannot_Open_Stream       &&
02033          FT_ERROR_BASE( error ) != FT_Err_Unknown_File_Format      &&
02034          FT_ERROR_BASE( error ) != FT_Err_Invalid_Stream_Operation )
02035       goto Fail2;
02036 
02037 #if !defined( FT_MACINTOSH ) && defined( FT_CONFIG_OPTION_MAC_FONTS )
02038     error = load_mac_face( library, stream, face_index, aface, args );
02039     if ( !error )
02040     {
02041       /* We don't want to go to Success here.  We've already done that. */
02042       /* On the other hand, if we succeeded we still need to close this */
02043       /* stream (we opened a different stream which extracted the       */
02044       /* interesting information out of this stream here.  That stream  */
02045       /* will still be open and the face will point to it).             */
02046       FT_Stream_Free( stream, external_stream );
02047       return error;
02048     }
02049 
02050     if ( FT_ERROR_BASE( error ) != FT_Err_Unknown_File_Format )
02051       goto Fail2;
02052 #endif  /* !FT_MACINTOSH && FT_CONFIG_OPTION_MAC_FONTS */
02053 
02054       /* no driver is able to handle this format */
02055       error = FT_Err_Unknown_File_Format;
02056 
02057   Fail2:
02058       FT_Stream_Free( stream, external_stream );
02059       goto Fail;
02060     }
02061 
02062   Success:
02063     FT_TRACE4(( "FT_Open_Face: New face object, adding to list\n" ));
02064 
02065     /* set the FT_FACE_FLAG_EXTERNAL_STREAM bit for FT_Done_Face */
02066     if ( external_stream )
02067       face->face_flags |= FT_FACE_FLAG_EXTERNAL_STREAM;
02068 
02069     /* add the face object to its driver's list */
02070     if ( FT_NEW( node ) )
02071       goto Fail;
02072 
02073     node->data = face;
02074     /* don't assume driver is the same as face->driver, so use */
02075     /* face->driver instead.                                   */
02076     FT_List_Add( &face->driver->faces_list, node );
02077 
02078     /* now allocate a glyph slot object for the face */
02079     FT_TRACE4(( "FT_Open_Face: Creating glyph slot\n" ));
02080 
02081     if ( face_index >= 0 )
02082     {
02083       error = FT_New_GlyphSlot( face, NULL );
02084       if ( error )
02085         goto Fail;
02086 
02087       /* finally, allocate a size object for the face */
02088       {
02089         FT_Size  size;
02090 
02091 
02092         FT_TRACE4(( "FT_Open_Face: Creating size object\n" ));
02093 
02094         error = FT_New_Size( face, &size );
02095         if ( error )
02096           goto Fail;
02097 
02098         face->size = size;
02099       }
02100     }
02101 
02102     /* some checks */
02103 
02104     if ( FT_IS_SCALABLE( face ) )
02105     {
02106       if ( face->height < 0 )
02107         face->height = (FT_Short)-face->height;
02108 
02109       if ( !FT_HAS_VERTICAL( face ) )
02110         face->max_advance_height = (FT_Short)face->height;
02111     }
02112 
02113     if ( FT_HAS_FIXED_SIZES( face ) )
02114     {
02115       FT_Int  i;
02116 
02117 
02118       for ( i = 0; i < face->num_fixed_sizes; i++ )
02119       {
02120         FT_Bitmap_Size*  bsize = face->available_sizes + i;
02121 
02122 
02123         if ( bsize->height < 0 )
02124           bsize->height = (FT_Short)-bsize->height;
02125         if ( bsize->x_ppem < 0 )
02126           bsize->x_ppem = (FT_Short)-bsize->x_ppem;
02127         if ( bsize->y_ppem < 0 )
02128           bsize->y_ppem = -bsize->y_ppem;
02129       }
02130     }
02131 
02132     /* initialize internal face data */
02133     {
02134       FT_Face_Internal  internal = face->internal;
02135 
02136 
02137       internal->transform_matrix.xx = 0x10000L;
02138       internal->transform_matrix.xy = 0;
02139       internal->transform_matrix.yx = 0;
02140       internal->transform_matrix.yy = 0x10000L;
02141 
02142       internal->transform_delta.x = 0;
02143       internal->transform_delta.y = 0;
02144     }
02145 
02146     if ( aface )
02147       *aface = face;
02148     else
02149       FT_Done_Face( face );
02150 
02151     goto Exit;
02152 
02153   Fail:
02154     FT_Done_Face( face );
02155 
02156   Exit:
02157     FT_TRACE4(( "FT_Open_Face: Return %d\n", error ));
02158 
02159     return error;
02160   }
02161 
02162 
02163   /* documentation is in freetype.h */
02164 
02165   FT_EXPORT_DEF( FT_Error )
02166   FT_Attach_File( FT_Face      face,
02167                   const char*  filepathname )
02168   {
02169     FT_Open_Args  open;
02170 
02171 
02172     /* test for valid `face' delayed to FT_Attach_Stream() */
02173 
02174     if ( !filepathname )
02175       return FT_Err_Invalid_Argument;
02176 
02177     open.stream   = NULL;
02178     open.flags    = FT_OPEN_PATHNAME;
02179     open.pathname = (char*)filepathname;
02180 
02181     return FT_Attach_Stream( face, &open );
02182   }
02183 
02184 
02185   /* documentation is in freetype.h */
02186 
02187   FT_EXPORT_DEF( FT_Error )
02188   FT_Attach_Stream( FT_Face        face,
02189                     FT_Open_Args*  parameters )
02190   {
02191     FT_Stream  stream;
02192     FT_Error   error;
02193     FT_Driver  driver;
02194 
02195     FT_Driver_Class  clazz;
02196 
02197 
02198     /* test for valid `parameters' delayed to FT_Stream_New() */
02199 
02200     if ( !face )
02201       return FT_Err_Invalid_Face_Handle;
02202 
02203     driver = face->driver;
02204     if ( !driver )
02205       return FT_Err_Invalid_Driver_Handle;
02206 
02207     error = FT_Stream_New( driver->root.library, parameters, &stream );
02208     if ( error )
02209       goto Exit;
02210 
02211     /* we implement FT_Attach_Stream in each driver through the */
02212     /* `attach_file' interface                                  */
02213 
02214     error = FT_Err_Unimplemented_Feature;
02215     clazz = driver->clazz;
02216     if ( clazz->attach_file )
02217       error = clazz->attach_file( face, stream );
02218 
02219     /* close the attached stream */
02220     FT_Stream_Free( stream,
02221                     (FT_Bool)( parameters->stream &&
02222                                ( parameters->flags & FT_OPEN_STREAM ) ) );
02223 
02224   Exit:
02225     return error;
02226   }
02227 
02228 
02229   /* documentation is in freetype.h */
02230 
02231   FT_EXPORT_DEF( FT_Error )
02232   FT_Done_Face( FT_Face  face )
02233   {
02234     FT_Error     error;
02235     FT_Driver    driver;
02236     FT_Memory    memory;
02237     FT_ListNode  node;
02238 
02239 
02240     error = FT_Err_Invalid_Face_Handle;
02241     if ( face && face->driver )
02242     {
02243       driver = face->driver;
02244       memory = driver->root.memory;
02245 
02246       /* find face in driver's list */
02247       node = FT_List_Find( &driver->faces_list, face );
02248       if ( node )
02249       {
02250         /* remove face object from the driver's list */
02251         FT_List_Remove( &driver->faces_list, node );
02252         FT_FREE( node );
02253 
02254         /* now destroy the object proper */
02255         destroy_face( memory, face, driver );
02256         error = FT_Err_Ok;
02257       }
02258     }
02259     return error;
02260   }
02261 
02262 
02263   /* documentation is in ftobjs.h */
02264 
02265   FT_EXPORT_DEF( FT_Error )
02266   FT_New_Size( FT_Face   face,
02267                FT_Size  *asize )
02268   {
02269     FT_Error         error;
02270     FT_Memory        memory;
02271     FT_Driver        driver;
02272     FT_Driver_Class  clazz;
02273 
02274     FT_Size          size = 0;
02275     FT_ListNode      node = 0;
02276 
02277 
02278     if ( !face )
02279       return FT_Err_Invalid_Face_Handle;
02280 
02281     if ( !asize )
02282       return FT_Err_Invalid_Size_Handle;
02283 
02284     if ( !face->driver )
02285       return FT_Err_Invalid_Driver_Handle;
02286 
02287     *asize = 0;
02288 
02289     driver = face->driver;
02290     clazz  = driver->clazz;
02291     memory = face->memory;
02292 
02293     /* Allocate new size object and perform basic initialisation */
02294     if ( FT_ALLOC( size, clazz->size_object_size ) || FT_NEW( node ) )
02295       goto Exit;
02296 
02297     size->face = face;
02298 
02299     /* for now, do not use any internal fields in size objects */
02300     size->internal = 0;
02301 
02302     if ( clazz->init_size )
02303       error = clazz->init_size( size );
02304 
02305     /* in case of success, add to the face's list */
02306     if ( !error )
02307     {
02308       *asize     = size;
02309       node->data = size;
02310       FT_List_Add( &face->sizes_list, node );
02311     }
02312 
02313   Exit:
02314     if ( error )
02315     {
02316       FT_FREE( node );
02317       FT_FREE( size );
02318     }
02319 
02320     return error;
02321   }
02322 
02323 
02324   /* documentation is in ftobjs.h */
02325 
02326   FT_EXPORT_DEF( FT_Error )
02327   FT_Done_Size( FT_Size  size )
02328   {
02329     FT_Error     error;
02330     FT_Driver    driver;
02331     FT_Memory    memory;
02332     FT_Face      face;
02333     FT_ListNode  node;
02334 
02335 
02336     if ( !size )
02337       return FT_Err_Invalid_Size_Handle;
02338 
02339     face = size->face;
02340     if ( !face )
02341       return FT_Err_Invalid_Face_Handle;
02342 
02343     driver = face->driver;
02344     if ( !driver )
02345       return FT_Err_Invalid_Driver_Handle;
02346 
02347     memory = driver->root.memory;
02348 
02349     error = FT_Err_Ok;
02350     node  = FT_List_Find( &face->sizes_list, size );
02351     if ( node )
02352     {
02353       FT_List_Remove( &face->sizes_list, node );
02354       FT_FREE( node );
02355 
02356       if ( face->size == size )
02357       {
02358         face->size = 0;
02359         if ( face->sizes_list.head )
02360           face->size = (FT_Size)(face->sizes_list.head->data);
02361       }
02362 
02363       destroy_size( memory, size, driver );
02364     }
02365     else
02366       error = FT_Err_Invalid_Size_Handle;
02367 
02368     return error;
02369   }
02370 
02371 
02372   /* documentation is in ftobjs.h */
02373 
02374   FT_BASE_DEF( FT_Error )
02375   FT_Match_Size( FT_Face          face,
02376                  FT_Size_Request  req,
02377                  FT_Bool          ignore_width,
02378                  FT_ULong*        size_index )
02379   {
02380     FT_Int   i;
02381     FT_Long  w, h;
02382 
02383 
02384     if ( !FT_HAS_FIXED_SIZES( face ) )
02385       return FT_Err_Invalid_Face_Handle;
02386 
02387     /* FT_Bitmap_Size doesn't provide enough info... */
02388     if ( req->type != FT_SIZE_REQUEST_TYPE_NOMINAL )
02389       return FT_Err_Unimplemented_Feature;
02390 
02391     w = FT_REQUEST_WIDTH ( req );
02392     h = FT_REQUEST_HEIGHT( req );
02393 
02394     if ( req->width && !req->height )
02395       h = w;
02396     else if ( !req->width && req->height )
02397       w = h;
02398 
02399     w = FT_PIX_ROUND( w );
02400     h = FT_PIX_ROUND( h );
02401 
02402     for ( i = 0; i < face->num_fixed_sizes; i++ )
02403     {
02404       FT_Bitmap_Size*  bsize = face->available_sizes + i;
02405 
02406 
02407       if ( h != FT_PIX_ROUND( bsize->y_ppem ) )
02408         continue;
02409 
02410       if ( w == FT_PIX_ROUND( bsize->x_ppem ) || ignore_width )
02411       {
02412         if ( size_index )
02413           *size_index = (FT_ULong)i;
02414 
02415         return FT_Err_Ok;
02416       }
02417     }
02418 
02419     return FT_Err_Invalid_Pixel_Size;
02420   }
02421 
02422 
02423   /* documentation is in ftobjs.h */
02424 
02425   FT_BASE_DEF( void )
02426   ft_synthesize_vertical_metrics( FT_Glyph_Metrics*  metrics,
02427                                   FT_Pos             advance )
02428   {
02429     FT_Pos  height = metrics->height;
02430 
02431 
02432     /* compensate for glyph with bbox above/below the baseline */
02433     if ( metrics->horiBearingY < 0 )
02434     {
02435       if ( height < metrics->horiBearingY )
02436         height = metrics->horiBearingY;
02437     }
02438     else if ( metrics->horiBearingY > 0 )
02439       height -= metrics->horiBearingY;
02440 
02441     /* the factor 1.2 is a heuristical value */
02442     if ( !advance )
02443       advance = height * 12 / 10;
02444 
02445     metrics->vertBearingX = metrics->horiBearingX - metrics->horiAdvance / 2;
02446     metrics->vertBearingY = ( advance - height ) / 2;
02447     metrics->vertAdvance  = advance;
02448   }
02449 
02450 
02451   static void
02452   ft_recompute_scaled_metrics( FT_Face           face,
02453                                FT_Size_Metrics*  metrics )
02454   {
02455     /* Compute root ascender, descender, test height, and max_advance */
02456 
02457 #ifdef GRID_FIT_METRICS
02458     metrics->ascender    = FT_PIX_CEIL( FT_MulFix( face->ascender,
02459                                                    metrics->y_scale ) );
02460 
02461     metrics->descender   = FT_PIX_FLOOR( FT_MulFix( face->descender,
02462                                                     metrics->y_scale ) );
02463 
02464     metrics->height      = FT_PIX_ROUND( FT_MulFix( face->height,
02465                                                     metrics->y_scale ) );
02466 
02467     metrics->max_advance = FT_PIX_ROUND( FT_MulFix( face->max_advance_width,
02468                                                     metrics->x_scale ) );
02469 #else /* !GRID_FIT_METRICS */
02470     metrics->ascender    = FT_MulFix( face->ascender,
02471                                       metrics->y_scale );
02472 
02473     metrics->descender   = FT_MulFix( face->descender,
02474                                       metrics->y_scale );
02475 
02476     metrics->height      = FT_MulFix( face->height,
02477                                       metrics->y_scale );
02478 
02479     metrics->max_advance = FT_MulFix( face->max_advance_width,
02480                                       metrics->x_scale );
02481 #endif /* !GRID_FIT_METRICS */
02482   }
02483 
02484 
02485   FT_BASE_DEF( void )
02486   FT_Select_Metrics( FT_Face   face,
02487                      FT_ULong  strike_index )
02488   {
02489     FT_Size_Metrics*  metrics;
02490     FT_Bitmap_Size*   bsize;
02491 
02492 
02493     metrics = &face->size->metrics;
02494     bsize   = face->available_sizes + strike_index;
02495 
02496     metrics->x_ppem = (FT_UShort)( ( bsize->x_ppem + 32 ) >> 6 );
02497     metrics->y_ppem = (FT_UShort)( ( bsize->y_ppem + 32 ) >> 6 );
02498 
02499     if ( FT_IS_SCALABLE( face ) )
02500     {
02501       metrics->x_scale = FT_DivFix( bsize->x_ppem,
02502                                     face->units_per_EM );
02503       metrics->y_scale = FT_DivFix( bsize->y_ppem,
02504                                     face->units_per_EM );
02505 
02506       ft_recompute_scaled_metrics( face, metrics );
02507     }
02508     else
02509     {
02510       metrics->x_scale     = 1L << 16;
02511       metrics->y_scale     = 1L << 16;
02512       metrics->ascender    = bsize->y_ppem;
02513       metrics->descender   = 0;
02514       metrics->height      = bsize->height << 6;
02515       metrics->max_advance = bsize->x_ppem;
02516     }
02517   }
02518 
02519 
02520   FT_BASE_DEF( void )
02521   FT_Request_Metrics( FT_Face          face,
02522                       FT_Size_Request  req )
02523   {
02524     FT_Size_Metrics*  metrics;
02525 
02526 
02527     metrics = &face->size->metrics;
02528 
02529     if ( FT_IS_SCALABLE( face ) )
02530     {
02531       FT_Long  w = 0, h = 0, scaled_w = 0, scaled_h = 0;
02532 
02533 
02534       switch ( req->type )
02535       {
02536       case FT_SIZE_REQUEST_TYPE_NOMINAL:
02537         w = h = face->units_per_EM;
02538         break;
02539 
02540       case FT_SIZE_REQUEST_TYPE_REAL_DIM:
02541         w = h = face->ascender - face->descender;
02542         break;
02543 
02544       case FT_SIZE_REQUEST_TYPE_BBOX:
02545         w = face->bbox.xMax - face->bbox.xMin;
02546         h = face->bbox.yMax - face->bbox.yMin;
02547         break;
02548 
02549       case FT_SIZE_REQUEST_TYPE_CELL:
02550         w = face->max_advance_width;
02551         h = face->ascender - face->descender;
02552         break;
02553 
02554       case FT_SIZE_REQUEST_TYPE_SCALES:
02555         metrics->x_scale = (FT_Fixed)req->width;
02556         metrics->y_scale = (FT_Fixed)req->height;
02557         if ( !metrics->x_scale )
02558           metrics->x_scale = metrics->y_scale;
02559         else if ( !metrics->y_scale )
02560           metrics->y_scale = metrics->x_scale;
02561         goto Calculate_Ppem;
02562 
02563       case FT_SIZE_REQUEST_TYPE_MAX:
02564         break;
02565       }
02566 
02567       /* to be on the safe side */
02568       if ( w < 0 )
02569         w = -w;
02570 
02571       if ( h < 0 )
02572         h = -h;
02573 
02574       scaled_w = FT_REQUEST_WIDTH ( req );
02575       scaled_h = FT_REQUEST_HEIGHT( req );
02576 
02577       /* determine scales */
02578       if ( req->width )
02579       {
02580         metrics->x_scale = FT_DivFix( scaled_w, w );
02581 
02582         if ( req->height )
02583         {
02584           metrics->y_scale = FT_DivFix( scaled_h, h );
02585 
02586           if ( req->type == FT_SIZE_REQUEST_TYPE_CELL )
02587           {
02588             if ( metrics->y_scale > metrics->x_scale )
02589               metrics->y_scale = metrics->x_scale;
02590             else
02591               metrics->x_scale = metrics->y_scale;
02592           }
02593         }
02594         else
02595         {
02596           metrics->y_scale = metrics->x_scale;
02597           scaled_h = FT_MulDiv( scaled_w, h, w );
02598         }
02599       }
02600       else
02601       {
02602         metrics->x_scale = metrics->y_scale = FT_DivFix( scaled_h, h );
02603         scaled_w = FT_MulDiv( scaled_h, w, h );
02604       }
02605 
02606   Calculate_Ppem:
02607       /* calculate the ppems */
02608       if ( req->type != FT_SIZE_REQUEST_TYPE_NOMINAL )
02609       {
02610         scaled_w = FT_MulFix( face->units_per_EM, metrics->x_scale );
02611         scaled_h = FT_MulFix( face->units_per_EM, metrics->y_scale );
02612       }
02613 
02614       metrics->x_ppem = (FT_UShort)( ( scaled_w + 32 ) >> 6 );
02615       metrics->y_ppem = (FT_UShort)( ( scaled_h + 32 ) >> 6 );
02616 
02617       ft_recompute_scaled_metrics( face, metrics );
02618     }
02619     else
02620     {
02621       FT_ZERO( metrics );
02622       metrics->x_scale = 1L << 16;
02623       metrics->y_scale = 1L << 16;
02624     }
02625   }
02626 
02627 
02628   /* documentation is in freetype.h */
02629 
02630   FT_EXPORT_DEF( FT_Error )
02631   FT_Select_Size( FT_Face  face,
02632                   FT_Int   strike_index )
02633   {
02634     FT_Driver_Class  clazz;
02635 
02636 
02637     if ( !face || !FT_HAS_FIXED_SIZES( face ) )
02638       return FT_Err_Invalid_Face_Handle;
02639 
02640     if ( strike_index < 0 || strike_index >= face->num_fixed_sizes )
02641       return FT_Err_Invalid_Argument;
02642 
02643     clazz = face->driver->clazz;
02644 
02645     if ( clazz->select_size )
02646       return clazz->select_size( face->size, (FT_ULong)strike_index );
02647 
02648     FT_Select_Metrics( face, (FT_ULong)strike_index );
02649 
02650     return FT_Err_Ok;
02651   }
02652 
02653 
02654   /* documentation is in freetype.h */
02655 
02656   FT_EXPORT_DEF( FT_Error )
02657   FT_Request_Size( FT_Face          face,
02658                    FT_Size_Request  req )
02659   {
02660     FT_Driver_Class  clazz;
02661     FT_ULong         strike_index;
02662 
02663 
02664     if ( !face )
02665       return FT_Err_Invalid_Face_Handle;
02666 
02667     if ( !req || req->width < 0 || req->height < 0 ||
02668          req->type >= FT_SIZE_REQUEST_TYPE_MAX )
02669       return FT_Err_Invalid_Argument;
02670 
02671     clazz = face->driver->clazz;
02672 
02673     if ( clazz->request_size )
02674       return clazz->request_size( face->size, req );
02675 
02676     /*
02677      * The reason that a driver doesn't have `request_size' defined is
02678      * either that the scaling here suffices or that the supported formats
02679      * are bitmap-only and size matching is not implemented.
02680      *
02681      * In the latter case, a simple size matching is done.
02682      */
02683     if ( !FT_IS_SCALABLE( face ) && FT_HAS_FIXED_SIZES( face ) )
02684     {
02685       FT_Error  error;
02686 
02687 
02688       error = FT_Match_Size( face, req, 0, &strike_index );
02689       if ( error )
02690         return error;
02691 
02692       FT_TRACE3(( "FT_Request_Size: bitmap strike %lu matched\n",
02693                   strike_index ));
02694 
02695       return FT_Select_Size( face, (FT_Int)strike_index );
02696     }
02697 
02698     FT_Request_Metrics( face, req );
02699 
02700     return FT_Err_Ok;
02701   }
02702 
02703 
02704   /* documentation is in freetype.h */
02705 
02706   FT_EXPORT_DEF( FT_Error )
02707   FT_Set_Char_Size( FT_Face     face,
02708                     FT_F26Dot6  char_width,
02709                     FT_F26Dot6  char_height,
02710                     FT_UInt     horz_resolution,
02711                     FT_UInt     vert_resolution )
02712   {
02713     FT_Size_RequestRec  req;
02714 
02715 
02716     if ( !char_width )
02717       char_width = char_height;
02718     else if ( !char_height )
02719       char_height = char_width;
02720 
02721     if ( !horz_resolution )
02722       horz_resolution = vert_resolution;
02723     else if ( !vert_resolution )
02724       vert_resolution = horz_resolution;
02725 
02726     if ( char_width  < 1 * 64 )
02727       char_width  = 1 * 64;
02728     if ( char_height < 1 * 64 )
02729       char_height = 1 * 64;
02730 
02731     if ( !horz_resolution )
02732       horz_resolution = vert_resolution = 72;
02733 
02734     req.type           = FT_SIZE_REQUEST_TYPE_NOMINAL;
02735     req.width          = char_width;
02736     req.height         = char_height;
02737     req.horiResolution = horz_resolution;
02738     req.vertResolution = vert_resolution;
02739 
02740     return FT_Request_Size( face, &req );
02741   }
02742 
02743 
02744   /* documentation is in freetype.h */
02745 
02746   FT_EXPORT_DEF( FT_Error )
02747   FT_Set_Pixel_Sizes( FT_Face  face,
02748                       FT_UInt  pixel_width,
02749                       FT_UInt  pixel_height )
02750   {
02751     FT_Size_RequestRec  req;
02752 
02753 
02754     if ( pixel_width == 0 )
02755       pixel_width = pixel_height;
02756     else if ( pixel_height == 0 )
02757       pixel_height = pixel_width;
02758 
02759     if ( pixel_width  < 1 )
02760       pixel_width  = 1;
02761     if ( pixel_height < 1 )
02762       pixel_height = 1;
02763 
02764     /* use `>=' to avoid potential compiler warning on 16bit platforms */
02765     if ( pixel_width  >= 0xFFFFU )
02766       pixel_width  = 0xFFFFU;
02767     if ( pixel_height >= 0xFFFFU )
02768       pixel_height = 0xFFFFU;
02769 
02770     req.type           = FT_SIZE_REQUEST_TYPE_NOMINAL;
02771     req.width          = pixel_width << 6;
02772     req.height         = pixel_height << 6;
02773     req.horiResolution = 0;
02774     req.vertResolution = 0;
02775 
02776     return FT_Request_Size( face, &req );
02777   }
02778 
02779 
02780   /* documentation is in freetype.h */
02781 
02782   FT_EXPORT_DEF( FT_Error )
02783   FT_Get_Kerning( FT_Face     face,
02784                   FT_UInt     left_glyph,
02785                   FT_UInt     right_glyph,
02786                   FT_UInt     kern_mode,
02787                   FT_Vector  *akerning )
02788   {
02789     FT_Error   error = FT_Err_Ok;
02790     FT_Driver  driver;
02791 
02792 
02793     if ( !face )
02794       return FT_Err_Invalid_Face_Handle;
02795 
02796     if ( !akerning )
02797       return FT_Err_Invalid_Argument;
02798 
02799     driver = face->driver;
02800 
02801     akerning->x = 0;
02802     akerning->y = 0;
02803 
02804     if ( driver->clazz->get_kerning )
02805     {
02806       error = driver->clazz->get_kerning( face,
02807                                           left_glyph,
02808                                           right_glyph,
02809                                           akerning );
02810       if ( !error )
02811       {
02812         if ( kern_mode != FT_KERNING_UNSCALED )
02813         {
02814           akerning->x = FT_MulFix( akerning->x, face->size->metrics.x_scale );
02815           akerning->y = FT_MulFix( akerning->y, face->size->metrics.y_scale );
02816 
02817           if ( kern_mode != FT_KERNING_UNFITTED )
02818           {
02819             /* we scale down kerning values for small ppem values */
02820             /* to avoid that rounding makes them too big.         */
02821             /* `25' has been determined heuristically.            */
02822             if ( face->size->metrics.x_ppem < 25 )
02823               akerning->x = FT_MulDiv( akerning->x,
02824                                        face->size->metrics.x_ppem, 25 );
02825             if ( face->size->metrics.y_ppem < 25 )
02826               akerning->y = FT_MulDiv( akerning->y,
02827                                        face->size->metrics.y_ppem, 25 );
02828 
02829             akerning->x = FT_PIX_ROUND( akerning->x );
02830             akerning->y = FT_PIX_ROUND( akerning->y );
02831           }
02832         }
02833       }
02834     }
02835 
02836     return error;
02837   }
02838 
02839 
02840   /* documentation is in freetype.h */
02841 
02842   FT_EXPORT_DEF( FT_Error )
02843   FT_Get_Track_Kerning( FT_Face    face,
02844                         FT_Fixed   point_size,
02845                         FT_Int     degree,
02846                         FT_Fixed*  akerning )
02847   {
02848     FT_Service_Kerning  service;
02849     FT_Error            error = FT_Err_Ok;
02850 
02851 
02852     if ( !face )
02853       return FT_Err_Invalid_Face_Handle;
02854 
02855     if ( !akerning )
02856       return FT_Err_Invalid_Argument;
02857 
02858     FT_FACE_FIND_SERVICE( face, service, KERNING );
02859     if ( !service )
02860       return FT_Err_Unimplemented_Feature;
02861 
02862     error = service->get_track( face,
02863                                 point_size,
02864                                 degree,
02865                                 akerning );
02866 
02867     return error;
02868   }
02869 
02870 
02871   /* documentation is in freetype.h */
02872 
02873   FT_EXPORT_DEF( FT_Error )
02874   FT_Select_Charmap( FT_Face      face,
02875                      FT_Encoding  encoding )
02876   {
02877     FT_CharMap*  cur;
02878     FT_CharMap*  limit;
02879 
02880 
02881     if ( !face )
02882       return FT_Err_Invalid_Face_Handle;
02883 
02884     if ( encoding == FT_ENCODING_NONE )
02885       return FT_Err_Invalid_Argument;
02886 
02887     /* FT_ENCODING_UNICODE is special.  We try to find the `best' Unicode */
02888     /* charmap available, i.e., one with UCS-4 characters, if possible.   */
02889     /*                                                                    */
02890     /* This is done by find_unicode_charmap() above, to share code.       */
02891     if ( encoding == FT_ENCODING_UNICODE )
02892       return find_unicode_charmap( face );
02893 
02894     cur = face->charmaps;
02895     if ( !cur )
02896       return FT_Err_Invalid_CharMap_Handle;
02897 
02898     limit = cur + face->num_charmaps;
02899 
02900     for ( ; cur < limit; cur++ )
02901     {
02902       if ( cur[0]->encoding == encoding )
02903       {
02904         face->charmap = cur[0];
02905         return 0;
02906       }
02907     }
02908 
02909     return FT_Err_Invalid_Argument;
02910   }
02911 
02912 
02913   /* documentation is in freetype.h */
02914 
02915   FT_EXPORT_DEF( FT_Error )
02916   FT_Set_Charmap( FT_Face     face,
02917                   FT_CharMap  charmap )
02918   {
02919     FT_CharMap*  cur;
02920     FT_CharMap*  limit;
02921 
02922 
02923     if ( !face )
02924       return FT_Err_Invalid_Face_Handle;
02925 
02926     cur = face->charmaps;
02927     if ( !cur )
02928       return FT_Err_Invalid_CharMap_Handle;
02929     if ( FT_Get_CMap_Format( charmap ) == 14 )
02930       return FT_Err_Invalid_Argument;
02931 
02932     limit = cur + face->num_charmaps;
02933 
02934     for ( ; cur < limit; cur++ )
02935     {
02936       if ( cur[0] == charmap )
02937       {
02938         face->charmap = cur[0];
02939         return 0;
02940       }
02941     }
02942     return FT_Err_Invalid_Argument;
02943   }
02944 
02945 
02946   /* documentation is in freetype.h */
02947 
02948   FT_EXPORT_DEF( FT_Int )
02949   FT_Get_Charmap_Index( FT_CharMap  charmap )
02950   {
02951     FT_Int  i;
02952 
02953 
02954     for ( i = 0; i < charmap->face->num_charmaps; i++ )
02955       if ( charmap->face->charmaps[i] == charmap )
02956         break;
02957 
02958     FT_ASSERT( i < charmap->face->num_charmaps );
02959 
02960     return i;
02961   }
02962 
02963 
02964   static void
02965   ft_cmap_done_internal( FT_CMap  cmap )
02966   {
02967     FT_CMap_Class  clazz  = cmap->clazz;
02968     FT_Face        face   = cmap->charmap.face;
02969     FT_Memory      memory = FT_FACE_MEMORY(face);
02970 
02971 
02972     if ( clazz->done )
02973       clazz->done( cmap );
02974 
02975     FT_FREE( cmap );
02976   }
02977 
02978 
02979   FT_BASE_DEF( void )
02980   FT_CMap_Done( FT_CMap  cmap )
02981   {
02982     if ( cmap )
02983     {
02984       FT_Face    face   = cmap->charmap.face;
02985       FT_Memory  memory = FT_FACE_MEMORY( face );
02986       FT_Error   error;
02987       FT_Int     i, j;
02988 
02989 
02990       for ( i = 0; i < face->num_charmaps; i++ )
02991       {
02992         if ( (FT_CMap)face->charmaps[i] == cmap )
02993         {
02994           FT_CharMap  last_charmap = face->charmaps[face->num_charmaps - 1];
02995 
02996 
02997           if ( FT_RENEW_ARRAY( face->charmaps,
02998                                face->num_charmaps,
02999                                face->num_charmaps - 1 ) )
03000             return;
03001 
03002           /* remove it from our list of charmaps */
03003           for ( j = i + 1; j < face->num_charmaps; j++ )
03004           {
03005             if ( j == face->num_charmaps - 1 )
03006               face->charmaps[j - 1] = last_charmap;
03007             else
03008               face->charmaps[j - 1] = face->charmaps[j];
03009           }
03010 
03011           face->num_charmaps--;
03012 
03013           if ( (FT_CMap)face->charmap == cmap )
03014             face->charmap = NULL;
03015 
03016           ft_cmap_done_internal( cmap );
03017 
03018           break;
03019         }
03020       }
03021     }
03022   }
03023 
03024 
03025   FT_BASE_DEF( FT_Error )
03026   FT_CMap_New( FT_CMap_Class  clazz,
03027                FT_Pointer     init_data,
03028                FT_CharMap     charmap,
03029                FT_CMap       *acmap )
03030   {
03031     FT_Error   error = FT_Err_Ok;
03032     FT_Face    face;
03033     FT_Memory  memory;
03034     FT_CMap    cmap;
03035 
03036 
03037     if ( clazz == NULL || charmap == NULL || charmap->face == NULL )
03038       return FT_Err_Invalid_Argument;
03039 
03040     face   = charmap->face;
03041     memory = FT_FACE_MEMORY( face );
03042 
03043     if ( !FT_ALLOC( cmap, clazz->size ) )
03044     {
03045       cmap->charmap = *charmap;
03046       cmap->clazz   = clazz;
03047 
03048       if ( clazz->init )
03049       {
03050         error = clazz->init( cmap, init_data );
03051         if ( error )
03052           goto Fail;
03053       }
03054 
03055       /* add it to our list of charmaps */
03056       if ( FT_RENEW_ARRAY( face->charmaps,
03057                            face->num_charmaps,
03058                            face->num_charmaps + 1 ) )
03059         goto Fail;
03060 
03061       face->charmaps[face->num_charmaps++] = (FT_CharMap)cmap;
03062     }
03063 
03064   Exit:
03065     if ( acmap )
03066       *acmap = cmap;
03067 
03068     return error;
03069 
03070   Fail:
03071     ft_cmap_done_internal( cmap );
03072     cmap = NULL;
03073     goto Exit;
03074   }
03075 
03076 
03077   /* documentation is in freetype.h */
03078 
03079   FT_EXPORT_DEF( FT_UInt )
03080   FT_Get_Char_Index( FT_Face   face,
03081                      FT_ULong  charcode )
03082   {
03083     FT_UInt  result = 0;
03084 
03085 
03086     if ( face && face->charmap )
03087     {
03088       FT_CMap  cmap = FT_CMAP( face->charmap );
03089 
03090 
03091       if ( charcode > 0xFFFFFFFFUL )
03092       {
03093         FT_TRACE1(( "FT_Get_Char_Index: too large charcode" ));
03094         FT_TRACE1(( " 0x%x is truncated\n", charcode ));
03095       }
03096       result = cmap->clazz->char_index( cmap, (FT_UInt32)charcode );
03097     }
03098     return  result;
03099   }
03100 
03101 
03102   /* documentation is in freetype.h */
03103 
03104   FT_EXPORT_DEF( FT_ULong )
03105   FT_Get_First_Char( FT_Face   face,
03106                      FT_UInt  *agindex )
03107   {
03108     FT_ULong  result = 0;
03109     FT_UInt   gindex = 0;
03110 
03111 
03112     if ( face && face->charmap )
03113     {
03114       gindex = FT_Get_Char_Index( face, 0 );
03115       if ( gindex == 0 )
03116         result = FT_Get_Next_Char( face, 0, &gindex );
03117     }
03118 
03119     if ( agindex  )
03120       *agindex = gindex;
03121 
03122     return result;
03123   }
03124 
03125 
03126   /* documentation is in freetype.h */
03127 
03128   FT_EXPORT_DEF( FT_ULong )
03129   FT_Get_Next_Char( FT_Face   face,
03130                     FT_ULong  charcode,
03131                     FT_UInt  *agindex )
03132   {
03133     FT_ULong  result = 0;
03134     FT_UInt   gindex = 0;
03135 
03136 
03137     if ( face && face->charmap )
03138     {
03139       FT_UInt32  code = (FT_UInt32)charcode;
03140       FT_CMap    cmap = FT_CMAP( face->charmap );
03141 
03142 
03143       gindex = cmap->clazz->char_next( cmap, &code );
03144       result = ( gindex == 0 ) ? 0 : code;
03145     }
03146 
03147     if ( agindex )
03148       *agindex = gindex;
03149 
03150     return result;
03151   }
03152 
03153 
03154   /* documentation is in freetype.h */
03155 
03156   FT_EXPORT_DEF( FT_UInt )
03157   FT_Face_GetCharVariantIndex( FT_Face   face,
03158                                FT_ULong  charcode,
03159                                FT_ULong  variantSelector )
03160   {
03161     FT_UInt  result = 0;
03162 
03163 
03164     if ( face && face->charmap &&
03165         face->charmap->encoding == FT_ENCODING_UNICODE )
03166     {
03167       FT_CharMap  charmap = find_variant_selector_charmap( face );
03168       FT_CMap     ucmap = FT_CMAP( face->charmap );
03169 
03170 
03171       if ( charmap != NULL )
03172       {
03173         FT_CMap  vcmap = FT_CMAP( charmap );
03174 
03175 
03176         if ( charcode > 0xFFFFFFFFUL )
03177         {
03178           FT_TRACE1(( "FT_Get_Char_Index: too large charcode" ));
03179           FT_TRACE1(( " 0x%x is truncated\n", charcode ));
03180         }
03181         if ( variantSelector > 0xFFFFFFFFUL )
03182         {
03183           FT_TRACE1(( "FT_Get_Char_Index: too large variantSelector" ));
03184           FT_TRACE1(( " 0x%x is truncated\n", variantSelector ));
03185         }
03186 
03187         result = vcmap->clazz->char_var_index( vcmap, ucmap,
03188                                                (FT_UInt32)charcode,
03189                                                (FT_UInt32)variantSelector );
03190       }
03191     }
03192 
03193     return result;
03194   }
03195 
03196 
03197   /* documentation is in freetype.h */
03198 
03199   FT_EXPORT_DEF( FT_Int )
03200   FT_Face_GetCharVariantIsDefault( FT_Face   face,
03201                                    FT_ULong  charcode,
03202                                    FT_ULong  variantSelector )
03203   {
03204     FT_Int  result = -1;
03205 
03206 
03207     if ( face )
03208     {
03209       FT_CharMap  charmap = find_variant_selector_charmap( face );
03210 
03211 
03212       if ( charmap != NULL )
03213       {
03214         FT_CMap  vcmap = FT_CMAP( charmap );
03215 
03216 
03217         if ( charcode > 0xFFFFFFFFUL )
03218         {
03219           FT_TRACE1(( "FT_Get_Char_Index: too large charcode" ));
03220           FT_TRACE1(( " 0x%x is truncated\n", charcode ));
03221         }
03222         if ( variantSelector > 0xFFFFFFFFUL )
03223         {
03224           FT_TRACE1(( "FT_Get_Char_Index: too large variantSelector" ));
03225           FT_TRACE1(( " 0x%x is truncated\n", variantSelector ));
03226         }
03227 
03228         result = vcmap->clazz->char_var_default( vcmap,
03229                                                  (FT_UInt32)charcode,
03230                                                  (FT_UInt32)variantSelector );
03231       }
03232     }
03233 
03234     return result;
03235   }
03236 
03237 
03238   /* documentation is in freetype.h */
03239 
03240   FT_EXPORT_DEF( FT_UInt32* )
03241   FT_Face_GetVariantSelectors( FT_Face  face )
03242   {
03243     FT_UInt32  *result = NULL;
03244 
03245 
03246     if ( face )
03247     {
03248       FT_CharMap  charmap = find_variant_selector_charmap( face );
03249 
03250 
03251       if ( charmap != NULL )
03252       {
03253         FT_CMap    vcmap  = FT_CMAP( charmap );
03254         FT_Memory  memory = FT_FACE_MEMORY( face );
03255 
03256 
03257         result = vcmap->clazz->variant_list( vcmap, memory );
03258       }
03259     }
03260 
03261     return result;
03262   }
03263 
03264 
03265   /* documentation is in freetype.h */
03266 
03267   FT_EXPORT_DEF( FT_UInt32* )
03268   FT_Face_GetVariantsOfChar( FT_Face   face,
03269                              FT_ULong  charcode )
03270   {
03271     FT_UInt32  *result = NULL;
03272 
03273 
03274     if ( face )
03275     {
03276       FT_CharMap  charmap = find_variant_selector_charmap( face );
03277 
03278 
03279       if ( charmap != NULL )
03280       {
03281         FT_CMap    vcmap  = FT_CMAP( charmap );
03282         FT_Memory  memory = FT_FACE_MEMORY( face );
03283 
03284 
03285         if ( charcode > 0xFFFFFFFFUL )
03286         {
03287           FT_TRACE1(( "FT_Get_Char_Index: too large charcode" ));
03288           FT_TRACE1(( " 0x%x is truncated\n", charcode ));
03289         }
03290 
03291         result = vcmap->clazz->charvariant_list( vcmap, memory,
03292                                                  (FT_UInt32)charcode );
03293       }
03294     }
03295     return result;
03296   }
03297 
03298 
03299   /* documentation is in freetype.h */
03300 
03301   FT_EXPORT_DEF( FT_UInt32* )
03302   FT_Face_GetCharsOfVariant( FT_Face   face,
03303                              FT_ULong  variantSelector )
03304   {
03305     FT_UInt32  *result = NULL;
03306 
03307 
03308     if ( face )
03309     {
03310       FT_CharMap  charmap = find_variant_selector_charmap( face );
03311 
03312 
03313       if ( charmap != NULL )
03314       {
03315         FT_CMap    vcmap  = FT_CMAP( charmap );
03316         FT_Memory  memory = FT_FACE_MEMORY( face );
03317 
03318 
03319         if ( variantSelector > 0xFFFFFFFFUL )
03320         {
03321           FT_TRACE1(( "FT_Get_Char_Index: too large variantSelector" ));
03322           FT_TRACE1(( " 0x%x is truncated\n", variantSelector ));
03323         }
03324 
03325         result = vcmap->clazz->variantchar_list( vcmap, memory,
03326                                                  (FT_UInt32)variantSelector );
03327       }
03328     }
03329 
03330     return result;
03331   }
03332 
03333 
03334   /* documentation is in freetype.h */
03335 
03336   FT_EXPORT_DEF( FT_UInt )
03337   FT_Get_Name_Index( FT_Face     face,
03338                      FT_String*  glyph_name )
03339   {
03340     FT_UInt  result = 0;
03341 
03342 
03343     if ( face && FT_HAS_GLYPH_NAMES( face ) )
03344     {
03345       FT_Service_GlyphDict  service;
03346 
03347 
03348       FT_FACE_LOOKUP_SERVICE( face,
03349                               service,
03350                               GLYPH_DICT );
03351 
03352       if ( service && service->name_index )
03353         result = service->name_index( face, glyph_name );
03354     }
03355 
03356     return result;
03357   }
03358 
03359 
03360   /* documentation is in freetype.h */
03361 
03362   FT_EXPORT_DEF( FT_Error )
03363   FT_Get_Glyph_Name( FT_Face     face,
03364                      FT_UInt     glyph_index,
03365                      FT_Pointer  buffer,
03366                      FT_UInt     buffer_max )
03367   {
03368     FT_Error  error = FT_Err_Invalid_Argument;
03369 
03370 
03371     /* clean up buffer */
03372     if ( buffer && buffer_max > 0 )
03373       ((FT_Byte*)buffer)[0] = 0;
03374 
03375     if ( face                                     &&
03376          (FT_Long)glyph_index <= face->num_glyphs &&
03377          FT_HAS_GLYPH_NAMES( face )               )
03378     {
03379       FT_Service_GlyphDict  service;
03380 
03381 
03382       FT_FACE_LOOKUP_SERVICE( face,
03383                               service,
03384                               GLYPH_DICT );
03385 
03386       if ( service && service->get_name )
03387         error = service->get_name( face, glyph_index, buffer, buffer_max );
03388     }
03389 
03390     return error;
03391   }
03392 
03393 
03394   /* documentation is in freetype.h */
03395 
03396   FT_EXPORT_DEF( const char* )
03397   FT_Get_Postscript_Name( FT_Face  face )
03398   {
03399     const char*  result = NULL;
03400 
03401 
03402     if ( !face )
03403       goto Exit;
03404 
03405     if ( !result )
03406     {
03407       FT_Service_PsFontName  service;
03408 
03409 
03410       FT_FACE_LOOKUP_SERVICE( face,
03411                               service,
03412                               POSTSCRIPT_FONT_NAME );
03413 
03414       if ( service && service->get_ps_font_name )
03415         result = service->get_ps_font_name( face );
03416     }
03417 
03418   Exit:
03419     return result;
03420   }
03421 
03422 
03423   /* documentation is in tttables.h */
03424 
03425   FT_EXPORT_DEF( void* )
03426   FT_Get_Sfnt_Table( FT_Face      face,
03427                      FT_Sfnt_Tag  tag )
03428   {
03429     void*                  table = 0;
03430     FT_Service_SFNT_Table  service;
03431 
03432 
03433     if ( face && FT_IS_SFNT( face ) )
03434     {
03435       FT_FACE_FIND_SERVICE( face, service, SFNT_TABLE );
03436       if ( service != NULL )
03437         table = service->get_table( face, tag );
03438     }
03439 
03440     return table;
03441   }
03442 
03443 
03444   /* documentation is in tttables.h */
03445 
03446   FT_EXPORT_DEF( FT_Error )
03447   FT_Load_Sfnt_Table( FT_Face    face,
03448                       FT_ULong   tag,
03449                       FT_Long    offset,
03450                       FT_Byte*   buffer,
03451                       FT_ULong*  length )
03452   {
03453     FT_Service_SFNT_Table  service;
03454 
03455 
03456     if ( !face || !FT_IS_SFNT( face ) )
03457       return FT_Err_Invalid_Face_Handle;
03458 
03459     FT_FACE_FIND_SERVICE( face, service, SFNT_TABLE );
03460     if ( service == NULL )
03461       return FT_Err_Unimplemented_Feature;
03462 
03463     return service->load_table( face, tag, offset, buffer, length );
03464   }
03465 
03466 
03467   /* documentation is in tttables.h */
03468 
03469   FT_EXPORT_DEF( FT_Error )
03470   FT_Sfnt_Table_Info( FT_Face    face,
03471                       FT_UInt    table_index,
03472                       FT_ULong  *tag,
03473                       FT_ULong  *length )
03474   {
03475     FT_Service_SFNT_Table  service;
03476     FT_ULong               offset;
03477 
03478 
03479     if ( !face || !FT_IS_SFNT( face ) )
03480       return FT_Err_Invalid_Face_Handle;
03481 
03482     FT_FACE_FIND_SERVICE( face, service, SFNT_TABLE );
03483     if ( service == NULL )
03484       return FT_Err_Unimplemented_Feature;
03485 
03486     return service->table_info( face, table_index, tag, &offset, length );
03487   }
03488 
03489 
03490   /* documentation is in tttables.h */
03491 
03492   FT_EXPORT_DEF( FT_ULong )
03493   FT_Get_CMap_Language_ID( FT_CharMap  charmap )
03494   {
03495     FT_Service_TTCMaps  service;
03496     FT_Face             face;
03497     TT_CMapInfo         cmap_info;
03498 
03499 
03500     if ( !charmap || !charmap->face )
03501       return 0;
03502 
03503     face = charmap->face;
03504     FT_FACE_FIND_SERVICE( face, service, TT_CMAP );
03505     if ( service == NULL )
03506       return 0;
03507     if ( service->get_cmap_info( charmap, &cmap_info ))
03508       return 0;
03509 
03510     return cmap_info.language;
03511   }
03512 
03513 
03514   /* documentation is in tttables.h */
03515 
03516   FT_EXPORT_DEF( FT_Long )
03517   FT_Get_CMap_Format( FT_CharMap  charmap )
03518   {
03519     FT_Service_TTCMaps  service;
03520     FT_Face             face;
03521     TT_CMapInfo         cmap_info;
03522 
03523 
03524     if ( !charmap || !charmap->face )
03525       return -1;
03526 
03527     face = charmap->face;
03528     FT_FACE_FIND_SERVICE( face, service, TT_CMAP );
03529     if ( service == NULL )
03530       return -1;
03531     if ( service->get_cmap_info( charmap, &cmap_info ))
03532       return -1;
03533 
03534     return cmap_info.format;
03535   }
03536 
03537 
03538   /* documentation is in ftsizes.h */
03539 
03540   FT_EXPORT_DEF( FT_Error )
03541   FT_Activate_Size( FT_Size  size )
03542   {
03543     FT_Face  face;
03544 
03545 
03546     if ( size == NULL )
03547       return FT_Err_Invalid_Argument;
03548 
03549     face = size->face;
03550     if ( face == NULL || face->driver == NULL )
03551       return FT_Err_Invalid_Argument;
03552 
03553     /* we don't need anything more complex than that; all size objects */
03554     /* are already listed by the face                                  */
03555     face->size = size;
03556 
03557     return FT_Err_Ok;
03558   }
03559 
03560 
03561   /*************************************************************************/
03562   /*************************************************************************/
03563   /*************************************************************************/
03564   /****                                                                 ****/
03565   /****                                                                 ****/
03566   /****                        R E N D E R E R S                        ****/
03567   /****                                                                 ****/
03568   /****                                                                 ****/
03569   /*************************************************************************/
03570   /*************************************************************************/
03571   /*************************************************************************/
03572 
03573   /* lookup a renderer by glyph format in the library's list */
03574   FT_BASE_DEF( FT_Renderer )
03575   FT_Lookup_Renderer( FT_Library       library,
03576                       FT_Glyph_Format  format,
03577                       FT_ListNode*     node )
03578   {
03579     FT_ListNode  cur;
03580     FT_Renderer  result = 0;
03581 
03582 
03583     if ( !library )
03584       goto Exit;
03585 
03586     cur = library->renderers.head;
03587 
03588     if ( node )
03589     {
03590       if ( *node )
03591         cur = (*node)->next;
03592       *node = 0;
03593     }
03594 
03595     while ( cur )
03596     {
03597       FT_Renderer  renderer = FT_RENDERER( cur->data );
03598 
03599 
03600       if ( renderer->glyph_format == format )
03601       {
03602         if ( node )
03603           *node = cur;
03604 
03605         result = renderer;
03606         break;
03607       }
03608       cur = cur->next;
03609     }
03610 
03611   Exit:
03612     return result;
03613   }
03614 
03615 
03616   static FT_Renderer
03617   ft_lookup_glyph_renderer( FT_GlyphSlot  slot )
03618   {
03619     FT_Face      face    = slot->face;
03620     FT_Library   library = FT_FACE_LIBRARY( face );
03621     FT_Renderer  result  = library->cur_renderer;
03622 
03623 
03624     if ( !result || result->glyph_format != slot->format )
03625       result = FT_Lookup_Renderer( library, slot->format, 0 );
03626 
03627     return result;
03628   }
03629 
03630 
03631   static void
03632   ft_set_current_renderer( FT_Library  library )
03633   {
03634     FT_Renderer  renderer;
03635 
03636 
03637     renderer = FT_Lookup_Renderer( library, FT_GLYPH_FORMAT_OUTLINE, 0 );
03638     library->cur_renderer = renderer;
03639   }
03640 
03641 
03642   static FT_Error
03643   ft_add_renderer( FT_Module  module )
03644   {
03645     FT_Library   library = module->library;
03646     FT_Memory    memory  = library->memory;
03647     FT_Error     error;
03648     FT_ListNode  node;
03649 
03650 
03651     if ( FT_NEW( node ) )
03652       goto Exit;
03653 
03654     {
03655       FT_Renderer         render = FT_RENDERER( module );
03656       FT_Renderer_Class*  clazz  = (FT_Renderer_Class*)module->clazz;
03657 
03658 
03659       render->clazz        = clazz;
03660       render->glyph_format = clazz->glyph_format;
03661 
03662       /* allocate raster object if needed */
03663       if ( clazz->glyph_format == FT_GLYPH_FORMAT_OUTLINE &&
03664            clazz->raster_class->raster_new )
03665       {
03666         error = clazz->raster_class->raster_new( memory, &render->raster );
03667         if ( error )
03668           goto Fail;
03669 
03670         render->raster_render = clazz->raster_class->raster_render;
03671         render->render        = clazz->render_glyph;
03672       }
03673 
03674       /* add to list */
03675       node->data = module;
03676       FT_List_Add( &library->renderers, node );
03677 
03678       ft_set_current_renderer( library );
03679     }
03680 
03681   Fail:
03682     if ( error )
03683       FT_FREE( node );
03684 
03685   Exit:
03686     return error;
03687   }
03688 
03689 
03690   static void
03691   ft_remove_renderer( FT_Module  module )
03692   {
03693     FT_Library   library = module->library;
03694     FT_Memory    memory  = library->memory;
03695     FT_ListNode  node;
03696 
03697 
03698     node = FT_List_Find( &library->renderers, module );
03699     if ( node )
03700     {
03701       FT_Renderer  render = FT_RENDERER( module );
03702 
03703 
03704       /* release raster object, if any */
03705       if ( render->raster )
03706         render->clazz->raster_class->raster_done( render->raster );
03707 
03708       /* remove from list */
03709       FT_List_Remove( &library->renderers, node );
03710       FT_FREE( node );
03711 
03712       ft_set_current_renderer( library );
03713     }
03714   }
03715 
03716 
03717   /* documentation is in ftrender.h */
03718 
03719   FT_EXPORT_DEF( FT_Renderer )
03720   FT_Get_Renderer( FT_Library       library,
03721                    FT_Glyph_Format  format )
03722   {
03723     /* test for valid `library' delayed to FT_Lookup_Renderer() */
03724 
03725     return FT_Lookup_Renderer( library, format, 0 );
03726   }
03727 
03728 
03729   /* documentation is in ftrender.h */
03730 
03731   FT_EXPORT_DEF( FT_Error )
03732   FT_Set_Renderer( FT_Library     library,
03733                    FT_Renderer    renderer,
03734                    FT_UInt        num_params,
03735                    FT_Parameter*  parameters )
03736   {
03737     FT_ListNode  node;
03738     FT_Error     error = FT_Err_Ok;
03739 
03740 
03741     if ( !library )
03742       return FT_Err_Invalid_Library_Handle;
03743 
03744     if ( !renderer )
03745       return FT_Err_Invalid_Argument;
03746 
03747     node = FT_List_Find( &library->renderers, renderer );
03748     if ( !node )
03749     {
03750       error = FT_Err_Invalid_Argument;
03751       goto Exit;
03752     }
03753 
03754     FT_List_Up( &library->renderers, node );
03755 
03756     if ( renderer->glyph_format == FT_GLYPH_FORMAT_OUTLINE )
03757       library->cur_renderer = renderer;
03758 
03759     if ( num_params > 0 )
03760     {
03761       FT_Renderer_SetModeFunc  set_mode = renderer->clazz->set_mode;
03762 
03763 
03764       for ( ; num_params > 0; num_params-- )
03765       {
03766         error = set_mode( renderer, parameters->tag, parameters->data );
03767         if ( error )
03768           break;
03769       }
03770     }
03771 
03772   Exit:
03773     return error;
03774   }
03775 
03776 
03777   FT_BASE_DEF( FT_Error )
03778   FT_Render_Glyph_Internal( FT_Library      library,
03779                             FT_GlyphSlot    slot,
03780                             FT_Render_Mode  render_mode )
03781   {
03782     FT_Error     error = FT_Err_Ok;
03783     FT_Renderer  renderer;
03784 
03785 
03786     /* if it is already a bitmap, no need to do anything */
03787     switch ( slot->format )
03788     {
03789     case FT_GLYPH_FORMAT_BITMAP:   /* already a bitmap, don't do anything */
03790       break;
03791 
03792     default:
03793       {
03794         FT_ListNode  node   = 0;
03795         FT_Bool      update = 0;
03796 
03797 
03798         /* small shortcut for the very common case */
03799         if ( slot->format == FT_GLYPH_FORMAT_OUTLINE )
03800         {
03801           renderer = library->cur_renderer;
03802           node     = library->renderers.head;
03803         }
03804         else
03805           renderer = FT_Lookup_Renderer( library, slot->format, &node );
03806 
03807         error = FT_Err_Unimplemented_Feature;
03808         while ( renderer )
03809         {
03810           error = renderer->render( renderer, slot, render_mode, NULL );
03811           if ( !error                                               ||
03812                FT_ERROR_BASE( error ) != FT_Err_Cannot_Render_Glyph )
03813             break;
03814 
03815           /* FT_Err_Cannot_Render_Glyph is returned if the render mode   */
03816           /* is unsupported by the current renderer for this glyph image */
03817           /* format.                                                     */
03818 
03819           /* now, look for another renderer that supports the same */
03820           /* format.                                               */
03821           renderer = FT_Lookup_Renderer( library, slot->format, &node );
03822           update   = 1;
03823         }
03824 
03825         /* if we changed the current renderer for the glyph image format */
03826         /* we need to select it as the next current one                  */
03827         if ( !error && update && renderer )
03828           FT_Set_Renderer( library, renderer, 0, 0 );
03829       }
03830     }
03831 
03832     return error;
03833   }
03834 
03835 
03836   /* documentation is in freetype.h */
03837 
03838   FT_EXPORT_DEF( FT_Error )
03839   FT_Render_Glyph( FT_GlyphSlot    slot,
03840                    FT_Render_Mode  render_mode )
03841   {
03842     FT_Library  library;
03843 
03844 
03845     if ( !slot )
03846       return FT_Err_Invalid_Argument;
03847 
03848     library = FT_FACE_LIBRARY( slot->face );
03849 
03850     return FT_Render_Glyph_Internal( library, slot, render_mode );
03851   }
03852 
03853 
03854   /*************************************************************************/
03855   /*************************************************************************/
03856   /*************************************************************************/
03857   /****                                                                 ****/
03858   /****                                                                 ****/
03859   /****                         M O D U L E S                           ****/
03860   /****                                                                 ****/
03861   /****                                                                 ****/
03862   /*************************************************************************/
03863   /*************************************************************************/
03864   /*************************************************************************/
03865 
03866 
03867   /*************************************************************************/
03868   /*                                                                       */
03869   /* <Function>                                                            */
03870   /*    Destroy_Module                                                     */
03871   /*                                                                       */
03872   /* <Description>                                                         */
03873   /*    Destroys a given module object.  For drivers, this also destroys   */
03874   /*    all child faces.                                                   */
03875   /*                                                                       */
03876   /* <InOut>                                                               */
03877   /*     module :: A handle to the target driver object.                   */
03878   /*                                                                       */
03879   /* <Note>                                                                */
03880   /*     The driver _must_ be LOCKED!                                      */
03881   /*                                                                       */
03882   static void
03883   Destroy_Module( FT_Module  module )
03884   {
03885     FT_Memory         memory  = module->memory;
03886     FT_Module_Class*  clazz   = module->clazz;
03887     FT_Library        library = module->library;
03888 
03889 
03890     /* finalize client-data - before anything else */
03891     if ( module->generic.finalizer )
03892       module->generic.finalizer( module );
03893 
03894     if ( library && library->auto_hinter == module )
03895       library->auto_hinter = 0;
03896 
03897     /* if the module is a renderer */
03898     if ( FT_MODULE_IS_RENDERER( module ) )
03899       ft_remove_renderer( module );
03900 
03901     /* if the module is a font driver, add some steps */
03902     if ( FT_MODULE_IS_DRIVER( module ) )
03903       Destroy_Driver( FT_DRIVER( module ) );
03904 
03905     /* finalize the module object */
03906     if ( clazz->module_done )
03907       clazz->module_done( module );
03908 
03909     /* discard it */
03910     FT_FREE( module );
03911   }
03912 
03913 
03914   /* documentation is in ftmodapi.h */
03915 
03916   FT_EXPORT_DEF( FT_Error )
03917   FT_Add_Module( FT_Library              library,
03918                  const FT_Module_Class*  clazz )
03919   {
03920     FT_Error   error;
03921     FT_Memory  memory;
03922     FT_Module  module;
03923     FT_UInt    nn;
03924 
03925 
03926 #define FREETYPE_VER_FIXED  ( ( (FT_Long)FREETYPE_MAJOR << 16 ) | \
03927                                 FREETYPE_MINOR                  )
03928 
03929     if ( !library )
03930       return FT_Err_Invalid_Library_Handle;
03931 
03932     if ( !clazz )
03933       return FT_Err_Invalid_Argument;
03934 
03935     /* check freetype version */
03936     if ( clazz->module_requires > FREETYPE_VER_FIXED )
03937       return FT_Err_Invalid_Version;
03938 
03939     /* look for a module with the same name in the library's table */
03940     for ( nn = 0; nn < library->num_modules; nn++ )
03941     {
03942       module = library->modules[nn];
03943       if ( ft_strcmp( module->clazz->module_name, clazz->module_name ) == 0 )
03944       {
03945         /* this installed module has the same name, compare their versions */
03946         if ( clazz->module_version <= module->clazz->module_version )
03947           return FT_Err_Lower_Module_Version;
03948 
03949         /* remove the module from our list, then exit the loop to replace */
03950         /* it by our new version..                                        */
03951         FT_Remove_Module( library, module );
03952         break;
03953       }
03954     }
03955 
03956     memory = library->memory;
03957     error  = FT_Err_Ok;
03958 
03959     if ( library->num_modules >= FT_MAX_MODULES )
03960     {
03961       error = FT_Err_Too_Many_Drivers;
03962       goto Exit;
03963     }
03964 
03965     /* allocate module object */
03966     if ( FT_ALLOC( module, clazz->module_size ) )
03967       goto Exit;
03968 
03969     /* base initialization */
03970     module->library = library;
03971     module->memory  = memory;
03972     module->clazz   = (FT_Module_Class*)clazz;
03973 
03974     /* check whether the module is a renderer - this must be performed */
03975     /* before the normal module initialization                         */
03976     if ( FT_MODULE_IS_RENDERER( module ) )
03977     {
03978       /* add to the renderers list */
03979       error = ft_add_renderer( module );
03980       if ( error )
03981         goto Fail;
03982     }
03983 
03984     /* is the module a auto-hinter? */
03985     if ( FT_MODULE_IS_HINTER( module ) )
03986       library->auto_hinter = module;
03987 
03988     /* if the module is a font driver */
03989     if ( FT_MODULE_IS_DRIVER( module ) )
03990     {
03991       /* allocate glyph loader if needed */
03992       FT_Driver  driver = FT_DRIVER( module );
03993 
03994 
03995       driver->clazz = (FT_Driver_Class)module->clazz;
03996       if ( FT_DRIVER_USES_OUTLINES( driver ) )
03997       {
03998         error = FT_GlyphLoader_New( memory, &driver->glyph_loader );
03999         if ( error )
04000           goto Fail;
04001       }
04002     }
04003 
04004     if ( clazz->module_init )
04005     {
04006       error = clazz->module_init( module );
04007       if ( error )
04008         goto Fail;
04009     }
04010 
04011     /* add module to the library's table */
04012     library->modules[library->num_modules++] = module;
04013 
04014   Exit:
04015     return error;
04016 
04017   Fail:
04018     if ( FT_MODULE_IS_DRIVER( module ) )
04019     {
04020       FT_Driver  driver = FT_DRIVER( module );
04021 
04022 
04023       if ( FT_DRIVER_USES_OUTLINES( driver ) )
04024         FT_GlyphLoader_Done( driver->glyph_loader );
04025     }
04026 
04027     if ( FT_MODULE_IS_RENDERER( module ) )
04028     {
04029       FT_Renderer  renderer = FT_RENDERER( module );
04030 
04031 
04032       if ( renderer->raster )
04033         renderer->clazz->raster_class->raster_done( renderer->raster );
04034     }
04035 
04036     FT_FREE( module );
04037     goto Exit;
04038   }
04039 
04040 
04041   /* documentation is in ftmodapi.h */
04042 
04043   FT_EXPORT_DEF( FT_Module )
04044   FT_Get_Module( FT_Library   library,
04045                  const char*  module_name )
04046   {
04047     FT_Module   result = 0;
04048     FT_Module*  cur;
04049     FT_Module*  limit;
04050 
04051 
04052     if ( !library || !module_name )
04053       return result;
04054 
04055     cur   = library->modules;
04056     limit = cur + library->num_modules;
04057 
04058     for ( ; cur < limit; cur++ )
04059       if ( ft_strcmp( cur[0]->clazz->module_name, module_name ) == 0 )
04060       {
04061         result = cur[0];
04062         break;
04063       }
04064 
04065     return result;
04066   }
04067 
04068 
04069   /* documentation is in ftobjs.h */
04070 
04071   FT_BASE_DEF( const void* )
04072   FT_Get_Module_Interface( FT_Library   library,
04073                            const char*  mod_name )
04074   {
04075     FT_Module  module;
04076 
04077 
04078     /* test for valid `library' delayed to FT_Get_Module() */
04079 
04080     module = FT_Get_Module( library, mod_name );
04081 
04082     return module ? module->clazz->module_interface : 0;
04083   }
04084 
04085 
04086   FT_BASE_DEF( FT_Pointer )
04087   ft_module_get_service( FT_Module    module,
04088                          const char*  service_id )
04089   {
04090     FT_Pointer  result = NULL;
04091 
04092     if ( module )
04093     {
04094       FT_ASSERT( module->clazz && module->clazz->get_interface );
04095 
04096      /* first, look for the service in the module
04097       */
04098       if ( module->clazz->get_interface )
04099         result = module->clazz->get_interface( module, service_id );
04100 
04101       if ( result == NULL )
04102       {
04103        /* we didn't find it, look in all other modules then
04104         */
04105         FT_Library  library = module->library;
04106         FT_Module*  cur     = library->modules;
04107         FT_Module*  limit   = cur + library->num_modules;
04108 
04109         for ( ; cur < limit; cur++ )
04110         {
04111           if ( cur[0] != module )
04112           {
04113             FT_ASSERT( cur[0]->clazz );
04114 
04115             if ( cur[0]->clazz->get_interface )
04116             {
04117               result = cur[0]->clazz->get_interface( cur[0], service_id );
04118               if ( result != NULL )
04119                 break;
04120             }
04121           }
04122         }
04123       }
04124     }
04125 
04126     return result;
04127   }
04128 
04129 
04130   /* documentation is in ftmodapi.h */
04131 
04132   FT_EXPORT_DEF( FT_Error )
04133   FT_Remove_Module( FT_Library  library,
04134                     FT_Module   module )
04135   {
04136     /* try to find the module from the table, then remove it from there */
04137 
04138     if ( !library )
04139       return FT_Err_Invalid_Library_Handle;
04140 
04141     if ( module )
04142     {
04143       FT_Module*  cur   = library->modules;
04144       FT_Module*  limit = cur + library->num_modules;
04145 
04146 
04147       for ( ; cur < limit; cur++ )
04148       {
04149         if ( cur[0] == module )
04150         {
04151           /* remove it from the table */
04152           library->num_modules--;
04153           limit--;
04154           while ( cur < limit )
04155           {
04156             cur[0] = cur[1];
04157             cur++;
04158           }
04159           limit[0] = 0;
04160 
04161           /* destroy the module */
04162           Destroy_Module( module );
04163 
04164           return FT_Err_Ok;
04165         }
04166       }
04167     }
04168     return FT_Err_Invalid_Driver_Handle;
04169   }
04170 
04171 
04172   /*************************************************************************/
04173   /*************************************************************************/
04174   /*************************************************************************/
04175   /****                                                                 ****/
04176   /****                                                                 ****/
04177   /****                         L I B R A R Y                           ****/
04178   /****                                                                 ****/
04179   /****                                                                 ****/
04180   /*************************************************************************/
04181   /*************************************************************************/
04182   /*************************************************************************/
04183 
04184 
04185   /* documentation is in ftmodapi.h */
04186 
04187   FT_EXPORT_DEF( FT_Error )
04188   FT_New_Library( FT_Memory    memory,
04189                   FT_Library  *alibrary )
04190   {
04191     FT_Library  library = 0;
04192     FT_Error    error;
04193 
04194 
04195     if ( !memory )
04196       return FT_Err_Invalid_Argument;
04197 
04198 #ifdef FT_DEBUG_LEVEL_ERROR
04199     /* init debugging support */
04200     ft_debug_init();
04201 #endif
04202 
04203     /* first of all, allocate the library object */
04204     if ( FT_NEW( library ) )
04205       return error;
04206 
04207     library->memory = memory;
04208 
04209 #ifdef FT_CONFIG_OPTION_PIC
04210     /* initialize position independent code containers */
04211     error = ft_pic_container_init( library );
04212     if ( error )
04213       goto Fail;
04214 #endif
04215 
04216     /* allocate the render pool */
04217     library->raster_pool_size = FT_RENDER_POOL_SIZE;
04218 #if FT_RENDER_POOL_SIZE > 0
04219     if ( FT_ALLOC( library->raster_pool, FT_RENDER_POOL_SIZE ) )
04220       goto Fail;
04221 #endif
04222 
04223     library->version_major = FREETYPE_MAJOR;
04224     library->version_minor = FREETYPE_MINOR;
04225     library->version_patch = FREETYPE_PATCH;
04226 
04227     /* That's ok now */
04228     *alibrary = library;
04229 
04230     return FT_Err_Ok;
04231 
04232   Fail:
04233 #ifdef FT_CONFIG_OPTION_PIC
04234     ft_pic_container_destroy( library );
04235 #endif
04236     FT_FREE( library );
04237     return error;
04238   }
04239 
04240 
04241   /* documentation is in freetype.h */
04242 
04243   FT_EXPORT_DEF( void )
04244   FT_Library_Version( FT_Library   library,
04245                       FT_Int      *amajor,
04246                       FT_Int      *aminor,
04247                       FT_Int      *apatch )
04248   {
04249     FT_Int  major = 0;
04250     FT_Int  minor = 0;
04251     FT_Int  patch = 0;
04252 
04253 
04254     if ( library )
04255     {
04256       major = library->version_major;
04257       minor = library->version_minor;
04258       patch = library->version_patch;
04259     }
04260 
04261     if ( amajor )
04262       *amajor = major;
04263 
04264     if ( aminor )
04265       *aminor = minor;
04266 
04267     if ( apatch )
04268       *apatch = patch;
04269   }
04270 
04271 
04272   /* documentation is in ftmodapi.h */
04273 
04274   FT_EXPORT_DEF( FT_Error )
04275   FT_Done_Library( FT_Library  library )
04276   {
04277     FT_Memory  memory;
04278 
04279 
04280     if ( !library )
04281       return FT_Err_Invalid_Library_Handle;
04282 
04283     memory = library->memory;
04284 
04285     /* Discard client-data */
04286     if ( library->generic.finalizer )
04287       library->generic.finalizer( library );
04288 
04289     /* Close all faces in the library.  If we don't do
04290      * this, we can have some subtle memory leaks.
04291      * Example:
04292      *
04293      *  - the cff font driver uses the pshinter module in cff_size_done
04294      *  - if the pshinter module is destroyed before the cff font driver,
04295      *    opened FT_Face objects managed by the driver are not properly
04296      *    destroyed, resulting in a memory leak
04297      */
04298     {
04299       FT_UInt  n;
04300 
04301 
04302       for ( n = 0; n < library->num_modules; n++ )
04303       {
04304         FT_Module  module = library->modules[n];
04305         FT_List    faces;
04306 
04307 
04308         if ( ( module->clazz->module_flags & FT_MODULE_FONT_DRIVER ) == 0 )
04309           continue;
04310 
04311         faces = &FT_DRIVER(module)->faces_list;
04312         while ( faces->head )
04313         {
04314           FT_Done_Face( FT_FACE( faces->head->data ) );
04315           if ( faces->head )
04316             FT_TRACE0(( "FT_Done_Library: failed to free some faces\n" ));
04317         }
04318       }
04319     }
04320 
04321     /* Close all other modules in the library */
04322 #if 1
04323     /* XXX Modules are removed in the reversed order so that  */
04324     /* type42 module is removed before truetype module.  This */
04325     /* avoids double free in some occasions.  It is a hack.   */
04326     while ( library->num_modules > 0 )
04327       FT_Remove_Module( library,
04328                         library->modules[library->num_modules - 1] );
04329 #else
04330     {
04331       FT_UInt  n;
04332 
04333 
04334       for ( n = 0; n < library->num_modules; n++ )
04335       {
04336         FT_Module  module = library->modules[n];
04337 
04338 
04339         if ( module )
04340         {
04341           Destroy_Module( module );
04342           library->modules[n] = 0;
04343         }
04344       }
04345     }
04346 #endif
04347 
04348     /* Destroy raster objects */
04349     FT_FREE( library->raster_pool );
04350     library->raster_pool_size = 0;
04351 
04352 #ifdef FT_CONFIG_OPTION_PIC
04353     /* Destroy pic container contents */
04354     ft_pic_container_destroy( library );
04355 #endif
04356 
04357     FT_FREE( library );
04358     return FT_Err_Ok;
04359   }
04360 
04361 
04362   /* documentation is in ftmodapi.h */
04363 
04364   FT_EXPORT_DEF( void )
04365   FT_Set_Debug_Hook( FT_Library         library,
04366                      FT_UInt            hook_index,
04367                      FT_DebugHook_Func  debug_hook )
04368   {
04369     if ( library && debug_hook &&
04370          hook_index <
04371            ( sizeof ( library->debug_hooks ) / sizeof ( void* ) ) )
04372       library->debug_hooks[hook_index] = debug_hook;
04373   }
04374 
04375 
04376   /* documentation is in ftmodapi.h */
04377 
04378   FT_EXPORT_DEF( FT_TrueTypeEngineType )
04379   FT_Get_TrueType_Engine_Type( FT_Library  library )
04380   {
04381     FT_TrueTypeEngineType  result = FT_TRUETYPE_ENGINE_TYPE_NONE;
04382 
04383 
04384     if ( library )
04385     {
04386       FT_Module  module = FT_Get_Module( library, "truetype" );
04387 
04388 
04389       if ( module )
04390       {
04391         FT_Service_TrueTypeEngine  service;
04392 
04393 
04394         service = (FT_Service_TrueTypeEngine)
04395                     ft_module_get_service( module,
04396                                            FT_SERVICE_ID_TRUETYPE_ENGINE );
04397         if ( service )
04398           result = service->engine_type;
04399       }
04400     }
04401 
04402     return result;
04403   }
04404 
04405 
04406 #ifdef FT_CONFIG_OPTION_OLD_INTERNALS
04407 
04408   FT_BASE_DEF( FT_Error )
04409   ft_stub_set_char_sizes( FT_Size     size,
04410                           FT_F26Dot6  width,
04411                           FT_F26Dot6  height,
04412                           FT_UInt     horz_res,
04413                           FT_UInt     vert_res )
04414   {
04415     FT_Size_RequestRec  req;
04416     FT_Driver           driver = size->face->driver;
04417 
04418 
04419     if ( driver->clazz->request_size )
04420     {
04421       req.type   = FT_SIZE_REQUEST_TYPE_NOMINAL;
04422       req.width  = width;
04423       req.height = height;
04424 
04425       if ( horz_res == 0 )
04426         horz_res = vert_res;
04427 
04428       if ( vert_res == 0 )
04429         vert_res = horz_res;
04430 
04431       if ( horz_res == 0 )
04432         horz_res = vert_res = 72;
04433 
04434       req.horiResolution = horz_res;
04435       req.vertResolution = vert_res;
04436 
04437       return driver->clazz->request_size( size, &req );
04438     }
04439 
04440     return 0;
04441   }
04442 
04443 
04444   FT_BASE_DEF( FT_Error )
04445   ft_stub_set_pixel_sizes( FT_Size  size,
04446                            FT_UInt  width,
04447                            FT_UInt  height )
04448   {
04449     FT_Size_RequestRec  req;
04450     FT_Driver           driver = size->face->driver;
04451 
04452 
04453     if ( driver->clazz->request_size )
04454     {
04455       req.type           = FT_SIZE_REQUEST_TYPE_NOMINAL;
04456       req.width          = width  << 6;
04457       req.height         = height << 6;
04458       req.horiResolution = 0;
04459       req.vertResolution = 0;
04460 
04461       return driver->clazz->request_size( size, &req );
04462     }
04463 
04464     return 0;
04465   }
04466 
04467 #endif /* FT_CONFIG_OPTION_OLD_INTERNALS */
04468 
04469 
04470   FT_EXPORT_DEF( FT_Error )
04471   FT_Get_SubGlyph_Info( FT_GlyphSlot  glyph,
04472                         FT_UInt       sub_index,
04473                         FT_Int       *p_index,
04474                         FT_UInt      *p_flags,
04475                         FT_Int       *p_arg1,
04476                         FT_Int       *p_arg2,
04477                         FT_Matrix    *p_transform )
04478   {
04479     FT_Error  error = FT_Err_Invalid_Argument;
04480 
04481 
04482     if ( glyph != NULL                              &&
04483          glyph->format == FT_GLYPH_FORMAT_COMPOSITE &&
04484          sub_index < glyph->num_subglyphs           )
04485     {
04486       FT_SubGlyph  subg = glyph->subglyphs + sub_index;
04487 
04488 
04489       *p_index     = subg->index;
04490       *p_flags     = subg->flags;
04491       *p_arg1      = subg->arg1;
04492       *p_arg2      = subg->arg2;
04493       *p_transform = subg->transform;
04494     }
04495 
04496     return error;
04497   }
04498 
04499 
04500 /* END */

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