1 /***************************************************************************/
5 /* The FreeType private base classes (body). */
7 /* Copyright 1996-2016 by */
8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
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. */
16 /***************************************************************************/
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
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
40 #ifdef FT_CONFIG_OPTION_MAC_FONTS
45 #ifdef FT_DEBUG_LEVEL_TRACE
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 )
58 /* It's easiest to include `md5.c' directly. However, since OpenSSL */
59 /* also provides the same functions, there might be conflicts if */
60 /* both FreeType and OpenSSL are built as static libraries. For */
61 /* this reason, we put the MD5 stuff into the `FT_' namespace. */
62 #define MD5_u32plus FT_MD5_u32plus
63 #define MD5_CTX FT_MD5_CTX
64 #define MD5_Init FT_MD5_Init
65 #define MD5_Update FT_MD5_Update
66 #define MD5_Final FT_MD5_Final
72 #if defined( _MSC_VER )
73 #pragma warning( pop )
76 #endif /* FT_DEBUG_LEVEL_TRACE */
79 #define GRID_FIT_METRICS
82 /* forward declaration */
84 ft_open_face_internal( FT_Library library
,
85 const FT_Open_Args
* args
,
88 FT_Bool test_mac_fonts
);
91 FT_BASE_DEF( FT_Pointer
)
92 ft_service_list_lookup( FT_ServiceDesc service_descriptors
,
93 const char* service_id
)
95 FT_Pointer result
= NULL
;
96 FT_ServiceDesc desc
= service_descriptors
;
99 if ( desc
&& service_id
)
101 for ( ; desc
->serv_id
!= NULL
; desc
++ )
103 if ( ft_strcmp( desc
->serv_id
, service_id
) == 0 )
105 result
= (FT_Pointer
)desc
->serv_data
;
116 ft_validator_init( FT_Validator valid
,
118 const FT_Byte
* limit
,
119 FT_ValidationLevel level
)
122 valid
->limit
= limit
;
123 valid
->level
= level
;
124 valid
->error
= FT_Err_Ok
;
128 FT_BASE_DEF( FT_Int
)
129 ft_validator_run( FT_Validator valid
)
131 /* This function doesn't work! None should call it. */
139 ft_validator_error( FT_Validator valid
,
142 /* since the cast below also disables the compiler's */
143 /* type check, we introduce a dummy variable, which */
144 /* will be optimized away */
145 volatile ft_jmp_buf
* jump_buffer
= &valid
->jump_buffer
;
148 valid
->error
= error
;
150 /* throw away volatileness; use `jump_buffer' or the */
151 /* compiler may warn about an unused local variable */
152 ft_longjmp( *(ft_jmp_buf
*) jump_buffer
, 1 );
156 /*************************************************************************/
157 /*************************************************************************/
158 /*************************************************************************/
161 /**** S T R E A M ****/
164 /*************************************************************************/
165 /*************************************************************************/
166 /*************************************************************************/
169 /* create a new input stream from an FT_Open_Args structure */
171 FT_BASE_DEF( FT_Error
)
172 FT_Stream_New( FT_Library library
,
173 const FT_Open_Args
* args
,
178 FT_Stream stream
= NULL
;
184 return FT_THROW( Invalid_Library_Handle
);
187 return FT_THROW( Invalid_Argument
);
189 memory
= library
->memory
;
191 if ( FT_NEW( stream
) )
194 stream
->memory
= memory
;
196 if ( args
->flags
& FT_OPEN_MEMORY
)
198 /* create a memory-based stream */
199 FT_Stream_OpenMemory( stream
,
200 (const FT_Byte
*)args
->memory_base
,
201 (FT_ULong
)args
->memory_size
);
204 #ifndef FT_CONFIG_OPTION_DISABLE_STREAM_SUPPORT
206 else if ( args
->flags
& FT_OPEN_PATHNAME
)
208 /* create a normal system stream */
209 error
= FT_Stream_Open( stream
, args
->pathname
);
210 stream
->pathname
.pointer
= args
->pathname
;
212 else if ( ( args
->flags
& FT_OPEN_STREAM
) && args
->stream
)
214 /* use an existing, user-provided stream */
216 /* in this case, we do not need to allocate a new stream object */
217 /* since the caller is responsible for closing it himself */
219 stream
= args
->stream
;
225 error
= FT_THROW( Invalid_Argument
);
230 stream
->memory
= memory
; /* just to be certain */
240 FT_Stream_Free( FT_Stream stream
,
245 FT_Memory memory
= stream
->memory
;
248 FT_Stream_Close( stream
);
256 /*************************************************************************/
258 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
259 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
260 /* messages during execution. */
263 #define FT_COMPONENT trace_objs
266 /*************************************************************************/
267 /*************************************************************************/
268 /*************************************************************************/
271 /**** FACE, SIZE & GLYPH SLOT OBJECTS ****/
274 /*************************************************************************/
275 /*************************************************************************/
276 /*************************************************************************/
280 ft_glyphslot_init( FT_GlyphSlot slot
)
282 FT_Driver driver
= slot
->face
->driver
;
283 FT_Driver_Class clazz
= driver
->clazz
;
284 FT_Memory memory
= driver
->root
.memory
;
285 FT_Error error
= FT_Err_Ok
;
286 FT_Slot_Internal internal
= NULL
;
289 slot
->library
= driver
->root
.library
;
291 if ( FT_NEW( internal
) )
294 slot
->internal
= internal
;
296 if ( FT_DRIVER_USES_OUTLINES( driver
) )
297 error
= FT_GlyphLoader_New( memory
, &internal
->loader
);
299 if ( !error
&& clazz
->init_slot
)
300 error
= clazz
->init_slot( slot
);
308 ft_glyphslot_free_bitmap( FT_GlyphSlot slot
)
310 if ( slot
->internal
&& ( slot
->internal
->flags
& FT_GLYPH_OWN_BITMAP
) )
312 FT_Memory memory
= FT_FACE_MEMORY( slot
->face
);
315 FT_FREE( slot
->bitmap
.buffer
);
316 slot
->internal
->flags
&= ~FT_GLYPH_OWN_BITMAP
;
320 /* assume that the bitmap buffer was stolen or not */
321 /* allocated from the heap */
322 slot
->bitmap
.buffer
= NULL
;
328 ft_glyphslot_set_bitmap( FT_GlyphSlot slot
,
331 ft_glyphslot_free_bitmap( slot
);
333 slot
->bitmap
.buffer
= buffer
;
335 FT_ASSERT( (slot
->internal
->flags
& FT_GLYPH_OWN_BITMAP
) == 0 );
339 FT_BASE_DEF( FT_Error
)
340 ft_glyphslot_alloc_bitmap( FT_GlyphSlot slot
,
343 FT_Memory memory
= FT_FACE_MEMORY( slot
->face
);
347 if ( slot
->internal
->flags
& FT_GLYPH_OWN_BITMAP
)
348 FT_FREE( slot
->bitmap
.buffer
);
350 slot
->internal
->flags
|= FT_GLYPH_OWN_BITMAP
;
352 (void)FT_ALLOC( slot
->bitmap
.buffer
, size
);
358 ft_glyphslot_clear( FT_GlyphSlot slot
)
360 /* free bitmap if needed */
361 ft_glyphslot_free_bitmap( slot
);
363 /* clear all public fields in the glyph slot */
364 FT_ZERO( &slot
->metrics
);
365 FT_ZERO( &slot
->outline
);
367 slot
->bitmap
.width
= 0;
368 slot
->bitmap
.rows
= 0;
369 slot
->bitmap
.pitch
= 0;
370 slot
->bitmap
.pixel_mode
= 0;
371 /* `slot->bitmap.buffer' has been handled by ft_glyphslot_free_bitmap */
373 slot
->bitmap_left
= 0;
374 slot
->bitmap_top
= 0;
375 slot
->num_subglyphs
= 0;
376 slot
->subglyphs
= NULL
;
377 slot
->control_data
= NULL
;
378 slot
->control_len
= 0;
380 slot
->format
= FT_GLYPH_FORMAT_NONE
;
382 slot
->linearHoriAdvance
= 0;
383 slot
->linearVertAdvance
= 0;
390 ft_glyphslot_done( FT_GlyphSlot slot
)
392 FT_Driver driver
= slot
->face
->driver
;
393 FT_Driver_Class clazz
= driver
->clazz
;
394 FT_Memory memory
= driver
->root
.memory
;
397 if ( clazz
->done_slot
)
398 clazz
->done_slot( slot
);
400 /* free bitmap buffer if needed */
401 ft_glyphslot_free_bitmap( slot
);
403 /* slot->internal might be NULL in out-of-memory situations */
404 if ( slot
->internal
)
406 /* free glyph loader */
407 if ( FT_DRIVER_USES_OUTLINES( driver
) )
409 FT_GlyphLoader_Done( slot
->internal
->loader
);
410 slot
->internal
->loader
= NULL
;
413 FT_FREE( slot
->internal
);
418 /* documentation is in ftobjs.h */
420 FT_BASE_DEF( FT_Error
)
421 FT_New_GlyphSlot( FT_Face face
,
422 FT_GlyphSlot
*aslot
)
426 FT_Driver_Class clazz
;
428 FT_GlyphSlot slot
= NULL
;
432 return FT_THROW( Invalid_Face_Handle
);
435 return FT_THROW( Invalid_Argument
);
437 driver
= face
->driver
;
438 clazz
= driver
->clazz
;
439 memory
= driver
->root
.memory
;
441 FT_TRACE4(( "FT_New_GlyphSlot: Creating new slot object\n" ));
442 if ( !FT_ALLOC( slot
, clazz
->slot_object_size
) )
446 error
= ft_glyphslot_init( slot
);
449 ft_glyphslot_done( slot
);
454 slot
->next
= face
->glyph
;
465 FT_TRACE4(( "FT_New_GlyphSlot: Return %d\n", error
));
470 /* documentation is in ftobjs.h */
473 FT_Done_GlyphSlot( FT_GlyphSlot slot
)
477 FT_Driver driver
= slot
->face
->driver
;
478 FT_Memory memory
= driver
->root
.memory
;
483 /* Remove slot from its parent face's list */
485 cur
= slot
->face
->glyph
;
492 slot
->face
->glyph
= cur
->next
;
494 prev
->next
= cur
->next
;
496 /* finalize client-specific data */
497 if ( slot
->generic
.finalizer
)
498 slot
->generic
.finalizer( slot
);
500 ft_glyphslot_done( slot
);
511 /* documentation is in freetype.h */
513 FT_EXPORT_DEF( void )
514 FT_Set_Transform( FT_Face face
,
518 FT_Face_Internal internal
;
524 internal
= face
->internal
;
526 internal
->transform_flags
= 0;
530 internal
->transform_matrix
.xx
= 0x10000L
;
531 internal
->transform_matrix
.xy
= 0;
532 internal
->transform_matrix
.yx
= 0;
533 internal
->transform_matrix
.yy
= 0x10000L
;
535 matrix
= &internal
->transform_matrix
;
538 internal
->transform_matrix
= *matrix
;
540 /* set transform_flags bit flag 0 if `matrix' isn't the identity */
541 if ( ( matrix
->xy
| matrix
->yx
) ||
542 matrix
->xx
!= 0x10000L
||
543 matrix
->yy
!= 0x10000L
)
544 internal
->transform_flags
|= 1;
548 internal
->transform_delta
.x
= 0;
549 internal
->transform_delta
.y
= 0;
551 delta
= &internal
->transform_delta
;
554 internal
->transform_delta
= *delta
;
556 /* set transform_flags bit flag 1 if `delta' isn't the null vector */
557 if ( delta
->x
| delta
->y
)
558 internal
->transform_flags
|= 2;
563 ft_lookup_glyph_renderer( FT_GlyphSlot slot
);
566 #ifdef GRID_FIT_METRICS
568 ft_glyphslot_grid_fit_metrics( FT_GlyphSlot slot
,
571 FT_Glyph_Metrics
* metrics
= &slot
->metrics
;
572 FT_Pos right
, bottom
;
577 metrics
->horiBearingX
= FT_PIX_FLOOR( metrics
->horiBearingX
);
578 metrics
->horiBearingY
= FT_PIX_CEIL ( metrics
->horiBearingY
);
580 right
= FT_PIX_CEIL( metrics
->vertBearingX
+ metrics
->width
);
581 bottom
= FT_PIX_CEIL( metrics
->vertBearingY
+ metrics
->height
);
583 metrics
->vertBearingX
= FT_PIX_FLOOR( metrics
->vertBearingX
);
584 metrics
->vertBearingY
= FT_PIX_FLOOR( metrics
->vertBearingY
);
586 metrics
->width
= right
- metrics
->vertBearingX
;
587 metrics
->height
= bottom
- metrics
->vertBearingY
;
591 metrics
->vertBearingX
= FT_PIX_FLOOR( metrics
->vertBearingX
);
592 metrics
->vertBearingY
= FT_PIX_FLOOR( metrics
->vertBearingY
);
594 right
= FT_PIX_CEIL ( metrics
->horiBearingX
+ metrics
->width
);
595 bottom
= FT_PIX_FLOOR( metrics
->horiBearingY
- metrics
->height
);
597 metrics
->horiBearingX
= FT_PIX_FLOOR( metrics
->horiBearingX
);
598 metrics
->horiBearingY
= FT_PIX_CEIL ( metrics
->horiBearingY
);
600 metrics
->width
= right
- metrics
->horiBearingX
;
601 metrics
->height
= metrics
->horiBearingY
- bottom
;
604 metrics
->horiAdvance
= FT_PIX_ROUND( metrics
->horiAdvance
);
605 metrics
->vertAdvance
= FT_PIX_ROUND( metrics
->vertAdvance
);
607 #endif /* GRID_FIT_METRICS */
610 /* documentation is in freetype.h */
612 FT_EXPORT_DEF( FT_Error
)
613 FT_Load_Glyph( FT_Face face
,
615 FT_Int32 load_flags
)
621 FT_Bool autohint
= FALSE
;
623 TT_Face ttface
= (TT_Face
)face
;
626 if ( !face
|| !face
->size
|| !face
->glyph
)
627 return FT_THROW( Invalid_Face_Handle
);
629 /* The validity test for `glyph_index' is performed by the */
633 ft_glyphslot_clear( slot
);
635 driver
= face
->driver
;
636 library
= driver
->root
.library
;
637 hinter
= library
->auto_hinter
;
639 /* resolve load flags dependencies */
641 if ( load_flags
& FT_LOAD_NO_RECURSE
)
642 load_flags
|= FT_LOAD_NO_SCALE
|
643 FT_LOAD_IGNORE_TRANSFORM
;
645 if ( load_flags
& FT_LOAD_NO_SCALE
)
647 load_flags
|= FT_LOAD_NO_HINTING
|
650 load_flags
&= ~FT_LOAD_RENDER
;
653 if ( load_flags
& FT_LOAD_BITMAP_METRICS_ONLY
)
654 load_flags
&= ~FT_LOAD_RENDER
;
657 * Determine whether we need to auto-hint or not.
658 * The general rules are:
660 * - Do only auto-hinting if we have a hinter module, a scalable font
661 * format dealing with outlines, and no transforms except simple
662 * slants and/or rotations by integer multiples of 90 degrees.
664 * - Then, auto-hint if FT_LOAD_FORCE_AUTOHINT is set or if we don't
665 * have a native font hinter.
667 * - Otherwise, auto-hint for LIGHT hinting mode or if there isn't
668 * any hinting bytecode in the TrueType/OpenType font.
670 * - Exception: The font is `tricky' and requires the native hinter to
675 !( load_flags
& FT_LOAD_NO_HINTING
) &&
676 !( load_flags
& FT_LOAD_NO_AUTOHINT
) &&
677 FT_DRIVER_IS_SCALABLE( driver
) &&
678 FT_DRIVER_USES_OUTLINES( driver
) &&
679 !FT_IS_TRICKY( face
) &&
680 ( ( load_flags
& FT_LOAD_IGNORE_TRANSFORM
) ||
681 ( face
->internal
->transform_matrix
.yx
== 0 &&
682 face
->internal
->transform_matrix
.xx
!= 0 ) ||
683 ( face
->internal
->transform_matrix
.xx
== 0 &&
684 face
->internal
->transform_matrix
.yx
!= 0 ) ) )
686 if ( ( load_flags
& FT_LOAD_FORCE_AUTOHINT
) ||
687 !FT_DRIVER_HAS_HINTER( driver
) )
691 FT_Render_Mode mode
= FT_LOAD_TARGET_MODE( load_flags
);
694 /* the check for `num_locations' assures that we actually */
695 /* test for instructions in a TTF and not in a CFF-based OTF */
697 /* since `maxSizeOfInstructions' might be unreliable, we */
698 /* check the size of the `fpgm' and `prep' tables, too -- */
699 /* the assumption is that there don't exist real TTFs where */
700 /* both `fpgm' and `prep' tables are missing */
701 if ( ( mode
== FT_RENDER_MODE_LIGHT
&&
702 !FT_DRIVER_HINTS_LIGHTLY( driver
) ) ||
703 ( FT_IS_SFNT( face
) &&
704 ttface
->num_locations
&&
705 ttface
->max_profile
.maxSizeOfInstructions
== 0 &&
706 ttface
->font_program_size
== 0 &&
707 ttface
->cvt_program_size
== 0 ) )
714 FT_AutoHinter_Interface hinting
;
717 /* try to load embedded bitmaps first if available */
719 /* XXX: This is really a temporary hack that should disappear */
720 /* promptly with FreeType 2.1! */
722 if ( FT_HAS_FIXED_SIZES( face
) &&
723 ( load_flags
& FT_LOAD_NO_BITMAP
) == 0 )
725 error
= driver
->clazz
->load_glyph( slot
, face
->size
,
727 load_flags
| FT_LOAD_SBITS_ONLY
);
729 if ( !error
&& slot
->format
== FT_GLYPH_FORMAT_BITMAP
)
734 FT_Face_Internal internal
= face
->internal
;
735 FT_Int transform_flags
= internal
->transform_flags
;
738 /* since the auto-hinter calls FT_Load_Glyph by itself, */
739 /* make sure that glyphs aren't transformed */
740 internal
->transform_flags
= 0;
742 /* load auto-hinted outline */
743 hinting
= (FT_AutoHinter_Interface
)hinter
->clazz
->module_interface
;
745 error
= hinting
->load_glyph( (FT_AutoHinter
)hinter
,
747 glyph_index
, load_flags
);
749 internal
->transform_flags
= transform_flags
;
754 error
= driver
->clazz
->load_glyph( slot
,
761 if ( slot
->format
== FT_GLYPH_FORMAT_OUTLINE
)
763 /* check that the loaded outline is correct */
764 error
= FT_Outline_Check( &slot
->outline
);
768 #ifdef GRID_FIT_METRICS
769 if ( !( load_flags
& FT_LOAD_NO_HINTING
) )
770 ft_glyphslot_grid_fit_metrics( slot
,
771 FT_BOOL( load_flags
& FT_LOAD_VERTICAL_LAYOUT
) );
777 /* compute the advance */
778 if ( load_flags
& FT_LOAD_VERTICAL_LAYOUT
)
781 slot
->advance
.y
= slot
->metrics
.vertAdvance
;
785 slot
->advance
.x
= slot
->metrics
.horiAdvance
;
789 /* compute the linear advance in 16.16 pixels */
790 if ( ( load_flags
& FT_LOAD_LINEAR_DESIGN
) == 0 &&
791 ( FT_IS_SCALABLE( face
) ) )
793 FT_Size_Metrics
* metrics
= &face
->size
->metrics
;
797 slot
->linearHoriAdvance
= FT_MulDiv( slot
->linearHoriAdvance
,
798 metrics
->x_scale
, 64 );
800 slot
->linearVertAdvance
= FT_MulDiv( slot
->linearVertAdvance
,
801 metrics
->y_scale
, 64 );
804 if ( ( load_flags
& FT_LOAD_IGNORE_TRANSFORM
) == 0 )
806 FT_Face_Internal internal
= face
->internal
;
809 /* now, transform the glyph image if needed */
810 if ( internal
->transform_flags
)
813 FT_Renderer renderer
= ft_lookup_glyph_renderer( slot
);
817 error
= renderer
->clazz
->transform_glyph(
819 &internal
->transform_matrix
,
820 &internal
->transform_delta
);
821 else if ( slot
->format
== FT_GLYPH_FORMAT_OUTLINE
)
823 /* apply `standard' transformation if no renderer is available */
824 if ( internal
->transform_flags
& 1 )
825 FT_Outline_Transform( &slot
->outline
,
826 &internal
->transform_matrix
);
828 if ( internal
->transform_flags
& 2 )
829 FT_Outline_Translate( &slot
->outline
,
830 internal
->transform_delta
.x
,
831 internal
->transform_delta
.y
);
834 /* transform advance */
835 FT_Vector_Transform( &slot
->advance
, &internal
->transform_matrix
);
839 FT_TRACE5(( " x advance: %d\n" , slot
->advance
.x
));
840 FT_TRACE5(( " y advance: %d\n" , slot
->advance
.y
));
842 FT_TRACE5(( " linear x advance: %d\n" , slot
->linearHoriAdvance
));
843 FT_TRACE5(( " linear y advance: %d\n" , slot
->linearVertAdvance
));
845 /* do we need to render the image now? */
847 slot
->format
!= FT_GLYPH_FORMAT_BITMAP
&&
848 slot
->format
!= FT_GLYPH_FORMAT_COMPOSITE
&&
849 load_flags
& FT_LOAD_RENDER
)
851 FT_Render_Mode mode
= FT_LOAD_TARGET_MODE( load_flags
);
854 if ( mode
== FT_RENDER_MODE_NORMAL
&&
855 (load_flags
& FT_LOAD_MONOCHROME
) )
856 mode
= FT_RENDER_MODE_MONO
;
858 error
= FT_Render_Glyph( slot
, mode
);
866 /* documentation is in freetype.h */
868 FT_EXPORT_DEF( FT_Error
)
869 FT_Load_Char( FT_Face face
,
871 FT_Int32 load_flags
)
877 return FT_THROW( Invalid_Face_Handle
);
879 glyph_index
= (FT_UInt
)char_code
;
881 glyph_index
= FT_Get_Char_Index( face
, char_code
);
883 return FT_Load_Glyph( face
, glyph_index
, load_flags
);
887 /* destructor for sizes list */
889 destroy_size( FT_Memory memory
,
893 /* finalize client-specific data */
894 if ( size
->generic
.finalizer
)
895 size
->generic
.finalizer( size
);
897 /* finalize format-specific stuff */
898 if ( driver
->clazz
->done_size
)
899 driver
->clazz
->done_size( size
);
901 FT_FREE( size
->internal
);
907 ft_cmap_done_internal( FT_CMap cmap
);
911 destroy_charmaps( FT_Face face
,
920 for ( n
= 0; n
< face
->num_charmaps
; n
++ )
922 FT_CMap cmap
= FT_CMAP( face
->charmaps
[n
] );
925 ft_cmap_done_internal( cmap
);
927 face
->charmaps
[n
] = NULL
;
930 FT_FREE( face
->charmaps
);
931 face
->num_charmaps
= 0;
935 /* destructor for faces list */
937 destroy_face( FT_Memory memory
,
941 FT_Driver_Class clazz
= driver
->clazz
;
944 /* discard auto-hinting data */
945 if ( face
->autohint
.finalizer
)
946 face
->autohint
.finalizer( face
->autohint
.data
);
948 /* Discard glyph slots for this face. */
949 /* Beware! FT_Done_GlyphSlot() changes the field `face->glyph' */
950 while ( face
->glyph
)
951 FT_Done_GlyphSlot( face
->glyph
);
953 /* discard all sizes for this face */
954 FT_List_Finalize( &face
->sizes_list
,
955 (FT_List_Destructor
)destroy_size
,
960 /* now discard client data */
961 if ( face
->generic
.finalizer
)
962 face
->generic
.finalizer( face
);
964 /* discard charmaps */
965 destroy_charmaps( face
, memory
);
967 /* finalize format-specific stuff */
968 if ( clazz
->done_face
)
969 clazz
->done_face( face
);
971 /* close the stream for this face if needed */
974 ( face
->face_flags
& FT_FACE_FLAG_EXTERNAL_STREAM
) != 0 );
979 if ( face
->internal
)
981 FT_FREE( face
->internal
);
988 Destroy_Driver( FT_Driver driver
)
990 FT_List_Finalize( &driver
->faces_list
,
991 (FT_List_Destructor
)destroy_face
,
997 /*************************************************************************/
1000 /* find_unicode_charmap */
1003 /* This function finds a Unicode charmap, if there is one. */
1004 /* And if there is more than one, it tries to favour the more */
1005 /* extensive one, i.e., one that supports UCS-4 against those which */
1006 /* are limited to the BMP (said UCS-2 encoding.) */
1008 /* This function is called from open_face() (just below), and also */
1009 /* from FT_Select_Charmap( ..., FT_ENCODING_UNICODE ). */
1012 find_unicode_charmap( FT_Face face
)
1018 /* caller should have already checked that `face' is valid */
1021 first
= face
->charmaps
;
1024 return FT_THROW( Invalid_CharMap_Handle
);
1027 * The original TrueType specification(s) only specified charmap
1028 * formats that are capable of mapping 8 or 16 bit character codes to
1031 * However, recent updates to the Apple and OpenType specifications
1032 * introduced new formats that are capable of mapping 32-bit character
1033 * codes as well. And these are already used on some fonts, mainly to
1034 * map non-BMP Asian ideographs as defined in Unicode.
1036 * For compatibility purposes, these fonts generally come with
1037 * *several* Unicode charmaps:
1039 * - One of them in the "old" 16-bit format, that cannot access
1040 * all glyphs in the font.
1042 * - Another one in the "new" 32-bit format, that can access all
1045 * This function has been written to always favor a 32-bit charmap
1046 * when found. Otherwise, a 16-bit one is returned when found.
1049 /* Since the `interesting' table, with IDs (3,10), is normally the */
1050 /* last one, we loop backwards. This loses with type1 fonts with */
1051 /* non-BMP characters (<.0001%), this wins with .ttf with non-BMP */
1052 /* chars (.01% ?), and this is the same about 99.99% of the time! */
1054 cur
= first
+ face
->num_charmaps
; /* points after the last one */
1056 for ( ; --cur
>= first
; )
1058 if ( cur
[0]->encoding
== FT_ENCODING_UNICODE
)
1060 /* XXX If some new encodings to represent UCS-4 are added, */
1061 /* they should be added here. */
1062 if ( ( cur
[0]->platform_id
== TT_PLATFORM_MICROSOFT
&&
1063 cur
[0]->encoding_id
== TT_MS_ID_UCS_4
) ||
1064 ( cur
[0]->platform_id
== TT_PLATFORM_APPLE_UNICODE
&&
1065 cur
[0]->encoding_id
== TT_APPLE_ID_UNICODE_32
) )
1067 face
->charmap
= cur
[0];
1073 /* We do not have any UCS-4 charmap. */
1074 /* Do the loop again and search for UCS-2 charmaps. */
1075 cur
= first
+ face
->num_charmaps
;
1077 for ( ; --cur
>= first
; )
1079 if ( cur
[0]->encoding
== FT_ENCODING_UNICODE
)
1081 face
->charmap
= cur
[0];
1086 return FT_THROW( Invalid_CharMap_Handle
);
1090 /*************************************************************************/
1093 /* find_variant_selector_charmap */
1096 /* This function finds the variant selector charmap, if there is one. */
1097 /* There can only be one (platform=0, specific=5, format=14). */
1100 find_variant_selector_charmap( FT_Face face
)
1107 /* caller should have already checked that `face' is valid */
1110 first
= face
->charmaps
;
1115 end
= first
+ face
->num_charmaps
; /* points after the last one */
1117 for ( cur
= first
; cur
< end
; cur
++ )
1119 if ( cur
[0]->platform_id
== TT_PLATFORM_APPLE_UNICODE
&&
1120 cur
[0]->encoding_id
== TT_APPLE_ID_VARIANT_SELECTOR
&&
1121 FT_Get_CMap_Format( cur
[0] ) == 14 )
1129 /*************************************************************************/
1135 /* This function does some work for FT_Open_Face(). */
1138 open_face( FT_Driver driver
,
1140 FT_Bool external_stream
,
1143 FT_Parameter
* params
,
1147 FT_Driver_Class clazz
;
1148 FT_Face face
= NULL
;
1149 FT_Face_Internal internal
= NULL
;
1151 FT_Error error
, error2
;
1154 clazz
= driver
->clazz
;
1155 memory
= driver
->root
.memory
;
1157 /* allocate the face object and perform basic initialization */
1158 if ( FT_ALLOC( face
, clazz
->face_object_size
) )
1161 face
->driver
= driver
;
1162 face
->memory
= memory
;
1163 face
->stream
= *astream
;
1165 /* set the FT_FACE_FLAG_EXTERNAL_STREAM bit for FT_Done_Face */
1166 if ( external_stream
)
1167 face
->face_flags
|= FT_FACE_FLAG_EXTERNAL_STREAM
;
1169 if ( FT_NEW( internal
) )
1172 face
->internal
= internal
;
1174 #ifdef FT_CONFIG_OPTION_INCREMENTAL
1179 face
->internal
->incremental_interface
= NULL
;
1180 for ( i
= 0; i
< num_params
&& !face
->internal
->incremental_interface
;
1182 if ( params
[i
].tag
== FT_PARAM_TAG_INCREMENTAL
)
1183 face
->internal
->incremental_interface
=
1184 (FT_Incremental_Interface
)params
[i
].data
;
1188 if ( clazz
->init_face
)
1189 error
= clazz
->init_face( *astream
,
1194 *astream
= face
->stream
; /* Stream may have been changed. */
1198 /* select Unicode charmap by default */
1199 error2
= find_unicode_charmap( face
);
1201 /* if no Unicode charmap can be found, FT_Err_Invalid_CharMap_Handle */
1204 /* no error should happen, but we want to play safe */
1205 if ( error2
&& FT_ERR_NEQ( error2
, Invalid_CharMap_Handle
) )
1216 destroy_charmaps( face
, memory
);
1217 if ( clazz
->done_face
)
1218 clazz
->done_face( face
);
1219 FT_FREE( internal
);
1228 /* there's a Mac-specific extended implementation of FT_New_Face() */
1229 /* in src/base/ftmac.c */
1231 #ifndef FT_MACINTOSH
1233 /* documentation is in freetype.h */
1235 FT_EXPORT_DEF( FT_Error
)
1236 FT_New_Face( FT_Library library
,
1237 const char* pathname
,
1244 /* test for valid `library' and `aface' delayed to `FT_Open_Face' */
1246 return FT_THROW( Invalid_Argument
);
1248 args
.flags
= FT_OPEN_PATHNAME
;
1249 args
.pathname
= (char*)pathname
;
1252 return ft_open_face_internal( library
, &args
, face_index
, aface
, 1 );
1258 /* documentation is in freetype.h */
1260 FT_EXPORT_DEF( FT_Error
)
1261 FT_New_Memory_Face( FT_Library library
,
1262 const FT_Byte
* file_base
,
1270 /* test for valid `library' and `face' delayed to `FT_Open_Face' */
1272 return FT_THROW( Invalid_Argument
);
1274 args
.flags
= FT_OPEN_MEMORY
;
1275 args
.memory_base
= file_base
;
1276 args
.memory_size
= file_size
;
1279 return ft_open_face_internal( library
, &args
, face_index
, aface
, 1 );
1283 #ifdef FT_CONFIG_OPTION_MAC_FONTS
1285 /* The behavior here is very similar to that in base/ftmac.c, but it */
1286 /* is designed to work on non-mac systems, so no mac specific calls. */
1288 /* We look at the file and determine if it is a mac dfont file or a mac */
1289 /* resource file, or a macbinary file containing a mac resource file. */
1291 /* Unlike ftmac I'm not going to look at a `FOND'. I don't really see */
1292 /* the point, especially since there may be multiple `FOND' resources. */
1293 /* Instead I'll just look for `sfnt' and `POST' resources, ordered as */
1294 /* they occur in the file. */
1296 /* Note that multiple `POST' resources do not mean multiple postscript */
1297 /* fonts; they all get jammed together to make what is essentially a */
1300 /* We aren't interested in `NFNT' or `FONT' bitmap resources. */
1302 /* As soon as we get an `sfnt' load it into memory and pass it off to */
1305 /* If we have a (set of) `POST' resources, massage them into a (memory) */
1306 /* pfb file and pass that to FT_Open_Face. (As with ftmac.c I'm not */
1307 /* going to try to save the kerning info. After all that lives in the */
1308 /* `FOND' which isn't in the file containing the `POST' resources so */
1309 /* we don't really have access to it. */
1312 /* Finalizer for a memory stream; gets called by FT_Done_Face(). */
1313 /* It frees the memory it uses. */
1314 /* From `ftmac.c'. */
1316 memory_stream_close( FT_Stream stream
)
1318 FT_Memory memory
= stream
->memory
;
1321 FT_FREE( stream
->base
);
1324 stream
->base
= NULL
;
1325 stream
->close
= NULL
;
1329 /* Create a new memory stream from a buffer and a size. */
1330 /* From `ftmac.c'. */
1332 new_memory_stream( FT_Library library
,
1335 FT_Stream_CloseFunc close
,
1336 FT_Stream
*astream
)
1340 FT_Stream stream
= NULL
;
1344 return FT_THROW( Invalid_Library_Handle
);
1347 return FT_THROW( Invalid_Argument
);
1350 memory
= library
->memory
;
1351 if ( FT_NEW( stream
) )
1354 FT_Stream_OpenMemory( stream
, base
, size
);
1356 stream
->close
= close
;
1365 /* Create a new FT_Face given a buffer and a driver name. */
1366 /* From `ftmac.c'. */
1367 FT_LOCAL_DEF( FT_Error
)
1368 open_face_from_buffer( FT_Library library
,
1372 const char* driver_name
,
1377 FT_Stream stream
= NULL
;
1378 FT_Memory memory
= library
->memory
;
1381 error
= new_memory_stream( library
,
1384 memory_stream_close
,
1392 args
.flags
= FT_OPEN_STREAM
;
1393 args
.stream
= stream
;
1396 args
.flags
= args
.flags
| FT_OPEN_DRIVER
;
1397 args
.driver
= FT_Get_Module( library
, driver_name
);
1401 /* At this point, the face index has served its purpose; */
1402 /* whoever calls this function has already used it to */
1403 /* locate the correct font data. We should not propagate */
1404 /* this index to FT_Open_Face() (unless it is negative). */
1406 if ( face_index
> 0 )
1407 face_index
&= 0x7FFF0000L
; /* retain GX data */
1410 error
= ft_open_face_internal( library
, &args
, face_index
, aface
, 0 );
1413 (*aface
)->face_flags
&= ~FT_FACE_FLAG_EXTERNAL_STREAM
;
1416 FT_Stream_Free( stream
, 0 );
1419 FT_Stream_Close( stream
);
1428 /* Look up `TYP1' or `CID ' table from sfnt table directory. */
1429 /* `offset' and `length' must exclude the binary header in tables. */
1431 /* Type 1 and CID-keyed font drivers should recognize sfnt-wrapped */
1432 /* format too. Here, since we can't expect that the TrueType font */
1433 /* driver is loaded unconditionally, we must parse the font by */
1434 /* ourselves. We are only interested in the name of the table and */
1438 ft_lookup_PS_in_sfnt_stream( FT_Stream stream
,
1442 FT_Bool
* is_sfnt_cid
)
1445 FT_UShort numTables
;
1446 FT_Long pstable_index
;
1453 *is_sfnt_cid
= FALSE
;
1455 /* TODO: support for sfnt-wrapped PS/CID in TTC format */
1457 /* version check for 'typ1' (should be ignored?) */
1458 if ( FT_READ_ULONG( tag
) )
1460 if ( tag
!= TTAG_typ1
)
1461 return FT_THROW( Unknown_File_Format
);
1463 if ( FT_READ_USHORT( numTables
) )
1465 if ( FT_STREAM_SKIP( 2 * 3 ) ) /* skip binary search header */
1469 *is_sfnt_cid
= FALSE
;
1471 for ( i
= 0; i
< numTables
; i
++ )
1473 if ( FT_READ_ULONG( tag
) || FT_STREAM_SKIP( 4 ) ||
1474 FT_READ_ULONG( *offset
) || FT_READ_ULONG( *length
) )
1477 if ( tag
== TTAG_CID
)
1482 *is_sfnt_cid
= TRUE
;
1483 if ( face_index
< 0 )
1486 else if ( tag
== TTAG_TYP1
)
1491 *is_sfnt_cid
= FALSE
;
1492 if ( face_index
< 0 )
1495 if ( face_index
>= 0 && pstable_index
== face_index
)
1499 return FT_THROW( Table_Missing
);
1503 FT_LOCAL_DEF( FT_Error
)
1504 open_face_PS_from_sfnt_stream( FT_Library library
,
1508 FT_Parameter
*params
,
1512 FT_Memory memory
= library
->memory
;
1513 FT_ULong offset
, length
;
1515 FT_Bool is_sfnt_cid
;
1516 FT_Byte
* sfnt_ps
= NULL
;
1518 FT_UNUSED( num_params
);
1519 FT_UNUSED( params
);
1522 /* ignore GX stuff */
1523 if ( face_index
> 0 )
1524 face_index
&= 0xFFFFL
;
1526 pos
= FT_STREAM_POS();
1528 error
= ft_lookup_PS_in_sfnt_stream( stream
,
1536 if ( offset
> stream
->size
)
1538 FT_TRACE2(( "open_face_PS_from_sfnt_stream: invalid table offset\n" ));
1539 error
= FT_THROW( Invalid_Table
);
1542 else if ( length
> stream
->size
- offset
)
1544 FT_TRACE2(( "open_face_PS_from_sfnt_stream: invalid table length\n" ));
1545 error
= FT_THROW( Invalid_Table
);
1549 error
= FT_Stream_Seek( stream
, pos
+ offset
);
1553 if ( FT_ALLOC( sfnt_ps
, (FT_Long
)length
) )
1556 error
= FT_Stream_Read( stream
, (FT_Byte
*)sfnt_ps
, length
);
1563 error
= open_face_from_buffer( library
,
1566 FT_MIN( face_index
, 0 ),
1567 is_sfnt_cid
? "cid" : "type1",
1574 if ( FT_ERR_EQ( error
, Unknown_File_Format
) )
1576 error1
= FT_Stream_Seek( stream
, pos
);
1586 #ifndef FT_MACINTOSH
1588 /* The resource header says we've got resource_cnt `POST' (type1) */
1589 /* resources in this file. They all need to be coalesced into */
1590 /* one lump which gets passed on to the type1 driver. */
1591 /* Here can be only one PostScript font in a file so face_index */
1592 /* must be 0 (or -1). */
1595 Mac_Read_POST_Resource( FT_Library library
,
1598 FT_Long resource_cnt
,
1602 FT_Error error
= FT_ERR( Cannot_Open_Resource
);
1603 FT_Memory memory
= library
->memory
;
1605 FT_Byte
* pfb_data
= NULL
;
1608 FT_ULong pfb_len
, pfb_pos
, pfb_lenpos
;
1609 FT_ULong rlen
, temp
;
1612 if ( face_index
== -1 )
1614 if ( face_index
!= 0 )
1617 /* Find the length of all the POST resources, concatenated. Assume */
1618 /* worst case (each resource in its own section). */
1620 for ( i
= 0; i
< resource_cnt
; i
++ )
1622 error
= FT_Stream_Seek( stream
, (FT_ULong
)offsets
[i
] );
1625 if ( FT_READ_ULONG( temp
) ) /* actually LONG */
1628 /* FT2 allocator takes signed long buffer length,
1629 * too large value causing overflow should be checked
1631 FT_TRACE4(( " POST fragment #%d: length=0x%08x"
1632 " total pfb_len=0x%08x\n",
1633 i
, temp
, pfb_len
+ temp
+ 6 ));
1635 if ( FT_MAC_RFORK_MAX_LEN
< temp
||
1636 FT_MAC_RFORK_MAX_LEN
- temp
< pfb_len
+ 6 )
1638 FT_TRACE2(( " MacOS resource length cannot exceed"
1640 FT_MAC_RFORK_MAX_LEN
));
1642 error
= FT_THROW( Invalid_Offset
);
1646 pfb_len
+= temp
+ 6;
1649 FT_TRACE2(( " total buffer size to concatenate"
1650 " %d POST fragments: 0x%08x\n",
1651 resource_cnt
, pfb_len
+ 2 ));
1653 if ( pfb_len
+ 2 < 6 )
1655 FT_TRACE2(( " too long fragment length makes"
1656 " pfb_len confused: pfb_len=0x%08x\n",
1659 error
= FT_THROW( Array_Too_Large
);
1663 if ( FT_ALLOC( pfb_data
, (FT_Long
)pfb_len
+ 2 ) )
1667 pfb_data
[1] = 1; /* Ascii section */
1668 pfb_data
[2] = 0; /* 4-byte length, fill in later */
1678 for ( i
= 0; i
< resource_cnt
; i
++ )
1680 error
= FT_Stream_Seek( stream
, (FT_ULong
)offsets
[i
] );
1683 if ( FT_READ_ULONG( rlen
) )
1686 /* FT2 allocator takes signed long buffer length,
1687 * too large fragment length causing overflow should be checked
1689 if ( 0x7FFFFFFFUL
< rlen
)
1691 error
= FT_THROW( Invalid_Offset
);
1695 if ( FT_READ_USHORT( flags
) )
1698 FT_TRACE3(( "POST fragment[%d]:"
1699 " offsets=0x%08x, rlen=0x%08x, flags=0x%04x\n",
1700 i
, offsets
[i
], rlen
, flags
));
1702 error
= FT_ERR( Array_Too_Large
);
1704 /* postpone the check of `rlen longer than buffer' */
1705 /* until `FT_Stream_Read' */
1707 if ( ( flags
>> 8 ) == 0 ) /* Comment, should not be loaded */
1709 FT_TRACE3(( " Skip POST fragment #%d because it is a comment\n",
1714 /* the flags are part of the resource, so rlen >= 2, */
1715 /* but some fonts declare rlen = 0 for empty fragment */
1721 if ( ( flags
>> 8 ) == type
)
1725 FT_TRACE3(( " Write POST fragment #%d header (4-byte) to buffer"
1727 i
, pfb_data
, pfb_lenpos
));
1729 if ( pfb_lenpos
+ 3 > pfb_len
+ 2 )
1732 pfb_data
[pfb_lenpos
] = (FT_Byte
)( len
);
1733 pfb_data
[pfb_lenpos
+ 1] = (FT_Byte
)( len
>> 8 );
1734 pfb_data
[pfb_lenpos
+ 2] = (FT_Byte
)( len
>> 16 );
1735 pfb_data
[pfb_lenpos
+ 3] = (FT_Byte
)( len
>> 24 );
1737 if ( ( flags
>> 8 ) == 5 ) /* End of font mark */
1740 FT_TRACE3(( " Write POST fragment #%d header (6-byte) to buffer"
1742 i
, pfb_data
, pfb_pos
));
1744 if ( pfb_pos
+ 6 > pfb_len
+ 2 )
1747 pfb_data
[pfb_pos
++] = 0x80;
1752 pfb_data
[pfb_pos
++] = (FT_Byte
)type
;
1753 pfb_lenpos
= pfb_pos
;
1754 pfb_data
[pfb_pos
++] = 0; /* 4-byte length, fill in later */
1755 pfb_data
[pfb_pos
++] = 0;
1756 pfb_data
[pfb_pos
++] = 0;
1757 pfb_data
[pfb_pos
++] = 0;
1760 if ( pfb_pos
> pfb_len
|| pfb_pos
+ rlen
> pfb_len
)
1763 FT_TRACE3(( " Load POST fragment #%d (%d byte) to buffer"
1765 i
, rlen
, pfb_data
, pfb_pos
));
1767 error
= FT_Stream_Read( stream
, (FT_Byte
*)pfb_data
+ pfb_pos
, rlen
);
1774 error
= FT_ERR( Array_Too_Large
);
1776 if ( pfb_pos
+ 2 > pfb_len
+ 2 )
1778 pfb_data
[pfb_pos
++] = 0x80;
1779 pfb_data
[pfb_pos
++] = 3;
1781 if ( pfb_lenpos
+ 3 > pfb_len
+ 2 )
1783 pfb_data
[pfb_lenpos
] = (FT_Byte
)( len
);
1784 pfb_data
[pfb_lenpos
+ 1] = (FT_Byte
)( len
>> 8 );
1785 pfb_data
[pfb_lenpos
+ 2] = (FT_Byte
)( len
>> 16 );
1786 pfb_data
[pfb_lenpos
+ 3] = (FT_Byte
)( len
>> 24 );
1788 return open_face_from_buffer( library
,
1796 if ( FT_ERR_EQ( error
, Array_Too_Large
) )
1797 FT_TRACE2(( " Abort due to too-short buffer to store"
1798 " all POST fragments\n" ));
1799 else if ( FT_ERR_EQ( error
, Invalid_Offset
) )
1800 FT_TRACE2(( " Abort due to invalid offset in a POST fragment\n" ));
1803 error
= FT_ERR( Cannot_Open_Resource
);
1804 FT_FREE( pfb_data
);
1811 /* The resource header says we've got resource_cnt `sfnt' */
1812 /* (TrueType/OpenType) resources in this file. Look through */
1813 /* them for the one indicated by face_index, load it into mem, */
1814 /* pass it on to the truetype driver, and return it. */
1817 Mac_Read_sfnt_Resource( FT_Library library
,
1820 FT_Long resource_cnt
,
1824 FT_Memory memory
= library
->memory
;
1825 FT_Byte
* sfnt_data
= NULL
;
1827 FT_ULong flag_offset
;
1830 FT_Long face_index_in_resource
= 0;
1833 if ( face_index
< 0 )
1834 face_index
= -face_index
- 1;
1835 if ( face_index
>= resource_cnt
)
1836 return FT_THROW( Cannot_Open_Resource
);
1838 flag_offset
= (FT_ULong
)offsets
[face_index
];
1839 error
= FT_Stream_Seek( stream
, flag_offset
);
1843 if ( FT_READ_LONG( rlen
) )
1846 return FT_THROW( Cannot_Open_Resource
);
1847 if ( (FT_ULong
)rlen
> FT_MAC_RFORK_MAX_LEN
)
1848 return FT_THROW( Invalid_Offset
);
1850 error
= open_face_PS_from_sfnt_stream( library
,
1858 /* rewind sfnt stream before open_face_PS_from_sfnt_stream() */
1859 error
= FT_Stream_Seek( stream
, flag_offset
+ 4 );
1863 if ( FT_ALLOC( sfnt_data
, rlen
) )
1865 error
= FT_Stream_Read( stream
, (FT_Byte
*)sfnt_data
, (FT_ULong
)rlen
);
1867 FT_FREE( sfnt_data
);
1871 is_cff
= rlen
> 4 && !ft_memcmp( sfnt_data
, "OTTO", 4 );
1872 error
= open_face_from_buffer( library
,
1875 face_index_in_resource
,
1876 is_cff
? "cff" : "truetype",
1884 /* Check for a valid resource fork header, or a valid dfont */
1885 /* header. In a resource fork the first 16 bytes are repeated */
1886 /* at the location specified by bytes 4-7. In a dfont bytes */
1887 /* 4-7 point to 16 bytes of zeroes instead. */
1890 IsMacResource( FT_Library library
,
1892 FT_Long resource_offset
,
1896 FT_Memory memory
= library
->memory
;
1898 FT_Long map_offset
, rdata_pos
;
1899 FT_Long
*data_offsets
;
1903 error
= FT_Raccess_Get_HeaderInfo( library
, stream
, resource_offset
,
1904 &map_offset
, &rdata_pos
);
1908 /* POST resources must be sorted to concatenate properly */
1909 error
= FT_Raccess_Get_DataOffsets( library
, stream
,
1910 map_offset
, rdata_pos
,
1912 &data_offsets
, &count
);
1915 error
= Mac_Read_POST_Resource( library
, stream
, data_offsets
, count
,
1916 face_index
, aface
);
1917 FT_FREE( data_offsets
);
1918 /* POST exists in an LWFN providing a single face */
1920 (*aface
)->num_faces
= 1;
1924 /* sfnt resources should not be sorted to preserve the face order by
1926 error
= FT_Raccess_Get_DataOffsets( library
, stream
,
1927 map_offset
, rdata_pos
,
1929 &data_offsets
, &count
);
1932 FT_Long face_index_internal
= face_index
% count
;
1935 error
= Mac_Read_sfnt_Resource( library
, stream
, data_offsets
, count
,
1936 face_index_internal
, aface
);
1937 FT_FREE( data_offsets
);
1939 (*aface
)->num_faces
= count
;
1946 /* Check for a valid macbinary header, and if we find one */
1947 /* check that the (flattened) resource fork in it is valid. */
1950 IsMacBinary( FT_Library library
,
1955 unsigned char header
[128];
1957 FT_Long dlen
, offset
;
1961 return FT_THROW( Invalid_Stream_Operation
);
1963 error
= FT_Stream_Seek( stream
, 0 );
1967 error
= FT_Stream_Read( stream
, (FT_Byte
*)header
, 128 );
1971 if ( header
[ 0] != 0 ||
1977 header
[2 + header
[1]] != 0 ||
1978 header
[0x53] > 0x7F )
1979 return FT_THROW( Unknown_File_Format
);
1981 dlen
= ( header
[0x53] << 24 ) |
1982 ( header
[0x54] << 16 ) |
1983 ( header
[0x55] << 8 ) |
1986 rlen
= ( header
[0x57] << 24 ) |
1987 ( header
[0x58] << 16 ) |
1988 ( header
[0x59] << 8 ) |
1991 offset
= 128 + ( ( dlen
+ 127 ) & ~127 );
1993 return IsMacResource( library
, stream
, offset
, face_index
, aface
);
2001 load_face_in_embedded_rfork( FT_Library library
,
2005 const FT_Open_Args
*args
)
2009 #define FT_COMPONENT trace_raccess
2011 FT_Memory memory
= library
->memory
;
2012 FT_Error error
= FT_ERR( Unknown_File_Format
);
2015 char * file_names
[FT_RACCESS_N_RULES
];
2016 FT_Long offsets
[FT_RACCESS_N_RULES
];
2017 FT_Error errors
[FT_RACCESS_N_RULES
];
2018 FT_Bool is_darwin_vfs
, vfs_rfork_has_no_font
= FALSE
; /* not tested */
2021 FT_Stream stream2
= NULL
;
2024 FT_Raccess_Guess( library
, stream
,
2025 args
->pathname
, file_names
, offsets
, errors
);
2027 for ( i
= 0; i
< FT_RACCESS_N_RULES
; i
++ )
2029 is_darwin_vfs
= ft_raccess_rule_by_darwin_vfs( library
, i
);
2030 if ( is_darwin_vfs
&& vfs_rfork_has_no_font
)
2032 FT_TRACE3(( "Skip rule %d: darwin vfs resource fork"
2033 " is already checked and"
2034 " no font is found\n", i
));
2040 FT_TRACE3(( "Error[%d] has occurred in rule %d\n", errors
[i
], i
));
2044 args2
.flags
= FT_OPEN_PATHNAME
;
2045 args2
.pathname
= file_names
[i
] ? file_names
[i
] : args
->pathname
;
2047 FT_TRACE3(( "Try rule %d: %s (offset=%d) ...",
2048 i
, args2
.pathname
, offsets
[i
] ));
2050 error
= FT_Stream_New( library
, &args2
, &stream2
);
2051 if ( is_darwin_vfs
&& FT_ERR_EQ( error
, Cannot_Open_Stream
) )
2052 vfs_rfork_has_no_font
= TRUE
;
2056 FT_TRACE3(( "failed\n" ));
2060 error
= IsMacResource( library
, stream2
, offsets
[i
],
2061 face_index
, aface
);
2062 FT_Stream_Free( stream2
, 0 );
2064 FT_TRACE3(( "%s\n", error
? "failed": "successful" ));
2068 else if ( is_darwin_vfs
)
2069 vfs_rfork_has_no_font
= TRUE
;
2072 for (i
= 0; i
< FT_RACCESS_N_RULES
; i
++)
2074 if ( file_names
[i
] )
2075 FT_FREE( file_names
[i
] );
2078 /* Caller (load_mac_face) requires FT_Err_Unknown_File_Format. */
2080 error
= FT_ERR( Unknown_File_Format
);
2085 #define FT_COMPONENT trace_objs
2090 /* Check for some macintosh formats without Carbon framework. */
2091 /* Is this a macbinary file? If so look at the resource fork. */
2092 /* Is this a mac dfont file? */
2093 /* Is this an old style resource fork? (in data) */
2094 /* Else call load_face_in_embedded_rfork to try extra rules */
2095 /* (defined in `ftrfork.c'). */
2098 load_mac_face( FT_Library library
,
2102 const FT_Open_Args
*args
)
2108 error
= IsMacBinary( library
, stream
, face_index
, aface
);
2109 if ( FT_ERR_EQ( error
, Unknown_File_Format
) )
2113 #define FT_COMPONENT trace_raccess
2115 #ifdef FT_DEBUG_LEVEL_TRACE
2116 FT_TRACE3(( "Try as dfont: " ));
2117 if ( !( args
->flags
& FT_OPEN_MEMORY
) )
2118 FT_TRACE3(( "%s ...", args
->pathname
));
2121 error
= IsMacResource( library
, stream
, 0, face_index
, aface
);
2123 FT_TRACE3(( "%s\n", error
? "failed" : "successful" ));
2126 #define FT_COMPONENT trace_objs
2130 if ( ( FT_ERR_EQ( error
, Unknown_File_Format
) ||
2131 FT_ERR_EQ( error
, Invalid_Stream_Operation
) ) &&
2132 ( args
->flags
& FT_OPEN_PATHNAME
) )
2133 error
= load_face_in_embedded_rfork( library
, stream
,
2134 face_index
, aface
, args
);
2139 #endif /* !FT_MACINTOSH && FT_CONFIG_OPTION_MAC_FONTS */
2142 /* documentation is in freetype.h */
2144 FT_EXPORT_DEF( FT_Error
)
2145 FT_Open_Face( FT_Library library
,
2146 const FT_Open_Args
* args
,
2150 return ft_open_face_internal( library
, args
, face_index
, aface
, 1 );
2155 ft_open_face_internal( FT_Library library
,
2156 const FT_Open_Args
* args
,
2159 FT_Bool test_mac_fonts
)
2162 FT_Driver driver
= NULL
;
2163 FT_Memory memory
= NULL
;
2164 FT_Stream stream
= NULL
;
2165 FT_Face face
= NULL
;
2166 FT_ListNode node
= NULL
;
2167 FT_Bool external_stream
;
2171 #ifndef FT_CONFIG_OPTION_MAC_FONTS
2172 FT_UNUSED( test_mac_fonts
);
2176 #ifdef FT_DEBUG_LEVEL_TRACE
2177 FT_TRACE3(( "FT_Open_Face: " ));
2178 if ( face_index
< 0 )
2179 FT_TRACE3(( "Requesting number of faces and named instances\n"));
2182 FT_TRACE3(( "Requesting face %ld", face_index
& 0xFFFFL
));
2183 if ( face_index
& 0x7FFF0000L
)
2184 FT_TRACE3(( ", named instance %ld", face_index
>> 16 ));
2185 FT_TRACE3(( "\n" ));
2189 /* test for valid `library' delayed to `FT_Stream_New' */
2191 if ( ( !aface
&& face_index
>= 0 ) || !args
)
2192 return FT_THROW( Invalid_Argument
);
2194 external_stream
= FT_BOOL( ( args
->flags
& FT_OPEN_STREAM
) &&
2197 /* create input stream */
2198 error
= FT_Stream_New( library
, args
, &stream
);
2202 memory
= library
->memory
;
2204 /* If the font driver is specified in the `args' structure, use */
2205 /* it. Otherwise, we scan the list of registered drivers. */
2206 if ( ( args
->flags
& FT_OPEN_DRIVER
) && args
->driver
)
2208 driver
= FT_DRIVER( args
->driver
);
2210 /* not all modules are drivers, so check... */
2211 if ( FT_MODULE_IS_DRIVER( driver
) )
2213 FT_Int num_params
= 0;
2214 FT_Parameter
* params
= NULL
;
2217 if ( args
->flags
& FT_OPEN_PARAMS
)
2219 num_params
= args
->num_params
;
2220 params
= args
->params
;
2223 error
= open_face( driver
, &stream
, external_stream
, face_index
,
2224 num_params
, params
, &face
);
2229 error
= FT_THROW( Invalid_Handle
);
2231 FT_Stream_Free( stream
, external_stream
);
2236 error
= FT_ERR( Missing_Module
);
2238 /* check each font driver for an appropriate format */
2239 cur
= library
->modules
;
2240 limit
= cur
+ library
->num_modules
;
2242 for ( ; cur
< limit
; cur
++ )
2244 /* not all modules are font drivers, so check... */
2245 if ( FT_MODULE_IS_DRIVER( cur
[0] ) )
2247 FT_Int num_params
= 0;
2248 FT_Parameter
* params
= NULL
;
2251 driver
= FT_DRIVER( cur
[0] );
2253 if ( args
->flags
& FT_OPEN_PARAMS
)
2255 num_params
= args
->num_params
;
2256 params
= args
->params
;
2259 error
= open_face( driver
, &stream
, external_stream
, face_index
,
2260 num_params
, params
, &face
);
2264 #ifdef FT_CONFIG_OPTION_MAC_FONTS
2265 if ( test_mac_fonts
&&
2266 ft_strcmp( cur
[0]->clazz
->module_name
, "truetype" ) == 0 &&
2267 FT_ERR_EQ( error
, Table_Missing
) )
2269 /* TrueType but essential tables are missing */
2270 error
= FT_Stream_Seek( stream
, 0 );
2274 error
= open_face_PS_from_sfnt_stream( library
,
2282 FT_Stream_Free( stream
, external_stream
);
2288 if ( FT_ERR_NEQ( error
, Unknown_File_Format
) )
2294 /* If we are on the mac, and we get an */
2295 /* FT_Err_Invalid_Stream_Operation it may be because we have an */
2296 /* empty data fork, so we need to check the resource fork. */
2297 if ( FT_ERR_NEQ( error
, Cannot_Open_Stream
) &&
2298 FT_ERR_NEQ( error
, Unknown_File_Format
) &&
2299 FT_ERR_NEQ( error
, Invalid_Stream_Operation
) )
2302 #if !defined( FT_MACINTOSH ) && defined( FT_CONFIG_OPTION_MAC_FONTS )
2303 if ( test_mac_fonts
)
2305 error
= load_mac_face( library
, stream
, face_index
, aface
, args
);
2308 /* We don't want to go to Success here. We've already done */
2309 /* that. On the other hand, if we succeeded we still need to */
2310 /* close this stream (we opened a different stream which */
2311 /* extracted the interesting information out of this stream */
2312 /* here. That stream will still be open and the face will */
2314 FT_Stream_Free( stream
, external_stream
);
2319 if ( FT_ERR_NEQ( error
, Unknown_File_Format
) )
2321 #endif /* !FT_MACINTOSH && FT_CONFIG_OPTION_MAC_FONTS */
2323 /* no driver is able to handle this format */
2324 error
= FT_THROW( Unknown_File_Format
);
2327 FT_Stream_Free( stream
, external_stream
);
2332 FT_TRACE4(( "FT_Open_Face: New face object, adding to list\n" ));
2334 /* add the face object to its driver's list */
2335 if ( FT_NEW( node
) )
2339 /* don't assume driver is the same as face->driver, so use */
2340 /* face->driver instead. */
2341 FT_List_Add( &face
->driver
->faces_list
, node
);
2343 /* now allocate a glyph slot object for the face */
2344 FT_TRACE4(( "FT_Open_Face: Creating glyph slot\n" ));
2346 if ( face_index
>= 0 )
2348 error
= FT_New_GlyphSlot( face
, NULL
);
2352 /* finally, allocate a size object for the face */
2357 FT_TRACE4(( "FT_Open_Face: Creating size object\n" ));
2359 error
= FT_New_Size( face
, &size
);
2369 if ( FT_IS_SCALABLE( face
) )
2371 if ( face
->height
< 0 )
2372 face
->height
= (FT_Short
)-face
->height
;
2374 if ( !FT_HAS_VERTICAL( face
) )
2375 face
->max_advance_height
= (FT_Short
)face
->height
;
2378 if ( FT_HAS_FIXED_SIZES( face
) )
2383 for ( i
= 0; i
< face
->num_fixed_sizes
; i
++ )
2385 FT_Bitmap_Size
* bsize
= face
->available_sizes
+ i
;
2388 if ( bsize
->height
< 0 )
2389 bsize
->height
= -bsize
->height
;
2390 if ( bsize
->x_ppem
< 0 )
2391 bsize
->x_ppem
= -bsize
->x_ppem
;
2392 if ( bsize
->y_ppem
< 0 )
2393 bsize
->y_ppem
= -bsize
->y_ppem
;
2395 /* check whether negation actually has worked */
2396 if ( bsize
->height
< 0 || bsize
->x_ppem
< 0 || bsize
->y_ppem
< 0 )
2398 FT_TRACE0(( "FT_Open_Face:"
2399 " Invalid bitmap dimensions for stroke %d,"
2400 " now disabled\n", i
));
2410 /* initialize internal face data */
2412 FT_Face_Internal internal
= face
->internal
;
2415 internal
->transform_matrix
.xx
= 0x10000L
;
2416 internal
->transform_matrix
.xy
= 0;
2417 internal
->transform_matrix
.yx
= 0;
2418 internal
->transform_matrix
.yy
= 0x10000L
;
2420 internal
->transform_delta
.x
= 0;
2421 internal
->transform_delta
.y
= 0;
2423 internal
->refcount
= 1;
2429 FT_Done_Face( face
);
2435 FT_Done_Face( face
); /* face must be in the driver's list */
2437 destroy_face( memory
, face
, driver
);
2440 #ifdef FT_DEBUG_LEVEL_TRACE
2441 if ( !error
&& face_index
< 0 )
2443 FT_TRACE3(( "FT_Open_Face: The font has %ld faces\n"
2444 " and %ld named instances for face %ld\n",
2446 face
->style_flags
>> 16,
2451 FT_TRACE4(( "FT_Open_Face: Return %d\n", error
));
2457 /* documentation is in freetype.h */
2459 FT_EXPORT_DEF( FT_Error
)
2460 FT_Attach_File( FT_Face face
,
2461 const char* filepathname
)
2466 /* test for valid `face' delayed to `FT_Attach_Stream' */
2468 if ( !filepathname
)
2469 return FT_THROW( Invalid_Argument
);
2472 open
.flags
= FT_OPEN_PATHNAME
;
2473 open
.pathname
= (char*)filepathname
;
2475 return FT_Attach_Stream( face
, &open
);
2479 /* documentation is in freetype.h */
2481 FT_EXPORT_DEF( FT_Error
)
2482 FT_Attach_Stream( FT_Face face
,
2483 FT_Open_Args
* parameters
)
2489 FT_Driver_Class clazz
;
2492 /* test for valid `parameters' delayed to `FT_Stream_New' */
2495 return FT_THROW( Invalid_Face_Handle
);
2497 driver
= face
->driver
;
2499 return FT_THROW( Invalid_Driver_Handle
);
2501 error
= FT_Stream_New( driver
->root
.library
, parameters
, &stream
);
2505 /* we implement FT_Attach_Stream in each driver through the */
2506 /* `attach_file' interface */
2508 error
= FT_ERR( Unimplemented_Feature
);
2509 clazz
= driver
->clazz
;
2510 if ( clazz
->attach_file
)
2511 error
= clazz
->attach_file( face
, stream
);
2513 /* close the attached stream */
2514 FT_Stream_Free( stream
,
2515 (FT_Bool
)( parameters
->stream
&&
2516 ( parameters
->flags
& FT_OPEN_STREAM
) ) );
2523 /* documentation is in freetype.h */
2525 FT_EXPORT_DEF( FT_Error
)
2526 FT_Reference_Face( FT_Face face
)
2529 return FT_THROW( Invalid_Face_Handle
);
2531 face
->internal
->refcount
++;
2537 /* documentation is in freetype.h */
2539 FT_EXPORT_DEF( FT_Error
)
2540 FT_Done_Face( FT_Face face
)
2548 error
= FT_ERR( Invalid_Face_Handle
);
2549 if ( face
&& face
->driver
)
2551 face
->internal
->refcount
--;
2552 if ( face
->internal
->refcount
> 0 )
2556 driver
= face
->driver
;
2557 memory
= driver
->root
.memory
;
2559 /* find face in driver's list */
2560 node
= FT_List_Find( &driver
->faces_list
, face
);
2563 /* remove face object from the driver's list */
2564 FT_List_Remove( &driver
->faces_list
, node
);
2567 /* now destroy the object proper */
2568 destroy_face( memory
, face
, driver
);
2578 /* documentation is in ftobjs.h */
2580 FT_EXPORT_DEF( FT_Error
)
2581 FT_New_Size( FT_Face face
,
2587 FT_Driver_Class clazz
;
2589 FT_Size size
= NULL
;
2590 FT_ListNode node
= NULL
;
2594 return FT_THROW( Invalid_Face_Handle
);
2597 return FT_THROW( Invalid_Argument
);
2599 if ( !face
->driver
)
2600 return FT_THROW( Invalid_Driver_Handle
);
2604 driver
= face
->driver
;
2605 clazz
= driver
->clazz
;
2606 memory
= face
->memory
;
2608 /* Allocate new size object and perform basic initialisation */
2609 if ( FT_ALLOC( size
, clazz
->size_object_size
) || FT_NEW( node
) )
2614 /* for now, do not use any internal fields in size objects */
2615 size
->internal
= NULL
;
2617 if ( clazz
->init_size
)
2618 error
= clazz
->init_size( size
);
2620 /* in case of success, add to the face's list */
2625 FT_List_Add( &face
->sizes_list
, node
);
2639 /* documentation is in ftobjs.h */
2641 FT_EXPORT_DEF( FT_Error
)
2642 FT_Done_Size( FT_Size size
)
2652 return FT_THROW( Invalid_Size_Handle
);
2656 return FT_THROW( Invalid_Face_Handle
);
2658 driver
= face
->driver
;
2660 return FT_THROW( Invalid_Driver_Handle
);
2662 memory
= driver
->root
.memory
;
2665 node
= FT_List_Find( &face
->sizes_list
, size
);
2668 FT_List_Remove( &face
->sizes_list
, node
);
2671 if ( face
->size
== size
)
2674 if ( face
->sizes_list
.head
)
2675 face
->size
= (FT_Size
)(face
->sizes_list
.head
->data
);
2678 destroy_size( memory
, size
, driver
);
2681 error
= FT_THROW( Invalid_Size_Handle
);
2687 /* documentation is in ftobjs.h */
2689 FT_BASE_DEF( FT_Error
)
2690 FT_Match_Size( FT_Face face
,
2691 FT_Size_Request req
,
2692 FT_Bool ignore_width
,
2693 FT_ULong
* size_index
)
2699 if ( !FT_HAS_FIXED_SIZES( face
) )
2700 return FT_THROW( Invalid_Face_Handle
);
2702 /* FT_Bitmap_Size doesn't provide enough info... */
2703 if ( req
->type
!= FT_SIZE_REQUEST_TYPE_NOMINAL
)
2704 return FT_THROW( Unimplemented_Feature
);
2706 w
= FT_REQUEST_WIDTH ( req
);
2707 h
= FT_REQUEST_HEIGHT( req
);
2709 if ( req
->width
&& !req
->height
)
2711 else if ( !req
->width
&& req
->height
)
2714 w
= FT_PIX_ROUND( w
);
2715 h
= FT_PIX_ROUND( h
);
2718 return FT_THROW( Invalid_Pixel_Size
);
2720 for ( i
= 0; i
< face
->num_fixed_sizes
; i
++ )
2722 FT_Bitmap_Size
* bsize
= face
->available_sizes
+ i
;
2725 if ( h
!= FT_PIX_ROUND( bsize
->y_ppem
) )
2728 if ( w
== FT_PIX_ROUND( bsize
->x_ppem
) || ignore_width
)
2730 FT_TRACE3(( "FT_Match_Size: bitmap strike %d matches\n", i
));
2733 *size_index
= (FT_ULong
)i
;
2739 FT_TRACE3(( "FT_Match_Size: no matching bitmap strike\n" ));
2741 return FT_THROW( Invalid_Pixel_Size
);
2745 /* documentation is in ftobjs.h */
2748 ft_synthesize_vertical_metrics( FT_Glyph_Metrics
* metrics
,
2751 FT_Pos height
= metrics
->height
;
2754 /* compensate for glyph with bbox above/below the baseline */
2755 if ( metrics
->horiBearingY
< 0 )
2757 if ( height
< metrics
->horiBearingY
)
2758 height
= metrics
->horiBearingY
;
2760 else if ( metrics
->horiBearingY
> 0 )
2761 height
-= metrics
->horiBearingY
;
2763 /* the factor 1.2 is a heuristical value */
2765 advance
= height
* 12 / 10;
2767 metrics
->vertBearingX
= metrics
->horiBearingX
- metrics
->horiAdvance
/ 2;
2768 metrics
->vertBearingY
= ( advance
- height
) / 2;
2769 metrics
->vertAdvance
= advance
;
2774 ft_recompute_scaled_metrics( FT_Face face
,
2775 FT_Size_Metrics
* metrics
)
2777 /* Compute root ascender, descender, test height, and max_advance */
2779 #ifdef GRID_FIT_METRICS
2780 metrics
->ascender
= FT_PIX_CEIL( FT_MulFix( face
->ascender
,
2781 metrics
->y_scale
) );
2783 metrics
->descender
= FT_PIX_FLOOR( FT_MulFix( face
->descender
,
2784 metrics
->y_scale
) );
2786 metrics
->height
= FT_PIX_ROUND( FT_MulFix( face
->height
,
2787 metrics
->y_scale
) );
2789 metrics
->max_advance
= FT_PIX_ROUND( FT_MulFix( face
->max_advance_width
,
2790 metrics
->x_scale
) );
2791 #else /* !GRID_FIT_METRICS */
2792 metrics
->ascender
= FT_MulFix( face
->ascender
,
2795 metrics
->descender
= FT_MulFix( face
->descender
,
2798 metrics
->height
= FT_MulFix( face
->height
,
2801 metrics
->max_advance
= FT_MulFix( face
->max_advance_width
,
2803 #endif /* !GRID_FIT_METRICS */
2808 FT_Select_Metrics( FT_Face face
,
2809 FT_ULong strike_index
)
2811 FT_Size_Metrics
* metrics
;
2812 FT_Bitmap_Size
* bsize
;
2815 metrics
= &face
->size
->metrics
;
2816 bsize
= face
->available_sizes
+ strike_index
;
2818 metrics
->x_ppem
= (FT_UShort
)( ( bsize
->x_ppem
+ 32 ) >> 6 );
2819 metrics
->y_ppem
= (FT_UShort
)( ( bsize
->y_ppem
+ 32 ) >> 6 );
2821 if ( FT_IS_SCALABLE( face
) )
2823 metrics
->x_scale
= FT_DivFix( bsize
->x_ppem
,
2824 face
->units_per_EM
);
2825 metrics
->y_scale
= FT_DivFix( bsize
->y_ppem
,
2826 face
->units_per_EM
);
2828 ft_recompute_scaled_metrics( face
, metrics
);
2832 metrics
->x_scale
= 1L << 16;
2833 metrics
->y_scale
= 1L << 16;
2834 metrics
->ascender
= bsize
->y_ppem
;
2835 metrics
->descender
= 0;
2836 metrics
->height
= bsize
->height
<< 6;
2837 metrics
->max_advance
= bsize
->x_ppem
;
2840 FT_TRACE5(( "FT_Select_Metrics:\n" ));
2841 FT_TRACE5(( " x scale: %d (%f)\n",
2842 metrics
->x_scale
, metrics
->x_scale
/ 65536.0 ));
2843 FT_TRACE5(( " y scale: %d (%f)\n",
2844 metrics
->y_scale
, metrics
->y_scale
/ 65536.0 ));
2845 FT_TRACE5(( " ascender: %f\n", metrics
->ascender
/ 64.0 ));
2846 FT_TRACE5(( " descender: %f\n", metrics
->descender
/ 64.0 ));
2847 FT_TRACE5(( " height: %f\n", metrics
->height
/ 64.0 ));
2848 FT_TRACE5(( " max advance: %f\n", metrics
->max_advance
/ 64.0 ));
2849 FT_TRACE5(( " x ppem: %d\n", metrics
->x_ppem
));
2850 FT_TRACE5(( " y ppem: %d\n", metrics
->y_ppem
));
2855 FT_Request_Metrics( FT_Face face
,
2856 FT_Size_Request req
)
2858 FT_Size_Metrics
* metrics
;
2861 metrics
= &face
->size
->metrics
;
2863 if ( FT_IS_SCALABLE( face
) )
2865 FT_Long w
= 0, h
= 0, scaled_w
= 0, scaled_h
= 0;
2868 switch ( req
->type
)
2870 case FT_SIZE_REQUEST_TYPE_NOMINAL
:
2871 w
= h
= face
->units_per_EM
;
2874 case FT_SIZE_REQUEST_TYPE_REAL_DIM
:
2875 w
= h
= face
->ascender
- face
->descender
;
2878 case FT_SIZE_REQUEST_TYPE_BBOX
:
2879 w
= face
->bbox
.xMax
- face
->bbox
.xMin
;
2880 h
= face
->bbox
.yMax
- face
->bbox
.yMin
;
2883 case FT_SIZE_REQUEST_TYPE_CELL
:
2884 w
= face
->max_advance_width
;
2885 h
= face
->ascender
- face
->descender
;
2888 case FT_SIZE_REQUEST_TYPE_SCALES
:
2889 metrics
->x_scale
= (FT_Fixed
)req
->width
;
2890 metrics
->y_scale
= (FT_Fixed
)req
->height
;
2891 if ( !metrics
->x_scale
)
2892 metrics
->x_scale
= metrics
->y_scale
;
2893 else if ( !metrics
->y_scale
)
2894 metrics
->y_scale
= metrics
->x_scale
;
2895 goto Calculate_Ppem
;
2897 case FT_SIZE_REQUEST_TYPE_MAX
:
2901 /* to be on the safe side */
2908 scaled_w
= FT_REQUEST_WIDTH ( req
);
2909 scaled_h
= FT_REQUEST_HEIGHT( req
);
2911 /* determine scales */
2914 metrics
->x_scale
= FT_DivFix( scaled_w
, w
);
2918 metrics
->y_scale
= FT_DivFix( scaled_h
, h
);
2920 if ( req
->type
== FT_SIZE_REQUEST_TYPE_CELL
)
2922 if ( metrics
->y_scale
> metrics
->x_scale
)
2923 metrics
->y_scale
= metrics
->x_scale
;
2925 metrics
->x_scale
= metrics
->y_scale
;
2930 metrics
->y_scale
= metrics
->x_scale
;
2931 scaled_h
= FT_MulDiv( scaled_w
, h
, w
);
2936 metrics
->x_scale
= metrics
->y_scale
= FT_DivFix( scaled_h
, h
);
2937 scaled_w
= FT_MulDiv( scaled_h
, w
, h
);
2941 /* calculate the ppems */
2942 if ( req
->type
!= FT_SIZE_REQUEST_TYPE_NOMINAL
)
2944 scaled_w
= FT_MulFix( face
->units_per_EM
, metrics
->x_scale
);
2945 scaled_h
= FT_MulFix( face
->units_per_EM
, metrics
->y_scale
);
2948 metrics
->x_ppem
= (FT_UShort
)( ( scaled_w
+ 32 ) >> 6 );
2949 metrics
->y_ppem
= (FT_UShort
)( ( scaled_h
+ 32 ) >> 6 );
2951 ft_recompute_scaled_metrics( face
, metrics
);
2956 metrics
->x_scale
= 1L << 16;
2957 metrics
->y_scale
= 1L << 16;
2960 FT_TRACE5(( "FT_Request_Metrics:\n" ));
2961 FT_TRACE5(( " x scale: %d (%f)\n",
2962 metrics
->x_scale
, metrics
->x_scale
/ 65536.0 ));
2963 FT_TRACE5(( " y scale: %d (%f)\n",
2964 metrics
->y_scale
, metrics
->y_scale
/ 65536.0 ));
2965 FT_TRACE5(( " ascender: %f\n", metrics
->ascender
/ 64.0 ));
2966 FT_TRACE5(( " descender: %f\n", metrics
->descender
/ 64.0 ));
2967 FT_TRACE5(( " height: %f\n", metrics
->height
/ 64.0 ));
2968 FT_TRACE5(( " max advance: %f\n", metrics
->max_advance
/ 64.0 ));
2969 FT_TRACE5(( " x ppem: %d\n", metrics
->x_ppem
));
2970 FT_TRACE5(( " y ppem: %d\n", metrics
->y_ppem
));
2974 /* documentation is in freetype.h */
2976 FT_EXPORT_DEF( FT_Error
)
2977 FT_Select_Size( FT_Face face
,
2978 FT_Int strike_index
)
2980 FT_Driver_Class clazz
;
2983 if ( !face
|| !FT_HAS_FIXED_SIZES( face
) )
2984 return FT_THROW( Invalid_Face_Handle
);
2986 if ( strike_index
< 0 || strike_index
>= face
->num_fixed_sizes
)
2987 return FT_THROW( Invalid_Argument
);
2989 clazz
= face
->driver
->clazz
;
2991 if ( clazz
->select_size
)
2996 error
= clazz
->select_size( face
->size
, (FT_ULong
)strike_index
);
2998 #ifdef FT_DEBUG_LEVEL_TRACE
3000 FT_Size_Metrics
* metrics
= &face
->size
->metrics
;
3003 FT_TRACE5(( "FT_Select_Size (font driver's `select_size'):\n" ));
3004 FT_TRACE5(( " x scale: %d (%f)\n",
3005 metrics
->x_scale
, metrics
->x_scale
/ 65536.0 ));
3006 FT_TRACE5(( " y scale: %d (%f)\n",
3007 metrics
->y_scale
, metrics
->y_scale
/ 65536.0 ));
3008 FT_TRACE5(( " ascender: %f\n", metrics
->ascender
/ 64.0 ));
3009 FT_TRACE5(( " descender: %f\n", metrics
->descender
/ 64.0 ));
3010 FT_TRACE5(( " height: %f\n", metrics
->height
/ 64.0 ));
3011 FT_TRACE5(( " max advance: %f\n", metrics
->max_advance
/ 64.0 ));
3012 FT_TRACE5(( " x ppem: %d\n", metrics
->x_ppem
));
3013 FT_TRACE5(( " y ppem: %d\n", metrics
->y_ppem
));
3020 FT_Select_Metrics( face
, (FT_ULong
)strike_index
);
3026 /* documentation is in freetype.h */
3028 FT_EXPORT_DEF( FT_Error
)
3029 FT_Request_Size( FT_Face face
,
3030 FT_Size_Request req
)
3032 FT_Driver_Class clazz
;
3033 FT_ULong strike_index
;
3037 return FT_THROW( Invalid_Face_Handle
);
3039 if ( !req
|| req
->width
< 0 || req
->height
< 0 ||
3040 req
->type
>= FT_SIZE_REQUEST_TYPE_MAX
)
3041 return FT_THROW( Invalid_Argument
);
3043 clazz
= face
->driver
->clazz
;
3045 if ( clazz
->request_size
)
3050 error
= clazz
->request_size( face
->size
, req
);
3052 #ifdef FT_DEBUG_LEVEL_TRACE
3054 FT_Size_Metrics
* metrics
= &face
->size
->metrics
;
3057 FT_TRACE5(( "FT_Request_Size (font driver's `request_size'):\n" ));
3058 FT_TRACE5(( " x scale: %d (%f)\n",
3059 metrics
->x_scale
, metrics
->x_scale
/ 65536.0 ));
3060 FT_TRACE5(( " y scale: %d (%f)\n",
3061 metrics
->y_scale
, metrics
->y_scale
/ 65536.0 ));
3062 FT_TRACE5(( " ascender: %f\n", metrics
->ascender
/ 64.0 ));
3063 FT_TRACE5(( " descender: %f\n", metrics
->descender
/ 64.0 ));
3064 FT_TRACE5(( " height: %f\n", metrics
->height
/ 64.0 ));
3065 FT_TRACE5(( " max advance: %f\n", metrics
->max_advance
/ 64.0 ));
3066 FT_TRACE5(( " x ppem: %d\n", metrics
->x_ppem
));
3067 FT_TRACE5(( " y ppem: %d\n", metrics
->y_ppem
));
3075 * The reason that a driver doesn't have `request_size' defined is
3076 * either that the scaling here suffices or that the supported formats
3077 * are bitmap-only and size matching is not implemented.
3079 * In the latter case, a simple size matching is done.
3081 if ( !FT_IS_SCALABLE( face
) && FT_HAS_FIXED_SIZES( face
) )
3086 error
= FT_Match_Size( face
, req
, 0, &strike_index
);
3090 return FT_Select_Size( face
, (FT_Int
)strike_index
);
3093 FT_Request_Metrics( face
, req
);
3099 /* documentation is in freetype.h */
3101 FT_EXPORT_DEF( FT_Error
)
3102 FT_Set_Char_Size( FT_Face face
,
3103 FT_F26Dot6 char_width
,
3104 FT_F26Dot6 char_height
,
3105 FT_UInt horz_resolution
,
3106 FT_UInt vert_resolution
)
3108 FT_Size_RequestRec req
;
3111 /* check of `face' delayed to `FT_Request_Size' */
3114 char_width
= char_height
;
3115 else if ( !char_height
)
3116 char_height
= char_width
;
3118 if ( !horz_resolution
)
3119 horz_resolution
= vert_resolution
;
3120 else if ( !vert_resolution
)
3121 vert_resolution
= horz_resolution
;
3123 if ( char_width
< 1 * 64 )
3124 char_width
= 1 * 64;
3125 if ( char_height
< 1 * 64 )
3126 char_height
= 1 * 64;
3128 if ( !horz_resolution
)
3129 horz_resolution
= vert_resolution
= 72;
3131 req
.type
= FT_SIZE_REQUEST_TYPE_NOMINAL
;
3132 req
.width
= char_width
;
3133 req
.height
= char_height
;
3134 req
.horiResolution
= horz_resolution
;
3135 req
.vertResolution
= vert_resolution
;
3137 return FT_Request_Size( face
, &req
);
3141 /* documentation is in freetype.h */
3143 FT_EXPORT_DEF( FT_Error
)
3144 FT_Set_Pixel_Sizes( FT_Face face
,
3145 FT_UInt pixel_width
,
3146 FT_UInt pixel_height
)
3148 FT_Size_RequestRec req
;
3151 /* check of `face' delayed to `FT_Request_Size' */
3153 if ( pixel_width
== 0 )
3154 pixel_width
= pixel_height
;
3155 else if ( pixel_height
== 0 )
3156 pixel_height
= pixel_width
;
3158 if ( pixel_width
< 1 )
3160 if ( pixel_height
< 1 )
3163 /* use `>=' to avoid potential compiler warning on 16bit platforms */
3164 if ( pixel_width
>= 0xFFFFU
)
3165 pixel_width
= 0xFFFFU
;
3166 if ( pixel_height
>= 0xFFFFU
)
3167 pixel_height
= 0xFFFFU
;
3169 req
.type
= FT_SIZE_REQUEST_TYPE_NOMINAL
;
3170 req
.width
= (FT_Long
)( pixel_width
<< 6 );
3171 req
.height
= (FT_Long
)( pixel_height
<< 6 );
3172 req
.horiResolution
= 0;
3173 req
.vertResolution
= 0;
3175 return FT_Request_Size( face
, &req
);
3179 /* documentation is in freetype.h */
3181 FT_EXPORT_DEF( FT_Error
)
3182 FT_Get_Kerning( FT_Face face
,
3184 FT_UInt right_glyph
,
3186 FT_Vector
*akerning
)
3188 FT_Error error
= FT_Err_Ok
;
3193 return FT_THROW( Invalid_Face_Handle
);
3196 return FT_THROW( Invalid_Argument
);
3198 driver
= face
->driver
;
3203 if ( driver
->clazz
->get_kerning
)
3205 error
= driver
->clazz
->get_kerning( face
,
3211 if ( kern_mode
!= FT_KERNING_UNSCALED
)
3213 akerning
->x
= FT_MulFix( akerning
->x
, face
->size
->metrics
.x_scale
);
3214 akerning
->y
= FT_MulFix( akerning
->y
, face
->size
->metrics
.y_scale
);
3216 if ( kern_mode
!= FT_KERNING_UNFITTED
)
3218 FT_Pos orig_x
= akerning
->x
;
3219 FT_Pos orig_y
= akerning
->y
;
3222 /* we scale down kerning values for small ppem values */
3223 /* to avoid that rounding makes them too big. */
3224 /* `25' has been determined heuristically. */
3225 if ( face
->size
->metrics
.x_ppem
< 25 )
3226 akerning
->x
= FT_MulDiv( orig_x
,
3227 face
->size
->metrics
.x_ppem
, 25 );
3228 if ( face
->size
->metrics
.y_ppem
< 25 )
3229 akerning
->y
= FT_MulDiv( orig_y
,
3230 face
->size
->metrics
.y_ppem
, 25 );
3232 akerning
->x
= FT_PIX_ROUND( akerning
->x
);
3233 akerning
->y
= FT_PIX_ROUND( akerning
->y
);
3235 #ifdef FT_DEBUG_LEVEL_TRACE
3237 FT_Pos orig_x_rounded
= FT_PIX_ROUND( orig_x
);
3238 FT_Pos orig_y_rounded
= FT_PIX_ROUND( orig_y
);
3241 if ( akerning
->x
!= orig_x_rounded
||
3242 akerning
->y
!= orig_y_rounded
)
3243 FT_TRACE5(( "FT_Get_Kerning: horizontal kerning"
3244 " (%d, %d) scaled down to (%d, %d) pixels\n",
3245 orig_x_rounded
/ 64, orig_y_rounded
/ 64,
3246 akerning
->x
/ 64, akerning
->y
/ 64 ));
3258 /* documentation is in freetype.h */
3260 FT_EXPORT_DEF( FT_Error
)
3261 FT_Get_Track_Kerning( FT_Face face
,
3262 FT_Fixed point_size
,
3264 FT_Fixed
* akerning
)
3266 FT_Service_Kerning service
;
3267 FT_Error error
= FT_Err_Ok
;
3271 return FT_THROW( Invalid_Face_Handle
);
3274 return FT_THROW( Invalid_Argument
);
3276 FT_FACE_FIND_SERVICE( face
, service
, KERNING
);
3278 return FT_THROW( Unimplemented_Feature
);
3280 error
= service
->get_track( face
,
3289 /* documentation is in freetype.h */
3291 FT_EXPORT_DEF( FT_Error
)
3292 FT_Select_Charmap( FT_Face face
,
3293 FT_Encoding encoding
)
3300 return FT_THROW( Invalid_Face_Handle
);
3302 if ( encoding
== FT_ENCODING_NONE
)
3303 return FT_THROW( Invalid_Argument
);
3305 /* FT_ENCODING_UNICODE is special. We try to find the `best' Unicode */
3306 /* charmap available, i.e., one with UCS-4 characters, if possible. */
3308 /* This is done by find_unicode_charmap() above, to share code. */
3309 if ( encoding
== FT_ENCODING_UNICODE
)
3310 return find_unicode_charmap( face
);
3312 cur
= face
->charmaps
;
3314 return FT_THROW( Invalid_CharMap_Handle
);
3316 limit
= cur
+ face
->num_charmaps
;
3318 for ( ; cur
< limit
; cur
++ )
3320 if ( cur
[0]->encoding
== encoding
)
3322 face
->charmap
= cur
[0];
3327 return FT_THROW( Invalid_Argument
);
3331 /* documentation is in freetype.h */
3333 FT_EXPORT_DEF( FT_Error
)
3334 FT_Set_Charmap( FT_Face face
,
3335 FT_CharMap charmap
)
3342 return FT_THROW( Invalid_Face_Handle
);
3344 cur
= face
->charmaps
;
3345 if ( !cur
|| !charmap
)
3346 return FT_THROW( Invalid_CharMap_Handle
);
3348 if ( FT_Get_CMap_Format( charmap
) == 14 )
3349 return FT_THROW( Invalid_Argument
);
3351 limit
= cur
+ face
->num_charmaps
;
3353 for ( ; cur
< limit
; cur
++ )
3355 if ( cur
[0] == charmap
)
3357 face
->charmap
= cur
[0];
3362 return FT_THROW( Invalid_Argument
);
3366 /* documentation is in freetype.h */
3368 FT_EXPORT_DEF( FT_Int
)
3369 FT_Get_Charmap_Index( FT_CharMap charmap
)
3374 if ( !charmap
|| !charmap
->face
)
3377 for ( i
= 0; i
< charmap
->face
->num_charmaps
; i
++ )
3378 if ( charmap
->face
->charmaps
[i
] == charmap
)
3381 FT_ASSERT( i
< charmap
->face
->num_charmaps
);
3388 ft_cmap_done_internal( FT_CMap cmap
)
3390 FT_CMap_Class clazz
= cmap
->clazz
;
3391 FT_Face face
= cmap
->charmap
.face
;
3392 FT_Memory memory
= FT_FACE_MEMORY( face
);
3396 clazz
->done( cmap
);
3403 FT_CMap_Done( FT_CMap cmap
)
3407 FT_Face face
= cmap
->charmap
.face
;
3408 FT_Memory memory
= FT_FACE_MEMORY( face
);
3413 for ( i
= 0; i
< face
->num_charmaps
; i
++ )
3415 if ( (FT_CMap
)face
->charmaps
[i
] == cmap
)
3417 FT_CharMap last_charmap
= face
->charmaps
[face
->num_charmaps
- 1];
3420 if ( FT_RENEW_ARRAY( face
->charmaps
,
3422 face
->num_charmaps
- 1 ) )
3425 /* remove it from our list of charmaps */
3426 for ( j
= i
+ 1; j
< face
->num_charmaps
; j
++ )
3428 if ( j
== face
->num_charmaps
- 1 )
3429 face
->charmaps
[j
- 1] = last_charmap
;
3431 face
->charmaps
[j
- 1] = face
->charmaps
[j
];
3434 face
->num_charmaps
--;
3436 if ( (FT_CMap
)face
->charmap
== cmap
)
3437 face
->charmap
= NULL
;
3439 ft_cmap_done_internal( cmap
);
3448 FT_BASE_DEF( FT_Error
)
3449 FT_CMap_New( FT_CMap_Class clazz
,
3450 FT_Pointer init_data
,
3454 FT_Error error
= FT_Err_Ok
;
3457 FT_CMap cmap
= NULL
;
3460 if ( !clazz
|| !charmap
|| !charmap
->face
)
3461 return FT_THROW( Invalid_Argument
);
3463 face
= charmap
->face
;
3464 memory
= FT_FACE_MEMORY( face
);
3466 if ( !FT_ALLOC( cmap
, clazz
->size
) )
3468 cmap
->charmap
= *charmap
;
3469 cmap
->clazz
= clazz
;
3473 error
= clazz
->init( cmap
, init_data
);
3478 /* add it to our list of charmaps */
3479 if ( FT_RENEW_ARRAY( face
->charmaps
,
3481 face
->num_charmaps
+ 1 ) )
3484 face
->charmaps
[face
->num_charmaps
++] = (FT_CharMap
)cmap
;
3494 ft_cmap_done_internal( cmap
);
3500 /* documentation is in freetype.h */
3502 FT_EXPORT_DEF( FT_UInt
)
3503 FT_Get_Char_Index( FT_Face face
,
3509 if ( face
&& face
->charmap
)
3511 FT_CMap cmap
= FT_CMAP( face
->charmap
);
3514 if ( charcode
> 0xFFFFFFFFUL
)
3516 FT_TRACE1(( "FT_Get_Char_Index: too large charcode" ));
3517 FT_TRACE1(( " 0x%x is truncated\n", charcode
));
3520 result
= cmap
->clazz
->char_index( cmap
, (FT_UInt32
)charcode
);
3521 if ( result
>= (FT_UInt
)face
->num_glyphs
)
3529 /* documentation is in freetype.h */
3531 FT_EXPORT_DEF( FT_ULong
)
3532 FT_Get_First_Char( FT_Face face
,
3535 FT_ULong result
= 0;
3539 /* only do something if we have a charmap, and we have glyphs at all */
3540 if ( face
&& face
->charmap
&& face
->num_glyphs
)
3542 gindex
= FT_Get_Char_Index( face
, 0 );
3544 result
= FT_Get_Next_Char( face
, 0, &gindex
);
3554 /* documentation is in freetype.h */
3556 FT_EXPORT_DEF( FT_ULong
)
3557 FT_Get_Next_Char( FT_Face face
,
3561 FT_ULong result
= 0;
3565 if ( face
&& face
->charmap
&& face
->num_glyphs
)
3567 FT_UInt32 code
= (FT_UInt32
)charcode
;
3568 FT_CMap cmap
= FT_CMAP( face
->charmap
);
3573 gindex
= cmap
->clazz
->char_next( cmap
, &code
);
3575 } while ( gindex
>= (FT_UInt
)face
->num_glyphs
);
3577 result
= ( gindex
== 0 ) ? 0 : code
;
3587 /* documentation is in freetype.h */
3589 FT_EXPORT_DEF( FT_UInt
)
3590 FT_Face_GetCharVariantIndex( FT_Face face
,
3592 FT_ULong variantSelector
)
3599 face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
3601 FT_CharMap charmap
= find_variant_selector_charmap( face
);
3602 FT_CMap ucmap
= FT_CMAP( face
->charmap
);
3607 FT_CMap vcmap
= FT_CMAP( charmap
);
3610 if ( charcode
> 0xFFFFFFFFUL
)
3612 FT_TRACE1(( "FT_Get_Char_Index: too large charcode" ));
3613 FT_TRACE1(( " 0x%x is truncated\n", charcode
));
3615 if ( variantSelector
> 0xFFFFFFFFUL
)
3617 FT_TRACE1(( "FT_Get_Char_Index: too large variantSelector" ));
3618 FT_TRACE1(( " 0x%x is truncated\n", variantSelector
));
3621 result
= vcmap
->clazz
->char_var_index( vcmap
, ucmap
,
3622 (FT_UInt32
)charcode
,
3623 (FT_UInt32
)variantSelector
);
3631 /* documentation is in freetype.h */
3633 FT_EXPORT_DEF( FT_Int
)
3634 FT_Face_GetCharVariantIsDefault( FT_Face face
,
3636 FT_ULong variantSelector
)
3643 FT_CharMap charmap
= find_variant_selector_charmap( face
);
3648 FT_CMap vcmap
= FT_CMAP( charmap
);
3651 if ( charcode
> 0xFFFFFFFFUL
)
3653 FT_TRACE1(( "FT_Get_Char_Index: too large charcode" ));
3654 FT_TRACE1(( " 0x%x is truncated\n", charcode
));
3656 if ( variantSelector
> 0xFFFFFFFFUL
)
3658 FT_TRACE1(( "FT_Get_Char_Index: too large variantSelector" ));
3659 FT_TRACE1(( " 0x%x is truncated\n", variantSelector
));
3662 result
= vcmap
->clazz
->char_var_default( vcmap
,
3663 (FT_UInt32
)charcode
,
3664 (FT_UInt32
)variantSelector
);
3672 /* documentation is in freetype.h */
3674 FT_EXPORT_DEF( FT_UInt32
* )
3675 FT_Face_GetVariantSelectors( FT_Face face
)
3677 FT_UInt32
*result
= NULL
;
3682 FT_CharMap charmap
= find_variant_selector_charmap( face
);
3687 FT_CMap vcmap
= FT_CMAP( charmap
);
3688 FT_Memory memory
= FT_FACE_MEMORY( face
);
3691 result
= vcmap
->clazz
->variant_list( vcmap
, memory
);
3699 /* documentation is in freetype.h */
3701 FT_EXPORT_DEF( FT_UInt32
* )
3702 FT_Face_GetVariantsOfChar( FT_Face face
,
3705 FT_UInt32
*result
= NULL
;
3710 FT_CharMap charmap
= find_variant_selector_charmap( face
);
3715 FT_CMap vcmap
= FT_CMAP( charmap
);
3716 FT_Memory memory
= FT_FACE_MEMORY( face
);
3719 if ( charcode
> 0xFFFFFFFFUL
)
3721 FT_TRACE1(( "FT_Get_Char_Index: too large charcode" ));
3722 FT_TRACE1(( " 0x%x is truncated\n", charcode
));
3725 result
= vcmap
->clazz
->charvariant_list( vcmap
, memory
,
3726 (FT_UInt32
)charcode
);
3733 /* documentation is in freetype.h */
3735 FT_EXPORT_DEF( FT_UInt32
* )
3736 FT_Face_GetCharsOfVariant( FT_Face face
,
3737 FT_ULong variantSelector
)
3739 FT_UInt32
*result
= NULL
;
3744 FT_CharMap charmap
= find_variant_selector_charmap( face
);
3749 FT_CMap vcmap
= FT_CMAP( charmap
);
3750 FT_Memory memory
= FT_FACE_MEMORY( face
);
3753 if ( variantSelector
> 0xFFFFFFFFUL
)
3755 FT_TRACE1(( "FT_Get_Char_Index: too large variantSelector" ));
3756 FT_TRACE1(( " 0x%x is truncated\n", variantSelector
));
3759 result
= vcmap
->clazz
->variantchar_list( vcmap
, memory
,
3760 (FT_UInt32
)variantSelector
);
3768 /* documentation is in freetype.h */
3770 FT_EXPORT_DEF( FT_UInt
)
3771 FT_Get_Name_Index( FT_Face face
,
3772 FT_String
* glyph_name
)
3778 FT_HAS_GLYPH_NAMES( face
) &&
3781 FT_Service_GlyphDict service
;
3784 FT_FACE_LOOKUP_SERVICE( face
,
3788 if ( service
&& service
->name_index
)
3789 result
= service
->name_index( face
, glyph_name
);
3796 /* documentation is in freetype.h */
3798 FT_EXPORT_DEF( FT_Error
)
3799 FT_Get_Glyph_Name( FT_Face face
,
3800 FT_UInt glyph_index
,
3802 FT_UInt buffer_max
)
3805 FT_Service_GlyphDict service
;
3809 return FT_THROW( Invalid_Face_Handle
);
3811 if ( !buffer
|| buffer_max
== 0 )
3812 return FT_THROW( Invalid_Argument
);
3814 /* clean up buffer */
3815 ((FT_Byte
*)buffer
)[0] = '\0';
3817 if ( (FT_Long
)glyph_index
>= face
->num_glyphs
)
3818 return FT_THROW( Invalid_Glyph_Index
);
3820 if ( !FT_HAS_GLYPH_NAMES( face
) )
3821 return FT_THROW( Invalid_Argument
);
3823 FT_FACE_LOOKUP_SERVICE( face
, service
, GLYPH_DICT
);
3824 if ( service
&& service
->get_name
)
3825 error
= service
->get_name( face
, glyph_index
, buffer
, buffer_max
);
3827 error
= FT_THROW( Invalid_Argument
);
3833 /* documentation is in freetype.h */
3835 FT_EXPORT_DEF( const char* )
3836 FT_Get_Postscript_Name( FT_Face face
)
3838 const char* result
= NULL
;
3846 FT_Service_PsFontName service
;
3849 FT_FACE_LOOKUP_SERVICE( face
,
3851 POSTSCRIPT_FONT_NAME
);
3853 if ( service
&& service
->get_ps_font_name
)
3854 result
= service
->get_ps_font_name( face
);
3862 /* documentation is in tttables.h */
3864 FT_EXPORT_DEF( void* )
3865 FT_Get_Sfnt_Table( FT_Face face
,
3869 FT_Service_SFNT_Table service
;
3872 if ( face
&& FT_IS_SFNT( face
) )
3874 FT_FACE_FIND_SERVICE( face
, service
, SFNT_TABLE
);
3876 table
= service
->get_table( face
, tag
);
3883 /* documentation is in tttables.h */
3885 FT_EXPORT_DEF( FT_Error
)
3886 FT_Load_Sfnt_Table( FT_Face face
,
3892 FT_Service_SFNT_Table service
;
3895 if ( !face
|| !FT_IS_SFNT( face
) )
3896 return FT_THROW( Invalid_Face_Handle
);
3898 FT_FACE_FIND_SERVICE( face
, service
, SFNT_TABLE
);
3900 return FT_THROW( Unimplemented_Feature
);
3902 return service
->load_table( face
, tag
, offset
, buffer
, length
);
3906 /* documentation is in tttables.h */
3908 FT_EXPORT_DEF( FT_Error
)
3909 FT_Sfnt_Table_Info( FT_Face face
,
3910 FT_UInt table_index
,
3914 FT_Service_SFNT_Table service
;
3918 /* test for valid `length' delayed to `service->table_info' */
3920 if ( !face
|| !FT_IS_SFNT( face
) )
3921 return FT_THROW( Invalid_Face_Handle
);
3923 FT_FACE_FIND_SERVICE( face
, service
, SFNT_TABLE
);
3925 return FT_THROW( Unimplemented_Feature
);
3927 return service
->table_info( face
, table_index
, tag
, &offset
, length
);
3931 /* documentation is in tttables.h */
3933 FT_EXPORT_DEF( FT_ULong
)
3934 FT_Get_CMap_Language_ID( FT_CharMap charmap
)
3936 FT_Service_TTCMaps service
;
3938 TT_CMapInfo cmap_info
;
3941 if ( !charmap
|| !charmap
->face
)
3944 face
= charmap
->face
;
3945 FT_FACE_FIND_SERVICE( face
, service
, TT_CMAP
);
3948 if ( service
->get_cmap_info( charmap
, &cmap_info
))
3951 return cmap_info
.language
;
3955 /* documentation is in tttables.h */
3957 FT_EXPORT_DEF( FT_Long
)
3958 FT_Get_CMap_Format( FT_CharMap charmap
)
3960 FT_Service_TTCMaps service
;
3962 TT_CMapInfo cmap_info
;
3965 if ( !charmap
|| !charmap
->face
)
3968 face
= charmap
->face
;
3969 FT_FACE_FIND_SERVICE( face
, service
, TT_CMAP
);
3972 if ( service
->get_cmap_info( charmap
, &cmap_info
))
3975 return cmap_info
.format
;
3979 /* documentation is in ftsizes.h */
3981 FT_EXPORT_DEF( FT_Error
)
3982 FT_Activate_Size( FT_Size size
)
3988 return FT_THROW( Invalid_Size_Handle
);
3991 if ( !face
|| !face
->driver
)
3992 return FT_THROW( Invalid_Face_Handle
);
3994 /* we don't need anything more complex than that; all size objects */
3995 /* are already listed by the face */
4002 /*************************************************************************/
4003 /*************************************************************************/
4004 /*************************************************************************/
4007 /**** R E N D E R E R S ****/
4010 /*************************************************************************/
4011 /*************************************************************************/
4012 /*************************************************************************/
4014 /* lookup a renderer by glyph format in the library's list */
4015 FT_BASE_DEF( FT_Renderer
)
4016 FT_Lookup_Renderer( FT_Library library
,
4017 FT_Glyph_Format format
,
4021 FT_Renderer result
= NULL
;
4027 cur
= library
->renderers
.head
;
4032 cur
= (*node
)->next
;
4038 FT_Renderer renderer
= FT_RENDERER( cur
->data
);
4041 if ( renderer
->glyph_format
== format
)
4058 ft_lookup_glyph_renderer( FT_GlyphSlot slot
)
4060 FT_Face face
= slot
->face
;
4061 FT_Library library
= FT_FACE_LIBRARY( face
);
4062 FT_Renderer result
= library
->cur_renderer
;
4065 if ( !result
|| result
->glyph_format
!= slot
->format
)
4066 result
= FT_Lookup_Renderer( library
, slot
->format
, 0 );
4073 ft_set_current_renderer( FT_Library library
)
4075 FT_Renderer renderer
;
4078 renderer
= FT_Lookup_Renderer( library
, FT_GLYPH_FORMAT_OUTLINE
, 0 );
4079 library
->cur_renderer
= renderer
;
4084 ft_add_renderer( FT_Module module
)
4086 FT_Library library
= module
->library
;
4087 FT_Memory memory
= library
->memory
;
4089 FT_ListNode node
= NULL
;
4092 if ( FT_NEW( node
) )
4096 FT_Renderer render
= FT_RENDERER( module
);
4097 FT_Renderer_Class
* clazz
= (FT_Renderer_Class
*)module
->clazz
;
4100 render
->clazz
= clazz
;
4101 render
->glyph_format
= clazz
->glyph_format
;
4103 /* allocate raster object if needed */
4104 if ( clazz
->glyph_format
== FT_GLYPH_FORMAT_OUTLINE
&&
4105 clazz
->raster_class
->raster_new
)
4107 error
= clazz
->raster_class
->raster_new( memory
, &render
->raster
);
4111 render
->raster_render
= clazz
->raster_class
->raster_render
;
4112 render
->render
= clazz
->render_glyph
;
4116 node
->data
= module
;
4117 FT_List_Add( &library
->renderers
, node
);
4119 ft_set_current_renderer( library
);
4132 ft_remove_renderer( FT_Module module
)
4139 library
= module
->library
;
4143 memory
= library
->memory
;
4145 node
= FT_List_Find( &library
->renderers
, module
);
4148 FT_Renderer render
= FT_RENDERER( module
);
4151 /* release raster object, if any */
4152 if ( render
->clazz
->glyph_format
== FT_GLYPH_FORMAT_OUTLINE
&&
4154 render
->clazz
->raster_class
->raster_done( render
->raster
);
4156 /* remove from list */
4157 FT_List_Remove( &library
->renderers
, node
);
4160 ft_set_current_renderer( library
);
4165 /* documentation is in ftrender.h */
4167 FT_EXPORT_DEF( FT_Renderer
)
4168 FT_Get_Renderer( FT_Library library
,
4169 FT_Glyph_Format format
)
4171 /* test for valid `library' delayed to `FT_Lookup_Renderer' */
4173 return FT_Lookup_Renderer( library
, format
, 0 );
4177 /* documentation is in ftrender.h */
4179 FT_EXPORT_DEF( FT_Error
)
4180 FT_Set_Renderer( FT_Library library
,
4181 FT_Renderer renderer
,
4183 FT_Parameter
* parameters
)
4186 FT_Error error
= FT_Err_Ok
;
4188 FT_Renderer_SetModeFunc set_mode
;
4193 error
= FT_THROW( Invalid_Library_Handle
);
4199 error
= FT_THROW( Invalid_Argument
);
4203 if ( num_params
> 0 && !parameters
)
4205 error
= FT_THROW( Invalid_Argument
);
4209 node
= FT_List_Find( &library
->renderers
, renderer
);
4212 error
= FT_THROW( Invalid_Argument
);
4216 FT_List_Up( &library
->renderers
, node
);
4218 if ( renderer
->glyph_format
== FT_GLYPH_FORMAT_OUTLINE
)
4219 library
->cur_renderer
= renderer
;
4221 set_mode
= renderer
->clazz
->set_mode
;
4223 for ( ; num_params
> 0; num_params
-- )
4225 error
= set_mode( renderer
, parameters
->tag
, parameters
->data
);
4236 FT_BASE_DEF( FT_Error
)
4237 FT_Render_Glyph_Internal( FT_Library library
,
4239 FT_Render_Mode render_mode
)
4241 FT_Error error
= FT_Err_Ok
;
4242 FT_Renderer renderer
;
4245 /* if it is already a bitmap, no need to do anything */
4246 switch ( slot
->format
)
4248 case FT_GLYPH_FORMAT_BITMAP
: /* already a bitmap, don't do anything */
4253 FT_ListNode node
= NULL
;
4256 /* small shortcut for the very common case */
4257 if ( slot
->format
== FT_GLYPH_FORMAT_OUTLINE
)
4259 renderer
= library
->cur_renderer
;
4260 node
= library
->renderers
.head
;
4263 renderer
= FT_Lookup_Renderer( library
, slot
->format
, &node
);
4265 error
= FT_ERR( Unimplemented_Feature
);
4268 error
= renderer
->render( renderer
, slot
, render_mode
, NULL
);
4270 FT_ERR_NEQ( error
, Cannot_Render_Glyph
) )
4273 /* FT_Err_Cannot_Render_Glyph is returned if the render mode */
4274 /* is unsupported by the current renderer for this glyph image */
4277 /* now, look for another renderer that supports the same */
4279 renderer
= FT_Lookup_Renderer( library
, slot
->format
, &node
);
4284 #ifdef FT_DEBUG_LEVEL_TRACE
4287 #define FT_COMPONENT trace_bitmap
4290 * Computing the MD5 checksum is expensive, unnecessarily distorting a
4291 * possible profiling of FreeType if compiled with tracing support. For
4292 * this reason, we execute the following code only if explicitly
4296 /* we use FT_TRACE3 in this block */
4297 if ( ft_trace_levels
[trace_bitmap
] >= 3 )
4299 /* we convert to a single bitmap format for computing the checksum */
4300 if ( !error
&& slot
->bitmap
.buffer
)
4306 FT_Bitmap_Init( &bitmap
);
4308 /* this also converts the bitmap flow to `down' (i.e., pitch > 0) */
4309 err
= FT_Bitmap_Convert( library
, &slot
->bitmap
, &bitmap
, 1 );
4313 unsigned char md5
[16];
4315 unsigned int rows
= bitmap
.rows
;
4316 unsigned int pitch
= (unsigned int)bitmap
.pitch
;
4320 if ( bitmap
.buffer
)
4321 MD5_Update( &ctx
, bitmap
.buffer
, rows
* pitch
);
4322 MD5_Final( md5
, &ctx
);
4324 FT_TRACE3(( "MD5 checksum for %dx%d bitmap:\n"
4327 for ( i
= 0; i
< 16; i
++ )
4328 FT_TRACE3(( "%02X", md5
[i
] ));
4329 FT_TRACE3(( "\n" ));
4332 FT_Bitmap_Done( library
, &bitmap
);
4337 #define FT_COMPONENT trace_objs
4339 #endif /* FT_DEBUG_LEVEL_TRACE */
4345 /* documentation is in freetype.h */
4347 FT_EXPORT_DEF( FT_Error
)
4348 FT_Render_Glyph( FT_GlyphSlot slot
,
4349 FT_Render_Mode render_mode
)
4354 if ( !slot
|| !slot
->face
)
4355 return FT_THROW( Invalid_Argument
);
4357 library
= FT_FACE_LIBRARY( slot
->face
);
4359 return FT_Render_Glyph_Internal( library
, slot
, render_mode
);
4363 /*************************************************************************/
4364 /*************************************************************************/
4365 /*************************************************************************/
4368 /**** M O D U L E S ****/
4371 /*************************************************************************/
4372 /*************************************************************************/
4373 /*************************************************************************/
4376 /*************************************************************************/
4379 /* Destroy_Module */
4382 /* Destroys a given module object. For drivers, this also destroys */
4383 /* all child faces. */
4386 /* module :: A handle to the target driver object. */
4389 /* The driver _must_ be LOCKED! */
4392 Destroy_Module( FT_Module module
)
4394 FT_Memory memory
= module
->memory
;
4395 FT_Module_Class
* clazz
= module
->clazz
;
4396 FT_Library library
= module
->library
;
4399 if ( library
&& library
->auto_hinter
== module
)
4400 library
->auto_hinter
= NULL
;
4402 /* if the module is a renderer */
4403 if ( FT_MODULE_IS_RENDERER( module
) )
4404 ft_remove_renderer( module
);
4406 /* if the module is a font driver, add some steps */
4407 if ( FT_MODULE_IS_DRIVER( module
) )
4408 Destroy_Driver( FT_DRIVER( module
) );
4410 /* finalize the module object */
4411 if ( clazz
->module_done
)
4412 clazz
->module_done( module
);
4419 /* documentation is in ftmodapi.h */
4421 FT_EXPORT_DEF( FT_Error
)
4422 FT_Add_Module( FT_Library library
,
4423 const FT_Module_Class
* clazz
)
4427 FT_Module module
= NULL
;
4431 #define FREETYPE_VER_FIXED ( ( (FT_Long)FREETYPE_MAJOR << 16 ) | \
4435 return FT_THROW( Invalid_Library_Handle
);
4438 return FT_THROW( Invalid_Argument
);
4440 /* check freetype version */
4441 if ( clazz
->module_requires
> FREETYPE_VER_FIXED
)
4442 return FT_THROW( Invalid_Version
);
4444 /* look for a module with the same name in the library's table */
4445 for ( nn
= 0; nn
< library
->num_modules
; nn
++ )
4447 module
= library
->modules
[nn
];
4448 if ( ft_strcmp( module
->clazz
->module_name
, clazz
->module_name
) == 0 )
4450 /* this installed module has the same name, compare their versions */
4451 if ( clazz
->module_version
<= module
->clazz
->module_version
)
4452 return FT_THROW( Lower_Module_Version
);
4454 /* remove the module from our list, then exit the loop to replace */
4455 /* it by our new version.. */
4456 FT_Remove_Module( library
, module
);
4461 memory
= library
->memory
;
4464 if ( library
->num_modules
>= FT_MAX_MODULES
)
4466 error
= FT_THROW( Too_Many_Drivers
);
4470 /* allocate module object */
4471 if ( FT_ALLOC( module
, clazz
->module_size
) )
4474 /* base initialization */
4475 module
->library
= library
;
4476 module
->memory
= memory
;
4477 module
->clazz
= (FT_Module_Class
*)clazz
;
4479 /* check whether the module is a renderer - this must be performed */
4480 /* before the normal module initialization */
4481 if ( FT_MODULE_IS_RENDERER( module
) )
4483 /* add to the renderers list */
4484 error
= ft_add_renderer( module
);
4489 /* is the module a auto-hinter? */
4490 if ( FT_MODULE_IS_HINTER( module
) )
4491 library
->auto_hinter
= module
;
4493 /* if the module is a font driver */
4494 if ( FT_MODULE_IS_DRIVER( module
) )
4496 FT_Driver driver
= FT_DRIVER( module
);
4499 driver
->clazz
= (FT_Driver_Class
)module
->clazz
;
4502 if ( clazz
->module_init
)
4504 error
= clazz
->module_init( module
);
4509 /* add module to the library's table */
4510 library
->modules
[library
->num_modules
++] = module
;
4516 if ( FT_MODULE_IS_RENDERER( module
) )
4518 FT_Renderer renderer
= FT_RENDERER( module
);
4521 if ( renderer
->clazz
&&
4522 renderer
->clazz
->glyph_format
== FT_GLYPH_FORMAT_OUTLINE
&&
4524 renderer
->clazz
->raster_class
->raster_done( renderer
->raster
);
4532 /* documentation is in ftmodapi.h */
4534 FT_EXPORT_DEF( FT_Module
)
4535 FT_Get_Module( FT_Library library
,
4536 const char* module_name
)
4538 FT_Module result
= NULL
;
4543 if ( !library
|| !module_name
)
4546 cur
= library
->modules
;
4547 limit
= cur
+ library
->num_modules
;
4549 for ( ; cur
< limit
; cur
++ )
4550 if ( ft_strcmp( cur
[0]->clazz
->module_name
, module_name
) == 0 )
4560 /* documentation is in ftobjs.h */
4562 FT_BASE_DEF( const void* )
4563 FT_Get_Module_Interface( FT_Library library
,
4564 const char* mod_name
)
4569 /* test for valid `library' delayed to FT_Get_Module() */
4571 module
= FT_Get_Module( library
, mod_name
);
4573 return module
? module
->clazz
->module_interface
: 0;
4577 FT_BASE_DEF( FT_Pointer
)
4578 ft_module_get_service( FT_Module module
,
4579 const char* service_id
,
4582 FT_Pointer result
= NULL
;
4587 FT_ASSERT( module
->clazz
&& module
->clazz
->get_interface
);
4589 /* first, look for the service in the module */
4590 if ( module
->clazz
->get_interface
)
4591 result
= module
->clazz
->get_interface( module
, service_id
);
4593 if ( global
&& !result
)
4595 /* we didn't find it, look in all other modules then */
4596 FT_Library library
= module
->library
;
4597 FT_Module
* cur
= library
->modules
;
4598 FT_Module
* limit
= cur
+ library
->num_modules
;
4601 for ( ; cur
< limit
; cur
++ )
4603 if ( cur
[0] != module
)
4605 FT_ASSERT( cur
[0]->clazz
);
4607 if ( cur
[0]->clazz
->get_interface
)
4609 result
= cur
[0]->clazz
->get_interface( cur
[0], service_id
);
4622 /* documentation is in ftmodapi.h */
4624 FT_EXPORT_DEF( FT_Error
)
4625 FT_Remove_Module( FT_Library library
,
4628 /* try to find the module from the table, then remove it from there */
4631 return FT_THROW( Invalid_Library_Handle
);
4635 FT_Module
* cur
= library
->modules
;
4636 FT_Module
* limit
= cur
+ library
->num_modules
;
4639 for ( ; cur
< limit
; cur
++ )
4641 if ( cur
[0] == module
)
4643 /* remove it from the table */
4644 library
->num_modules
--;
4646 while ( cur
< limit
)
4653 /* destroy the module */
4654 Destroy_Module( module
);
4660 return FT_THROW( Invalid_Driver_Handle
);
4665 ft_property_do( FT_Library library
,
4666 const FT_String
* module_name
,
4667 const FT_String
* property_name
,
4670 FT_Bool value_is_string
)
4674 FT_Module_Interface interface
;
4676 FT_Service_Properties service
;
4678 #ifdef FT_DEBUG_LEVEL_ERROR
4679 const FT_String
* set_name
= "FT_Property_Set";
4680 const FT_String
* get_name
= "FT_Property_Get";
4681 const FT_String
* func_name
= set
? set_name
: get_name
;
4684 FT_Bool missing_func
;
4688 return FT_THROW( Invalid_Library_Handle
);
4690 if ( !module_name
|| !property_name
|| !value
)
4691 return FT_THROW( Invalid_Argument
);
4693 cur
= library
->modules
;
4694 limit
= cur
+ library
->num_modules
;
4697 for ( ; cur
< limit
; cur
++ )
4698 if ( !ft_strcmp( cur
[0]->clazz
->module_name
, module_name
) )
4703 FT_ERROR(( "%s: can't find module `%s'\n",
4704 func_name
, module_name
));
4705 return FT_THROW( Missing_Module
);
4708 /* check whether we have a service interface */
4709 if ( !cur
[0]->clazz
->get_interface
)
4711 FT_ERROR(( "%s: module `%s' doesn't support properties\n",
4712 func_name
, module_name
));
4713 return FT_THROW( Unimplemented_Feature
);
4716 /* search property service */
4717 interface
= cur
[0]->clazz
->get_interface( cur
[0],
4718 FT_SERVICE_ID_PROPERTIES
);
4721 FT_ERROR(( "%s: module `%s' doesn't support properties\n",
4722 func_name
, module_name
));
4723 return FT_THROW( Unimplemented_Feature
);
4726 service
= (FT_Service_Properties
)interface
;
4729 missing_func
= (FT_Bool
)( !service
->set_property
);
4731 missing_func
= (FT_Bool
)( !service
->get_property
);
4735 FT_ERROR(( "%s: property service of module `%s' is broken\n",
4736 func_name
, module_name
));
4737 return FT_THROW( Unimplemented_Feature
);
4740 return set
? service
->set_property( cur
[0],
4744 : service
->get_property( cur
[0],
4750 /* documentation is in ftmodapi.h */
4752 FT_EXPORT_DEF( FT_Error
)
4753 FT_Property_Set( FT_Library library
,
4754 const FT_String
* module_name
,
4755 const FT_String
* property_name
,
4758 return ft_property_do( library
,
4767 /* documentation is in ftmodapi.h */
4769 FT_EXPORT_DEF( FT_Error
)
4770 FT_Property_Get( FT_Library library
,
4771 const FT_String
* module_name
,
4772 const FT_String
* property_name
,
4775 return ft_property_do( library
,
4784 #ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES
4786 /* this variant is used for handling the FREETYPE_PROPERTIES */
4787 /* environment variable */
4789 FT_BASE_DEF( FT_Error
)
4790 ft_property_string_set( FT_Library library
,
4791 const FT_String
* module_name
,
4792 const FT_String
* property_name
,
4795 return ft_property_do( library
,
4806 /*************************************************************************/
4807 /*************************************************************************/
4808 /*************************************************************************/
4811 /**** L I B R A R Y ****/
4814 /*************************************************************************/
4815 /*************************************************************************/
4816 /*************************************************************************/
4819 /* documentation is in ftmodapi.h */
4821 FT_EXPORT_DEF( FT_Error
)
4822 FT_Reference_Library( FT_Library library
)
4825 return FT_THROW( Invalid_Library_Handle
);
4827 library
->refcount
++;
4833 /* documentation is in ftmodapi.h */
4835 FT_EXPORT_DEF( FT_Error
)
4836 FT_New_Library( FT_Memory memory
,
4837 FT_Library
*alibrary
)
4839 FT_Library library
= NULL
;
4843 if ( !memory
|| !alibrary
)
4844 return FT_THROW( Invalid_Argument
);
4846 #ifdef FT_DEBUG_LEVEL_ERROR
4847 /* init debugging support */
4851 /* first of all, allocate the library object */
4852 if ( FT_NEW( library
) )
4855 library
->memory
= memory
;
4857 #ifdef FT_CONFIG_OPTION_PIC
4858 /* initialize position independent code containers */
4859 error
= ft_pic_container_init( library
);
4864 /* we don't use raster_pool anymore. */
4865 library
->raster_pool_size
= 0;
4866 library
->raster_pool
= NULL
;
4868 library
->version_major
= FREETYPE_MAJOR
;
4869 library
->version_minor
= FREETYPE_MINOR
;
4870 library
->version_patch
= FREETYPE_PATCH
;
4872 library
->refcount
= 1;
4875 *alibrary
= library
;
4879 #ifdef FT_CONFIG_OPTION_PIC
4881 ft_pic_container_destroy( library
);
4888 /* documentation is in freetype.h */
4890 FT_EXPORT_DEF( void )
4891 FT_Library_Version( FT_Library library
,
4903 major
= library
->version_major
;
4904 minor
= library
->version_minor
;
4905 patch
= library
->version_patch
;
4919 /* documentation is in ftmodapi.h */
4921 FT_EXPORT_DEF( FT_Error
)
4922 FT_Done_Library( FT_Library library
)
4928 return FT_THROW( Invalid_Library_Handle
);
4930 library
->refcount
--;
4931 if ( library
->refcount
> 0 )
4934 memory
= library
->memory
;
4937 * Close all faces in the library. If we don't do this, we can have
4938 * some subtle memory leaks.
4942 * - the cff font driver uses the pshinter module in cff_size_done
4943 * - if the pshinter module is destroyed before the cff font driver,
4944 * opened FT_Face objects managed by the driver are not properly
4945 * destroyed, resulting in a memory leak
4947 * Some faces are dependent on other faces, like Type42 faces that
4948 * depend on TrueType faces synthesized internally.
4950 * The order of drivers should be specified in driver_name[].
4954 const char* driver_name
[] = { "type42", NULL
};
4958 m
< sizeof ( driver_name
) / sizeof ( driver_name
[0] );
4961 for ( n
= 0; n
< library
->num_modules
; n
++ )
4963 FT_Module module
= library
->modules
[n
];
4964 const char* module_name
= module
->clazz
->module_name
;
4968 if ( driver_name
[m
] &&
4969 ft_strcmp( module_name
, driver_name
[m
] ) != 0 )
4972 if ( ( module
->clazz
->module_flags
& FT_MODULE_FONT_DRIVER
) == 0 )
4975 FT_TRACE7(( "FT_Done_Library: close faces for %s\n", module_name
));
4977 faces
= &FT_DRIVER( module
)->faces_list
;
4978 while ( faces
->head
)
4980 FT_Done_Face( FT_FACE( faces
->head
->data
) );
4982 FT_TRACE0(( "FT_Done_Library: failed to free some faces\n" ));
4988 /* Close all other modules in the library */
4990 /* XXX Modules are removed in the reversed order so that */
4991 /* type42 module is removed before truetype module. This */
4992 /* avoids double free in some occasions. It is a hack. */
4993 while ( library
->num_modules
> 0 )
4994 FT_Remove_Module( library
,
4995 library
->modules
[library
->num_modules
- 1] );
5001 for ( n
= 0; n
< library
->num_modules
; n
++ )
5003 FT_Module module
= library
->modules
[n
];
5008 Destroy_Module( module
);
5009 library
->modules
[n
] = NULL
;
5015 #ifdef FT_CONFIG_OPTION_PIC
5016 /* Destroy pic container contents */
5017 ft_pic_container_destroy( library
);
5027 /* documentation is in ftmodapi.h */
5029 FT_EXPORT_DEF( void )
5030 FT_Set_Debug_Hook( FT_Library library
,
5032 FT_DebugHook_Func debug_hook
)
5034 if ( library
&& debug_hook
&&
5036 ( sizeof ( library
->debug_hooks
) / sizeof ( void* ) ) )
5037 library
->debug_hooks
[hook_index
] = debug_hook
;
5041 /* documentation is in ftmodapi.h */
5043 FT_EXPORT_DEF( FT_TrueTypeEngineType
)
5044 FT_Get_TrueType_Engine_Type( FT_Library library
)
5046 FT_TrueTypeEngineType result
= FT_TRUETYPE_ENGINE_TYPE_NONE
;
5051 FT_Module module
= FT_Get_Module( library
, "truetype" );
5056 FT_Service_TrueTypeEngine service
;
5059 service
= (FT_Service_TrueTypeEngine
)
5060 ft_module_get_service( module
,
5061 FT_SERVICE_ID_TRUETYPE_ENGINE
,
5064 result
= service
->engine_type
;
5072 /* documentation is in freetype.h */
5074 FT_EXPORT_DEF( FT_Error
)
5075 FT_Get_SubGlyph_Info( FT_GlyphSlot glyph
,
5081 FT_Matrix
*p_transform
)
5083 FT_Error error
= FT_ERR( Invalid_Argument
);
5088 glyph
->format
== FT_GLYPH_FORMAT_COMPOSITE
&&
5089 sub_index
< glyph
->num_subglyphs
)
5091 FT_SubGlyph subg
= glyph
->subglyphs
+ sub_index
;
5094 *p_index
= subg
->index
;
5095 *p_flags
= subg
->flags
;
5096 *p_arg1
= subg
->arg1
;
5097 *p_arg2
= subg
->arg2
;
5098 *p_transform
= subg
->transform
;