1 /***************************************************************************/
5 /* The FreeType private base classes (body). */
7 /* Copyright 1996-2013 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 */
59 #define free md5_free /* suppress a shadow warning */
63 #if defined( _MSC_VER )
64 #pragma warning( pop )
67 #endif /* FT_DEBUG_LEVEL_TRACE */
70 #define GRID_FIT_METRICS
73 FT_BASE_DEF( FT_Pointer
)
74 ft_service_list_lookup( FT_ServiceDesc service_descriptors
,
75 const char* service_id
)
77 FT_Pointer result
= NULL
;
78 FT_ServiceDesc desc
= service_descriptors
;
81 if ( desc
&& service_id
)
83 for ( ; desc
->serv_id
!= NULL
; desc
++ )
85 if ( ft_strcmp( desc
->serv_id
, service_id
) == 0 )
87 result
= (FT_Pointer
)desc
->serv_data
;
98 ft_validator_init( FT_Validator valid
,
100 const FT_Byte
* limit
,
101 FT_ValidationLevel level
)
104 valid
->limit
= limit
;
105 valid
->level
= level
;
106 valid
->error
= FT_Err_Ok
;
110 FT_BASE_DEF( FT_Int
)
111 ft_validator_run( FT_Validator valid
)
113 /* This function doesn't work! None should call it. */
121 ft_validator_error( FT_Validator valid
,
124 /* since the cast below also disables the compiler's */
125 /* type check, we introduce a dummy variable, which */
126 /* will be optimized away */
127 volatile ft_jmp_buf
* jump_buffer
= &valid
->jump_buffer
;
130 valid
->error
= error
;
132 /* throw away volatileness; use `jump_buffer' or the */
133 /* compiler may warn about an unused local variable */
134 ft_longjmp( *(ft_jmp_buf
*) jump_buffer
, 1 );
138 /*************************************************************************/
139 /*************************************************************************/
140 /*************************************************************************/
143 /**** S T R E A M ****/
146 /*************************************************************************/
147 /*************************************************************************/
148 /*************************************************************************/
151 /* create a new input stream from an FT_Open_Args structure */
153 FT_BASE_DEF( FT_Error
)
154 FT_Stream_New( FT_Library library
,
155 const FT_Open_Args
* args
,
160 FT_Stream stream
= NULL
;
166 return FT_THROW( Invalid_Library_Handle
);
169 return FT_THROW( Invalid_Argument
);
171 memory
= library
->memory
;
173 if ( FT_NEW( stream
) )
176 stream
->memory
= memory
;
178 if ( args
->flags
& FT_OPEN_MEMORY
)
180 /* create a memory-based stream */
181 FT_Stream_OpenMemory( stream
,
182 (const FT_Byte
*)args
->memory_base
,
186 #ifndef FT_CONFIG_OPTION_DISABLE_STREAM_SUPPORT
188 else if ( args
->flags
& FT_OPEN_PATHNAME
)
190 /* create a normal system stream */
191 error
= FT_Stream_Open( stream
, args
->pathname
);
192 stream
->pathname
.pointer
= args
->pathname
;
194 else if ( ( args
->flags
& FT_OPEN_STREAM
) && args
->stream
)
196 /* use an existing, user-provided stream */
198 /* in this case, we do not need to allocate a new stream object */
199 /* since the caller is responsible for closing it himself */
201 stream
= args
->stream
;
207 error
= FT_THROW( Invalid_Argument
);
212 stream
->memory
= memory
; /* just to be certain */
222 FT_Stream_Free( FT_Stream stream
,
227 FT_Memory memory
= stream
->memory
;
230 FT_Stream_Close( stream
);
238 /*************************************************************************/
240 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
241 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
242 /* messages during execution. */
245 #define FT_COMPONENT trace_objs
248 /*************************************************************************/
249 /*************************************************************************/
250 /*************************************************************************/
253 /**** FACE, SIZE & GLYPH SLOT OBJECTS ****/
256 /*************************************************************************/
257 /*************************************************************************/
258 /*************************************************************************/
262 ft_glyphslot_init( FT_GlyphSlot slot
)
264 FT_Driver driver
= slot
->face
->driver
;
265 FT_Driver_Class clazz
= driver
->clazz
;
266 FT_Memory memory
= driver
->root
.memory
;
267 FT_Error error
= FT_Err_Ok
;
268 FT_Slot_Internal internal
= NULL
;
271 slot
->library
= driver
->root
.library
;
273 if ( FT_NEW( internal
) )
276 slot
->internal
= internal
;
278 if ( FT_DRIVER_USES_OUTLINES( driver
) )
279 error
= FT_GlyphLoader_New( memory
, &internal
->loader
);
281 if ( !error
&& clazz
->init_slot
)
282 error
= clazz
->init_slot( slot
);
290 ft_glyphslot_free_bitmap( FT_GlyphSlot slot
)
292 if ( slot
->internal
&& ( slot
->internal
->flags
& FT_GLYPH_OWN_BITMAP
) )
294 FT_Memory memory
= FT_FACE_MEMORY( slot
->face
);
297 FT_FREE( slot
->bitmap
.buffer
);
298 slot
->internal
->flags
&= ~FT_GLYPH_OWN_BITMAP
;
302 /* assume that the bitmap buffer was stolen or not */
303 /* allocated from the heap */
304 slot
->bitmap
.buffer
= NULL
;
310 ft_glyphslot_set_bitmap( FT_GlyphSlot slot
,
313 ft_glyphslot_free_bitmap( slot
);
315 slot
->bitmap
.buffer
= buffer
;
317 FT_ASSERT( (slot
->internal
->flags
& FT_GLYPH_OWN_BITMAP
) == 0 );
321 FT_BASE_DEF( FT_Error
)
322 ft_glyphslot_alloc_bitmap( FT_GlyphSlot slot
,
325 FT_Memory memory
= FT_FACE_MEMORY( slot
->face
);
329 if ( slot
->internal
->flags
& FT_GLYPH_OWN_BITMAP
)
330 FT_FREE( slot
->bitmap
.buffer
);
332 slot
->internal
->flags
|= FT_GLYPH_OWN_BITMAP
;
334 (void)FT_ALLOC( slot
->bitmap
.buffer
, size
);
340 ft_glyphslot_clear( FT_GlyphSlot slot
)
342 /* free bitmap if needed */
343 ft_glyphslot_free_bitmap( slot
);
345 /* clear all public fields in the glyph slot */
346 FT_ZERO( &slot
->metrics
);
347 FT_ZERO( &slot
->outline
);
349 slot
->bitmap
.width
= 0;
350 slot
->bitmap
.rows
= 0;
351 slot
->bitmap
.pitch
= 0;
352 slot
->bitmap
.pixel_mode
= 0;
353 /* `slot->bitmap.buffer' has been handled by ft_glyphslot_free_bitmap */
355 slot
->bitmap_left
= 0;
356 slot
->bitmap_top
= 0;
357 slot
->num_subglyphs
= 0;
359 slot
->control_data
= 0;
360 slot
->control_len
= 0;
362 slot
->format
= FT_GLYPH_FORMAT_NONE
;
364 slot
->linearHoriAdvance
= 0;
365 slot
->linearVertAdvance
= 0;
372 ft_glyphslot_done( FT_GlyphSlot slot
)
374 FT_Driver driver
= slot
->face
->driver
;
375 FT_Driver_Class clazz
= driver
->clazz
;
376 FT_Memory memory
= driver
->root
.memory
;
379 if ( clazz
->done_slot
)
380 clazz
->done_slot( slot
);
382 /* free bitmap buffer if needed */
383 ft_glyphslot_free_bitmap( slot
);
385 /* slot->internal might be NULL in out-of-memory situations */
386 if ( slot
->internal
)
388 /* free glyph loader */
389 if ( FT_DRIVER_USES_OUTLINES( driver
) )
391 FT_GlyphLoader_Done( slot
->internal
->loader
);
392 slot
->internal
->loader
= 0;
395 FT_FREE( slot
->internal
);
400 /* documentation is in ftobjs.h */
402 FT_BASE_DEF( FT_Error
)
403 FT_New_GlyphSlot( FT_Face face
,
404 FT_GlyphSlot
*aslot
)
408 FT_Driver_Class clazz
;
410 FT_GlyphSlot slot
= NULL
;
413 if ( !face
|| !face
->driver
)
414 return FT_THROW( Invalid_Argument
);
416 driver
= face
->driver
;
417 clazz
= driver
->clazz
;
418 memory
= driver
->root
.memory
;
420 FT_TRACE4(( "FT_New_GlyphSlot: Creating new slot object\n" ));
421 if ( !FT_ALLOC( slot
, clazz
->slot_object_size
) )
425 error
= ft_glyphslot_init( slot
);
428 ft_glyphslot_done( slot
);
433 slot
->next
= face
->glyph
;
444 FT_TRACE4(( "FT_New_GlyphSlot: Return %d\n", error
));
449 /* documentation is in ftobjs.h */
452 FT_Done_GlyphSlot( FT_GlyphSlot slot
)
456 FT_Driver driver
= slot
->face
->driver
;
457 FT_Memory memory
= driver
->root
.memory
;
462 /* Remove slot from its parent face's list */
464 cur
= slot
->face
->glyph
;
471 slot
->face
->glyph
= cur
->next
;
473 prev
->next
= cur
->next
;
475 /* finalize client-specific data */
476 if ( slot
->generic
.finalizer
)
477 slot
->generic
.finalizer( slot
);
479 ft_glyphslot_done( slot
);
490 /* documentation is in freetype.h */
492 FT_EXPORT_DEF( void )
493 FT_Set_Transform( FT_Face face
,
497 FT_Face_Internal internal
;
503 internal
= face
->internal
;
505 internal
->transform_flags
= 0;
509 internal
->transform_matrix
.xx
= 0x10000L
;
510 internal
->transform_matrix
.xy
= 0;
511 internal
->transform_matrix
.yx
= 0;
512 internal
->transform_matrix
.yy
= 0x10000L
;
513 matrix
= &internal
->transform_matrix
;
516 internal
->transform_matrix
= *matrix
;
518 /* set transform_flags bit flag 0 if `matrix' isn't the identity */
519 if ( ( matrix
->xy
| matrix
->yx
) ||
520 matrix
->xx
!= 0x10000L
||
521 matrix
->yy
!= 0x10000L
)
522 internal
->transform_flags
|= 1;
526 internal
->transform_delta
.x
= 0;
527 internal
->transform_delta
.y
= 0;
528 delta
= &internal
->transform_delta
;
531 internal
->transform_delta
= *delta
;
533 /* set transform_flags bit flag 1 if `delta' isn't the null vector */
534 if ( delta
->x
| delta
->y
)
535 internal
->transform_flags
|= 2;
540 ft_lookup_glyph_renderer( FT_GlyphSlot slot
);
543 #ifdef GRID_FIT_METRICS
545 ft_glyphslot_grid_fit_metrics( FT_GlyphSlot slot
,
548 FT_Glyph_Metrics
* metrics
= &slot
->metrics
;
549 FT_Pos right
, bottom
;
554 metrics
->horiBearingX
= FT_PIX_FLOOR( metrics
->horiBearingX
);
555 metrics
->horiBearingY
= FT_PIX_CEIL ( metrics
->horiBearingY
);
557 right
= FT_PIX_CEIL( metrics
->vertBearingX
+ metrics
->width
);
558 bottom
= FT_PIX_CEIL( metrics
->vertBearingY
+ metrics
->height
);
560 metrics
->vertBearingX
= FT_PIX_FLOOR( metrics
->vertBearingX
);
561 metrics
->vertBearingY
= FT_PIX_FLOOR( metrics
->vertBearingY
);
563 metrics
->width
= right
- metrics
->vertBearingX
;
564 metrics
->height
= bottom
- metrics
->vertBearingY
;
568 metrics
->vertBearingX
= FT_PIX_FLOOR( metrics
->vertBearingX
);
569 metrics
->vertBearingY
= FT_PIX_FLOOR( metrics
->vertBearingY
);
571 right
= FT_PIX_CEIL ( metrics
->horiBearingX
+ metrics
->width
);
572 bottom
= FT_PIX_FLOOR( metrics
->horiBearingY
- metrics
->height
);
574 metrics
->horiBearingX
= FT_PIX_FLOOR( metrics
->horiBearingX
);
575 metrics
->horiBearingY
= FT_PIX_CEIL ( metrics
->horiBearingY
);
577 metrics
->width
= right
- metrics
->horiBearingX
;
578 metrics
->height
= metrics
->horiBearingY
- bottom
;
581 metrics
->horiAdvance
= FT_PIX_ROUND( metrics
->horiAdvance
);
582 metrics
->vertAdvance
= FT_PIX_ROUND( metrics
->vertAdvance
);
584 #endif /* GRID_FIT_METRICS */
587 /* documentation is in freetype.h */
589 FT_EXPORT_DEF( FT_Error
)
590 FT_Load_Glyph( FT_Face face
,
592 FT_Int32 load_flags
)
598 FT_Bool autohint
= FALSE
;
600 TT_Face ttface
= (TT_Face
)face
;
603 if ( !face
|| !face
->size
|| !face
->glyph
)
604 return FT_THROW( Invalid_Face_Handle
);
606 /* The validity test for `glyph_index' is performed by the */
610 ft_glyphslot_clear( slot
);
612 driver
= face
->driver
;
613 library
= driver
->root
.library
;
614 hinter
= library
->auto_hinter
;
616 /* resolve load flags dependencies */
618 if ( load_flags
& FT_LOAD_NO_RECURSE
)
619 load_flags
|= FT_LOAD_NO_SCALE
|
620 FT_LOAD_IGNORE_TRANSFORM
;
622 if ( load_flags
& FT_LOAD_NO_SCALE
)
624 load_flags
|= FT_LOAD_NO_HINTING
|
627 load_flags
&= ~FT_LOAD_RENDER
;
631 * Determine whether we need to auto-hint or not.
632 * The general rules are:
634 * - Do only auto-hinting if we have a hinter module, a scalable font
635 * format dealing with outlines, and no transforms except simple
636 * slants and/or rotations by integer multiples of 90 degrees.
638 * - Then, auto-hint if FT_LOAD_FORCE_AUTOHINT is set or if we don't
639 * have a native font hinter.
641 * - Otherwise, auto-hint for LIGHT hinting mode or if there isn't
642 * any hinting bytecode in the TrueType/OpenType font.
644 * - Exception: The font is `tricky' and requires the native hinter to
649 !( load_flags
& FT_LOAD_NO_HINTING
) &&
650 !( load_flags
& FT_LOAD_NO_AUTOHINT
) &&
651 FT_DRIVER_IS_SCALABLE( driver
) &&
652 FT_DRIVER_USES_OUTLINES( driver
) &&
653 !FT_IS_TRICKY( face
) &&
654 ( ( load_flags
& FT_LOAD_IGNORE_TRANSFORM
) ||
655 ( face
->internal
->transform_matrix
.yx
== 0 &&
656 face
->internal
->transform_matrix
.xx
!= 0 ) ||
657 ( face
->internal
->transform_matrix
.xx
== 0 &&
658 face
->internal
->transform_matrix
.yx
!= 0 ) ) )
660 if ( ( load_flags
& FT_LOAD_FORCE_AUTOHINT
) ||
661 !FT_DRIVER_HAS_HINTER( driver
) )
665 FT_Render_Mode mode
= FT_LOAD_TARGET_MODE( load_flags
);
668 /* the check for `num_locations' assures that we actually */
669 /* test for instructions in a TTF and not in a CFF-based OTF */
670 if ( mode
== FT_RENDER_MODE_LIGHT
||
671 face
->internal
->ignore_unpatented_hinter
||
672 ( FT_IS_SFNT( face
) &&
673 ttface
->num_locations
&&
674 ttface
->max_profile
.maxSizeOfInstructions
== 0 ) )
681 FT_AutoHinter_Interface hinting
;
684 /* try to load embedded bitmaps first if available */
686 /* XXX: This is really a temporary hack that should disappear */
687 /* promptly with FreeType 2.1! */
689 if ( FT_HAS_FIXED_SIZES( face
) &&
690 ( load_flags
& FT_LOAD_NO_BITMAP
) == 0 )
692 error
= driver
->clazz
->load_glyph( slot
, face
->size
,
694 load_flags
| FT_LOAD_SBITS_ONLY
);
696 if ( !error
&& slot
->format
== FT_GLYPH_FORMAT_BITMAP
)
701 FT_Face_Internal internal
= face
->internal
;
702 FT_Int transform_flags
= internal
->transform_flags
;
705 /* since the auto-hinter calls FT_Load_Glyph by itself, */
706 /* make sure that glyphs aren't transformed */
707 internal
->transform_flags
= 0;
709 /* load auto-hinted outline */
710 hinting
= (FT_AutoHinter_Interface
)hinter
->clazz
->module_interface
;
712 error
= hinting
->load_glyph( (FT_AutoHinter
)hinter
,
714 glyph_index
, load_flags
);
716 internal
->transform_flags
= transform_flags
;
721 error
= driver
->clazz
->load_glyph( slot
,
728 if ( slot
->format
== FT_GLYPH_FORMAT_OUTLINE
)
730 /* check that the loaded outline is correct */
731 error
= FT_Outline_Check( &slot
->outline
);
735 #ifdef GRID_FIT_METRICS
736 if ( !( load_flags
& FT_LOAD_NO_HINTING
) )
737 ft_glyphslot_grid_fit_metrics( slot
,
738 FT_BOOL( load_flags
& FT_LOAD_VERTICAL_LAYOUT
) );
744 /* compute the advance */
745 if ( load_flags
& FT_LOAD_VERTICAL_LAYOUT
)
748 slot
->advance
.y
= slot
->metrics
.vertAdvance
;
752 slot
->advance
.x
= slot
->metrics
.horiAdvance
;
756 /* compute the linear advance in 16.16 pixels */
757 if ( ( load_flags
& FT_LOAD_LINEAR_DESIGN
) == 0 &&
758 ( FT_IS_SCALABLE( face
) ) )
760 FT_Size_Metrics
* metrics
= &face
->size
->metrics
;
764 slot
->linearHoriAdvance
= FT_MulDiv( slot
->linearHoriAdvance
,
765 metrics
->x_scale
, 64 );
767 slot
->linearVertAdvance
= FT_MulDiv( slot
->linearVertAdvance
,
768 metrics
->y_scale
, 64 );
771 if ( ( load_flags
& FT_LOAD_IGNORE_TRANSFORM
) == 0 )
773 FT_Face_Internal internal
= face
->internal
;
776 /* now, transform the glyph image if needed */
777 if ( internal
->transform_flags
)
780 FT_Renderer renderer
= ft_lookup_glyph_renderer( slot
);
784 error
= renderer
->clazz
->transform_glyph(
786 &internal
->transform_matrix
,
787 &internal
->transform_delta
);
788 else if ( slot
->format
== FT_GLYPH_FORMAT_OUTLINE
)
790 /* apply `standard' transformation if no renderer is available */
791 if ( internal
->transform_flags
& 1 )
792 FT_Outline_Transform( &slot
->outline
,
793 &internal
->transform_matrix
);
795 if ( internal
->transform_flags
& 2 )
796 FT_Outline_Translate( &slot
->outline
,
797 internal
->transform_delta
.x
,
798 internal
->transform_delta
.y
);
801 /* transform advance */
802 FT_Vector_Transform( &slot
->advance
, &internal
->transform_matrix
);
806 FT_TRACE5(( " x advance: %d\n" , slot
->advance
.x
));
807 FT_TRACE5(( " y advance: %d\n" , slot
->advance
.y
));
809 FT_TRACE5(( " linear x advance: %d\n" , slot
->linearHoriAdvance
));
810 FT_TRACE5(( " linear y advance: %d\n" , slot
->linearVertAdvance
));
812 /* do we need to render the image now? */
814 slot
->format
!= FT_GLYPH_FORMAT_BITMAP
&&
815 slot
->format
!= FT_GLYPH_FORMAT_COMPOSITE
&&
816 load_flags
& FT_LOAD_RENDER
)
818 FT_Render_Mode mode
= FT_LOAD_TARGET_MODE( load_flags
);
821 if ( mode
== FT_RENDER_MODE_NORMAL
&&
822 (load_flags
& FT_LOAD_MONOCHROME
) )
823 mode
= FT_RENDER_MODE_MONO
;
825 error
= FT_Render_Glyph( slot
, mode
);
833 /* documentation is in freetype.h */
835 FT_EXPORT_DEF( FT_Error
)
836 FT_Load_Char( FT_Face face
,
838 FT_Int32 load_flags
)
844 return FT_THROW( Invalid_Face_Handle
);
846 glyph_index
= (FT_UInt
)char_code
;
848 glyph_index
= FT_Get_Char_Index( face
, char_code
);
850 return FT_Load_Glyph( face
, glyph_index
, load_flags
);
854 /* destructor for sizes list */
856 destroy_size( FT_Memory memory
,
860 /* finalize client-specific data */
861 if ( size
->generic
.finalizer
)
862 size
->generic
.finalizer( size
);
864 /* finalize format-specific stuff */
865 if ( driver
->clazz
->done_size
)
866 driver
->clazz
->done_size( size
);
868 FT_FREE( size
->internal
);
874 ft_cmap_done_internal( FT_CMap cmap
);
878 destroy_charmaps( FT_Face face
,
887 for ( n
= 0; n
< face
->num_charmaps
; n
++ )
889 FT_CMap cmap
= FT_CMAP( face
->charmaps
[n
] );
892 ft_cmap_done_internal( cmap
);
894 face
->charmaps
[n
] = NULL
;
897 FT_FREE( face
->charmaps
);
898 face
->num_charmaps
= 0;
902 /* destructor for faces list */
904 destroy_face( FT_Memory memory
,
908 FT_Driver_Class clazz
= driver
->clazz
;
911 /* discard auto-hinting data */
912 if ( face
->autohint
.finalizer
)
913 face
->autohint
.finalizer( face
->autohint
.data
);
915 /* Discard glyph slots for this face. */
916 /* Beware! FT_Done_GlyphSlot() changes the field `face->glyph' */
917 while ( face
->glyph
)
918 FT_Done_GlyphSlot( face
->glyph
);
920 /* discard all sizes for this face */
921 FT_List_Finalize( &face
->sizes_list
,
922 (FT_List_Destructor
)destroy_size
,
927 /* now discard client data */
928 if ( face
->generic
.finalizer
)
929 face
->generic
.finalizer( face
);
931 /* discard charmaps */
932 destroy_charmaps( face
, memory
);
934 /* finalize format-specific stuff */
935 if ( clazz
->done_face
)
936 clazz
->done_face( face
);
938 /* close the stream for this face if needed */
941 ( face
->face_flags
& FT_FACE_FLAG_EXTERNAL_STREAM
) != 0 );
946 if ( face
->internal
)
948 FT_FREE( face
->internal
);
955 Destroy_Driver( FT_Driver driver
)
957 FT_List_Finalize( &driver
->faces_list
,
958 (FT_List_Destructor
)destroy_face
,
962 /* check whether we need to drop the driver's glyph loader */
963 if ( FT_DRIVER_USES_OUTLINES( driver
) )
964 FT_GlyphLoader_Done( driver
->glyph_loader
);
968 /*************************************************************************/
971 /* find_unicode_charmap */
974 /* This function finds a Unicode charmap, if there is one. */
975 /* And if there is more than one, it tries to favour the more */
976 /* extensive one, i.e., one that supports UCS-4 against those which */
977 /* are limited to the BMP (said UCS-2 encoding.) */
979 /* This function is called from open_face() (just below), and also */
980 /* from FT_Select_Charmap( ..., FT_ENCODING_UNICODE ). */
983 find_unicode_charmap( FT_Face face
)
989 /* caller should have already checked that `face' is valid */
992 first
= face
->charmaps
;
995 return FT_THROW( Invalid_CharMap_Handle
);
998 * The original TrueType specification(s) only specified charmap
999 * formats that are capable of mapping 8 or 16 bit character codes to
1002 * However, recent updates to the Apple and OpenType specifications
1003 * introduced new formats that are capable of mapping 32-bit character
1004 * codes as well. And these are already used on some fonts, mainly to
1005 * map non-BMP Asian ideographs as defined in Unicode.
1007 * For compatibility purposes, these fonts generally come with
1008 * *several* Unicode charmaps:
1010 * - One of them in the "old" 16-bit format, that cannot access
1011 * all glyphs in the font.
1013 * - Another one in the "new" 32-bit format, that can access all
1016 * This function has been written to always favor a 32-bit charmap
1017 * when found. Otherwise, a 16-bit one is returned when found.
1020 /* Since the `interesting' table, with IDs (3,10), is normally the */
1021 /* last one, we loop backwards. This loses with type1 fonts with */
1022 /* non-BMP characters (<.0001%), this wins with .ttf with non-BMP */
1023 /* chars (.01% ?), and this is the same about 99.99% of the time! */
1025 cur
= first
+ face
->num_charmaps
; /* points after the last one */
1027 for ( ; --cur
>= first
; )
1029 if ( cur
[0]->encoding
== FT_ENCODING_UNICODE
)
1031 /* XXX If some new encodings to represent UCS-4 are added, */
1032 /* they should be added here. */
1033 if ( ( cur
[0]->platform_id
== TT_PLATFORM_MICROSOFT
&&
1034 cur
[0]->encoding_id
== TT_MS_ID_UCS_4
) ||
1035 ( cur
[0]->platform_id
== TT_PLATFORM_APPLE_UNICODE
&&
1036 cur
[0]->encoding_id
== TT_APPLE_ID_UNICODE_32
) )
1038 #ifdef FT_MAX_CHARMAP_CACHEABLE
1039 if ( cur
- first
> FT_MAX_CHARMAP_CACHEABLE
)
1041 FT_ERROR(( "find_unicode_charmap: UCS-4 cmap is found "
1042 "at too late position (%d)\n", cur
- first
));
1046 face
->charmap
= cur
[0];
1052 /* We do not have any UCS-4 charmap. */
1053 /* Do the loop again and search for UCS-2 charmaps. */
1054 cur
= first
+ face
->num_charmaps
;
1056 for ( ; --cur
>= first
; )
1058 if ( cur
[0]->encoding
== FT_ENCODING_UNICODE
)
1060 #ifdef FT_MAX_CHARMAP_CACHEABLE
1061 if ( cur
- first
> FT_MAX_CHARMAP_CACHEABLE
)
1063 FT_ERROR(( "find_unicode_charmap: UCS-2 cmap is found "
1064 "at too late position (%d)\n", cur
- first
));
1068 face
->charmap
= cur
[0];
1073 return FT_THROW( Invalid_CharMap_Handle
);
1077 /*************************************************************************/
1080 /* find_variant_selector_charmap */
1083 /* This function finds the variant selector charmap, if there is one. */
1084 /* There can only be one (platform=0, specific=5, format=14). */
1087 find_variant_selector_charmap( FT_Face face
)
1094 /* caller should have already checked that `face' is valid */
1097 first
= face
->charmaps
;
1102 end
= first
+ face
->num_charmaps
; /* points after the last one */
1104 for ( cur
= first
; cur
< end
; ++cur
)
1106 if ( cur
[0]->platform_id
== TT_PLATFORM_APPLE_UNICODE
&&
1107 cur
[0]->encoding_id
== TT_APPLE_ID_VARIANT_SELECTOR
&&
1108 FT_Get_CMap_Format( cur
[0] ) == 14 )
1110 #ifdef FT_MAX_CHARMAP_CACHEABLE
1111 if ( cur
- first
> FT_MAX_CHARMAP_CACHEABLE
)
1113 FT_ERROR(( "find_unicode_charmap: UVS cmap is found "
1114 "at too late position (%d)\n", cur
- first
));
1126 /*************************************************************************/
1132 /* This function does some work for FT_Open_Face(). */
1135 open_face( FT_Driver driver
,
1139 FT_Parameter
* params
,
1143 FT_Driver_Class clazz
;
1145 FT_Error error
, error2
;
1146 FT_Face_Internal internal
= NULL
;
1149 clazz
= driver
->clazz
;
1150 memory
= driver
->root
.memory
;
1152 /* allocate the face object and perform basic initialization */
1153 if ( FT_ALLOC( face
, clazz
->face_object_size
) )
1156 face
->driver
= driver
;
1157 face
->memory
= memory
;
1158 face
->stream
= stream
;
1160 if ( FT_NEW( internal
) )
1163 face
->internal
= internal
;
1165 #ifdef FT_CONFIG_OPTION_INCREMENTAL
1170 face
->internal
->incremental_interface
= 0;
1171 for ( i
= 0; i
< num_params
&& !face
->internal
->incremental_interface
;
1173 if ( params
[i
].tag
== FT_PARAM_TAG_INCREMENTAL
)
1174 face
->internal
->incremental_interface
=
1175 (FT_Incremental_Interface
)params
[i
].data
;
1179 if ( clazz
->init_face
)
1180 error
= clazz
->init_face( stream
,
1188 /* select Unicode charmap by default */
1189 error2
= find_unicode_charmap( face
);
1191 /* if no Unicode charmap can be found, FT_Err_Invalid_CharMap_Handle */
1194 /* no error should happen, but we want to play safe */
1195 if ( error2
&& FT_ERR_NEQ( error2
, Invalid_CharMap_Handle
) )
1206 destroy_charmaps( face
, memory
);
1207 if ( clazz
->done_face
)
1208 clazz
->done_face( face
);
1209 FT_FREE( internal
);
1218 /* there's a Mac-specific extended implementation of FT_New_Face() */
1219 /* in src/base/ftmac.c */
1221 #ifndef FT_MACINTOSH
1223 /* documentation is in freetype.h */
1225 FT_EXPORT_DEF( FT_Error
)
1226 FT_New_Face( FT_Library library
,
1227 const char* pathname
,
1234 /* test for valid `library' and `aface' delayed to FT_Open_Face() */
1236 return FT_THROW( Invalid_Argument
);
1238 args
.flags
= FT_OPEN_PATHNAME
;
1239 args
.pathname
= (char*)pathname
;
1242 return FT_Open_Face( library
, &args
, face_index
, aface
);
1248 /* documentation is in freetype.h */
1250 FT_EXPORT_DEF( FT_Error
)
1251 FT_New_Memory_Face( FT_Library library
,
1252 const FT_Byte
* file_base
,
1260 /* test for valid `library' and `face' delayed to FT_Open_Face() */
1262 return FT_THROW( Invalid_Argument
);
1264 args
.flags
= FT_OPEN_MEMORY
;
1265 args
.memory_base
= file_base
;
1266 args
.memory_size
= file_size
;
1269 return FT_Open_Face( library
, &args
, face_index
, aface
);
1273 #ifdef FT_CONFIG_OPTION_MAC_FONTS
1275 /* The behavior here is very similar to that in base/ftmac.c, but it */
1276 /* is designed to work on non-mac systems, so no mac specific calls. */
1278 /* We look at the file and determine if it is a mac dfont file or a mac */
1279 /* resource file, or a macbinary file containing a mac resource file. */
1281 /* Unlike ftmac I'm not going to look at a `FOND'. I don't really see */
1282 /* the point, especially since there may be multiple `FOND' resources. */
1283 /* Instead I'll just look for `sfnt' and `POST' resources, ordered as */
1284 /* they occur in the file. */
1286 /* Note that multiple `POST' resources do not mean multiple postscript */
1287 /* fonts; they all get jammed together to make what is essentially a */
1290 /* We aren't interested in `NFNT' or `FONT' bitmap resources. */
1292 /* As soon as we get an `sfnt' load it into memory and pass it off to */
1295 /* If we have a (set of) `POST' resources, massage them into a (memory) */
1296 /* pfb file and pass that to FT_Open_Face. (As with ftmac.c I'm not */
1297 /* going to try to save the kerning info. After all that lives in the */
1298 /* `FOND' which isn't in the file containing the `POST' resources so */
1299 /* we don't really have access to it. */
1302 /* Finalizer for a memory stream; gets called by FT_Done_Face(). */
1303 /* It frees the memory it uses. */
1306 memory_stream_close( FT_Stream stream
)
1308 FT_Memory memory
= stream
->memory
;
1311 FT_FREE( stream
->base
);
1319 /* Create a new memory stream from a buffer and a size. */
1322 new_memory_stream( FT_Library library
,
1325 FT_Stream_CloseFunc close
,
1326 FT_Stream
*astream
)
1330 FT_Stream stream
= NULL
;
1334 return FT_THROW( Invalid_Library_Handle
);
1337 return FT_THROW( Invalid_Argument
);
1340 memory
= library
->memory
;
1341 if ( FT_NEW( stream
) )
1344 FT_Stream_OpenMemory( stream
, base
, size
);
1346 stream
->close
= close
;
1355 /* Create a new FT_Face given a buffer and a driver name. */
1357 FT_LOCAL_DEF( FT_Error
)
1358 open_face_from_buffer( FT_Library library
,
1362 const char* driver_name
,
1367 FT_Stream stream
= NULL
;
1368 FT_Memory memory
= library
->memory
;
1371 error
= new_memory_stream( library
,
1374 memory_stream_close
,
1382 args
.flags
= FT_OPEN_STREAM
;
1383 args
.stream
= stream
;
1386 args
.flags
= args
.flags
| FT_OPEN_DRIVER
;
1387 args
.driver
= FT_Get_Module( library
, driver_name
);
1391 /* At this point, face_index has served its purpose; */
1392 /* whoever calls this function has already used it to */
1393 /* locate the correct font data. We should not propagate */
1394 /* this index to FT_Open_Face() (unless it is negative). */
1396 if ( face_index
> 0 )
1400 error
= FT_Open_Face( library
, &args
, face_index
, aface
);
1402 if ( error
== FT_Err_Ok
)
1403 (*aface
)->face_flags
&= ~FT_FACE_FLAG_EXTERNAL_STREAM
;
1406 FT_Stream_Free( stream
, 0 );
1409 FT_Stream_Close( stream
);
1418 /* Look up `TYP1' or `CID ' table from sfnt table directory. */
1419 /* `offset' and `length' must exclude the binary header in tables. */
1421 /* Type 1 and CID-keyed font drivers should recognize sfnt-wrapped */
1422 /* format too. Here, since we can't expect that the TrueType font */
1423 /* driver is loaded unconditially, we must parse the font by */
1424 /* ourselves. We are only interested in the name of the table and */
1428 ft_lookup_PS_in_sfnt_stream( FT_Stream stream
,
1432 FT_Bool
* is_sfnt_cid
)
1435 FT_UShort numTables
;
1436 FT_Long pstable_index
;
1443 *is_sfnt_cid
= FALSE
;
1445 /* TODO: support for sfnt-wrapped PS/CID in TTC format */
1447 /* version check for 'typ1' (should be ignored?) */
1448 if ( FT_READ_ULONG( tag
) )
1450 if ( tag
!= TTAG_typ1
)
1451 return FT_THROW( Unknown_File_Format
);
1453 if ( FT_READ_USHORT( numTables
) )
1455 if ( FT_STREAM_SKIP( 2 * 3 ) ) /* skip binary search header */
1459 *is_sfnt_cid
= FALSE
;
1461 for ( i
= 0; i
< numTables
; i
++ )
1463 if ( FT_READ_ULONG( tag
) || FT_STREAM_SKIP( 4 ) ||
1464 FT_READ_ULONG( *offset
) || FT_READ_ULONG( *length
) )
1467 if ( tag
== TTAG_CID
)
1472 *is_sfnt_cid
= TRUE
;
1473 if ( face_index
< 0 )
1476 else if ( tag
== TTAG_TYP1
)
1481 *is_sfnt_cid
= FALSE
;
1482 if ( face_index
< 0 )
1485 if ( face_index
>= 0 && pstable_index
== face_index
)
1488 return FT_THROW( Table_Missing
);
1492 FT_LOCAL_DEF( FT_Error
)
1493 open_face_PS_from_sfnt_stream( FT_Library library
,
1497 FT_Parameter
*params
,
1501 FT_Memory memory
= library
->memory
;
1502 FT_ULong offset
, length
;
1504 FT_Bool is_sfnt_cid
;
1505 FT_Byte
* sfnt_ps
= NULL
;
1507 FT_UNUSED( num_params
);
1508 FT_UNUSED( params
);
1511 pos
= FT_Stream_Pos( stream
);
1513 error
= ft_lookup_PS_in_sfnt_stream( stream
,
1521 if ( FT_Stream_Seek( stream
, pos
+ offset
) )
1524 if ( FT_ALLOC( sfnt_ps
, (FT_Long
)length
) )
1527 error
= FT_Stream_Read( stream
, (FT_Byte
*)sfnt_ps
, length
);
1531 error
= open_face_from_buffer( library
,
1534 FT_MIN( face_index
, 0 ),
1535 is_sfnt_cid
? "cid" : "type1",
1542 if ( FT_ERR_EQ( error
, Unknown_File_Format
) )
1544 error1
= FT_Stream_Seek( stream
, pos
);
1554 #ifndef FT_MACINTOSH
1556 /* The resource header says we've got resource_cnt `POST' (type1) */
1557 /* resources in this file. They all need to be coalesced into */
1558 /* one lump which gets passed on to the type1 driver. */
1559 /* Here can be only one PostScript font in a file so face_index */
1560 /* must be 0 (or -1). */
1563 Mac_Read_POST_Resource( FT_Library library
,
1566 FT_Long resource_cnt
,
1570 FT_Error error
= FT_ERR( Cannot_Open_Resource
);
1571 FT_Memory memory
= library
->memory
;
1572 FT_Byte
* pfb_data
= NULL
;
1575 FT_Long pfb_len
, pfb_pos
, pfb_lenpos
;
1579 if ( face_index
== -1 )
1581 if ( face_index
!= 0 )
1584 /* Find the length of all the POST resources, concatenated. Assume */
1585 /* worst case (each resource in its own section). */
1587 for ( i
= 0; i
< resource_cnt
; ++i
)
1589 error
= FT_Stream_Seek( stream
, offsets
[i
] );
1592 if ( FT_READ_LONG( temp
) )
1594 pfb_len
+= temp
+ 6;
1597 if ( FT_ALLOC( pfb_data
, (FT_Long
)pfb_len
+ 2 ) )
1601 pfb_data
[1] = 1; /* Ascii section */
1602 pfb_data
[2] = 0; /* 4-byte length, fill in later */
1611 for ( i
= 0; i
< resource_cnt
; ++i
)
1613 error
= FT_Stream_Seek( stream
, offsets
[i
] );
1616 if ( FT_READ_LONG( rlen
) )
1618 if ( FT_READ_USHORT( flags
) )
1620 FT_TRACE3(( "POST fragment[%d]: offsets=0x%08x, rlen=0x%08x, flags=0x%04x\n",
1621 i
, offsets
[i
], rlen
, flags
));
1623 /* postpone the check of rlen longer than buffer until FT_Stream_Read() */
1624 if ( ( flags
>> 8 ) == 0 ) /* Comment, should not be loaded */
1627 /* the flags are part of the resource, so rlen >= 2. */
1628 /* but some fonts declare rlen = 0 for empty fragment */
1634 if ( ( flags
>> 8 ) == type
)
1638 if ( pfb_lenpos
+ 3 > pfb_len
+ 2 )
1640 pfb_data
[pfb_lenpos
] = (FT_Byte
)( len
);
1641 pfb_data
[pfb_lenpos
+ 1] = (FT_Byte
)( len
>> 8 );
1642 pfb_data
[pfb_lenpos
+ 2] = (FT_Byte
)( len
>> 16 );
1643 pfb_data
[pfb_lenpos
+ 3] = (FT_Byte
)( len
>> 24 );
1645 if ( ( flags
>> 8 ) == 5 ) /* End of font mark */
1648 if ( pfb_pos
+ 6 > pfb_len
+ 2 )
1650 pfb_data
[pfb_pos
++] = 0x80;
1655 pfb_data
[pfb_pos
++] = (FT_Byte
)type
;
1656 pfb_lenpos
= pfb_pos
;
1657 pfb_data
[pfb_pos
++] = 0; /* 4-byte length, fill in later */
1658 pfb_data
[pfb_pos
++] = 0;
1659 pfb_data
[pfb_pos
++] = 0;
1660 pfb_data
[pfb_pos
++] = 0;
1663 error
= FT_ERR( Cannot_Open_Resource
);
1664 if ( pfb_pos
> pfb_len
|| pfb_pos
+ rlen
> pfb_len
)
1667 error
= FT_Stream_Read( stream
, (FT_Byte
*)pfb_data
+ pfb_pos
, rlen
);
1673 if ( pfb_pos
+ 2 > pfb_len
+ 2 )
1675 pfb_data
[pfb_pos
++] = 0x80;
1676 pfb_data
[pfb_pos
++] = 3;
1678 if ( pfb_lenpos
+ 3 > pfb_len
+ 2 )
1680 pfb_data
[pfb_lenpos
] = (FT_Byte
)( len
);
1681 pfb_data
[pfb_lenpos
+ 1] = (FT_Byte
)( len
>> 8 );
1682 pfb_data
[pfb_lenpos
+ 2] = (FT_Byte
)( len
>> 16 );
1683 pfb_data
[pfb_lenpos
+ 3] = (FT_Byte
)( len
>> 24 );
1685 return open_face_from_buffer( library
,
1693 FT_FREE( pfb_data
);
1700 /* The resource header says we've got resource_cnt `sfnt' */
1701 /* (TrueType/OpenType) resources in this file. Look through */
1702 /* them for the one indicated by face_index, load it into mem, */
1703 /* pass it on the the truetype driver and return it. */
1706 Mac_Read_sfnt_Resource( FT_Library library
,
1709 FT_Long resource_cnt
,
1713 FT_Memory memory
= library
->memory
;
1714 FT_Byte
* sfnt_data
= NULL
;
1716 FT_Long flag_offset
;
1719 FT_Long face_index_in_resource
= 0;
1722 if ( face_index
== -1 )
1724 if ( face_index
>= resource_cnt
)
1725 return FT_THROW( Cannot_Open_Resource
);
1727 flag_offset
= offsets
[face_index
];
1728 error
= FT_Stream_Seek( stream
, flag_offset
);
1732 if ( FT_READ_LONG( rlen
) )
1735 return FT_THROW( Cannot_Open_Resource
);
1737 error
= open_face_PS_from_sfnt_stream( library
,
1745 /* rewind sfnt stream before open_face_PS_from_sfnt_stream() */
1746 if ( FT_Stream_Seek( stream
, flag_offset
+ 4 ) )
1749 if ( FT_ALLOC( sfnt_data
, (FT_Long
)rlen
) )
1751 error
= FT_Stream_Read( stream
, (FT_Byte
*)sfnt_data
, rlen
);
1755 is_cff
= rlen
> 4 && !ft_memcmp( sfnt_data
, "OTTO", 4 );
1756 error
= open_face_from_buffer( library
,
1759 face_index_in_resource
,
1760 is_cff
? "cff" : "truetype",
1768 /* Check for a valid resource fork header, or a valid dfont */
1769 /* header. In a resource fork the first 16 bytes are repeated */
1770 /* at the location specified by bytes 4-7. In a dfont bytes */
1771 /* 4-7 point to 16 bytes of zeroes instead. */
1774 IsMacResource( FT_Library library
,
1776 FT_Long resource_offset
,
1780 FT_Memory memory
= library
->memory
;
1782 FT_Long map_offset
, rdara_pos
;
1783 FT_Long
*data_offsets
;
1787 error
= FT_Raccess_Get_HeaderInfo( library
, stream
, resource_offset
,
1788 &map_offset
, &rdara_pos
);
1792 error
= FT_Raccess_Get_DataOffsets( library
, stream
,
1793 map_offset
, rdara_pos
,
1795 &data_offsets
, &count
);
1798 error
= Mac_Read_POST_Resource( library
, stream
, data_offsets
, count
,
1799 face_index
, aface
);
1800 FT_FREE( data_offsets
);
1801 /* POST exists in an LWFN providing a single face */
1803 (*aface
)->num_faces
= 1;
1807 error
= FT_Raccess_Get_DataOffsets( library
, stream
,
1808 map_offset
, rdara_pos
,
1810 &data_offsets
, &count
);
1813 FT_Long face_index_internal
= face_index
% count
;
1816 error
= Mac_Read_sfnt_Resource( library
, stream
, data_offsets
, count
,
1817 face_index_internal
, aface
);
1818 FT_FREE( data_offsets
);
1820 (*aface
)->num_faces
= count
;
1827 /* Check for a valid macbinary header, and if we find one */
1828 /* check that the (flattened) resource fork in it is valid. */
1831 IsMacBinary( FT_Library library
,
1836 unsigned char header
[128];
1838 FT_Long dlen
, offset
;
1841 if ( NULL
== stream
)
1842 return FT_THROW( Invalid_Stream_Operation
);
1844 error
= FT_Stream_Seek( stream
, 0 );
1848 error
= FT_Stream_Read( stream
, (FT_Byte
*)header
, 128 );
1852 if ( header
[ 0] != 0 ||
1858 header
[2 + header
[1]] != 0 )
1859 return FT_THROW( Unknown_File_Format
);
1861 dlen
= ( header
[0x53] << 24 ) |
1862 ( header
[0x54] << 16 ) |
1863 ( header
[0x55] << 8 ) |
1866 rlen
= ( header
[0x57] << 24 ) |
1867 ( header
[0x58] << 16 ) |
1868 ( header
[0x59] << 8 ) |
1871 offset
= 128 + ( ( dlen
+ 127 ) & ~127 );
1873 return IsMacResource( library
, stream
, offset
, face_index
, aface
);
1881 load_face_in_embedded_rfork( FT_Library library
,
1885 const FT_Open_Args
*args
)
1889 #define FT_COMPONENT trace_raccess
1891 FT_Memory memory
= library
->memory
;
1892 FT_Error error
= FT_ERR( Unknown_File_Format
);
1895 char * file_names
[FT_RACCESS_N_RULES
];
1896 FT_Long offsets
[FT_RACCESS_N_RULES
];
1897 FT_Error errors
[FT_RACCESS_N_RULES
];
1898 FT_Bool is_darwin_vfs
, vfs_rfork_has_no_font
= FALSE
; /* not tested */
1901 FT_Stream stream2
= 0;
1904 FT_Raccess_Guess( library
, stream
,
1905 args
->pathname
, file_names
, offsets
, errors
);
1907 for ( i
= 0; i
< FT_RACCESS_N_RULES
; i
++ )
1909 is_darwin_vfs
= ft_raccess_rule_by_darwin_vfs( library
, i
);
1910 if ( is_darwin_vfs
&& vfs_rfork_has_no_font
)
1912 FT_TRACE3(( "Skip rule %d: darwin vfs resource fork"
1913 " is already checked and"
1914 " no font is found\n", i
));
1920 FT_TRACE3(( "Error[%d] has occurred in rule %d\n", errors
[i
], i
));
1924 args2
.flags
= FT_OPEN_PATHNAME
;
1925 args2
.pathname
= file_names
[i
] ? file_names
[i
] : args
->pathname
;
1927 FT_TRACE3(( "Try rule %d: %s (offset=%d) ...",
1928 i
, args2
.pathname
, offsets
[i
] ));
1930 error
= FT_Stream_New( library
, &args2
, &stream2
);
1931 if ( is_darwin_vfs
&& FT_ERR_EQ( error
, Cannot_Open_Stream
) )
1932 vfs_rfork_has_no_font
= TRUE
;
1936 FT_TRACE3(( "failed\n" ));
1940 error
= IsMacResource( library
, stream2
, offsets
[i
],
1941 face_index
, aface
);
1942 FT_Stream_Free( stream2
, 0 );
1944 FT_TRACE3(( "%s\n", error
? "failed": "successful" ));
1948 else if ( is_darwin_vfs
)
1949 vfs_rfork_has_no_font
= TRUE
;
1952 for (i
= 0; i
< FT_RACCESS_N_RULES
; i
++)
1954 if ( file_names
[i
] )
1955 FT_FREE( file_names
[i
] );
1958 /* Caller (load_mac_face) requires FT_Err_Unknown_File_Format. */
1960 error
= FT_ERR( Unknown_File_Format
);
1965 #define FT_COMPONENT trace_objs
1970 /* Check for some macintosh formats without Carbon framework. */
1971 /* Is this a macbinary file? If so look at the resource fork. */
1972 /* Is this a mac dfont file? */
1973 /* Is this an old style resource fork? (in data) */
1974 /* Else call load_face_in_embedded_rfork to try extra rules */
1975 /* (defined in `ftrfork.c'). */
1978 load_mac_face( FT_Library library
,
1982 const FT_Open_Args
*args
)
1988 error
= IsMacBinary( library
, stream
, face_index
, aface
);
1989 if ( FT_ERR_EQ( error
, Unknown_File_Format
) )
1993 #define FT_COMPONENT trace_raccess
1995 FT_TRACE3(( "Try as dfont: %s ...", args
->pathname
));
1997 error
= IsMacResource( library
, stream
, 0, face_index
, aface
);
1999 FT_TRACE3(( "%s\n", error
? "failed" : "successful" ));
2002 #define FT_COMPONENT trace_objs
2006 if ( ( FT_ERR_EQ( error
, Unknown_File_Format
) ||
2007 FT_ERR_EQ( error
, Invalid_Stream_Operation
) ) &&
2008 ( args
->flags
& FT_OPEN_PATHNAME
) )
2009 error
= load_face_in_embedded_rfork( library
, stream
,
2010 face_index
, aface
, args
);
2015 #endif /* !FT_MACINTOSH && FT_CONFIG_OPTION_MAC_FONTS */
2018 /* documentation is in freetype.h */
2020 FT_EXPORT_DEF( FT_Error
)
2021 FT_Open_Face( FT_Library library
,
2022 const FT_Open_Args
* args
,
2027 FT_Driver driver
= NULL
;
2028 FT_Memory memory
= NULL
;
2029 FT_Stream stream
= NULL
;
2030 FT_Face face
= NULL
;
2031 FT_ListNode node
= NULL
;
2032 FT_Bool external_stream
;
2037 /* test for valid `library' delayed to */
2038 /* FT_Stream_New() */
2040 if ( ( !aface
&& face_index
>= 0 ) || !args
)
2041 return FT_THROW( Invalid_Argument
);
2043 external_stream
= FT_BOOL( ( args
->flags
& FT_OPEN_STREAM
) &&
2046 /* create input stream */
2047 error
= FT_Stream_New( library
, args
, &stream
);
2051 memory
= library
->memory
;
2053 /* If the font driver is specified in the `args' structure, use */
2054 /* it. Otherwise, we scan the list of registered drivers. */
2055 if ( ( args
->flags
& FT_OPEN_DRIVER
) && args
->driver
)
2057 driver
= FT_DRIVER( args
->driver
);
2059 /* not all modules are drivers, so check... */
2060 if ( FT_MODULE_IS_DRIVER( driver
) )
2062 FT_Int num_params
= 0;
2063 FT_Parameter
* params
= 0;
2066 if ( args
->flags
& FT_OPEN_PARAMS
)
2068 num_params
= args
->num_params
;
2069 params
= args
->params
;
2072 error
= open_face( driver
, stream
, face_index
,
2073 num_params
, params
, &face
);
2078 error
= FT_THROW( Invalid_Handle
);
2080 FT_Stream_Free( stream
, external_stream
);
2085 error
= FT_ERR( Missing_Module
);
2087 /* check each font driver for an appropriate format */
2088 cur
= library
->modules
;
2089 limit
= cur
+ library
->num_modules
;
2091 for ( ; cur
< limit
; cur
++ )
2093 /* not all modules are font drivers, so check... */
2094 if ( FT_MODULE_IS_DRIVER( cur
[0] ) )
2096 FT_Int num_params
= 0;
2097 FT_Parameter
* params
= 0;
2100 driver
= FT_DRIVER( cur
[0] );
2102 if ( args
->flags
& FT_OPEN_PARAMS
)
2104 num_params
= args
->num_params
;
2105 params
= args
->params
;
2108 error
= open_face( driver
, stream
, face_index
,
2109 num_params
, params
, &face
);
2113 #ifdef FT_CONFIG_OPTION_MAC_FONTS
2114 if ( ft_strcmp( cur
[0]->clazz
->module_name
, "truetype" ) == 0 &&
2115 FT_ERR_EQ( error
, Table_Missing
) )
2117 /* TrueType but essential tables are missing */
2118 if ( FT_Stream_Seek( stream
, 0 ) )
2121 error
= open_face_PS_from_sfnt_stream( library
,
2129 FT_Stream_Free( stream
, external_stream
);
2135 if ( FT_ERR_NEQ( error
, Unknown_File_Format
) )
2141 /* If we are on the mac, and we get an */
2142 /* FT_Err_Invalid_Stream_Operation it may be because we have an */
2143 /* empty data fork, so we need to check the resource fork. */
2144 if ( FT_ERR_NEQ( error
, Cannot_Open_Stream
) &&
2145 FT_ERR_NEQ( error
, Unknown_File_Format
) &&
2146 FT_ERR_NEQ( error
, Invalid_Stream_Operation
) )
2149 #if !defined( FT_MACINTOSH ) && defined( FT_CONFIG_OPTION_MAC_FONTS )
2150 error
= load_mac_face( library
, stream
, face_index
, aface
, args
);
2153 /* We don't want to go to Success here. We've already done that. */
2154 /* On the other hand, if we succeeded we still need to close this */
2155 /* stream (we opened a different stream which extracted the */
2156 /* interesting information out of this stream here. That stream */
2157 /* will still be open and the face will point to it). */
2158 FT_Stream_Free( stream
, external_stream
);
2162 if ( FT_ERR_NEQ( error
, Unknown_File_Format
) )
2164 #endif /* !FT_MACINTOSH && FT_CONFIG_OPTION_MAC_FONTS */
2166 /* no driver is able to handle this format */
2167 error
= FT_THROW( Unknown_File_Format
);
2170 FT_Stream_Free( stream
, external_stream
);
2175 FT_TRACE4(( "FT_Open_Face: New face object, adding to list\n" ));
2177 /* set the FT_FACE_FLAG_EXTERNAL_STREAM bit for FT_Done_Face */
2178 if ( external_stream
)
2179 face
->face_flags
|= FT_FACE_FLAG_EXTERNAL_STREAM
;
2181 /* add the face object to its driver's list */
2182 if ( FT_NEW( node
) )
2186 /* don't assume driver is the same as face->driver, so use */
2187 /* face->driver instead. */
2188 FT_List_Add( &face
->driver
->faces_list
, node
);
2190 /* now allocate a glyph slot object for the face */
2191 FT_TRACE4(( "FT_Open_Face: Creating glyph slot\n" ));
2193 if ( face_index
>= 0 )
2195 error
= FT_New_GlyphSlot( face
, NULL
);
2199 /* finally, allocate a size object for the face */
2204 FT_TRACE4(( "FT_Open_Face: Creating size object\n" ));
2206 error
= FT_New_Size( face
, &size
);
2216 if ( FT_IS_SCALABLE( face
) )
2218 if ( face
->height
< 0 )
2219 face
->height
= (FT_Short
)-face
->height
;
2221 if ( !FT_HAS_VERTICAL( face
) )
2222 face
->max_advance_height
= (FT_Short
)face
->height
;
2225 if ( FT_HAS_FIXED_SIZES( face
) )
2230 for ( i
= 0; i
< face
->num_fixed_sizes
; i
++ )
2232 FT_Bitmap_Size
* bsize
= face
->available_sizes
+ i
;
2235 if ( bsize
->height
< 0 )
2236 bsize
->height
= (FT_Short
)-bsize
->height
;
2237 if ( bsize
->x_ppem
< 0 )
2238 bsize
->x_ppem
= (FT_Short
)-bsize
->x_ppem
;
2239 if ( bsize
->y_ppem
< 0 )
2240 bsize
->y_ppem
= -bsize
->y_ppem
;
2244 /* initialize internal face data */
2246 FT_Face_Internal internal
= face
->internal
;
2249 internal
->transform_matrix
.xx
= 0x10000L
;
2250 internal
->transform_matrix
.xy
= 0;
2251 internal
->transform_matrix
.yx
= 0;
2252 internal
->transform_matrix
.yy
= 0x10000L
;
2254 internal
->transform_delta
.x
= 0;
2255 internal
->transform_delta
.y
= 0;
2257 internal
->refcount
= 1;
2263 FT_Done_Face( face
);
2269 FT_Done_Face( face
); /* face must be in the driver's list */
2271 destroy_face( memory
, face
, driver
);
2274 FT_TRACE4(( "FT_Open_Face: Return %d\n", error
));
2280 /* documentation is in freetype.h */
2282 FT_EXPORT_DEF( FT_Error
)
2283 FT_Attach_File( FT_Face face
,
2284 const char* filepathname
)
2289 /* test for valid `face' delayed to FT_Attach_Stream() */
2291 if ( !filepathname
)
2292 return FT_THROW( Invalid_Argument
);
2295 open
.flags
= FT_OPEN_PATHNAME
;
2296 open
.pathname
= (char*)filepathname
;
2298 return FT_Attach_Stream( face
, &open
);
2302 /* documentation is in freetype.h */
2304 FT_EXPORT_DEF( FT_Error
)
2305 FT_Attach_Stream( FT_Face face
,
2306 FT_Open_Args
* parameters
)
2312 FT_Driver_Class clazz
;
2315 /* test for valid `parameters' delayed to FT_Stream_New() */
2318 return FT_THROW( Invalid_Face_Handle
);
2320 driver
= face
->driver
;
2322 return FT_THROW( Invalid_Driver_Handle
);
2324 error
= FT_Stream_New( driver
->root
.library
, parameters
, &stream
);
2328 /* we implement FT_Attach_Stream in each driver through the */
2329 /* `attach_file' interface */
2331 error
= FT_ERR( Unimplemented_Feature
);
2332 clazz
= driver
->clazz
;
2333 if ( clazz
->attach_file
)
2334 error
= clazz
->attach_file( face
, stream
);
2336 /* close the attached stream */
2337 FT_Stream_Free( stream
,
2338 (FT_Bool
)( parameters
->stream
&&
2339 ( parameters
->flags
& FT_OPEN_STREAM
) ) );
2346 /* documentation is in freetype.h */
2348 FT_EXPORT_DEF( FT_Error
)
2349 FT_Reference_Face( FT_Face face
)
2351 face
->internal
->refcount
++;
2357 /* documentation is in freetype.h */
2359 FT_EXPORT_DEF( FT_Error
)
2360 FT_Done_Face( FT_Face face
)
2368 error
= FT_ERR( Invalid_Face_Handle
);
2369 if ( face
&& face
->driver
)
2371 face
->internal
->refcount
--;
2372 if ( face
->internal
->refcount
> 0 )
2376 driver
= face
->driver
;
2377 memory
= driver
->root
.memory
;
2379 /* find face in driver's list */
2380 node
= FT_List_Find( &driver
->faces_list
, face
);
2383 /* remove face object from the driver's list */
2384 FT_List_Remove( &driver
->faces_list
, node
);
2387 /* now destroy the object proper */
2388 destroy_face( memory
, face
, driver
);
2398 /* documentation is in ftobjs.h */
2400 FT_EXPORT_DEF( FT_Error
)
2401 FT_New_Size( FT_Face face
,
2407 FT_Driver_Class clazz
;
2410 FT_ListNode node
= 0;
2414 return FT_THROW( Invalid_Face_Handle
);
2417 return FT_THROW( Invalid_Size_Handle
);
2419 if ( !face
->driver
)
2420 return FT_THROW( Invalid_Driver_Handle
);
2424 driver
= face
->driver
;
2425 clazz
= driver
->clazz
;
2426 memory
= face
->memory
;
2428 /* Allocate new size object and perform basic initialisation */
2429 if ( FT_ALLOC( size
, clazz
->size_object_size
) || FT_NEW( node
) )
2434 /* for now, do not use any internal fields in size objects */
2437 if ( clazz
->init_size
)
2438 error
= clazz
->init_size( size
);
2440 /* in case of success, add to the face's list */
2445 FT_List_Add( &face
->sizes_list
, node
);
2459 /* documentation is in ftobjs.h */
2461 FT_EXPORT_DEF( FT_Error
)
2462 FT_Done_Size( FT_Size size
)
2472 return FT_THROW( Invalid_Size_Handle
);
2476 return FT_THROW( Invalid_Face_Handle
);
2478 driver
= face
->driver
;
2480 return FT_THROW( Invalid_Driver_Handle
);
2482 memory
= driver
->root
.memory
;
2485 node
= FT_List_Find( &face
->sizes_list
, size
);
2488 FT_List_Remove( &face
->sizes_list
, node
);
2491 if ( face
->size
== size
)
2494 if ( face
->sizes_list
.head
)
2495 face
->size
= (FT_Size
)(face
->sizes_list
.head
->data
);
2498 destroy_size( memory
, size
, driver
);
2501 error
= FT_THROW( Invalid_Size_Handle
);
2507 /* documentation is in ftobjs.h */
2509 FT_BASE_DEF( FT_Error
)
2510 FT_Match_Size( FT_Face face
,
2511 FT_Size_Request req
,
2512 FT_Bool ignore_width
,
2513 FT_ULong
* size_index
)
2519 if ( !FT_HAS_FIXED_SIZES( face
) )
2520 return FT_THROW( Invalid_Face_Handle
);
2522 /* FT_Bitmap_Size doesn't provide enough info... */
2523 if ( req
->type
!= FT_SIZE_REQUEST_TYPE_NOMINAL
)
2524 return FT_THROW( Unimplemented_Feature
);
2526 w
= FT_REQUEST_WIDTH ( req
);
2527 h
= FT_REQUEST_HEIGHT( req
);
2529 if ( req
->width
&& !req
->height
)
2531 else if ( !req
->width
&& req
->height
)
2534 w
= FT_PIX_ROUND( w
);
2535 h
= FT_PIX_ROUND( h
);
2537 for ( i
= 0; i
< face
->num_fixed_sizes
; i
++ )
2539 FT_Bitmap_Size
* bsize
= face
->available_sizes
+ i
;
2542 if ( h
!= FT_PIX_ROUND( bsize
->y_ppem
) )
2545 if ( w
== FT_PIX_ROUND( bsize
->x_ppem
) || ignore_width
)
2547 FT_TRACE3(( "FT_Match_Size: bitmap strike %d matches\n", i
));
2550 *size_index
= (FT_ULong
)i
;
2556 return FT_THROW( Invalid_Pixel_Size
);
2560 /* documentation is in ftobjs.h */
2563 ft_synthesize_vertical_metrics( FT_Glyph_Metrics
* metrics
,
2566 FT_Pos height
= metrics
->height
;
2569 /* compensate for glyph with bbox above/below the baseline */
2570 if ( metrics
->horiBearingY
< 0 )
2572 if ( height
< metrics
->horiBearingY
)
2573 height
= metrics
->horiBearingY
;
2575 else if ( metrics
->horiBearingY
> 0 )
2576 height
-= metrics
->horiBearingY
;
2578 /* the factor 1.2 is a heuristical value */
2580 advance
= height
* 12 / 10;
2582 metrics
->vertBearingX
= metrics
->horiBearingX
- metrics
->horiAdvance
/ 2;
2583 metrics
->vertBearingY
= ( advance
- height
) / 2;
2584 metrics
->vertAdvance
= advance
;
2589 ft_recompute_scaled_metrics( FT_Face face
,
2590 FT_Size_Metrics
* metrics
)
2592 /* Compute root ascender, descender, test height, and max_advance */
2594 #ifdef GRID_FIT_METRICS
2595 metrics
->ascender
= FT_PIX_CEIL( FT_MulFix( face
->ascender
,
2596 metrics
->y_scale
) );
2598 metrics
->descender
= FT_PIX_FLOOR( FT_MulFix( face
->descender
,
2599 metrics
->y_scale
) );
2601 metrics
->height
= FT_PIX_ROUND( FT_MulFix( face
->height
,
2602 metrics
->y_scale
) );
2604 metrics
->max_advance
= FT_PIX_ROUND( FT_MulFix( face
->max_advance_width
,
2605 metrics
->x_scale
) );
2606 #else /* !GRID_FIT_METRICS */
2607 metrics
->ascender
= FT_MulFix( face
->ascender
,
2610 metrics
->descender
= FT_MulFix( face
->descender
,
2613 metrics
->height
= FT_MulFix( face
->height
,
2616 metrics
->max_advance
= FT_MulFix( face
->max_advance_width
,
2618 #endif /* !GRID_FIT_METRICS */
2623 FT_Select_Metrics( FT_Face face
,
2624 FT_ULong strike_index
)
2626 FT_Size_Metrics
* metrics
;
2627 FT_Bitmap_Size
* bsize
;
2630 metrics
= &face
->size
->metrics
;
2631 bsize
= face
->available_sizes
+ strike_index
;
2633 metrics
->x_ppem
= (FT_UShort
)( ( bsize
->x_ppem
+ 32 ) >> 6 );
2634 metrics
->y_ppem
= (FT_UShort
)( ( bsize
->y_ppem
+ 32 ) >> 6 );
2636 if ( FT_IS_SCALABLE( face
) )
2638 metrics
->x_scale
= FT_DivFix( bsize
->x_ppem
,
2639 face
->units_per_EM
);
2640 metrics
->y_scale
= FT_DivFix( bsize
->y_ppem
,
2641 face
->units_per_EM
);
2643 ft_recompute_scaled_metrics( face
, metrics
);
2647 metrics
->x_scale
= 1L << 16;
2648 metrics
->y_scale
= 1L << 16;
2649 metrics
->ascender
= bsize
->y_ppem
;
2650 metrics
->descender
= 0;
2651 metrics
->height
= bsize
->height
<< 6;
2652 metrics
->max_advance
= bsize
->x_ppem
;
2655 FT_TRACE5(( "FT_Select_Metrics:\n" ));
2656 FT_TRACE5(( " x scale: %d (%f)\n",
2657 metrics
->x_scale
, metrics
->x_scale
/ 65536.0 ));
2658 FT_TRACE5(( " y scale: %d (%f)\n",
2659 metrics
->y_scale
, metrics
->y_scale
/ 65536.0 ));
2660 FT_TRACE5(( " ascender: %f\n", metrics
->ascender
/ 64.0 ));
2661 FT_TRACE5(( " descender: %f\n", metrics
->descender
/ 64.0 ));
2662 FT_TRACE5(( " height: %f\n", metrics
->height
/ 64.0 ));
2663 FT_TRACE5(( " max advance: %f\n", metrics
->max_advance
/ 64.0 ));
2664 FT_TRACE5(( " x ppem: %d\n", metrics
->x_ppem
));
2665 FT_TRACE5(( " y ppem: %d\n", metrics
->y_ppem
));
2670 FT_Request_Metrics( FT_Face face
,
2671 FT_Size_Request req
)
2673 FT_Size_Metrics
* metrics
;
2676 metrics
= &face
->size
->metrics
;
2678 if ( FT_IS_SCALABLE( face
) )
2680 FT_Long w
= 0, h
= 0, scaled_w
= 0, scaled_h
= 0;
2683 switch ( req
->type
)
2685 case FT_SIZE_REQUEST_TYPE_NOMINAL
:
2686 w
= h
= face
->units_per_EM
;
2689 case FT_SIZE_REQUEST_TYPE_REAL_DIM
:
2690 w
= h
= face
->ascender
- face
->descender
;
2693 case FT_SIZE_REQUEST_TYPE_BBOX
:
2694 w
= face
->bbox
.xMax
- face
->bbox
.xMin
;
2695 h
= face
->bbox
.yMax
- face
->bbox
.yMin
;
2698 case FT_SIZE_REQUEST_TYPE_CELL
:
2699 w
= face
->max_advance_width
;
2700 h
= face
->ascender
- face
->descender
;
2703 case FT_SIZE_REQUEST_TYPE_SCALES
:
2704 metrics
->x_scale
= (FT_Fixed
)req
->width
;
2705 metrics
->y_scale
= (FT_Fixed
)req
->height
;
2706 if ( !metrics
->x_scale
)
2707 metrics
->x_scale
= metrics
->y_scale
;
2708 else if ( !metrics
->y_scale
)
2709 metrics
->y_scale
= metrics
->x_scale
;
2710 goto Calculate_Ppem
;
2712 case FT_SIZE_REQUEST_TYPE_MAX
:
2716 /* to be on the safe side */
2723 scaled_w
= FT_REQUEST_WIDTH ( req
);
2724 scaled_h
= FT_REQUEST_HEIGHT( req
);
2726 /* determine scales */
2729 metrics
->x_scale
= FT_DivFix( scaled_w
, w
);
2733 metrics
->y_scale
= FT_DivFix( scaled_h
, h
);
2735 if ( req
->type
== FT_SIZE_REQUEST_TYPE_CELL
)
2737 if ( metrics
->y_scale
> metrics
->x_scale
)
2738 metrics
->y_scale
= metrics
->x_scale
;
2740 metrics
->x_scale
= metrics
->y_scale
;
2745 metrics
->y_scale
= metrics
->x_scale
;
2746 scaled_h
= FT_MulDiv( scaled_w
, h
, w
);
2751 metrics
->x_scale
= metrics
->y_scale
= FT_DivFix( scaled_h
, h
);
2752 scaled_w
= FT_MulDiv( scaled_h
, w
, h
);
2756 /* calculate the ppems */
2757 if ( req
->type
!= FT_SIZE_REQUEST_TYPE_NOMINAL
)
2759 scaled_w
= FT_MulFix( face
->units_per_EM
, metrics
->x_scale
);
2760 scaled_h
= FT_MulFix( face
->units_per_EM
, metrics
->y_scale
);
2763 metrics
->x_ppem
= (FT_UShort
)( ( scaled_w
+ 32 ) >> 6 );
2764 metrics
->y_ppem
= (FT_UShort
)( ( scaled_h
+ 32 ) >> 6 );
2766 ft_recompute_scaled_metrics( face
, metrics
);
2771 metrics
->x_scale
= 1L << 16;
2772 metrics
->y_scale
= 1L << 16;
2775 FT_TRACE5(( "FT_Request_Metrics:\n" ));
2776 FT_TRACE5(( " x scale: %d (%f)\n",
2777 metrics
->x_scale
, metrics
->x_scale
/ 65536.0 ));
2778 FT_TRACE5(( " y scale: %d (%f)\n",
2779 metrics
->y_scale
, metrics
->y_scale
/ 65536.0 ));
2780 FT_TRACE5(( " ascender: %f\n", metrics
->ascender
/ 64.0 ));
2781 FT_TRACE5(( " descender: %f\n", metrics
->descender
/ 64.0 ));
2782 FT_TRACE5(( " height: %f\n", metrics
->height
/ 64.0 ));
2783 FT_TRACE5(( " max advance: %f\n", metrics
->max_advance
/ 64.0 ));
2784 FT_TRACE5(( " x ppem: %d\n", metrics
->x_ppem
));
2785 FT_TRACE5(( " y ppem: %d\n", metrics
->y_ppem
));
2789 /* documentation is in freetype.h */
2791 FT_EXPORT_DEF( FT_Error
)
2792 FT_Select_Size( FT_Face face
,
2793 FT_Int strike_index
)
2795 FT_Driver_Class clazz
;
2798 if ( !face
|| !FT_HAS_FIXED_SIZES( face
) )
2799 return FT_THROW( Invalid_Face_Handle
);
2801 if ( strike_index
< 0 || strike_index
>= face
->num_fixed_sizes
)
2802 return FT_THROW( Invalid_Argument
);
2804 clazz
= face
->driver
->clazz
;
2806 if ( clazz
->select_size
)
2811 error
= clazz
->select_size( face
->size
, (FT_ULong
)strike_index
);
2813 #ifdef FT_DEBUG_LEVEL_TRACE
2815 FT_Size_Metrics
* metrics
= &face
->size
->metrics
;
2818 FT_TRACE5(( "FT_Select_Size (font driver's `select_size'):\n" ));
2819 FT_TRACE5(( " x scale: %d (%f)\n",
2820 metrics
->x_scale
, metrics
->x_scale
/ 65536.0 ));
2821 FT_TRACE5(( " y scale: %d (%f)\n",
2822 metrics
->y_scale
, metrics
->y_scale
/ 65536.0 ));
2823 FT_TRACE5(( " ascender: %f\n", metrics
->ascender
/ 64.0 ));
2824 FT_TRACE5(( " descender: %f\n", metrics
->descender
/ 64.0 ));
2825 FT_TRACE5(( " height: %f\n", metrics
->height
/ 64.0 ));
2826 FT_TRACE5(( " max advance: %f\n", metrics
->max_advance
/ 64.0 ));
2827 FT_TRACE5(( " x ppem: %d\n", metrics
->x_ppem
));
2828 FT_TRACE5(( " y ppem: %d\n", metrics
->y_ppem
));
2835 FT_Select_Metrics( face
, (FT_ULong
)strike_index
);
2841 /* documentation is in freetype.h */
2843 FT_EXPORT_DEF( FT_Error
)
2844 FT_Request_Size( FT_Face face
,
2845 FT_Size_Request req
)
2847 FT_Driver_Class clazz
;
2848 FT_ULong strike_index
;
2852 return FT_THROW( Invalid_Face_Handle
);
2854 if ( !req
|| req
->width
< 0 || req
->height
< 0 ||
2855 req
->type
>= FT_SIZE_REQUEST_TYPE_MAX
)
2856 return FT_THROW( Invalid_Argument
);
2858 clazz
= face
->driver
->clazz
;
2860 if ( clazz
->request_size
)
2865 error
= clazz
->request_size( face
->size
, req
);
2867 #ifdef FT_DEBUG_LEVEL_TRACE
2869 FT_Size_Metrics
* metrics
= &face
->size
->metrics
;
2872 FT_TRACE5(( "FT_Request_Size (font driver's `request_size'):\n" ));
2873 FT_TRACE5(( " x scale: %d (%f)\n",
2874 metrics
->x_scale
, metrics
->x_scale
/ 65536.0 ));
2875 FT_TRACE5(( " y scale: %d (%f)\n",
2876 metrics
->y_scale
, metrics
->y_scale
/ 65536.0 ));
2877 FT_TRACE5(( " ascender: %f\n", metrics
->ascender
/ 64.0 ));
2878 FT_TRACE5(( " descender: %f\n", metrics
->descender
/ 64.0 ));
2879 FT_TRACE5(( " height: %f\n", metrics
->height
/ 64.0 ));
2880 FT_TRACE5(( " max advance: %f\n", metrics
->max_advance
/ 64.0 ));
2881 FT_TRACE5(( " x ppem: %d\n", metrics
->x_ppem
));
2882 FT_TRACE5(( " y ppem: %d\n", metrics
->y_ppem
));
2890 * The reason that a driver doesn't have `request_size' defined is
2891 * either that the scaling here suffices or that the supported formats
2892 * are bitmap-only and size matching is not implemented.
2894 * In the latter case, a simple size matching is done.
2896 if ( !FT_IS_SCALABLE( face
) && FT_HAS_FIXED_SIZES( face
) )
2901 error
= FT_Match_Size( face
, req
, 0, &strike_index
);
2905 return FT_Select_Size( face
, (FT_Int
)strike_index
);
2908 FT_Request_Metrics( face
, req
);
2914 /* documentation is in freetype.h */
2916 FT_EXPORT_DEF( FT_Error
)
2917 FT_Set_Char_Size( FT_Face face
,
2918 FT_F26Dot6 char_width
,
2919 FT_F26Dot6 char_height
,
2920 FT_UInt horz_resolution
,
2921 FT_UInt vert_resolution
)
2923 FT_Size_RequestRec req
;
2927 char_width
= char_height
;
2928 else if ( !char_height
)
2929 char_height
= char_width
;
2931 if ( !horz_resolution
)
2932 horz_resolution
= vert_resolution
;
2933 else if ( !vert_resolution
)
2934 vert_resolution
= horz_resolution
;
2936 if ( char_width
< 1 * 64 )
2937 char_width
= 1 * 64;
2938 if ( char_height
< 1 * 64 )
2939 char_height
= 1 * 64;
2941 if ( !horz_resolution
)
2942 horz_resolution
= vert_resolution
= 72;
2944 req
.type
= FT_SIZE_REQUEST_TYPE_NOMINAL
;
2945 req
.width
= char_width
;
2946 req
.height
= char_height
;
2947 req
.horiResolution
= horz_resolution
;
2948 req
.vertResolution
= vert_resolution
;
2950 return FT_Request_Size( face
, &req
);
2954 /* documentation is in freetype.h */
2956 FT_EXPORT_DEF( FT_Error
)
2957 FT_Set_Pixel_Sizes( FT_Face face
,
2958 FT_UInt pixel_width
,
2959 FT_UInt pixel_height
)
2961 FT_Size_RequestRec req
;
2964 if ( pixel_width
== 0 )
2965 pixel_width
= pixel_height
;
2966 else if ( pixel_height
== 0 )
2967 pixel_height
= pixel_width
;
2969 if ( pixel_width
< 1 )
2971 if ( pixel_height
< 1 )
2974 /* use `>=' to avoid potential compiler warning on 16bit platforms */
2975 if ( pixel_width
>= 0xFFFFU
)
2976 pixel_width
= 0xFFFFU
;
2977 if ( pixel_height
>= 0xFFFFU
)
2978 pixel_height
= 0xFFFFU
;
2980 req
.type
= FT_SIZE_REQUEST_TYPE_NOMINAL
;
2981 req
.width
= pixel_width
<< 6;
2982 req
.height
= pixel_height
<< 6;
2983 req
.horiResolution
= 0;
2984 req
.vertResolution
= 0;
2986 return FT_Request_Size( face
, &req
);
2990 /* documentation is in freetype.h */
2992 FT_EXPORT_DEF( FT_Error
)
2993 FT_Get_Kerning( FT_Face face
,
2995 FT_UInt right_glyph
,
2997 FT_Vector
*akerning
)
2999 FT_Error error
= FT_Err_Ok
;
3004 return FT_THROW( Invalid_Face_Handle
);
3007 return FT_THROW( Invalid_Argument
);
3009 driver
= face
->driver
;
3014 if ( driver
->clazz
->get_kerning
)
3016 error
= driver
->clazz
->get_kerning( face
,
3022 if ( kern_mode
!= FT_KERNING_UNSCALED
)
3024 akerning
->x
= FT_MulFix( akerning
->x
, face
->size
->metrics
.x_scale
);
3025 akerning
->y
= FT_MulFix( akerning
->y
, face
->size
->metrics
.y_scale
);
3027 if ( kern_mode
!= FT_KERNING_UNFITTED
)
3029 /* we scale down kerning values for small ppem values */
3030 /* to avoid that rounding makes them too big. */
3031 /* `25' has been determined heuristically. */
3032 if ( face
->size
->metrics
.x_ppem
< 25 )
3033 akerning
->x
= FT_MulDiv( akerning
->x
,
3034 face
->size
->metrics
.x_ppem
, 25 );
3035 if ( face
->size
->metrics
.y_ppem
< 25 )
3036 akerning
->y
= FT_MulDiv( akerning
->y
,
3037 face
->size
->metrics
.y_ppem
, 25 );
3039 akerning
->x
= FT_PIX_ROUND( akerning
->x
);
3040 akerning
->y
= FT_PIX_ROUND( akerning
->y
);
3050 /* documentation is in freetype.h */
3052 FT_EXPORT_DEF( FT_Error
)
3053 FT_Get_Track_Kerning( FT_Face face
,
3054 FT_Fixed point_size
,
3056 FT_Fixed
* akerning
)
3058 FT_Service_Kerning service
;
3059 FT_Error error
= FT_Err_Ok
;
3063 return FT_THROW( Invalid_Face_Handle
);
3066 return FT_THROW( Invalid_Argument
);
3068 FT_FACE_FIND_SERVICE( face
, service
, KERNING
);
3070 return FT_THROW( Unimplemented_Feature
);
3072 error
= service
->get_track( face
,
3081 /* documentation is in freetype.h */
3083 FT_EXPORT_DEF( FT_Error
)
3084 FT_Select_Charmap( FT_Face face
,
3085 FT_Encoding encoding
)
3092 return FT_THROW( Invalid_Face_Handle
);
3094 if ( encoding
== FT_ENCODING_NONE
)
3095 return FT_THROW( Invalid_Argument
);
3097 /* FT_ENCODING_UNICODE is special. We try to find the `best' Unicode */
3098 /* charmap available, i.e., one with UCS-4 characters, if possible. */
3100 /* This is done by find_unicode_charmap() above, to share code. */
3101 if ( encoding
== FT_ENCODING_UNICODE
)
3102 return find_unicode_charmap( face
);
3104 cur
= face
->charmaps
;
3106 return FT_THROW( Invalid_CharMap_Handle
);
3108 limit
= cur
+ face
->num_charmaps
;
3110 for ( ; cur
< limit
; cur
++ )
3112 if ( cur
[0]->encoding
== encoding
)
3114 #ifdef FT_MAX_CHARMAP_CACHEABLE
3115 if ( cur
- face
->charmaps
> FT_MAX_CHARMAP_CACHEABLE
)
3117 FT_ERROR(( "FT_Select_Charmap: requested charmap is found (%d), "
3118 "but in too late position to cache\n",
3119 cur
- face
->charmaps
));
3123 face
->charmap
= cur
[0];
3128 return FT_THROW( Invalid_Argument
);
3132 /* documentation is in freetype.h */
3134 FT_EXPORT_DEF( FT_Error
)
3135 FT_Set_Charmap( FT_Face face
,
3136 FT_CharMap charmap
)
3143 return FT_THROW( Invalid_Face_Handle
);
3145 cur
= face
->charmaps
;
3147 return FT_THROW( Invalid_CharMap_Handle
);
3148 if ( FT_Get_CMap_Format( charmap
) == 14 )
3149 return FT_THROW( Invalid_Argument
);
3151 limit
= cur
+ face
->num_charmaps
;
3153 for ( ; cur
< limit
; cur
++ )
3155 if ( cur
[0] == charmap
)
3157 #ifdef FT_MAX_CHARMAP_CACHEABLE
3158 if ( cur
- face
->charmaps
> FT_MAX_CHARMAP_CACHEABLE
)
3160 FT_ERROR(( "FT_Set_Charmap: requested charmap is found (%d), "
3161 "but in too late position to cache\n",
3162 cur
- face
->charmaps
));
3166 face
->charmap
= cur
[0];
3170 return FT_THROW( Invalid_Argument
);
3174 /* documentation is in freetype.h */
3176 FT_EXPORT_DEF( FT_Int
)
3177 FT_Get_Charmap_Index( FT_CharMap charmap
)
3182 if ( !charmap
|| !charmap
->face
)
3185 for ( i
= 0; i
< charmap
->face
->num_charmaps
; i
++ )
3186 if ( charmap
->face
->charmaps
[i
] == charmap
)
3189 FT_ASSERT( i
< charmap
->face
->num_charmaps
);
3191 #ifdef FT_MAX_CHARMAP_CACHEABLE
3192 if ( i
> FT_MAX_CHARMAP_CACHEABLE
)
3194 FT_ERROR(( "FT_Get_Charmap_Index: requested charmap is found (%d), "
3195 "but in too late position to cache\n",
3205 ft_cmap_done_internal( FT_CMap cmap
)
3207 FT_CMap_Class clazz
= cmap
->clazz
;
3208 FT_Face face
= cmap
->charmap
.face
;
3209 FT_Memory memory
= FT_FACE_MEMORY( face
);
3213 clazz
->done( cmap
);
3220 FT_CMap_Done( FT_CMap cmap
)
3224 FT_Face face
= cmap
->charmap
.face
;
3225 FT_Memory memory
= FT_FACE_MEMORY( face
);
3230 for ( i
= 0; i
< face
->num_charmaps
; i
++ )
3232 if ( (FT_CMap
)face
->charmaps
[i
] == cmap
)
3234 FT_CharMap last_charmap
= face
->charmaps
[face
->num_charmaps
- 1];
3237 if ( FT_RENEW_ARRAY( face
->charmaps
,
3239 face
->num_charmaps
- 1 ) )
3242 /* remove it from our list of charmaps */
3243 for ( j
= i
+ 1; j
< face
->num_charmaps
; j
++ )
3245 if ( j
== face
->num_charmaps
- 1 )
3246 face
->charmaps
[j
- 1] = last_charmap
;
3248 face
->charmaps
[j
- 1] = face
->charmaps
[j
];
3251 face
->num_charmaps
--;
3253 if ( (FT_CMap
)face
->charmap
== cmap
)
3254 face
->charmap
= NULL
;
3256 ft_cmap_done_internal( cmap
);
3265 FT_BASE_DEF( FT_Error
)
3266 FT_CMap_New( FT_CMap_Class clazz
,
3267 FT_Pointer init_data
,
3271 FT_Error error
= FT_Err_Ok
;
3274 FT_CMap cmap
= NULL
;
3277 if ( clazz
== NULL
|| charmap
== NULL
|| charmap
->face
== NULL
)
3278 return FT_THROW( Invalid_Argument
);
3280 face
= charmap
->face
;
3281 memory
= FT_FACE_MEMORY( face
);
3283 if ( !FT_ALLOC( cmap
, clazz
->size
) )
3285 cmap
->charmap
= *charmap
;
3286 cmap
->clazz
= clazz
;
3290 error
= clazz
->init( cmap
, init_data
);
3295 /* add it to our list of charmaps */
3296 if ( FT_RENEW_ARRAY( face
->charmaps
,
3298 face
->num_charmaps
+ 1 ) )
3301 face
->charmaps
[face
->num_charmaps
++] = (FT_CharMap
)cmap
;
3311 ft_cmap_done_internal( cmap
);
3317 /* documentation is in freetype.h */
3319 FT_EXPORT_DEF( FT_UInt
)
3320 FT_Get_Char_Index( FT_Face face
,
3326 if ( face
&& face
->charmap
)
3328 FT_CMap cmap
= FT_CMAP( face
->charmap
);
3331 if ( charcode
> 0xFFFFFFFFUL
)
3333 FT_TRACE1(( "FT_Get_Char_Index: too large charcode" ));
3334 FT_TRACE1(( " 0x%x is truncated\n", charcode
));
3336 result
= cmap
->clazz
->char_index( cmap
, (FT_UInt32
)charcode
);
3342 /* documentation is in freetype.h */
3344 FT_EXPORT_DEF( FT_ULong
)
3345 FT_Get_First_Char( FT_Face face
,
3348 FT_ULong result
= 0;
3352 if ( face
&& face
->charmap
&& face
->num_glyphs
)
3354 gindex
= FT_Get_Char_Index( face
, 0 );
3355 if ( gindex
== 0 || gindex
>= (FT_UInt
)face
->num_glyphs
)
3356 result
= FT_Get_Next_Char( face
, 0, &gindex
);
3366 /* documentation is in freetype.h */
3368 FT_EXPORT_DEF( FT_ULong
)
3369 FT_Get_Next_Char( FT_Face face
,
3373 FT_ULong result
= 0;
3377 if ( face
&& face
->charmap
&& face
->num_glyphs
)
3379 FT_UInt32 code
= (FT_UInt32
)charcode
;
3380 FT_CMap cmap
= FT_CMAP( face
->charmap
);
3384 gindex
= cmap
->clazz
->char_next( cmap
, &code
);
3385 } while ( gindex
>= (FT_UInt
)face
->num_glyphs
);
3387 result
= ( gindex
== 0 ) ? 0 : code
;
3397 /* documentation is in freetype.h */
3399 FT_EXPORT_DEF( FT_UInt
)
3400 FT_Face_GetCharVariantIndex( FT_Face face
,
3402 FT_ULong variantSelector
)
3407 if ( face
&& face
->charmap
&&
3408 face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
3410 FT_CharMap charmap
= find_variant_selector_charmap( face
);
3411 FT_CMap ucmap
= FT_CMAP( face
->charmap
);
3414 if ( charmap
!= NULL
)
3416 FT_CMap vcmap
= FT_CMAP( charmap
);
3419 if ( charcode
> 0xFFFFFFFFUL
)
3421 FT_TRACE1(( "FT_Get_Char_Index: too large charcode" ));
3422 FT_TRACE1(( " 0x%x is truncated\n", charcode
));
3424 if ( variantSelector
> 0xFFFFFFFFUL
)
3426 FT_TRACE1(( "FT_Get_Char_Index: too large variantSelector" ));
3427 FT_TRACE1(( " 0x%x is truncated\n", variantSelector
));
3430 result
= vcmap
->clazz
->char_var_index( vcmap
, ucmap
,
3431 (FT_UInt32
)charcode
,
3432 (FT_UInt32
)variantSelector
);
3440 /* documentation is in freetype.h */
3442 FT_EXPORT_DEF( FT_Int
)
3443 FT_Face_GetCharVariantIsDefault( FT_Face face
,
3445 FT_ULong variantSelector
)
3452 FT_CharMap charmap
= find_variant_selector_charmap( face
);
3455 if ( charmap
!= NULL
)
3457 FT_CMap vcmap
= FT_CMAP( charmap
);
3460 if ( charcode
> 0xFFFFFFFFUL
)
3462 FT_TRACE1(( "FT_Get_Char_Index: too large charcode" ));
3463 FT_TRACE1(( " 0x%x is truncated\n", charcode
));
3465 if ( variantSelector
> 0xFFFFFFFFUL
)
3467 FT_TRACE1(( "FT_Get_Char_Index: too large variantSelector" ));
3468 FT_TRACE1(( " 0x%x is truncated\n", variantSelector
));
3471 result
= vcmap
->clazz
->char_var_default( vcmap
,
3472 (FT_UInt32
)charcode
,
3473 (FT_UInt32
)variantSelector
);
3481 /* documentation is in freetype.h */
3483 FT_EXPORT_DEF( FT_UInt32
* )
3484 FT_Face_GetVariantSelectors( FT_Face face
)
3486 FT_UInt32
*result
= NULL
;
3491 FT_CharMap charmap
= find_variant_selector_charmap( face
);
3494 if ( charmap
!= NULL
)
3496 FT_CMap vcmap
= FT_CMAP( charmap
);
3497 FT_Memory memory
= FT_FACE_MEMORY( face
);
3500 result
= vcmap
->clazz
->variant_list( vcmap
, memory
);
3508 /* documentation is in freetype.h */
3510 FT_EXPORT_DEF( FT_UInt32
* )
3511 FT_Face_GetVariantsOfChar( FT_Face face
,
3514 FT_UInt32
*result
= NULL
;
3519 FT_CharMap charmap
= find_variant_selector_charmap( face
);
3522 if ( charmap
!= NULL
)
3524 FT_CMap vcmap
= FT_CMAP( charmap
);
3525 FT_Memory memory
= FT_FACE_MEMORY( face
);
3528 if ( charcode
> 0xFFFFFFFFUL
)
3530 FT_TRACE1(( "FT_Get_Char_Index: too large charcode" ));
3531 FT_TRACE1(( " 0x%x is truncated\n", charcode
));
3534 result
= vcmap
->clazz
->charvariant_list( vcmap
, memory
,
3535 (FT_UInt32
)charcode
);
3542 /* documentation is in freetype.h */
3544 FT_EXPORT_DEF( FT_UInt32
* )
3545 FT_Face_GetCharsOfVariant( FT_Face face
,
3546 FT_ULong variantSelector
)
3548 FT_UInt32
*result
= NULL
;
3553 FT_CharMap charmap
= find_variant_selector_charmap( face
);
3556 if ( charmap
!= NULL
)
3558 FT_CMap vcmap
= FT_CMAP( charmap
);
3559 FT_Memory memory
= FT_FACE_MEMORY( face
);
3562 if ( variantSelector
> 0xFFFFFFFFUL
)
3564 FT_TRACE1(( "FT_Get_Char_Index: too large variantSelector" ));
3565 FT_TRACE1(( " 0x%x is truncated\n", variantSelector
));
3568 result
= vcmap
->clazz
->variantchar_list( vcmap
, memory
,
3569 (FT_UInt32
)variantSelector
);
3577 /* documentation is in freetype.h */
3579 FT_EXPORT_DEF( FT_UInt
)
3580 FT_Get_Name_Index( FT_Face face
,
3581 FT_String
* glyph_name
)
3586 if ( face
&& FT_HAS_GLYPH_NAMES( face
) )
3588 FT_Service_GlyphDict service
;
3591 FT_FACE_LOOKUP_SERVICE( face
,
3595 if ( service
&& service
->name_index
)
3596 result
= service
->name_index( face
, glyph_name
);
3603 /* documentation is in freetype.h */
3605 FT_EXPORT_DEF( FT_Error
)
3606 FT_Get_Glyph_Name( FT_Face face
,
3607 FT_UInt glyph_index
,
3609 FT_UInt buffer_max
)
3611 FT_Error error
= FT_ERR( Invalid_Argument
);
3614 /* clean up buffer */
3615 if ( buffer
&& buffer_max
> 0 )
3616 ((FT_Byte
*)buffer
)[0] = 0;
3619 (FT_Long
)glyph_index
<= face
->num_glyphs
&&
3620 FT_HAS_GLYPH_NAMES( face
) )
3622 FT_Service_GlyphDict service
;
3625 FT_FACE_LOOKUP_SERVICE( face
,
3629 if ( service
&& service
->get_name
)
3630 error
= service
->get_name( face
, glyph_index
, buffer
, buffer_max
);
3637 /* documentation is in freetype.h */
3639 FT_EXPORT_DEF( const char* )
3640 FT_Get_Postscript_Name( FT_Face face
)
3642 const char* result
= NULL
;
3650 FT_Service_PsFontName service
;
3653 FT_FACE_LOOKUP_SERVICE( face
,
3655 POSTSCRIPT_FONT_NAME
);
3657 if ( service
&& service
->get_ps_font_name
)
3658 result
= service
->get_ps_font_name( face
);
3666 /* documentation is in tttables.h */
3668 FT_EXPORT_DEF( void* )
3669 FT_Get_Sfnt_Table( FT_Face face
,
3673 FT_Service_SFNT_Table service
;
3676 if ( face
&& FT_IS_SFNT( face
) )
3678 FT_FACE_FIND_SERVICE( face
, service
, SFNT_TABLE
);
3679 if ( service
!= NULL
)
3680 table
= service
->get_table( face
, tag
);
3687 /* documentation is in tttables.h */
3689 FT_EXPORT_DEF( FT_Error
)
3690 FT_Load_Sfnt_Table( FT_Face face
,
3696 FT_Service_SFNT_Table service
;
3699 if ( !face
|| !FT_IS_SFNT( face
) )
3700 return FT_THROW( Invalid_Face_Handle
);
3702 FT_FACE_FIND_SERVICE( face
, service
, SFNT_TABLE
);
3703 if ( service
== NULL
)
3704 return FT_THROW( Unimplemented_Feature
);
3706 return service
->load_table( face
, tag
, offset
, buffer
, length
);
3710 /* documentation is in tttables.h */
3712 FT_EXPORT_DEF( FT_Error
)
3713 FT_Sfnt_Table_Info( FT_Face face
,
3714 FT_UInt table_index
,
3718 FT_Service_SFNT_Table service
;
3722 if ( !face
|| !FT_IS_SFNT( face
) )
3723 return FT_THROW( Invalid_Face_Handle
);
3725 FT_FACE_FIND_SERVICE( face
, service
, SFNT_TABLE
);
3726 if ( service
== NULL
)
3727 return FT_THROW( Unimplemented_Feature
);
3729 return service
->table_info( face
, table_index
, tag
, &offset
, length
);
3733 /* documentation is in tttables.h */
3735 FT_EXPORT_DEF( FT_ULong
)
3736 FT_Get_CMap_Language_ID( FT_CharMap charmap
)
3738 FT_Service_TTCMaps service
;
3740 TT_CMapInfo cmap_info
;
3743 if ( !charmap
|| !charmap
->face
)
3746 face
= charmap
->face
;
3747 FT_FACE_FIND_SERVICE( face
, service
, TT_CMAP
);
3748 if ( service
== NULL
)
3750 if ( service
->get_cmap_info( charmap
, &cmap_info
))
3753 return cmap_info
.language
;
3757 /* documentation is in tttables.h */
3759 FT_EXPORT_DEF( FT_Long
)
3760 FT_Get_CMap_Format( FT_CharMap charmap
)
3762 FT_Service_TTCMaps service
;
3764 TT_CMapInfo cmap_info
;
3767 if ( !charmap
|| !charmap
->face
)
3770 face
= charmap
->face
;
3771 FT_FACE_FIND_SERVICE( face
, service
, TT_CMAP
);
3772 if ( service
== NULL
)
3774 if ( service
->get_cmap_info( charmap
, &cmap_info
))
3777 return cmap_info
.format
;
3781 /* documentation is in ftsizes.h */
3783 FT_EXPORT_DEF( FT_Error
)
3784 FT_Activate_Size( FT_Size size
)
3790 return FT_THROW( Invalid_Argument
);
3793 if ( face
== NULL
|| face
->driver
== NULL
)
3794 return FT_THROW( Invalid_Argument
);
3796 /* we don't need anything more complex than that; all size objects */
3797 /* are already listed by the face */
3804 /*************************************************************************/
3805 /*************************************************************************/
3806 /*************************************************************************/
3809 /**** R E N D E R E R S ****/
3812 /*************************************************************************/
3813 /*************************************************************************/
3814 /*************************************************************************/
3816 /* lookup a renderer by glyph format in the library's list */
3817 FT_BASE_DEF( FT_Renderer
)
3818 FT_Lookup_Renderer( FT_Library library
,
3819 FT_Glyph_Format format
,
3823 FT_Renderer result
= 0;
3829 cur
= library
->renderers
.head
;
3834 cur
= (*node
)->next
;
3840 FT_Renderer renderer
= FT_RENDERER( cur
->data
);
3843 if ( renderer
->glyph_format
== format
)
3860 ft_lookup_glyph_renderer( FT_GlyphSlot slot
)
3862 FT_Face face
= slot
->face
;
3863 FT_Library library
= FT_FACE_LIBRARY( face
);
3864 FT_Renderer result
= library
->cur_renderer
;
3867 if ( !result
|| result
->glyph_format
!= slot
->format
)
3868 result
= FT_Lookup_Renderer( library
, slot
->format
, 0 );
3875 ft_set_current_renderer( FT_Library library
)
3877 FT_Renderer renderer
;
3880 renderer
= FT_Lookup_Renderer( library
, FT_GLYPH_FORMAT_OUTLINE
, 0 );
3881 library
->cur_renderer
= renderer
;
3886 ft_add_renderer( FT_Module module
)
3888 FT_Library library
= module
->library
;
3889 FT_Memory memory
= library
->memory
;
3891 FT_ListNode node
= NULL
;
3894 if ( FT_NEW( node
) )
3898 FT_Renderer render
= FT_RENDERER( module
);
3899 FT_Renderer_Class
* clazz
= (FT_Renderer_Class
*)module
->clazz
;
3902 render
->clazz
= clazz
;
3903 render
->glyph_format
= clazz
->glyph_format
;
3905 /* allocate raster object if needed */
3906 if ( clazz
->glyph_format
== FT_GLYPH_FORMAT_OUTLINE
&&
3907 clazz
->raster_class
->raster_new
)
3909 error
= clazz
->raster_class
->raster_new( memory
, &render
->raster
);
3913 render
->raster_render
= clazz
->raster_class
->raster_render
;
3914 render
->render
= clazz
->render_glyph
;
3918 node
->data
= module
;
3919 FT_List_Add( &library
->renderers
, node
);
3921 ft_set_current_renderer( library
);
3934 ft_remove_renderer( FT_Module module
)
3936 FT_Library library
= module
->library
;
3937 FT_Memory memory
= library
->memory
;
3941 node
= FT_List_Find( &library
->renderers
, module
);
3944 FT_Renderer render
= FT_RENDERER( module
);
3947 /* release raster object, if any */
3948 if ( render
->clazz
->glyph_format
== FT_GLYPH_FORMAT_OUTLINE
&&
3950 render
->clazz
->raster_class
->raster_done( render
->raster
);
3952 /* remove from list */
3953 FT_List_Remove( &library
->renderers
, node
);
3956 ft_set_current_renderer( library
);
3961 /* documentation is in ftrender.h */
3963 FT_EXPORT_DEF( FT_Renderer
)
3964 FT_Get_Renderer( FT_Library library
,
3965 FT_Glyph_Format format
)
3967 /* test for valid `library' delayed to FT_Lookup_Renderer() */
3969 return FT_Lookup_Renderer( library
, format
, 0 );
3973 /* documentation is in ftrender.h */
3975 FT_EXPORT_DEF( FT_Error
)
3976 FT_Set_Renderer( FT_Library library
,
3977 FT_Renderer renderer
,
3979 FT_Parameter
* parameters
)
3982 FT_Error error
= FT_Err_Ok
;
3986 return FT_THROW( Invalid_Library_Handle
);
3989 return FT_THROW( Invalid_Argument
);
3991 node
= FT_List_Find( &library
->renderers
, renderer
);
3994 error
= FT_THROW( Invalid_Argument
);
3998 FT_List_Up( &library
->renderers
, node
);
4000 if ( renderer
->glyph_format
== FT_GLYPH_FORMAT_OUTLINE
)
4001 library
->cur_renderer
= renderer
;
4003 if ( num_params
> 0 )
4005 FT_Renderer_SetModeFunc set_mode
= renderer
->clazz
->set_mode
;
4008 for ( ; num_params
> 0; num_params
-- )
4010 error
= set_mode( renderer
, parameters
->tag
, parameters
->data
);
4022 FT_BASE_DEF( FT_Error
)
4023 FT_Render_Glyph_Internal( FT_Library library
,
4025 FT_Render_Mode render_mode
)
4027 FT_Error error
= FT_Err_Ok
;
4028 FT_Renderer renderer
;
4031 /* if it is already a bitmap, no need to do anything */
4032 switch ( slot
->format
)
4034 case FT_GLYPH_FORMAT_BITMAP
: /* already a bitmap, don't do anything */
4039 FT_ListNode node
= 0;
4043 /* small shortcut for the very common case */
4044 if ( slot
->format
== FT_GLYPH_FORMAT_OUTLINE
)
4046 renderer
= library
->cur_renderer
;
4047 node
= library
->renderers
.head
;
4050 renderer
= FT_Lookup_Renderer( library
, slot
->format
, &node
);
4052 error
= FT_ERR( Unimplemented_Feature
);
4055 error
= renderer
->render( renderer
, slot
, render_mode
, NULL
);
4057 FT_ERR_NEQ( error
, Cannot_Render_Glyph
) )
4060 /* FT_Err_Cannot_Render_Glyph is returned if the render mode */
4061 /* is unsupported by the current renderer for this glyph image */
4064 /* now, look for another renderer that supports the same */
4066 renderer
= FT_Lookup_Renderer( library
, slot
->format
, &node
);
4070 /* if we changed the current renderer for the glyph image format */
4071 /* we need to select it as the next current one */
4072 if ( !error
&& update
&& renderer
)
4073 FT_Set_Renderer( library
, renderer
, 0, 0 );
4077 #ifdef FT_DEBUG_LEVEL_TRACE
4080 #define FT_COMPONENT trace_bitmap
4082 /* we convert to a single bitmap format for computing the checksum */
4088 FT_Bitmap_New( &bitmap
);
4090 err
= FT_Bitmap_Convert( library
, &slot
->bitmap
, &bitmap
, 1 );
4094 unsigned char md5
[16];
4099 MD5_Update( &ctx
, bitmap
.buffer
, bitmap
.rows
* bitmap
.pitch
);
4100 MD5_Final( md5
, &ctx
);
4102 FT_TRACE3(( "MD5 checksum for %dx%d bitmap:\n"
4104 bitmap
.rows
, bitmap
.pitch
));
4105 for ( i
= 0; i
< 16; i
++ )
4106 FT_TRACE3(( "%02X", md5
[i
] ));
4107 FT_TRACE3(( "\n" ));
4110 FT_Bitmap_Done( library
, &bitmap
);
4114 #define FT_COMPONENT trace_objs
4116 #endif /* FT_DEBUG_LEVEL_TRACE */
4122 /* documentation is in freetype.h */
4124 FT_EXPORT_DEF( FT_Error
)
4125 FT_Render_Glyph( FT_GlyphSlot slot
,
4126 FT_Render_Mode render_mode
)
4131 if ( !slot
|| !slot
->face
)
4132 return FT_THROW( Invalid_Argument
);
4134 library
= FT_FACE_LIBRARY( slot
->face
);
4136 return FT_Render_Glyph_Internal( library
, slot
, render_mode
);
4140 /*************************************************************************/
4141 /*************************************************************************/
4142 /*************************************************************************/
4145 /**** M O D U L E S ****/
4148 /*************************************************************************/
4149 /*************************************************************************/
4150 /*************************************************************************/
4153 /*************************************************************************/
4156 /* Destroy_Module */
4159 /* Destroys a given module object. For drivers, this also destroys */
4160 /* all child faces. */
4163 /* module :: A handle to the target driver object. */
4166 /* The driver _must_ be LOCKED! */
4169 Destroy_Module( FT_Module module
)
4171 FT_Memory memory
= module
->memory
;
4172 FT_Module_Class
* clazz
= module
->clazz
;
4173 FT_Library library
= module
->library
;
4176 if ( library
&& library
->auto_hinter
== module
)
4177 library
->auto_hinter
= 0;
4179 /* if the module is a renderer */
4180 if ( FT_MODULE_IS_RENDERER( module
) )
4181 ft_remove_renderer( module
);
4183 /* if the module is a font driver, add some steps */
4184 if ( FT_MODULE_IS_DRIVER( module
) )
4185 Destroy_Driver( FT_DRIVER( module
) );
4187 /* finalize the module object */
4188 if ( clazz
->module_done
)
4189 clazz
->module_done( module
);
4196 /* documentation is in ftmodapi.h */
4198 FT_EXPORT_DEF( FT_Error
)
4199 FT_Add_Module( FT_Library library
,
4200 const FT_Module_Class
* clazz
)
4208 #define FREETYPE_VER_FIXED ( ( (FT_Long)FREETYPE_MAJOR << 16 ) | \
4212 return FT_THROW( Invalid_Library_Handle
);
4215 return FT_THROW( Invalid_Argument
);
4217 /* check freetype version */
4218 if ( clazz
->module_requires
> FREETYPE_VER_FIXED
)
4219 return FT_THROW( Invalid_Version
);
4221 /* look for a module with the same name in the library's table */
4222 for ( nn
= 0; nn
< library
->num_modules
; nn
++ )
4224 module
= library
->modules
[nn
];
4225 if ( ft_strcmp( module
->clazz
->module_name
, clazz
->module_name
) == 0 )
4227 /* this installed module has the same name, compare their versions */
4228 if ( clazz
->module_version
<= module
->clazz
->module_version
)
4229 return FT_THROW( Lower_Module_Version
);
4231 /* remove the module from our list, then exit the loop to replace */
4232 /* it by our new version.. */
4233 FT_Remove_Module( library
, module
);
4238 memory
= library
->memory
;
4241 if ( library
->num_modules
>= FT_MAX_MODULES
)
4243 error
= FT_THROW( Too_Many_Drivers
);
4247 /* allocate module object */
4248 if ( FT_ALLOC( module
, clazz
->module_size
) )
4251 /* base initialization */
4252 module
->library
= library
;
4253 module
->memory
= memory
;
4254 module
->clazz
= (FT_Module_Class
*)clazz
;
4256 /* check whether the module is a renderer - this must be performed */
4257 /* before the normal module initialization */
4258 if ( FT_MODULE_IS_RENDERER( module
) )
4260 /* add to the renderers list */
4261 error
= ft_add_renderer( module
);
4266 /* is the module a auto-hinter? */
4267 if ( FT_MODULE_IS_HINTER( module
) )
4268 library
->auto_hinter
= module
;
4270 /* if the module is a font driver */
4271 if ( FT_MODULE_IS_DRIVER( module
) )
4273 /* allocate glyph loader if needed */
4274 FT_Driver driver
= FT_DRIVER( module
);
4277 driver
->clazz
= (FT_Driver_Class
)module
->clazz
;
4278 if ( FT_DRIVER_USES_OUTLINES( driver
) )
4280 error
= FT_GlyphLoader_New( memory
, &driver
->glyph_loader
);
4286 if ( clazz
->module_init
)
4288 error
= clazz
->module_init( module
);
4293 /* add module to the library's table */
4294 library
->modules
[library
->num_modules
++] = module
;
4300 if ( FT_MODULE_IS_DRIVER( module
) )
4302 FT_Driver driver
= FT_DRIVER( module
);
4305 if ( FT_DRIVER_USES_OUTLINES( driver
) )
4306 FT_GlyphLoader_Done( driver
->glyph_loader
);
4309 if ( FT_MODULE_IS_RENDERER( module
) )
4311 FT_Renderer renderer
= FT_RENDERER( module
);
4314 if ( renderer
->clazz
&&
4315 renderer
->clazz
->glyph_format
== FT_GLYPH_FORMAT_OUTLINE
&&
4317 renderer
->clazz
->raster_class
->raster_done( renderer
->raster
);
4325 /* documentation is in ftmodapi.h */
4327 FT_EXPORT_DEF( FT_Module
)
4328 FT_Get_Module( FT_Library library
,
4329 const char* module_name
)
4331 FT_Module result
= 0;
4336 if ( !library
|| !module_name
)
4339 cur
= library
->modules
;
4340 limit
= cur
+ library
->num_modules
;
4342 for ( ; cur
< limit
; cur
++ )
4343 if ( ft_strcmp( cur
[0]->clazz
->module_name
, module_name
) == 0 )
4353 /* documentation is in ftobjs.h */
4355 FT_BASE_DEF( const void* )
4356 FT_Get_Module_Interface( FT_Library library
,
4357 const char* mod_name
)
4362 /* test for valid `library' delayed to FT_Get_Module() */
4364 module
= FT_Get_Module( library
, mod_name
);
4366 return module
? module
->clazz
->module_interface
: 0;
4370 FT_BASE_DEF( FT_Pointer
)
4371 ft_module_get_service( FT_Module module
,
4372 const char* service_id
)
4374 FT_Pointer result
= NULL
;
4379 FT_ASSERT( module
->clazz
&& module
->clazz
->get_interface
);
4381 /* first, look for the service in the module */
4382 if ( module
->clazz
->get_interface
)
4383 result
= module
->clazz
->get_interface( module
, service_id
);
4385 if ( result
== NULL
)
4387 /* we didn't find it, look in all other modules then */
4388 FT_Library library
= module
->library
;
4389 FT_Module
* cur
= library
->modules
;
4390 FT_Module
* limit
= cur
+ library
->num_modules
;
4393 for ( ; cur
< limit
; cur
++ )
4395 if ( cur
[0] != module
)
4397 FT_ASSERT( cur
[0]->clazz
);
4399 if ( cur
[0]->clazz
->get_interface
)
4401 result
= cur
[0]->clazz
->get_interface( cur
[0], service_id
);
4402 if ( result
!= NULL
)
4414 /* documentation is in ftmodapi.h */
4416 FT_EXPORT_DEF( FT_Error
)
4417 FT_Remove_Module( FT_Library library
,
4420 /* try to find the module from the table, then remove it from there */
4423 return FT_THROW( Invalid_Library_Handle
);
4427 FT_Module
* cur
= library
->modules
;
4428 FT_Module
* limit
= cur
+ library
->num_modules
;
4431 for ( ; cur
< limit
; cur
++ )
4433 if ( cur
[0] == module
)
4435 /* remove it from the table */
4436 library
->num_modules
--;
4438 while ( cur
< limit
)
4445 /* destroy the module */
4446 Destroy_Module( module
);
4452 return FT_THROW( Invalid_Driver_Handle
);
4457 ft_property_do( FT_Library library
,
4458 const FT_String
* module_name
,
4459 const FT_String
* property_name
,
4465 FT_Module_Interface interface
;
4467 FT_Service_Properties service
;
4469 #ifdef FT_DEBUG_LEVEL_ERROR
4470 const FT_String
* set_name
= "FT_Property_Set";
4471 const FT_String
* get_name
= "FT_Property_Get";
4472 const FT_String
* func_name
= set
? set_name
: get_name
;
4475 FT_Bool missing_func
;
4479 return FT_THROW( Invalid_Library_Handle
);
4481 if ( !module_name
|| !property_name
|| !value
)
4482 return FT_THROW( Invalid_Argument
);
4484 cur
= library
->modules
;
4485 limit
= cur
+ library
->num_modules
;
4488 for ( ; cur
< limit
; cur
++ )
4489 if ( !ft_strcmp( cur
[0]->clazz
->module_name
, module_name
) )
4494 FT_ERROR(( "%s: can't find module `%s'\n",
4495 func_name
, module_name
));
4496 return FT_THROW( Missing_Module
);
4499 /* check whether we have a service interface */
4500 if ( !cur
[0]->clazz
->get_interface
)
4502 FT_ERROR(( "%s: module `%s' doesn't support properties\n",
4503 func_name
, module_name
));
4504 return FT_THROW( Unimplemented_Feature
);
4507 /* search property service */
4508 interface
= cur
[0]->clazz
->get_interface( cur
[0],
4509 FT_SERVICE_ID_PROPERTIES
);
4512 FT_ERROR(( "%s: module `%s' doesn't support properties\n",
4513 func_name
, module_name
));
4514 return FT_THROW( Unimplemented_Feature
);
4517 service
= (FT_Service_Properties
)interface
;
4520 missing_func
= (FT_Bool
)( !service
->set_property
);
4522 missing_func
= (FT_Bool
)( !service
->get_property
);
4526 FT_ERROR(( "%s: property service of module `%s' is broken\n",
4527 func_name
, module_name
));
4528 return FT_THROW( Unimplemented_Feature
);
4531 return set
? service
->set_property( cur
[0], property_name
, value
)
4532 : service
->get_property( cur
[0], property_name
, value
);
4536 /* documentation is in ftmodapi.h */
4538 FT_EXPORT_DEF( FT_Error
)
4539 FT_Property_Set( FT_Library library
,
4540 const FT_String
* module_name
,
4541 const FT_String
* property_name
,
4544 return ft_property_do( library
,
4552 /* documentation is in ftmodapi.h */
4554 FT_EXPORT_DEF( FT_Error
)
4555 FT_Property_Get( FT_Library library
,
4556 const FT_String
* module_name
,
4557 const FT_String
* property_name
,
4560 return ft_property_do( library
,
4568 /*************************************************************************/
4569 /*************************************************************************/
4570 /*************************************************************************/
4573 /**** L I B R A R Y ****/
4576 /*************************************************************************/
4577 /*************************************************************************/
4578 /*************************************************************************/
4581 /* documentation is in ftmodapi.h */
4583 FT_EXPORT_DEF( FT_Error
)
4584 FT_Reference_Library( FT_Library library
)
4586 library
->refcount
++;
4592 /* documentation is in ftmodapi.h */
4594 FT_EXPORT_DEF( FT_Error
)
4595 FT_New_Library( FT_Memory memory
,
4596 FT_Library
*alibrary
)
4598 FT_Library library
= NULL
;
4603 return FT_THROW( Invalid_Argument
);
4605 #ifdef FT_DEBUG_LEVEL_ERROR
4606 /* init debugging support */
4610 /* first of all, allocate the library object */
4611 if ( FT_NEW( library
) )
4614 library
->memory
= memory
;
4616 #ifdef FT_CONFIG_OPTION_PIC
4617 /* initialize position independent code containers */
4618 error
= ft_pic_container_init( library
);
4623 /* allocate the render pool */
4624 library
->raster_pool_size
= FT_RENDER_POOL_SIZE
;
4625 #if FT_RENDER_POOL_SIZE > 0
4626 if ( FT_ALLOC( library
->raster_pool
, FT_RENDER_POOL_SIZE
) )
4630 library
->version_major
= FREETYPE_MAJOR
;
4631 library
->version_minor
= FREETYPE_MINOR
;
4632 library
->version_patch
= FREETYPE_PATCH
;
4634 library
->refcount
= 1;
4637 *alibrary
= library
;
4642 #ifdef FT_CONFIG_OPTION_PIC
4643 ft_pic_container_destroy( library
);
4650 /* documentation is in freetype.h */
4652 FT_EXPORT_DEF( void )
4653 FT_Library_Version( FT_Library library
,
4665 major
= library
->version_major
;
4666 minor
= library
->version_minor
;
4667 patch
= library
->version_patch
;
4681 /* documentation is in ftmodapi.h */
4683 FT_EXPORT_DEF( FT_Error
)
4684 FT_Done_Library( FT_Library library
)
4690 return FT_THROW( Invalid_Library_Handle
);
4692 library
->refcount
--;
4693 if ( library
->refcount
> 0 )
4696 memory
= library
->memory
;
4699 * Close all faces in the library. If we don't do this, we can have
4700 * some subtle memory leaks.
4704 * - the cff font driver uses the pshinter module in cff_size_done
4705 * - if the pshinter module is destroyed before the cff font driver,
4706 * opened FT_Face objects managed by the driver are not properly
4707 * destroyed, resulting in a memory leak
4709 * Some faces are dependent on other faces, like Type42 faces that
4710 * depend on TrueType faces synthesized internally.
4712 * The order of drivers should be specified in driver_name[].
4716 const char* driver_name
[] = { "type42", NULL
};
4720 m
< sizeof ( driver_name
) / sizeof ( driver_name
[0] );
4723 for ( n
= 0; n
< library
->num_modules
; n
++ )
4725 FT_Module module
= library
->modules
[n
];
4726 const char* module_name
= module
->clazz
->module_name
;
4730 if ( driver_name
[m
] &&
4731 ft_strcmp( module_name
, driver_name
[m
] ) != 0 )
4734 if ( ( module
->clazz
->module_flags
& FT_MODULE_FONT_DRIVER
) == 0 )
4737 FT_TRACE7(( "FT_Done_Library: close faces for %s\n", module_name
));
4739 faces
= &FT_DRIVER( module
)->faces_list
;
4740 while ( faces
->head
)
4742 FT_Done_Face( FT_FACE( faces
->head
->data
) );
4744 FT_TRACE0(( "FT_Done_Library: failed to free some faces\n" ));
4750 /* Close all other modules in the library */
4752 /* XXX Modules are removed in the reversed order so that */
4753 /* type42 module is removed before truetype module. This */
4754 /* avoids double free in some occasions. It is a hack. */
4755 while ( library
->num_modules
> 0 )
4756 FT_Remove_Module( library
,
4757 library
->modules
[library
->num_modules
- 1] );
4763 for ( n
= 0; n
< library
->num_modules
; n
++ )
4765 FT_Module module
= library
->modules
[n
];
4770 Destroy_Module( module
);
4771 library
->modules
[n
] = 0;
4777 /* Destroy raster objects */
4778 FT_FREE( library
->raster_pool
);
4779 library
->raster_pool_size
= 0;
4781 #ifdef FT_CONFIG_OPTION_PIC
4782 /* Destroy pic container contents */
4783 ft_pic_container_destroy( library
);
4793 /* documentation is in ftmodapi.h */
4795 FT_EXPORT_DEF( void )
4796 FT_Set_Debug_Hook( FT_Library library
,
4798 FT_DebugHook_Func debug_hook
)
4800 if ( library
&& debug_hook
&&
4802 ( sizeof ( library
->debug_hooks
) / sizeof ( void* ) ) )
4803 library
->debug_hooks
[hook_index
] = debug_hook
;
4807 /* documentation is in ftmodapi.h */
4809 FT_EXPORT_DEF( FT_TrueTypeEngineType
)
4810 FT_Get_TrueType_Engine_Type( FT_Library library
)
4812 FT_TrueTypeEngineType result
= FT_TRUETYPE_ENGINE_TYPE_NONE
;
4817 FT_Module module
= FT_Get_Module( library
, "truetype" );
4822 FT_Service_TrueTypeEngine service
;
4825 service
= (FT_Service_TrueTypeEngine
)
4826 ft_module_get_service( module
,
4827 FT_SERVICE_ID_TRUETYPE_ENGINE
);
4829 result
= service
->engine_type
;
4837 /* documentation is in freetype.h */
4839 FT_EXPORT_DEF( FT_Error
)
4840 FT_Get_SubGlyph_Info( FT_GlyphSlot glyph
,
4846 FT_Matrix
*p_transform
)
4848 FT_Error error
= FT_ERR( Invalid_Argument
);
4853 glyph
->format
== FT_GLYPH_FORMAT_COMPOSITE
&&
4854 sub_index
< glyph
->num_subglyphs
)
4856 FT_SubGlyph subg
= glyph
->subglyphs
+ sub_index
;
4859 *p_index
= subg
->index
;
4860 *p_flags
= subg
->flags
;
4861 *p_arg1
= subg
->arg1
;
4862 *p_arg2
= subg
->arg2
;
4863 *p_transform
= subg
->transform
;