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