source: trunk/poppler/freetype2/src/base/ftobjs.c @ 269

Last change on this file since 269 was 269, checked in by Eugene Romanenko, 13 years ago

PDF plugin: freetype library updated to version 2.3.9

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