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