xref: /inferno-os/libfreetype/ftobjs.c (revision 7ef44d652ae9e5e1f5b3465d73684e4a54de73c0)
1 /***************************************************************************/
2 /*                                                                         */
3 /*  ftobjs.c                                                               */
4 /*                                                                         */
5 /*    The FreeType private base classes (body).                            */
6 /*                                                                         */
7 /*  Copyright 1996-2001, 2002 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_OBJECTS_H
23 #include FT_INTERNAL_DEBUG_H
24 #include FT_INTERNAL_STREAM_H
25 #include FT_TRUETYPE_TABLES_H
26 #include FT_OUTLINE_H
27 
28 
29   FT_BASE_DEF( void )
30   ft_validator_init( FT_Validator        valid,
31                      const FT_Byte*      base,
32                      const FT_Byte*      limit,
33                      FT_ValidationLevel  level )
34   {
35     valid->base  = base;
36     valid->limit = limit;
37     valid->level = level;
38     valid->error = 0;
39   }
40 
41 
42   FT_BASE_DEF( FT_Int )
43   ft_validator_run( FT_Validator  valid )
44   {
45     int  result;
46 
47 
48     result = ft_setjmp( valid->jump_buffer );
49     return result;
50   }
51 
52 
53   FT_BASE_DEF( void )
54   ft_validator_error( FT_Validator  valid,
55                       FT_Error      error )
56   {
57     valid->error = error;
58     ft_longjmp( valid->jump_buffer, 1 );
59   }
60 
61 
62   /*************************************************************************/
63   /*************************************************************************/
64   /*************************************************************************/
65   /****                                                                 ****/
66   /****                                                                 ****/
67   /****                           S T R E A M                           ****/
68   /****                                                                 ****/
69   /****                                                                 ****/
70   /*************************************************************************/
71   /*************************************************************************/
72   /*************************************************************************/
73 
74 
75   /* create a new input stream from a FT_Open_Args structure */
76   /*                                                         */
77   static FT_Error
78   ft_input_stream_new( FT_Library           library,
79                        const FT_Open_Args*  args,
80                        FT_Stream*           astream )
81   {
82     FT_Error   error;
83     FT_Memory  memory;
84     FT_Stream  stream;
85 
86 
87     if ( !library )
88       return FT_Err_Invalid_Library_Handle;
89 
90     if ( !args )
91       return FT_Err_Invalid_Argument;
92 
93     *astream = 0;
94     memory   = library->memory;
95 
96     if ( FT_NEW( stream ) )
97       goto Exit;
98 
99     stream->memory = memory;
100 
101     if ( args->flags & FT_OPEN_MEMORY )
102     {
103       /* create a memory-based stream */
104       FT_Stream_OpenMemory( stream,
105                             (const FT_Byte*)args->memory_base,
106                             args->memory_size );
107     }
108     else if ( args->flags & FT_OPEN_PATHNAME )
109     {
110       /* create a normal system stream */
111       error = FT_Stream_Open( stream, args->pathname );
112       stream->pathname.pointer = args->pathname;
113     }
114     else if ( ( args->flags & FT_OPEN_STREAM ) && args->stream )
115     {
116       /* use an existing, user-provided stream */
117 
118       /* in this case, we do not need to allocate a new stream object */
119       /* since the caller is responsible for closing it himself       */
120       FT_FREE( stream );
121       stream = args->stream;
122     }
123     else
124       error = FT_Err_Invalid_Argument;
125 
126     if ( error )
127       FT_FREE( stream );
128     else
129       stream->memory = memory;  /* just to be certain */
130 
131     *astream = stream;
132 
133   Exit:
134     return error;
135   }
136 
137 
138   static void
139   ft_input_stream_free( FT_Stream  stream,
140                         FT_Int     external )
141   {
142     if ( stream )
143     {
144       FT_Memory  memory = stream->memory;
145 
146 
147       FT_Stream_Close( stream );
148 
149       if ( !external )
150         FT_FREE( stream );
151     }
152   }
153 
154 
155 #undef  FT_COMPONENT
156 #define FT_COMPONENT  trace_objs
157 
158 
159   /*************************************************************************/
160   /*************************************************************************/
161   /*************************************************************************/
162   /****                                                                 ****/
163   /****                                                                 ****/
164   /****               FACE, SIZE & GLYPH SLOT OBJECTS                   ****/
165   /****                                                                 ****/
166   /****                                                                 ****/
167   /*************************************************************************/
168   /*************************************************************************/
169   /*************************************************************************/
170 
171 
172   static FT_Error
173   ft_glyphslot_init( FT_GlyphSlot  slot )
174   {
175     FT_Driver         driver = slot->face->driver;
176     FT_Driver_Class   clazz  = driver->clazz;
177     FT_Memory         memory = driver->root.memory;
178     FT_Error          error  = FT_Err_Ok;
179     FT_Slot_Internal  internal;
180 
181 
182     slot->library = driver->root.library;
183 
184     if ( FT_NEW( internal ) )
185       goto Exit;
186 
187     slot->internal = internal;
188 
189     if ( FT_DRIVER_USES_OUTLINES( driver ) )
190       error = FT_GlyphLoader_New( memory, &internal->loader );
191 
192     if ( !error && clazz->init_slot )
193       error = clazz->init_slot( slot );
194 
195   Exit:
196     return error;
197   }
198 
199 
200   static void
201   ft_glyphslot_clear( FT_GlyphSlot  slot )
202   {
203     /* free bitmap if needed */
204     if ( slot->flags & FT_GLYPH_OWN_BITMAP )
205     {
206       FT_Memory  memory = FT_FACE_MEMORY( slot->face );
207 
208 
209       FT_FREE( slot->bitmap.buffer );
210       slot->flags &= ~FT_GLYPH_OWN_BITMAP;
211     }
212 
213     /* clear all public fields in the glyph slot */
214     FT_ZERO( &slot->metrics );
215     FT_ZERO( &slot->outline );
216 
217     slot->bitmap.width = 0;
218     slot->bitmap.rows  = 0;
219     slot->bitmap.pitch = 0;
220     slot->bitmap.pixel_mode = 0;
221     /* don't touch 'slot->bitmap.buffer' !! */
222 
223     slot->bitmap_left   = 0;
224     slot->bitmap_top    = 0;
225     slot->num_subglyphs = 0;
226     slot->subglyphs     = 0;
227     slot->control_data  = 0;
228     slot->control_len   = 0;
229     slot->other         = 0;
230     slot->format        = FT_GLYPH_FORMAT_NONE;
231 
232     slot->linearHoriAdvance = 0;
233     slot->linearVertAdvance = 0;
234   }
235 
236 
237   static void
238   ft_glyphslot_done( FT_GlyphSlot  slot )
239   {
240     FT_Driver         driver = slot->face->driver;
241     FT_Driver_Class   clazz  = driver->clazz;
242     FT_Memory         memory = driver->root.memory;
243 
244 
245     if ( clazz->done_slot )
246       clazz->done_slot( slot );
247 
248     /* free bitmap buffer if needed */
249     if ( slot->flags & FT_GLYPH_OWN_BITMAP )
250       FT_FREE( slot->bitmap.buffer );
251 
252     /* free glyph loader */
253     if ( FT_DRIVER_USES_OUTLINES( driver ) )
254     {
255       FT_GlyphLoader_Done( slot->internal->loader );
256       slot->internal->loader = 0;
257     }
258 
259     FT_FREE( slot->internal );
260   }
261 
262 
263   /* documentation is in ftobjs.h */
264 
265   FT_BASE_DEF( FT_Error )
266   FT_New_GlyphSlot( FT_Face        face,
267                     FT_GlyphSlot  *aslot )
268   {
269     FT_Error          error;
270     FT_Driver         driver;
271     FT_Driver_Class   clazz;
272     FT_Memory         memory;
273     FT_GlyphSlot      slot;
274 
275 
276     if ( !face || !aslot || !face->driver )
277       return FT_Err_Invalid_Argument;
278 
279     *aslot = 0;
280 
281     driver = face->driver;
282     clazz  = driver->clazz;
283     memory = driver->root.memory;
284 
285     FT_TRACE4(( "FT_New_GlyphSlot: Creating new slot object\n" ));
286     if ( !FT_ALLOC( slot, clazz->slot_object_size ) )
287     {
288       slot->face = face;
289 
290       error = ft_glyphslot_init( slot );
291       if ( error )
292       {
293         ft_glyphslot_done( slot );
294         FT_FREE( slot );
295         goto Exit;
296       }
297 
298       *aslot = slot;
299     }
300 
301   Exit:
302     FT_TRACE4(( "FT_New_GlyphSlot: Return %d\n", error ));
303     return error;
304   }
305 
306 
307   /* documentation is in ftobjs.h */
308 
309   FT_BASE_DEF( void )
310   FT_Done_GlyphSlot( FT_GlyphSlot  slot )
311   {
312     if ( slot )
313     {
314       FT_Driver      driver = slot->face->driver;
315       FT_Memory      memory = driver->root.memory;
316       FT_GlyphSlot*  parent;
317       FT_GlyphSlot   cur;
318 
319 
320       /* Remove slot from its parent face's list */
321       parent = &slot->face->glyph;
322       cur    = *parent;
323 
324       while ( cur )
325       {
326         if ( cur == slot )
327         {
328           *parent = cur->next;
329           ft_glyphslot_done( slot );
330           FT_FREE( slot );
331           break;
332         }
333         cur = cur->next;
334       }
335     }
336   }
337 
338 
339   /* documentation is in freetype.h */
340 
341   FT_EXPORT_DEF( void )
342   FT_Set_Transform( FT_Face     face,
343                     FT_Matrix*  matrix,
344                     FT_Vector*  delta )
345   {
346     FT_Face_Internal  internal;
347 
348 
349     if ( !face )
350       return;
351 
352     internal = face->internal;
353 
354     internal->transform_flags = 0;
355 
356     if ( !matrix )
357     {
358       internal->transform_matrix.xx = 0x10000L;
359       internal->transform_matrix.xy = 0;
360       internal->transform_matrix.yx = 0;
361       internal->transform_matrix.yy = 0x10000L;
362       matrix = &internal->transform_matrix;
363     }
364     else
365       internal->transform_matrix = *matrix;
366 
367     /* set transform_flags bit flag 0 if `matrix' isn't the identity */
368     if ( ( matrix->xy | matrix->yx ) ||
369          matrix->xx != 0x10000L      ||
370          matrix->yy != 0x10000L      )
371       internal->transform_flags |= 1;
372 
373     if ( !delta )
374     {
375       internal->transform_delta.x = 0;
376       internal->transform_delta.y = 0;
377       delta = &internal->transform_delta;
378     }
379     else
380       internal->transform_delta = *delta;
381 
382     /* set transform_flags bit flag 1 if `delta' isn't the null vector */
383     if ( delta->x | delta->y )
384       internal->transform_flags |= 2;
385   }
386 
387 
388   /* documentation is in freetype.h */
389 
390   FT_EXPORT_DEF( void )
391   FT_Set_Hint_Flags( FT_Face     face,
392                      FT_ULong    flags )
393   {
394     FT_Face_Internal  internal;
395 
396     if ( !face )
397       return;
398 
399     internal = face->internal;
400 
401     internal->hint_flags = (FT_UInt)flags;
402   }
403 
404 
405   static FT_Renderer
406   ft_lookup_glyph_renderer( FT_GlyphSlot  slot );
407 
408 
409   /* documentation is in freetype.h */
410 
411   FT_EXPORT_DEF( FT_Error )
412   FT_Load_Glyph( FT_Face   face,
413                  FT_UInt   glyph_index,
414                  FT_Int32  load_flags )
415   {
416     FT_Error      error;
417     FT_Driver     driver;
418     FT_GlyphSlot  slot;
419     FT_Library    library;
420     FT_Bool       autohint;
421     FT_Module     hinter;
422 
423 
424     if ( !face || !face->size || !face->glyph )
425       return FT_Err_Invalid_Face_Handle;
426 
427     if ( glyph_index > (FT_UInt)face->num_glyphs )
428       return FT_Err_Invalid_Argument;
429 
430     slot = face->glyph;
431     ft_glyphslot_clear( slot );
432 
433     driver = face->driver;
434 
435     /* if the flag NO_RECURSE is set, we disable hinting and scaling */
436     if ( load_flags & FT_LOAD_NO_RECURSE )
437     {
438       /* disable scaling, hinting, and transformation */
439       load_flags |= FT_LOAD_NO_SCALE         |
440                     FT_LOAD_NO_HINTING       |
441                     FT_LOAD_NO_BITMAP        |
442                     FT_LOAD_IGNORE_TRANSFORM;
443 
444       /* disable bitmap rendering */
445       load_flags &= ~FT_LOAD_RENDER;
446     }
447 
448     /* do we need to load the glyph through the auto-hinter? */
449     library  = driver->root.library;
450     hinter   = library->auto_hinter;
451     autohint =
452       FT_BOOL( hinter                                      &&
453                !( load_flags & ( FT_LOAD_NO_SCALE    |
454                                  FT_LOAD_NO_HINTING  |
455                                  FT_LOAD_NO_AUTOHINT ) )   &&
456                FT_DRIVER_IS_SCALABLE( driver )             &&
457                FT_DRIVER_USES_OUTLINES( driver )           );
458     if ( autohint )
459     {
460       if ( FT_DRIVER_HAS_HINTER( driver ) &&
461            !( load_flags & FT_LOAD_FORCE_AUTOHINT ) )
462         autohint = 0;
463     }
464 
465     if ( autohint )
466     {
467       FT_AutoHinter_Service  hinting;
468 
469 
470       /* try to load embedded bitmaps first if available            */
471       /*                                                            */
472       /* XXX: This is really a temporary hack that should disappear */
473       /*      promptly with FreeType 2.1!                           */
474       /*                                                            */
475       if ( FT_HAS_FIXED_SIZES( face )             &&
476           ( load_flags & FT_LOAD_NO_BITMAP ) == 0 )
477       {
478         error = driver->clazz->load_glyph( slot, face->size,
479                                            glyph_index,
480                                            load_flags | FT_LOAD_SBITS_ONLY );
481 
482         if ( !error && slot->format == FT_GLYPH_FORMAT_BITMAP )
483           goto Load_Ok;
484       }
485 
486       /* load auto-hinted outline */
487       hinting = (FT_AutoHinter_Service)hinter->clazz->module_interface;
488 
489       error   = hinting->load_glyph( (FT_AutoHinter)hinter,
490                                      slot, face->size,
491                                      glyph_index, load_flags );
492     }
493     else
494     {
495       error = driver->clazz->load_glyph( slot,
496                                          face->size,
497                                          glyph_index,
498                                          load_flags );
499       if ( error )
500         goto Exit;
501 
502       /* check that the loaded outline is correct */
503       error = FT_Outline_Check( &slot->outline );
504       if ( error )
505         goto Exit;
506     }
507 
508   Load_Ok:
509     /* compute the advance */
510     if ( load_flags & FT_LOAD_VERTICAL_LAYOUT )
511     {
512       slot->advance.x = 0;
513       slot->advance.y = slot->metrics.vertAdvance;
514     }
515     else
516     {
517       slot->advance.x = slot->metrics.horiAdvance;
518       slot->advance.y = 0;
519     }
520 
521     /* compute the linear advance in 16.16 pixels */
522     if ( ( load_flags & FT_LOAD_LINEAR_DESIGN ) == 0 )
523     {
524       FT_UInt           EM      = face->units_per_EM;
525       FT_Size_Metrics*  metrics = &face->size->metrics;
526 
527 
528       slot->linearHoriAdvance = FT_MulDiv( slot->linearHoriAdvance,
529                                            (FT_Long)metrics->x_ppem << 16, EM );
530 
531       slot->linearVertAdvance = FT_MulDiv( slot->linearVertAdvance,
532                                            (FT_Long)metrics->y_ppem << 16, EM );
533     }
534 
535     if ( ( load_flags & FT_LOAD_IGNORE_TRANSFORM ) == 0 )
536     {
537       FT_Face_Internal  internal = face->internal;
538 
539 
540       /* now, transform the glyph image if needed */
541       if ( internal->transform_flags )
542       {
543         /* get renderer */
544         FT_Renderer  renderer = ft_lookup_glyph_renderer( slot );
545 
546 
547         if ( renderer )
548           error = renderer->clazz->transform_glyph(
549                                      renderer, slot,
550                                      &internal->transform_matrix,
551                                      &internal->transform_delta );
552         /* transform advance */
553         FT_Vector_Transform( &slot->advance, &internal->transform_matrix );
554       }
555     }
556 
557     /* do we need to render the image now? */
558     if ( !error                                    &&
559          slot->format != FT_GLYPH_FORMAT_BITMAP    &&
560          slot->format != FT_GLYPH_FORMAT_COMPOSITE &&
561          load_flags & FT_LOAD_RENDER )
562     {
563       FT_Render_Mode  mode = FT_LOAD_TARGET_MODE( load_flags );
564 
565 
566       if ( mode == FT_RENDER_MODE_NORMAL      &&
567            (load_flags & FT_LOAD_MONOCHROME ) )
568         mode = FT_RENDER_MODE_MONO;
569 
570       error = FT_Render_Glyph( slot, mode );
571     }
572 
573   Exit:
574     return error;
575   }
576 
577 
578   /* documentation is in freetype.h */
579 
580   FT_EXPORT_DEF( FT_Error )
581   FT_Load_Char( FT_Face   face,
582                 FT_ULong  char_code,
583                 FT_Int32  load_flags )
584   {
585     FT_UInt  glyph_index;
586 
587 
588     if ( !face )
589       return FT_Err_Invalid_Face_Handle;
590 
591     glyph_index = (FT_UInt)char_code;
592     if ( face->charmap )
593       glyph_index = FT_Get_Char_Index( face, char_code );
594 
595     return FT_Load_Glyph( face, glyph_index, load_flags );
596   }
597 
598 
599   /* destructor for sizes list */
600   static void
601   destroy_size( FT_Memory  memory,
602                 FT_Size    size,
603                 FT_Driver  driver )
604   {
605     /* finalize client-specific data */
606     if ( size->generic.finalizer )
607       size->generic.finalizer( size );
608 
609     /* finalize format-specific stuff */
610     if ( driver->clazz->done_size )
611       driver->clazz->done_size( size );
612 
613     FT_FREE( size->internal );
614     FT_FREE( size );
615   }
616 
617 
618   /* destructor for faces list */
619   static void
620   destroy_face( FT_Memory  memory,
621                 FT_Face    face,
622                 FT_Driver  driver )
623   {
624     FT_Driver_Class  clazz = driver->clazz;
625 
626 
627     /* discard auto-hinting data */
628     if ( face->autohint.finalizer )
629       face->autohint.finalizer( face->autohint.data );
630 
631     /* Discard glyph slots for this face.                           */
632     /* Beware!  FT_Done_GlyphSlot() changes the field `face->glyph' */
633     while ( face->glyph )
634       FT_Done_GlyphSlot( face->glyph );
635 
636     /* discard all sizes for this face */
637     FT_List_Finalize( &face->sizes_list,
638                      (FT_List_Destructor)destroy_size,
639                      memory,
640                      driver );
641     face->size = 0;
642 
643     /* now discard client data */
644     if ( face->generic.finalizer )
645       face->generic.finalizer( face );
646 
647     /* discard charmaps */
648     {
649       FT_Int  n;
650 
651 
652       for ( n = 0; n < face->num_charmaps; n++ )
653       {
654         FT_CMap  cmap = FT_CMAP( face->charmaps[n] );
655 
656 
657         FT_CMap_Done( cmap );
658 
659         face->charmaps[n] = NULL;
660       }
661 
662       FT_FREE( face->charmaps );
663       face->num_charmaps = 0;
664     }
665 
666 
667     /* finalize format-specific stuff */
668     if ( clazz->done_face )
669       clazz->done_face( face );
670 
671     /* close the stream for this face if needed */
672     ft_input_stream_free(
673       face->stream,
674       ( face->face_flags & FT_FACE_FLAG_EXTERNAL_STREAM ) != 0 );
675 
676     face->stream = 0;
677 
678     /* get rid of it */
679     if ( face->internal )
680     {
681       FT_FREE( face->internal->postscript_name );
682       FT_FREE( face->internal );
683     }
684     FT_FREE( face );
685   }
686 
687 
688   static void
689   Destroy_Driver( FT_Driver  driver )
690   {
691     FT_List_Finalize( &driver->faces_list,
692                       (FT_List_Destructor)destroy_face,
693                       driver->root.memory,
694                       driver );
695 
696     /* check whether we need to drop the driver's glyph loader */
697     if ( FT_DRIVER_USES_OUTLINES( driver ) )
698       FT_GlyphLoader_Done( driver->glyph_loader );
699   }
700 
701 
702   /*************************************************************************/
703   /*                                                                       */
704   /* <Function>                                                            */
705   /*    open_face                                                          */
706   /*                                                                       */
707   /* <Description>                                                         */
708   /*    This function does some work for FT_Open_Face().                   */
709   /*                                                                       */
710   static FT_Error
711   open_face( FT_Driver      driver,
712              FT_Stream      stream,
713              FT_Long        face_index,
714              FT_Int         num_params,
715              FT_Parameter*  params,
716              FT_Face*       aface )
717   {
718     FT_Memory         memory;
719     FT_Driver_Class  clazz;
720     FT_Face           face = 0;
721     FT_Error          error;
722     FT_Face_Internal  internal;
723 
724 
725     clazz  = driver->clazz;
726     memory = driver->root.memory;
727 
728     /* allocate the face object and perform basic initialization */
729     if ( FT_ALLOC( face, clazz->face_object_size ) )
730       goto Fail;
731 
732     if ( FT_NEW( internal ) )
733       goto Fail;
734 
735     face->internal = internal;
736 
737     face->driver   = driver;
738     face->memory   = memory;
739     face->stream   = stream;
740 
741 #ifdef FT_CONFIG_OPTION_INCREMENTAL
742     {
743       int  i;
744 
745 
746       face->internal->incremental_interface = 0;
747       for ( i = 0; i < num_params && !face->internal->incremental_interface;
748             i++ )
749         if ( params[i].tag == FT_PARAM_TAG_INCREMENTAL )
750           face->internal->incremental_interface = params[i].data;
751 	}
752 #endif
753 
754     error = clazz->init_face( stream,
755                               face,
756                               (FT_Int)face_index,
757                               num_params,
758                               params );
759     if ( error )
760       goto Fail;
761 
762     /* select Unicode charmap by default */
763     {
764       FT_Int      nn;
765       FT_CharMap  unicmap = NULL, cmap;
766 
767 
768       for ( nn = 0; nn < face->num_charmaps; nn++ )
769       {
770         cmap = face->charmaps[nn];
771 
772         if ( cmap->encoding == FT_ENCODING_UNICODE )
773         {
774           unicmap = cmap;
775           break;
776         }
777       }
778 
779       if ( unicmap != NULL )
780         face->charmap = unicmap;
781     }
782 
783     *aface = face;
784 
785   Fail:
786     if ( error )
787     {
788       clazz->done_face( face );
789       FT_FREE( face->internal );
790       FT_FREE( face );
791       *aface = 0;
792     }
793 
794     return error;
795   }
796 
797 
798   /* there's a Mac-specific extended implementation of FT_New_Face() */
799   /* in src/base/ftmac.c                                             */
800 
801 #ifndef FT_MACINTOSH
802 
803   /* documentation is in freetype.h */
804 
805   FT_EXPORT_DEF( FT_Error )
806   FT_New_Face( FT_Library   library,
807                const char*  pathname,
808                FT_Long      face_index,
809                FT_Face     *aface )
810   {
811     FT_Open_Args  args;
812 
813 
814     /* test for valid `library' and `aface' delayed to FT_Open_Face() */
815     if ( !pathname )
816       return FT_Err_Invalid_Argument;
817 
818     args.flags    = FT_OPEN_PATHNAME;
819     args.pathname = (char*)pathname;
820 
821     return FT_Open_Face( library, &args, face_index, aface );
822   }
823 
824 #endif  /* !FT_MACINTOSH */
825 
826 
827   /* documentation is in freetype.h */
828 
829   FT_EXPORT_DEF( FT_Error )
830   FT_New_Memory_Face( FT_Library      library,
831                       const FT_Byte*  file_base,
832                       FT_Long         file_size,
833                       FT_Long         face_index,
834                       FT_Face        *aface )
835   {
836     FT_Open_Args  args;
837 
838 
839     /* test for valid `library' and `face' delayed to FT_Open_Face() */
840     if ( !file_base )
841       return FT_Err_Invalid_Argument;
842 
843     args.flags       = FT_OPEN_MEMORY;
844     args.memory_base = file_base;
845     args.memory_size = file_size;
846 
847     return FT_Open_Face( library, &args, face_index, aface );
848   }
849 
850 
851   /* documentation is in freetype.h */
852 
853   FT_EXPORT_DEF( FT_Error )
854   FT_Open_Face( FT_Library           library,
855                 const FT_Open_Args*  args,
856                 FT_Long              face_index,
857                 FT_Face             *aface )
858   {
859     FT_Error     error;
860     FT_Driver    driver;
861     FT_Memory    memory;
862     FT_Stream    stream;
863     FT_Face      face = 0;
864     FT_ListNode  node = 0;
865     FT_Bool      external_stream;
866 
867 
868     /* test for valid `library' delayed to */
869     /* ft_input_stream_new()               */
870 
871     if ( !aface || !args )
872       return FT_Err_Invalid_Argument;
873 
874     *aface = 0;
875 
876     external_stream = FT_BOOL( ( args->flags & FT_OPEN_STREAM ) &&
877                                args->stream                     );
878 
879     /* create input stream */
880     error = ft_input_stream_new( library, args, &stream );
881     if ( error )
882       goto Exit;
883 
884     memory = library->memory;
885 
886     /* If the font driver is specified in the `args' structure, use */
887     /* it.  Otherwise, we scan the list of registered drivers.      */
888     if ( ( args->flags & FT_OPEN_DRIVER ) && args->driver )
889     {
890       driver = FT_DRIVER( args->driver );
891 
892       /* not all modules are drivers, so check... */
893       if ( FT_MODULE_IS_DRIVER( driver ) )
894       {
895         FT_Int         num_params = 0;
896         FT_Parameter*  params     = 0;
897 
898 
899         if ( args->flags & FT_OPEN_PARAMS )
900         {
901           num_params = args->num_params;
902           params     = args->params;
903         }
904 
905         error = open_face( driver, stream, face_index,
906                            num_params, params, &face );
907         if ( !error )
908           goto Success;
909       }
910       else
911         error = FT_Err_Invalid_Handle;
912 
913       ft_input_stream_free( stream, external_stream );
914       goto Fail;
915     }
916     else
917     {
918       /* check each font driver for an appropriate format */
919       FT_Module*  cur   = library->modules;
920       FT_Module*  limit = cur + library->num_modules;
921 
922 
923       for ( ; cur < limit; cur++ )
924       {
925         /* not all modules are font drivers, so check... */
926         if ( FT_MODULE_IS_DRIVER( cur[0] ) )
927         {
928           FT_Int         num_params = 0;
929           FT_Parameter*  params     = 0;
930 
931 
932           driver = FT_DRIVER( cur[0] );
933 
934           if ( args->flags & FT_OPEN_PARAMS )
935           {
936             num_params = args->num_params;
937             params     = args->params;
938           }
939 
940           error = open_face( driver, stream, face_index,
941                             num_params, params, &face );
942           if ( !error )
943             goto Success;
944 
945           if ( FT_ERROR_BASE( error ) != FT_Err_Unknown_File_Format )
946             goto Fail2;
947         }
948       }
949 
950       /* no driver is able to handle this format */
951       error = FT_Err_Unknown_File_Format;
952 
953   Fail2:
954       ft_input_stream_free( stream, external_stream );
955       goto Fail;
956     }
957 
958   Success:
959     FT_TRACE4(( "FT_Open_Face: New face object, adding to list\n" ));
960 
961     /* set the FT_FACE_FLAG_EXTERNAL_STREAM bit for FT_Done_Face */
962     if ( external_stream )
963       face->face_flags |= FT_FACE_FLAG_EXTERNAL_STREAM;
964 
965     /* add the face object to its driver's list */
966     if ( FT_NEW( node ) )
967       goto Fail;
968 
969     node->data = face;
970     /* don't assume driver is the same as face->driver, so use */
971     /* face->driver instead.                                   */
972     FT_List_Add( &face->driver->faces_list, node );
973 
974     /* now allocate a glyph slot object for the face */
975     {
976       FT_GlyphSlot  slot;
977 
978 
979       FT_TRACE4(( "FT_Open_Face: Creating glyph slot\n" ));
980 
981       error = FT_New_GlyphSlot( face, &slot );
982       if ( error )
983         goto Fail;
984 
985       face->glyph = slot;
986     }
987 
988     /* finally, allocate a size object for the face */
989     {
990       FT_Size  size;
991 
992 
993       FT_TRACE4(( "FT_Open_Face: Creating size object\n" ));
994 
995       error = FT_New_Size( face, &size );
996       if ( error )
997         goto Fail;
998 
999       face->size = size;
1000     }
1001 
1002     /* initialize internal face data */
1003     {
1004       FT_Face_Internal  internal = face->internal;
1005 
1006 
1007       internal->transform_matrix.xx = 0x10000L;
1008       internal->transform_matrix.xy = 0;
1009       internal->transform_matrix.yx = 0;
1010       internal->transform_matrix.yy = 0x10000L;
1011 
1012       internal->transform_delta.x = 0;
1013       internal->transform_delta.y = 0;
1014     }
1015 
1016     *aface = face;
1017     goto Exit;
1018 
1019   Fail:
1020     FT_Done_Face( face );
1021 
1022   Exit:
1023     FT_TRACE4(( "FT_Open_Face: Return %d\n", error ));
1024 
1025     return error;
1026   }
1027 
1028 
1029   /* documentation is in freetype.h */
1030 
1031   FT_EXPORT_DEF( FT_Error )
1032   FT_Attach_File( FT_Face      face,
1033                   const char*  filepathname )
1034   {
1035     FT_Open_Args  open;
1036 
1037 
1038     /* test for valid `face' delayed to FT_Attach_Stream() */
1039 
1040     if ( !filepathname )
1041       return FT_Err_Invalid_Argument;
1042 
1043     open.flags    = FT_OPEN_PATHNAME;
1044     open.pathname = (char*)filepathname;
1045 
1046     return FT_Attach_Stream( face, &open );
1047   }
1048 
1049 
1050   /* documentation is in freetype.h */
1051 
1052   FT_EXPORT_DEF( FT_Error )
1053   FT_Attach_Stream( FT_Face        face,
1054                     FT_Open_Args*  parameters )
1055   {
1056     FT_Stream  stream;
1057     FT_Error   error;
1058     FT_Driver  driver;
1059 
1060     FT_Driver_Class  clazz;
1061 
1062 
1063     /* test for valid `parameters' delayed to ft_input_stream_new() */
1064 
1065     if ( !face )
1066       return FT_Err_Invalid_Face_Handle;
1067 
1068     driver = face->driver;
1069     if ( !driver )
1070       return FT_Err_Invalid_Driver_Handle;
1071 
1072     error = ft_input_stream_new( driver->root.library, parameters, &stream );
1073     if ( error )
1074       goto Exit;
1075 
1076     /* we implement FT_Attach_Stream in each driver through the */
1077     /* `attach_file' interface                                  */
1078 
1079     error = FT_Err_Unimplemented_Feature;
1080     clazz = driver->clazz;
1081     if ( clazz->attach_file )
1082       error = clazz->attach_file( face, stream );
1083 
1084     /* close the attached stream */
1085     ft_input_stream_free( stream,
1086                     (FT_Bool)( parameters->stream &&
1087                                ( parameters->flags & FT_OPEN_STREAM ) ) );
1088 
1089   Exit:
1090     return error;
1091   }
1092 
1093 
1094   /* documentation is in freetype.h */
1095 
1096   FT_EXPORT_DEF( FT_Error )
1097   FT_Done_Face( FT_Face  face )
1098   {
1099     FT_Error     error;
1100     FT_Driver    driver;
1101     FT_Memory    memory;
1102     FT_ListNode  node;
1103 
1104 
1105     error = FT_Err_Invalid_Face_Handle;
1106     if ( face && face->driver )
1107     {
1108       driver = face->driver;
1109       memory = driver->root.memory;
1110 
1111       /* find face in driver's list */
1112       node = FT_List_Find( &driver->faces_list, face );
1113       if ( node )
1114       {
1115         /* remove face object from the driver's list */
1116         FT_List_Remove( &driver->faces_list, node );
1117         FT_FREE( node );
1118 
1119         /* now destroy the object proper */
1120         destroy_face( memory, face, driver );
1121         error = FT_Err_Ok;
1122       }
1123     }
1124     return error;
1125   }
1126 
1127 
1128   /* documentation is in ftobjs.h */
1129 
1130   FT_EXPORT_DEF( FT_Error )
1131   FT_New_Size( FT_Face   face,
1132                FT_Size  *asize )
1133   {
1134     FT_Error         error;
1135     FT_Memory        memory;
1136     FT_Driver        driver;
1137     FT_Driver_Class  clazz;
1138 
1139     FT_Size          size = 0;
1140     FT_ListNode      node = 0;
1141 
1142 
1143     if ( !face )
1144       return FT_Err_Invalid_Face_Handle;
1145 
1146     if ( !asize )
1147       return FT_Err_Invalid_Size_Handle;
1148 
1149     if ( !face->driver )
1150       return FT_Err_Invalid_Driver_Handle;
1151 
1152     *asize = 0;
1153 
1154     driver = face->driver;
1155     clazz  = driver->clazz;
1156     memory = face->memory;
1157 
1158     /* Allocate new size object and perform basic initialisation */
1159     if ( FT_ALLOC( size, clazz->size_object_size ) || FT_NEW( node ) )
1160       goto Exit;
1161 
1162     size->face = face;
1163 
1164     /* for now, do not use any internal fields in size objects */
1165     size->internal = 0;
1166 
1167     if ( clazz->init_size )
1168       error = clazz->init_size( size );
1169 
1170     /* in case of success, add to the face's list */
1171     if ( !error )
1172     {
1173       *asize     = size;
1174       node->data = size;
1175       FT_List_Add( &face->sizes_list, node );
1176     }
1177 
1178   Exit:
1179     if ( error )
1180     {
1181       FT_FREE( node );
1182       FT_FREE( size );
1183     }
1184 
1185     return error;
1186   }
1187 
1188 
1189   /* documentation is in ftobjs.h */
1190 
1191   FT_EXPORT_DEF( FT_Error )
1192   FT_Done_Size( FT_Size  size )
1193   {
1194     FT_Error     error;
1195     FT_Driver    driver;
1196     FT_Memory    memory;
1197     FT_Face      face;
1198     FT_ListNode  node;
1199 
1200 
1201     if ( !size )
1202       return FT_Err_Invalid_Size_Handle;
1203 
1204     face = size->face;
1205     if ( !face )
1206       return FT_Err_Invalid_Face_Handle;
1207 
1208     driver = face->driver;
1209     if ( !driver )
1210       return FT_Err_Invalid_Driver_Handle;
1211 
1212     memory = driver->root.memory;
1213 
1214     error = FT_Err_Ok;
1215     node  = FT_List_Find( &face->sizes_list, size );
1216     if ( node )
1217     {
1218       FT_List_Remove( &face->sizes_list, node );
1219       FT_FREE( node );
1220 
1221       if ( face->size == size )
1222       {
1223         face->size = 0;
1224         if ( face->sizes_list.head )
1225           face->size = (FT_Size)(face->sizes_list.head->data);
1226       }
1227 
1228       destroy_size( memory, size, driver );
1229     }
1230     else
1231       error = FT_Err_Invalid_Size_Handle;
1232 
1233     return error;
1234   }
1235 
1236 
1237   static void
1238   ft_recompute_scaled_metrics( FT_Face           face,
1239                                FT_Size_Metrics*  metrics )
1240   {
1241     /* Compute root ascender, descender, test height, and max_advance */
1242 
1243     metrics->ascender    = ( FT_MulFix( face->ascender,
1244                                         metrics->y_scale ) + 32 ) & -64;
1245 
1246     metrics->descender   = ( FT_MulFix( face->descender,
1247                                         metrics->y_scale ) + 32 ) & -64;
1248 
1249     metrics->height      = ( FT_MulFix( face->height,
1250                                         metrics->y_scale ) + 32 ) & -64;
1251 
1252     metrics->max_advance = ( FT_MulFix( face->max_advance_width,
1253                                         metrics->x_scale ) + 32 ) & -64;
1254   }
1255 
1256 
1257   /* documentation is in freetype.h */
1258 
1259   FT_EXPORT_DEF( FT_Error )
1260   FT_Set_Char_Size( FT_Face     face,
1261                     FT_F26Dot6  char_width,
1262                     FT_F26Dot6  char_height,
1263                     FT_UInt     horz_resolution,
1264                     FT_UInt     vert_resolution )
1265   {
1266     FT_Error          error = FT_Err_Ok;
1267     FT_Driver         driver;
1268     FT_Driver_Class   clazz;
1269     FT_Size_Metrics*  metrics;
1270     FT_Long           dim_x, dim_y;
1271 
1272 
1273     if ( !face || !face->size || !face->driver )
1274       return FT_Err_Invalid_Face_Handle;
1275 
1276     driver  = face->driver;
1277     metrics = &face->size->metrics;
1278 
1279     if ( !char_width )
1280       char_width = char_height;
1281 
1282     else if ( !char_height )
1283       char_height = char_width;
1284 
1285     if ( !horz_resolution )
1286       horz_resolution = 72;
1287 
1288     if ( !vert_resolution )
1289       vert_resolution = 72;
1290 
1291     driver = face->driver;
1292     clazz  = driver->clazz;
1293 
1294     /* default processing -- this can be overridden by the driver */
1295     if ( char_width  < 1 * 64 )
1296       char_width  = 1 * 64;
1297     if ( char_height < 1 * 64 )
1298       char_height = 1 * 64;
1299 
1300     /* Compute pixel sizes in 26.6 units */
1301     dim_x = ( ( ( char_width  * horz_resolution ) / 72 ) + 32 ) & -64;
1302     dim_y = ( ( ( char_height * vert_resolution ) / 72 ) + 32 ) & -64;
1303 
1304     metrics->x_ppem  = (FT_UShort)( dim_x >> 6 );
1305     metrics->y_ppem  = (FT_UShort)( dim_y >> 6 );
1306 
1307     metrics->x_scale = 0x10000L;
1308     metrics->y_scale = 0x10000L;
1309 
1310     if ( face->face_flags & FT_FACE_FLAG_SCALABLE )
1311     {
1312       metrics->x_scale = FT_DivFix( dim_x, face->units_per_EM );
1313       metrics->y_scale = FT_DivFix( dim_y, face->units_per_EM );
1314 
1315       ft_recompute_scaled_metrics( face, metrics );
1316     }
1317 
1318     if ( clazz->set_char_sizes )
1319       error = clazz->set_char_sizes( face->size,
1320                                      char_width,
1321                                      char_height,
1322                                      horz_resolution,
1323                                      vert_resolution );
1324     return error;
1325   }
1326 
1327 
1328   /* documentation is in freetype.h */
1329 
1330   FT_EXPORT_DEF( FT_Error )
1331   FT_Set_Pixel_Sizes( FT_Face  face,
1332                       FT_UInt  pixel_width,
1333                       FT_UInt  pixel_height )
1334   {
1335     FT_Error          error = FT_Err_Ok;
1336     FT_Driver         driver;
1337     FT_Driver_Class   clazz;
1338     FT_Size_Metrics*  metrics = &face->size->metrics;
1339 
1340 
1341     if ( !face || !face->size || !face->driver )
1342       return FT_Err_Invalid_Face_Handle;
1343 
1344     driver = face->driver;
1345     clazz  = driver->clazz;
1346 
1347     /* default processing -- this can be overridden by the driver */
1348     if ( pixel_width == 0 )
1349       pixel_width = pixel_height;
1350 
1351     else if ( pixel_height == 0 )
1352       pixel_height = pixel_width;
1353 
1354     if ( pixel_width  < 1 )
1355       pixel_width  = 1;
1356     if ( pixel_height < 1 )
1357       pixel_height = 1;
1358 
1359     metrics->x_ppem = (FT_UShort)pixel_width;
1360     metrics->y_ppem = (FT_UShort)pixel_height;
1361 
1362     if ( face->face_flags & FT_FACE_FLAG_SCALABLE )
1363     {
1364       metrics->x_scale = FT_DivFix( metrics->x_ppem << 6,
1365                                     face->units_per_EM );
1366 
1367       metrics->y_scale = FT_DivFix( metrics->y_ppem << 6,
1368                                     face->units_per_EM );
1369 
1370       ft_recompute_scaled_metrics( face, metrics );
1371     }
1372 
1373     if ( clazz->set_pixel_sizes )
1374       error = clazz->set_pixel_sizes( face->size,
1375                                       pixel_width,
1376                                       pixel_height );
1377     return error;
1378   }
1379 
1380 
1381   /* documentation is in freetype.h */
1382 
1383   FT_EXPORT_DEF( FT_Error )
1384   FT_Get_Kerning( FT_Face     face,
1385                   FT_UInt     left_glyph,
1386                   FT_UInt     right_glyph,
1387                   FT_UInt     kern_mode,
1388                   FT_Vector  *akerning )
1389   {
1390     FT_Error   error = FT_Err_Ok;
1391     FT_Driver  driver;
1392 
1393 
1394     if ( !face )
1395       return FT_Err_Invalid_Face_Handle;
1396 
1397     if ( !akerning )
1398       return FT_Err_Invalid_Argument;
1399 
1400     driver = face->driver;
1401 
1402     akerning->x = 0;
1403     akerning->y = 0;
1404 
1405     if ( driver->clazz->get_kerning )
1406     {
1407       error = driver->clazz->get_kerning( face,
1408                                           left_glyph,
1409                                           right_glyph,
1410                                           akerning );
1411       if ( !error )
1412       {
1413         if ( kern_mode != FT_KERNING_UNSCALED )
1414         {
1415           akerning->x = FT_MulFix( akerning->x, face->size->metrics.x_scale );
1416           akerning->y = FT_MulFix( akerning->y, face->size->metrics.y_scale );
1417 
1418           if ( kern_mode != FT_KERNING_UNFITTED )
1419           {
1420             akerning->x = ( akerning->x + 32 ) & -64;
1421             akerning->y = ( akerning->y + 32 ) & -64;
1422           }
1423         }
1424       }
1425     }
1426 
1427     return error;
1428   }
1429 
1430 
1431   /* documentation is in freetype.h */
1432 
1433   FT_EXPORT_DEF( FT_Error )
1434   FT_Select_Charmap( FT_Face      face,
1435                      FT_Encoding  encoding )
1436   {
1437     FT_CharMap*  cur;
1438     FT_CharMap*  limit;
1439 
1440 
1441     if ( !face )
1442       return FT_Err_Invalid_Face_Handle;
1443 
1444     cur = face->charmaps;
1445     if ( !cur )
1446       return FT_Err_Invalid_CharMap_Handle;
1447 
1448     limit = cur + face->num_charmaps;
1449 
1450     for ( ; cur < limit; cur++ )
1451     {
1452       if ( cur[0]->encoding == encoding )
1453       {
1454         face->charmap = cur[0];
1455         return 0;
1456       }
1457     }
1458 
1459     return FT_Err_Invalid_Argument;
1460   }
1461 
1462 
1463   /* documentation is in freetype.h */
1464 
1465   FT_EXPORT_DEF( FT_Error )
1466   FT_Set_Charmap( FT_Face     face,
1467                   FT_CharMap  charmap )
1468   {
1469     FT_CharMap*  cur;
1470     FT_CharMap*  limit;
1471 
1472 
1473     if ( !face )
1474       return FT_Err_Invalid_Face_Handle;
1475 
1476     cur = face->charmaps;
1477     if ( !cur )
1478       return FT_Err_Invalid_CharMap_Handle;
1479 
1480     limit = cur + face->num_charmaps;
1481 
1482     for ( ; cur < limit; cur++ )
1483     {
1484       if ( cur[0] == charmap )
1485       {
1486         face->charmap = cur[0];
1487         return 0;
1488       }
1489     }
1490     return FT_Err_Invalid_Argument;
1491   }
1492 
1493 
1494   FT_BASE_DEF( void )
1495   FT_CMap_Done( FT_CMap  cmap )
1496   {
1497     if ( cmap )
1498     {
1499       FT_CMap_Class  clazz  = cmap->clazz;
1500       FT_Face        face   = cmap->charmap.face;
1501       FT_Memory      memory = FT_FACE_MEMORY(face);
1502 
1503 
1504       if ( clazz->done )
1505         clazz->done( cmap );
1506 
1507       FT_FREE( cmap );
1508     }
1509   }
1510 
1511 
1512   FT_BASE_DEF( FT_Error )
1513   FT_CMap_New( FT_CMap_Class   clazz,
1514                FT_Pointer      init_data,
1515                FT_CharMap      charmap,
1516                FT_CMap        *acmap )
1517   {
1518     FT_Error   error = 0;
1519     FT_Face    face;
1520     FT_Memory  memory;
1521     FT_CMap    cmap;
1522 
1523 
1524     if ( clazz == NULL || charmap == NULL || charmap->face == NULL )
1525       return FT_Err_Invalid_Argument;
1526 
1527     face   = charmap->face;
1528     memory = FT_FACE_MEMORY(face);
1529 
1530     if ( !FT_ALLOC( cmap, clazz->size ) )
1531     {
1532       cmap->charmap = *charmap;
1533       cmap->clazz   = clazz;
1534 
1535       if ( clazz->init )
1536       {
1537         error = clazz->init( cmap, init_data );
1538         if ( error )
1539           goto Fail;
1540       }
1541 
1542       /* add it to our list of charmaps */
1543       if ( FT_RENEW_ARRAY( face->charmaps,
1544                            face->num_charmaps,
1545                            face->num_charmaps+1 ) )
1546         goto Fail;
1547 
1548       face->charmaps[face->num_charmaps++] = (FT_CharMap)cmap;
1549     }
1550 
1551   Exit:
1552     if ( acmap )
1553       *acmap = cmap;
1554 
1555     return error;
1556 
1557   Fail:
1558     FT_CMap_Done( cmap );
1559     cmap = NULL;
1560     goto Exit;
1561   }
1562 
1563 
1564   /* documentation is in freetype.h */
1565 
1566   FT_EXPORT_DEF( FT_UInt )
1567   FT_Get_Char_Index( FT_Face   face,
1568                      FT_ULong  charcode )
1569   {
1570     FT_UInt  result = 0;
1571 
1572 
1573     if ( face && face->charmap )
1574     {
1575       FT_CMap  cmap = FT_CMAP( face->charmap );
1576 
1577 
1578       result = cmap->clazz->char_index( cmap, charcode );
1579     }
1580     return  result;
1581   }
1582 
1583 
1584 
1585   /* documentation is in freetype.h */
1586 
1587   FT_EXPORT_DEF( FT_ULong )
1588   FT_Get_First_Char( FT_Face   face,
1589                      FT_UInt  *agindex )
1590   {
1591     FT_ULong  result = 0;
1592     FT_UInt   gindex = 0;
1593 
1594 
1595     if ( face && face->charmap )
1596     {
1597       gindex = FT_Get_Char_Index( face, 0 );
1598       if ( gindex == 0 )
1599         result = FT_Get_Next_Char( face, 0, &gindex );
1600     }
1601 
1602     if ( agindex  )
1603       *agindex = gindex;
1604 
1605     return result;
1606   }
1607 
1608   /* documentation is in freetype.h */
1609 
1610 
1611   FT_EXPORT_DEF( FT_ULong )
1612   FT_Get_Next_Char( FT_Face   face,
1613                     FT_ULong  charcode,
1614                     FT_UInt  *agindex )
1615   {
1616     FT_ULong  result = 0;
1617     FT_UInt   gindex = 0;
1618 
1619 
1620     if ( face && face->charmap )
1621     {
1622       FT_UInt32  code = (FT_UInt32)charcode;
1623       FT_CMap    cmap = FT_CMAP( face->charmap );
1624 
1625 
1626       gindex = cmap->clazz->char_next( cmap, &code );
1627       result = ( gindex == 0 ) ? 0 : code;
1628     }
1629 
1630     if ( agindex )
1631       *agindex = gindex;
1632 
1633     return result;
1634   }
1635 
1636 
1637 
1638   /* documentation is in freetype.h */
1639 
1640   FT_EXPORT_DEF( FT_UInt )
1641   FT_Get_Name_Index( FT_Face     face,
1642                      FT_String*  glyph_name )
1643   {
1644     FT_UInt  result = 0;
1645 
1646 
1647     if ( face && FT_HAS_GLYPH_NAMES( face ) )
1648     {
1649       /* now, lookup for glyph name */
1650       FT_Driver         driver = face->driver;
1651       FT_Module_Class*  clazz  = FT_MODULE_CLASS( driver );
1652 
1653 
1654       if ( clazz->get_interface )
1655       {
1656         FT_Face_GetGlyphNameIndexFunc  requester;
1657 
1658 
1659         requester = (FT_Face_GetGlyphNameIndexFunc)clazz->get_interface(
1660                       FT_MODULE( driver ), "name_index" );
1661         if ( requester )
1662           result = requester( face, glyph_name );
1663       }
1664     }
1665 
1666     return result;
1667   }
1668 
1669 
1670   /* documentation is in freetype.h */
1671 
1672   FT_EXPORT_DEF( FT_Error )
1673   FT_Get_Glyph_Name( FT_Face     face,
1674                      FT_UInt     glyph_index,
1675                      FT_Pointer  buffer,
1676                      FT_UInt     buffer_max )
1677   {
1678     FT_Error  error = FT_Err_Invalid_Argument;
1679 
1680 
1681     /* clean up buffer */
1682     if ( buffer && buffer_max > 0 )
1683       ((FT_Byte*)buffer)[0] = 0;
1684 
1685     if ( face                                     &&
1686          glyph_index <= (FT_UInt)face->num_glyphs &&
1687          FT_HAS_GLYPH_NAMES( face )               )
1688     {
1689       /* now, lookup for glyph name */
1690       FT_Driver         driver = face->driver;
1691       FT_Module_Class*  clazz  = FT_MODULE_CLASS( driver );
1692 
1693 
1694       if ( clazz->get_interface )
1695       {
1696         FT_Face_GetGlyphNameFunc  requester;
1697 
1698 
1699         requester = (FT_Face_GetGlyphNameFunc)clazz->get_interface(
1700                       FT_MODULE( driver ), "glyph_name" );
1701         if ( requester )
1702           error = requester( face, glyph_index, buffer, buffer_max );
1703       }
1704     }
1705 
1706     return error;
1707   }
1708 
1709 
1710   /* documentation is in freetype.h */
1711 
1712   FT_EXPORT_DEF( const char* )
1713   FT_Get_Postscript_Name( FT_Face  face )
1714   {
1715     const char*  result = NULL;
1716 
1717 
1718     if ( !face )
1719       goto Exit;
1720 
1721     result = face->internal->postscript_name;
1722     if ( !result )
1723     {
1724       /* now, look up glyph name */
1725       FT_Driver         driver = face->driver;
1726       FT_Module_Class*  clazz  = FT_MODULE_CLASS( driver );
1727 
1728 
1729       if ( clazz->get_interface )
1730       {
1731         FT_Face_GetPostscriptNameFunc  requester;
1732 
1733 
1734         requester = (FT_Face_GetPostscriptNameFunc)clazz->get_interface(
1735                       FT_MODULE( driver ), "postscript_name" );
1736         if ( requester )
1737           result = requester( face );
1738       }
1739     }
1740   Exit:
1741     return result;
1742   }
1743 
1744 
1745   /* documentation is in tttables.h */
1746 
1747   FT_EXPORT_DEF( void* )
1748   FT_Get_Sfnt_Table( FT_Face      face,
1749                      FT_Sfnt_Tag  tag )
1750   {
1751     void*                   table = 0;
1752     FT_Get_Sfnt_Table_Func  func;
1753     FT_Driver               driver;
1754 
1755 
1756     if ( !face || !FT_IS_SFNT( face ) )
1757       goto Exit;
1758 
1759     driver = face->driver;
1760     func = (FT_Get_Sfnt_Table_Func)driver->root.clazz->get_interface(
1761                                      FT_MODULE( driver ), "get_sfnt" );
1762     if ( func )
1763       table = func( face, tag );
1764 
1765   Exit:
1766     return table;
1767   }
1768 
1769 
1770   FT_EXPORT_DEF( FT_Error )
1771   FT_Activate_Size( FT_Size  size )
1772   {
1773     FT_Face  face;
1774 
1775 
1776     if ( size == NULL )
1777       return FT_Err_Bad_Argument;
1778 
1779     face = size->face;
1780     if ( face == NULL || face->driver == NULL )
1781       return FT_Err_Bad_Argument;
1782 
1783     /* we don't need anything more complex than that; all size objects */
1784     /* are already listed by the face                                  */
1785     face->size = size;
1786 
1787     return FT_Err_Ok;
1788   }
1789 
1790 
1791   /*************************************************************************/
1792   /*************************************************************************/
1793   /*************************************************************************/
1794   /****                                                                 ****/
1795   /****                                                                 ****/
1796   /****                        R E N D E R E R S                        ****/
1797   /****                                                                 ****/
1798   /****                                                                 ****/
1799   /*************************************************************************/
1800   /*************************************************************************/
1801   /*************************************************************************/
1802 
1803   /* lookup a renderer by glyph format in the library's list */
1804   FT_BASE_DEF( FT_Renderer )
1805   FT_Lookup_Renderer( FT_Library       library,
1806                       FT_Glyph_Format  format,
1807                       FT_ListNode*     node )
1808   {
1809     FT_ListNode  cur;
1810     FT_Renderer  result = 0;
1811 
1812 
1813     if ( !library )
1814       goto Exit;
1815 
1816     cur = library->renderers.head;
1817 
1818     if ( node )
1819     {
1820       if ( *node )
1821         cur = (*node)->next;
1822       *node = 0;
1823     }
1824 
1825     while ( cur )
1826     {
1827       FT_Renderer  renderer = FT_RENDERER( cur->data );
1828 
1829 
1830       if ( renderer->glyph_format == format )
1831       {
1832         if ( node )
1833           *node = cur;
1834 
1835         result = renderer;
1836         break;
1837       }
1838       cur = cur->next;
1839     }
1840 
1841   Exit:
1842     return result;
1843   }
1844 
1845 
1846   static FT_Renderer
1847   ft_lookup_glyph_renderer( FT_GlyphSlot  slot )
1848   {
1849     FT_Face      face    = slot->face;
1850     FT_Library   library = FT_FACE_LIBRARY( face );
1851     FT_Renderer  result  = library->cur_renderer;
1852 
1853 
1854     if ( !result || result->glyph_format != slot->format )
1855       result = FT_Lookup_Renderer( library, slot->format, 0 );
1856 
1857     return result;
1858   }
1859 
1860 
1861   static void
1862   ft_set_current_renderer( FT_Library  library )
1863   {
1864     FT_Renderer  renderer;
1865 
1866 
1867     renderer = FT_Lookup_Renderer( library, FT_GLYPH_FORMAT_OUTLINE, 0 );
1868     library->cur_renderer = renderer;
1869   }
1870 
1871 
1872   static FT_Error
1873   ft_add_renderer( FT_Module  module )
1874   {
1875     FT_Library   library = module->library;
1876     FT_Memory    memory  = library->memory;
1877     FT_Error     error;
1878     FT_ListNode  node;
1879 
1880 
1881     if ( FT_NEW( node ) )
1882       goto Exit;
1883 
1884     {
1885       FT_Renderer         render = FT_RENDERER( module );
1886       FT_Renderer_Class*  clazz  = (FT_Renderer_Class*)module->clazz;
1887 
1888 
1889       render->clazz        = clazz;
1890       render->glyph_format = clazz->glyph_format;
1891 
1892       /* allocate raster object if needed */
1893       if ( clazz->glyph_format == FT_GLYPH_FORMAT_OUTLINE &&
1894            clazz->raster_class->raster_new )
1895       {
1896         error = clazz->raster_class->raster_new( memory, &render->raster );
1897         if ( error )
1898           goto Fail;
1899 
1900         render->raster_render = clazz->raster_class->raster_render;
1901         render->render        = clazz->render_glyph;
1902       }
1903 
1904       /* add to list */
1905       node->data = module;
1906       FT_List_Add( &library->renderers, node );
1907 
1908       ft_set_current_renderer( library );
1909     }
1910 
1911   Fail:
1912     if ( error )
1913       FT_FREE( node );
1914 
1915   Exit:
1916     return error;
1917   }
1918 
1919 
1920   static void
1921   ft_remove_renderer( FT_Module  module )
1922   {
1923     FT_Library   library = module->library;
1924     FT_Memory    memory  = library->memory;
1925     FT_ListNode  node;
1926 
1927 
1928     node = FT_List_Find( &library->renderers, module );
1929     if ( node )
1930     {
1931       FT_Renderer  render = FT_RENDERER( module );
1932 
1933 
1934       /* release raster object, if any */
1935       if ( render->raster )
1936         render->clazz->raster_class->raster_done( render->raster );
1937 
1938       /* remove from list */
1939       FT_List_Remove( &library->renderers, node );
1940       FT_FREE( node );
1941 
1942       ft_set_current_renderer( library );
1943     }
1944   }
1945 
1946 
1947   /* documentation is in ftrender.h */
1948 
1949   FT_EXPORT_DEF( FT_Renderer )
1950   FT_Get_Renderer( FT_Library       library,
1951                    FT_Glyph_Format  format )
1952   {
1953     /* test for valid `library' delayed to FT_Lookup_Renderer() */
1954 
1955     return FT_Lookup_Renderer( library, format, 0 );
1956   }
1957 
1958 
1959   /* documentation is in ftrender.h */
1960 
1961   FT_EXPORT_DEF( FT_Error )
1962   FT_Set_Renderer( FT_Library     library,
1963                    FT_Renderer    renderer,
1964                    FT_UInt        num_params,
1965                    FT_Parameter*  parameters )
1966   {
1967     FT_ListNode  node;
1968     FT_Error     error = FT_Err_Ok;
1969 
1970 
1971     if ( !library )
1972       return FT_Err_Invalid_Library_Handle;
1973 
1974     if ( !renderer )
1975       return FT_Err_Invalid_Argument;
1976 
1977     node = FT_List_Find( &library->renderers, renderer );
1978     if ( !node )
1979     {
1980       error = FT_Err_Invalid_Argument;
1981       goto Exit;
1982     }
1983 
1984     FT_List_Up( &library->renderers, node );
1985 
1986     if ( renderer->glyph_format == FT_GLYPH_FORMAT_OUTLINE )
1987       library->cur_renderer = renderer;
1988 
1989     if ( num_params > 0 )
1990     {
1991       FT_Renderer_SetModeFunc  set_mode = renderer->clazz->set_mode;
1992 
1993 
1994       for ( ; num_params > 0; num_params-- )
1995       {
1996         error = set_mode( renderer, parameters->tag, parameters->data );
1997         if ( error )
1998           break;
1999       }
2000     }
2001 
2002   Exit:
2003     return error;
2004   }
2005 
2006 
2007   FT_BASE_DEF( FT_Error )
2008   FT_Render_Glyph_Internal( FT_Library      library,
2009                             FT_GlyphSlot    slot,
2010                             FT_Render_Mode  render_mode )
2011   {
2012     FT_Error     error = FT_Err_Ok;
2013     FT_Renderer  renderer;
2014 
2015 
2016     /* if it is already a bitmap, no need to do anything */
2017     switch ( slot->format )
2018     {
2019     case FT_GLYPH_FORMAT_BITMAP:   /* already a bitmap, don't do anything */
2020       break;
2021 
2022     default:
2023       {
2024         FT_ListNode  node   = 0;
2025         FT_Bool      update = 0;
2026 
2027 
2028         /* small shortcut for the very common case */
2029         if ( slot->format == FT_GLYPH_FORMAT_OUTLINE )
2030         {
2031           renderer = library->cur_renderer;
2032           node     = library->renderers.head;
2033         }
2034         else
2035           renderer = FT_Lookup_Renderer( library, slot->format, &node );
2036 
2037         error = FT_Err_Unimplemented_Feature;
2038         while ( renderer )
2039         {
2040           error = renderer->render( renderer, slot, render_mode, NULL );
2041           if ( !error ||
2042                FT_ERROR_BASE( error ) != FT_Err_Cannot_Render_Glyph )
2043             break;
2044 
2045           /* FT_Err_Cannot_Render_Glyph is returned if the render mode   */
2046           /* is unsupported by the current renderer for this glyph image */
2047           /* format.                                                     */
2048 
2049           /* now, look for another renderer that supports the same */
2050           /* format.                                               */
2051           renderer = FT_Lookup_Renderer( library, slot->format, &node );
2052           update   = 1;
2053         }
2054 
2055         /* if we changed the current renderer for the glyph image format */
2056         /* we need to select it as the next current one                  */
2057         if ( !error && update && renderer )
2058           FT_Set_Renderer( library, renderer, 0, 0 );
2059       }
2060     }
2061 
2062     return error;
2063   }
2064 
2065 
2066   /* documentation is in freetype.h */
2067 
2068   FT_EXPORT_DEF( FT_Error )
2069   FT_Render_Glyph( FT_GlyphSlot    slot,
2070                    FT_Render_Mode  render_mode )
2071   {
2072     FT_Library  library;
2073 
2074 
2075     if ( !slot )
2076       return FT_Err_Invalid_Argument;
2077 
2078     library = FT_FACE_LIBRARY( slot->face );
2079 
2080     return FT_Render_Glyph_Internal( library, slot, render_mode );
2081   }
2082 
2083 
2084   /*************************************************************************/
2085   /*************************************************************************/
2086   /*************************************************************************/
2087   /****                                                                 ****/
2088   /****                                                                 ****/
2089   /****                         M O D U L E S                           ****/
2090   /****                                                                 ****/
2091   /****                                                                 ****/
2092   /*************************************************************************/
2093   /*************************************************************************/
2094   /*************************************************************************/
2095 
2096 
2097   /*************************************************************************/
2098   /*                                                                       */
2099   /* <Function>                                                            */
2100   /*    Destroy_Module                                                     */
2101   /*                                                                       */
2102   /* <Description>                                                         */
2103   /*    Destroys a given module object.  For drivers, this also destroys   */
2104   /*    all child faces.                                                   */
2105   /*                                                                       */
2106   /* <InOut>                                                               */
2107   /*     module :: A handle to the target driver object.                   */
2108   /*                                                                       */
2109   /* <Note>                                                                */
2110   /*     The driver _must_ be LOCKED!                                      */
2111   /*                                                                       */
2112   static void
2113   Destroy_Module( FT_Module  module )
2114   {
2115     FT_Memory         memory  = module->memory;
2116     FT_Module_Class*  clazz   = module->clazz;
2117     FT_Library        library = module->library;
2118 
2119 
2120     /* finalize client-data - before anything else */
2121     if ( module->generic.finalizer )
2122       module->generic.finalizer( module );
2123 
2124     if ( library && library->auto_hinter == module )
2125       library->auto_hinter = 0;
2126 
2127     /* if the module is a renderer */
2128     if ( FT_MODULE_IS_RENDERER( module ) )
2129       ft_remove_renderer( module );
2130 
2131     /* if the module is a font driver, add some steps */
2132     if ( FT_MODULE_IS_DRIVER( module ) )
2133       Destroy_Driver( FT_DRIVER( module ) );
2134 
2135     /* finalize the module object */
2136     if ( clazz->module_done )
2137       clazz->module_done( module );
2138 
2139     /* discard it */
2140     FT_FREE( module );
2141   }
2142 
2143 
2144   /* documentation is in ftmodule.h */
2145 
2146   FT_EXPORT_DEF( FT_Error )
2147   FT_Add_Module( FT_Library              library,
2148                  const FT_Module_Class*  clazz )
2149   {
2150     FT_Error   error;
2151     FT_Memory  memory;
2152     FT_Module  module;
2153     FT_UInt    nn;
2154 
2155 
2156 #define FREETYPE_VER_FIXED  ( ( (FT_Long)FREETYPE_MAJOR << 16 ) | \
2157                                 FREETYPE_MINOR                  )
2158 
2159     if ( !library )
2160       return FT_Err_Invalid_Library_Handle;
2161 
2162     if ( !clazz )
2163       return FT_Err_Invalid_Argument;
2164 
2165     /* check freetype version */
2166     if ( clazz->module_requires > FREETYPE_VER_FIXED )
2167       return FT_Err_Invalid_Version;
2168 
2169     /* look for a module with the same name in the library's table */
2170     for ( nn = 0; nn < library->num_modules; nn++ )
2171     {
2172       module = library->modules[nn];
2173       if ( ft_strcmp( module->clazz->module_name, clazz->module_name ) == 0 )
2174       {
2175         /* this installed module has the same name, compare their versions */
2176         if ( clazz->module_version <= module->clazz->module_version )
2177           return FT_Err_Lower_Module_Version;
2178 
2179         /* remove the module from our list, then exit the loop to replace */
2180         /* it by our new version..                                        */
2181         FT_Remove_Module( library, module );
2182         break;
2183       }
2184     }
2185 
2186     memory = library->memory;
2187     error  = FT_Err_Ok;
2188 
2189     if ( library->num_modules >= FT_MAX_MODULES )
2190     {
2191       error = FT_Err_Too_Many_Drivers;
2192       goto Exit;
2193     }
2194 
2195     /* allocate module object */
2196     if ( FT_ALLOC( module, clazz->module_size ) )
2197       goto Exit;
2198 
2199     /* base initialization */
2200     module->library = library;
2201     module->memory  = memory;
2202     module->clazz   = (FT_Module_Class*)clazz;
2203 
2204     /* check whether the module is a renderer - this must be performed */
2205     /* before the normal module initialization                         */
2206     if ( FT_MODULE_IS_RENDERER( module ) )
2207     {
2208       /* add to the renderers list */
2209       error = ft_add_renderer( module );
2210       if ( error )
2211         goto Fail;
2212     }
2213 
2214     /* is the module a auto-hinter? */
2215     if ( FT_MODULE_IS_HINTER( module ) )
2216       library->auto_hinter = module;
2217 
2218     /* if the module is a font driver */
2219     if ( FT_MODULE_IS_DRIVER( module ) )
2220     {
2221       /* allocate glyph loader if needed */
2222       FT_Driver  driver = FT_DRIVER( module );
2223 
2224 
2225       driver->clazz = (FT_Driver_Class)module->clazz;
2226       if ( FT_DRIVER_USES_OUTLINES( driver ) )
2227       {
2228         error = FT_GlyphLoader_New( memory, &driver->glyph_loader );
2229         if ( error )
2230           goto Fail;
2231       }
2232     }
2233 
2234     if ( clazz->module_init )
2235     {
2236       error = clazz->module_init( module );
2237       if ( error )
2238         goto Fail;
2239     }
2240 
2241     /* add module to the library's table */
2242     library->modules[library->num_modules++] = module;
2243 
2244   Exit:
2245     return error;
2246 
2247   Fail:
2248     if ( FT_MODULE_IS_DRIVER( module ) )
2249     {
2250       FT_Driver  driver = FT_DRIVER( module );
2251 
2252 
2253       if ( FT_DRIVER_USES_OUTLINES( driver ) )
2254         FT_GlyphLoader_Done( driver->glyph_loader );
2255     }
2256 
2257     if ( FT_MODULE_IS_RENDERER( module ) )
2258     {
2259       FT_Renderer  renderer = FT_RENDERER( module );
2260 
2261 
2262       if ( renderer->raster )
2263         renderer->clazz->raster_class->raster_done( renderer->raster );
2264     }
2265 
2266     FT_FREE( module );
2267     goto Exit;
2268   }
2269 
2270 
2271   /* documentation is in ftmodule.h */
2272 
2273   FT_EXPORT_DEF( FT_Module )
2274   FT_Get_Module( FT_Library   library,
2275                  const char*  module_name )
2276   {
2277     FT_Module   result = 0;
2278     FT_Module*  cur;
2279     FT_Module*  limit;
2280 
2281 
2282     if ( !library || !module_name )
2283       return result;
2284 
2285     cur   = library->modules;
2286     limit = cur + library->num_modules;
2287 
2288     for ( ; cur < limit; cur++ )
2289       if ( ft_strcmp( cur[0]->clazz->module_name, module_name ) == 0 )
2290       {
2291         result = cur[0];
2292         break;
2293       }
2294 
2295     return result;
2296   }
2297 
2298 
2299   /* documentation is in ftobjs.h */
2300 
2301   FT_BASE_DEF( const void* )
2302   FT_Get_Module_Interface( FT_Library   library,
2303                            const char*  mod_name )
2304   {
2305     FT_Module  module;
2306 
2307 
2308     /* test for valid `library' delayed to FT_Get_Module() */
2309 
2310     module = FT_Get_Module( library, mod_name );
2311 
2312     return module ? module->clazz->module_interface : 0;
2313   }
2314 
2315 
2316   /* documentation is in ftmodule.h */
2317 
2318   FT_EXPORT_DEF( FT_Error )
2319   FT_Remove_Module( FT_Library  library,
2320                     FT_Module   module )
2321   {
2322     /* try to find the module from the table, then remove it from there */
2323 
2324     if ( !library )
2325       return FT_Err_Invalid_Library_Handle;
2326 
2327     if ( module )
2328     {
2329       FT_Module*  cur   = library->modules;
2330       FT_Module*  limit = cur + library->num_modules;
2331 
2332 
2333       for ( ; cur < limit; cur++ )
2334       {
2335         if ( cur[0] == module )
2336         {
2337           /* remove it from the table */
2338           library->num_modules--;
2339           limit--;
2340           while ( cur < limit )
2341           {
2342             cur[0] = cur[1];
2343             cur++;
2344           }
2345           limit[0] = 0;
2346 
2347           /* destroy the module */
2348           Destroy_Module( module );
2349 
2350           return FT_Err_Ok;
2351         }
2352       }
2353     }
2354     return FT_Err_Invalid_Driver_Handle;
2355   }
2356 
2357 
2358   /*************************************************************************/
2359   /*************************************************************************/
2360   /*************************************************************************/
2361   /****                                                                 ****/
2362   /****                                                                 ****/
2363   /****                         L I B R A R Y                           ****/
2364   /****                                                                 ****/
2365   /****                                                                 ****/
2366   /*************************************************************************/
2367   /*************************************************************************/
2368   /*************************************************************************/
2369 
2370 
2371   /* documentation is in ftmodule.h */
2372 
2373   FT_EXPORT_DEF( FT_Error )
2374   FT_New_Library( FT_Memory    memory,
2375                   FT_Library  *alibrary )
2376   {
2377     FT_Library  library = 0;
2378     FT_Error    error;
2379 
2380 
2381     if ( !memory )
2382       return FT_Err_Invalid_Argument;
2383 
2384 #ifdef FT_DEBUG_LEVEL_ERROR
2385     /* init debugging support */
2386     ft_debug_init();
2387 #endif
2388 
2389     /* first of all, allocate the library object */
2390     if ( FT_NEW( library ) )
2391       return error;
2392 
2393     library->memory = memory;
2394 
2395     /* allocate the render pool */
2396     library->raster_pool_size = FT_RENDER_POOL_SIZE;
2397     if ( FT_ALLOC( library->raster_pool, FT_RENDER_POOL_SIZE ) )
2398       goto Fail;
2399 
2400     /* That's ok now */
2401     *alibrary = library;
2402 
2403     return FT_Err_Ok;
2404 
2405   Fail:
2406     FT_FREE( library );
2407     return error;
2408   }
2409 
2410 
2411   /* documentation is in freetype.h */
2412 
2413   FT_EXPORT_DEF( void )
2414   FT_Library_Version( FT_Library   library,
2415                       FT_Int      *amajor,
2416                       FT_Int      *aminor,
2417                       FT_Int      *apatch )
2418   {
2419     FT_Int  major = 0;
2420     FT_Int  minor = 0;
2421     FT_Int  patch = 0;
2422 
2423 
2424     if ( library )
2425     {
2426       major = library->version_major;
2427       minor = library->version_minor;
2428       patch = library->version_patch;
2429     }
2430 
2431     if ( amajor )
2432       *amajor = major;
2433 
2434     if ( aminor )
2435       *aminor = minor;
2436 
2437     if ( apatch )
2438       *apatch = patch;
2439   }
2440 
2441 
2442   /* documentation is in ftmodule.h */
2443 
2444   FT_EXPORT_DEF( FT_Error )
2445   FT_Done_Library( FT_Library  library )
2446   {
2447     FT_Memory  memory;
2448 
2449 
2450     if ( !library )
2451       return FT_Err_Invalid_Library_Handle;
2452 
2453     memory = library->memory;
2454 
2455     /* Discard client-data */
2456     if ( library->generic.finalizer )
2457       library->generic.finalizer( library );
2458 
2459     /* Close all modules in the library */
2460 #if 1
2461     while ( library->num_modules > 0 )
2462       FT_Remove_Module( library, library->modules[0] );
2463 #else
2464     {
2465       FT_UInt  n;
2466 
2467 
2468       for ( n = 0; n < library->num_modules; n++ )
2469       {
2470         FT_Module  module = library->modules[n];
2471 
2472 
2473         if ( module )
2474         {
2475           Destroy_Module( module );
2476           library->modules[n] = 0;
2477         }
2478       }
2479     }
2480 #endif
2481 
2482     /* Destroy raster objects */
2483     FT_FREE( library->raster_pool );
2484     library->raster_pool_size = 0;
2485 
2486     FT_FREE( library );
2487     return FT_Err_Ok;
2488   }
2489 
2490 
2491   /* documentation is in ftmodule.h */
2492 
2493   FT_EXPORT_DEF( void )
2494   FT_Set_Debug_Hook( FT_Library         library,
2495                      FT_UInt            hook_index,
2496                      FT_DebugHook_Func  debug_hook )
2497   {
2498     if ( library && debug_hook &&
2499          hook_index <
2500            ( sizeof ( library->debug_hooks ) / sizeof ( void* ) ) )
2501       library->debug_hooks[hook_index] = debug_hook;
2502   }
2503 
2504 
2505 /* END */
2506