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