1 /***************************************************************************/
5 /* The FreeType private base classes (body). */
7 /* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007 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_IDS_H
32 #include FT_SERVICE_SFNT_H
33 #include FT_SERVICE_POSTSCRIPT_NAME_H
34 #include FT_SERVICE_GLYPH_DICT_H
35 #include FT_SERVICE_TT_CMAP_H
36 #include FT_SERVICE_KERNING_H
37 #include FT_SERVICE_TRUETYPE_ENGINE_H
39 #define GRID_FIT_METRICS
41 FT_BASE_DEF( FT_Pointer
)
42 ft_service_list_lookup( FT_ServiceDesc service_descriptors
,
43 const char* service_id
)
45 FT_Pointer result
= NULL
;
46 FT_ServiceDesc desc
= service_descriptors
;
49 if ( desc
&& service_id
)
51 for ( ; desc
->serv_id
!= NULL
; desc
++ )
53 if ( ft_strcmp( desc
->serv_id
, service_id
) == 0 )
55 result
= (FT_Pointer
)desc
->serv_data
;
66 ft_validator_init( FT_Validator valid
,
69 FT_ValidationLevel level
)
74 valid
->error
= FT_Err_Ok
;
79 ft_validator_run( FT_Validator valid
)
81 /* This function doesn't work! None should call it. */
89 ft_validator_error( FT_Validator valid
,
92 /* since the cast below also disables the compiler's */
93 /* type check, we introduce a dummy variable, which */
94 /* will be optimized away */
95 volatile ft_jmp_buf
* jump_buffer
= &valid
->jump_buffer
;
100 /* throw away volatileness; use `jump_buffer' or the */
101 /* compiler may warn about an unused local variable */
102 ft_longjmp( *(ft_jmp_buf
*) jump_buffer
, 1 );
106 /*************************************************************************/
107 /*************************************************************************/
108 /*************************************************************************/
111 /**** S T R E A M ****/
114 /*************************************************************************/
115 /*************************************************************************/
116 /*************************************************************************/
119 /* create a new input stream from an FT_Open_Args structure */
121 FT_BASE_DEF( FT_Error
)
122 FT_Stream_New( FT_Library library
,
123 const FT_Open_Args
* args
,
132 return FT_Err_Invalid_Library_Handle
;
135 return FT_Err_Invalid_Argument
;
138 memory
= library
->memory
;
140 if ( FT_NEW( stream
) )
143 stream
->memory
= memory
;
145 if ( args
->flags
& FT_OPEN_MEMORY
)
147 /* create a memory-based stream */
148 FT_Stream_OpenMemory( stream
,
149 (const FT_Byte
*)args
->memory_base
,
152 else if ( args
->flags
& FT_OPEN_PATHNAME
)
154 /* create a normal system stream */
155 error
= FT_Stream_Open( stream
, args
->pathname
);
156 stream
->pathname
.pointer
= args
->pathname
;
158 else if ( ( args
->flags
& FT_OPEN_STREAM
) && args
->stream
)
160 /* use an existing, user-provided stream */
162 /* in this case, we do not need to allocate a new stream object */
163 /* since the caller is responsible for closing it himself */
165 stream
= args
->stream
;
168 error
= FT_Err_Invalid_Argument
;
173 stream
->memory
= memory
; /* just to be certain */
183 FT_Stream_Free( FT_Stream stream
,
188 FT_Memory memory
= stream
->memory
;
191 FT_Stream_Close( stream
);
200 #define FT_COMPONENT trace_objs
203 /*************************************************************************/
204 /*************************************************************************/
205 /*************************************************************************/
208 /**** FACE, SIZE & GLYPH SLOT OBJECTS ****/
211 /*************************************************************************/
212 /*************************************************************************/
213 /*************************************************************************/
217 ft_glyphslot_init( FT_GlyphSlot slot
)
219 FT_Driver driver
= slot
->face
->driver
;
220 FT_Driver_Class clazz
= driver
->clazz
;
221 FT_Memory memory
= driver
->root
.memory
;
222 FT_Error error
= FT_Err_Ok
;
223 FT_Slot_Internal internal
;
226 slot
->library
= driver
->root
.library
;
228 if ( FT_NEW( internal
) )
231 slot
->internal
= internal
;
233 if ( FT_DRIVER_USES_OUTLINES( driver
) )
234 error
= FT_GlyphLoader_New( memory
, &internal
->loader
);
236 if ( !error
&& clazz
->init_slot
)
237 error
= clazz
->init_slot( slot
);
245 ft_glyphslot_free_bitmap( FT_GlyphSlot slot
)
247 if ( slot
->internal
->flags
& FT_GLYPH_OWN_BITMAP
)
249 FT_Memory memory
= FT_FACE_MEMORY( slot
->face
);
252 FT_FREE( slot
->bitmap
.buffer
);
253 slot
->internal
->flags
&= ~FT_GLYPH_OWN_BITMAP
;
257 /* assume that the bitmap buffer was stolen or not */
258 /* allocated from the heap */
259 slot
->bitmap
.buffer
= NULL
;
265 ft_glyphslot_set_bitmap( FT_GlyphSlot slot
,
268 ft_glyphslot_free_bitmap( slot
);
270 slot
->bitmap
.buffer
= buffer
;
272 FT_ASSERT( (slot
->internal
->flags
& FT_GLYPH_OWN_BITMAP
) == 0 );
276 FT_BASE_DEF( FT_Error
)
277 ft_glyphslot_alloc_bitmap( FT_GlyphSlot slot
,
280 FT_Memory memory
= FT_FACE_MEMORY( slot
->face
);
284 if ( slot
->internal
->flags
& FT_GLYPH_OWN_BITMAP
)
285 FT_FREE( slot
->bitmap
.buffer
);
287 slot
->internal
->flags
|= FT_GLYPH_OWN_BITMAP
;
289 (void)FT_ALLOC( slot
->bitmap
.buffer
, size
);
295 ft_glyphslot_clear( FT_GlyphSlot slot
)
297 /* free bitmap if needed */
298 ft_glyphslot_free_bitmap( slot
);
300 /* clear all public fields in the glyph slot */
301 FT_ZERO( &slot
->metrics
);
302 FT_ZERO( &slot
->outline
);
304 slot
->bitmap
.width
= 0;
305 slot
->bitmap
.rows
= 0;
306 slot
->bitmap
.pitch
= 0;
307 slot
->bitmap
.pixel_mode
= 0;
308 /* `slot->bitmap.buffer' has been handled by ft_glyphslot_free_bitmap */
310 slot
->bitmap_left
= 0;
311 slot
->bitmap_top
= 0;
312 slot
->num_subglyphs
= 0;
314 slot
->control_data
= 0;
315 slot
->control_len
= 0;
317 slot
->format
= FT_GLYPH_FORMAT_NONE
;
319 slot
->linearHoriAdvance
= 0;
320 slot
->linearVertAdvance
= 0;
327 ft_glyphslot_done( FT_GlyphSlot slot
)
329 FT_Driver driver
= slot
->face
->driver
;
330 FT_Driver_Class clazz
= driver
->clazz
;
331 FT_Memory memory
= driver
->root
.memory
;
334 if ( clazz
->done_slot
)
335 clazz
->done_slot( slot
);
337 /* free bitmap buffer if needed */
338 ft_glyphslot_free_bitmap( slot
);
340 /* free glyph loader */
341 if ( FT_DRIVER_USES_OUTLINES( driver
) )
343 FT_GlyphLoader_Done( slot
->internal
->loader
);
344 slot
->internal
->loader
= 0;
347 FT_FREE( slot
->internal
);
351 /* documentation is in ftobjs.h */
353 FT_BASE_DEF( FT_Error
)
354 FT_New_GlyphSlot( FT_Face face
,
355 FT_GlyphSlot
*aslot
)
359 FT_Driver_Class clazz
;
364 if ( !face
|| !face
->driver
)
365 return FT_Err_Invalid_Argument
;
367 driver
= face
->driver
;
368 clazz
= driver
->clazz
;
369 memory
= driver
->root
.memory
;
371 FT_TRACE4(( "FT_New_GlyphSlot: Creating new slot object\n" ));
372 if ( !FT_ALLOC( slot
, clazz
->slot_object_size
) )
376 error
= ft_glyphslot_init( slot
);
379 ft_glyphslot_done( slot
);
384 slot
->next
= face
->glyph
;
395 FT_TRACE4(( "FT_New_GlyphSlot: Return %d\n", error
));
400 /* documentation is in ftobjs.h */
403 FT_Done_GlyphSlot( FT_GlyphSlot slot
)
407 FT_Driver driver
= slot
->face
->driver
;
408 FT_Memory memory
= driver
->root
.memory
;
413 /* Remove slot from its parent face's list */
415 cur
= slot
->face
->glyph
;
422 slot
->face
->glyph
= cur
->next
;
424 prev
->next
= cur
->next
;
426 ft_glyphslot_done( slot
);
437 /* documentation is in freetype.h */
439 FT_EXPORT_DEF( void )
440 FT_Set_Transform( FT_Face face
,
444 FT_Face_Internal internal
;
450 internal
= face
->internal
;
452 internal
->transform_flags
= 0;
456 internal
->transform_matrix
.xx
= 0x10000L
;
457 internal
->transform_matrix
.xy
= 0;
458 internal
->transform_matrix
.yx
= 0;
459 internal
->transform_matrix
.yy
= 0x10000L
;
460 matrix
= &internal
->transform_matrix
;
463 internal
->transform_matrix
= *matrix
;
465 /* set transform_flags bit flag 0 if `matrix' isn't the identity */
466 if ( ( matrix
->xy
| matrix
->yx
) ||
467 matrix
->xx
!= 0x10000L
||
468 matrix
->yy
!= 0x10000L
)
469 internal
->transform_flags
|= 1;
473 internal
->transform_delta
.x
= 0;
474 internal
->transform_delta
.y
= 0;
475 delta
= &internal
->transform_delta
;
478 internal
->transform_delta
= *delta
;
480 /* set transform_flags bit flag 1 if `delta' isn't the null vector */
481 if ( delta
->x
| delta
->y
)
482 internal
->transform_flags
|= 2;
487 ft_lookup_glyph_renderer( FT_GlyphSlot slot
);
490 #ifdef GRID_FIT_METRICS
492 ft_glyphslot_grid_fit_metrics( FT_GlyphSlot slot
,
495 FT_Glyph_Metrics
* metrics
= &slot
->metrics
;
496 FT_Pos right
, bottom
;
501 metrics
->horiBearingX
= FT_PIX_FLOOR( metrics
->horiBearingX
);
502 metrics
->horiBearingY
= FT_PIX_CEIL ( metrics
->horiBearingY
);
504 right
= FT_PIX_CEIL( metrics
->vertBearingX
+ metrics
->width
);
505 bottom
= FT_PIX_CEIL( metrics
->vertBearingY
+ metrics
->height
);
507 metrics
->vertBearingX
= FT_PIX_FLOOR( metrics
->vertBearingX
);
508 metrics
->vertBearingY
= FT_PIX_FLOOR( metrics
->vertBearingY
);
510 metrics
->width
= right
- metrics
->vertBearingX
;
511 metrics
->height
= bottom
- metrics
->vertBearingY
;
515 metrics
->vertBearingX
= FT_PIX_FLOOR( metrics
->vertBearingX
);
516 metrics
->vertBearingY
= FT_PIX_FLOOR( metrics
->vertBearingY
);
518 right
= FT_PIX_CEIL ( metrics
->horiBearingX
+ metrics
->width
);
519 bottom
= FT_PIX_FLOOR( metrics
->horiBearingY
- metrics
->height
);
521 metrics
->horiBearingX
= FT_PIX_FLOOR( metrics
->horiBearingX
);
522 metrics
->horiBearingY
= FT_PIX_CEIL ( metrics
->horiBearingY
);
524 metrics
->width
= right
- metrics
->horiBearingX
;
525 metrics
->height
= metrics
->horiBearingY
- bottom
;
528 metrics
->horiAdvance
= FT_PIX_ROUND( metrics
->horiAdvance
);
529 metrics
->vertAdvance
= FT_PIX_ROUND( metrics
->vertAdvance
);
531 #endif /* GRID_FIT_METRICS */
534 /* documentation is in freetype.h */
536 FT_EXPORT_DEF( FT_Error
)
537 FT_Load_Glyph( FT_Face face
,
539 FT_Int32 load_flags
)
545 FT_Bool autohint
= 0;
549 if ( !face
|| !face
->size
|| !face
->glyph
)
550 return FT_Err_Invalid_Face_Handle
;
552 /* The validity test for `glyph_index' is performed by the */
556 ft_glyphslot_clear( slot
);
558 driver
= face
->driver
;
559 library
= driver
->root
.library
;
560 hinter
= library
->auto_hinter
;
562 /* resolve load flags dependencies */
564 if ( load_flags
& FT_LOAD_NO_RECURSE
)
565 load_flags
|= FT_LOAD_NO_SCALE
|
566 FT_LOAD_IGNORE_TRANSFORM
;
568 if ( load_flags
& FT_LOAD_NO_SCALE
)
570 load_flags
|= FT_LOAD_NO_HINTING
|
573 load_flags
&= ~FT_LOAD_RENDER
;
577 * Determine whether we need to auto-hint or not.
578 * The general rules are:
580 * - Do only auto-hinting if we have a hinter module,
581 * a scalable font format dealing with outlines,
582 * and no transforms except simple slants.
584 * - Then, autohint if FT_LOAD_FORCE_AUTOHINT is set
585 * or if we don't have a native font hinter.
587 * - Otherwise, auto-hint for LIGHT hinting mode.
589 * - Exception: The font requires the unpatented
590 * bytecode interpreter to load properly.
595 ( load_flags
& FT_LOAD_NO_HINTING
) == 0 &&
596 ( load_flags
& FT_LOAD_NO_AUTOHINT
) == 0 &&
597 FT_DRIVER_IS_SCALABLE( driver
) &&
598 FT_DRIVER_USES_OUTLINES( driver
) &&
599 face
->internal
->transform_matrix
.yy
> 0 &&
600 face
->internal
->transform_matrix
.yx
== 0 )
602 if ( ( load_flags
& FT_LOAD_FORCE_AUTOHINT
) != 0 ||
603 !FT_DRIVER_HAS_HINTER( driver
) )
607 FT_Render_Mode mode
= FT_LOAD_TARGET_MODE( load_flags
);
610 if ( mode
== FT_RENDER_MODE_LIGHT
||
611 face
->internal
->ignore_unpatented_hinter
)
618 FT_AutoHinter_Service hinting
;
621 /* try to load embedded bitmaps first if available */
623 /* XXX: This is really a temporary hack that should disappear */
624 /* promptly with FreeType 2.1! */
626 if ( FT_HAS_FIXED_SIZES( face
) &&
627 ( load_flags
& FT_LOAD_NO_BITMAP
) == 0 )
629 error
= driver
->clazz
->load_glyph( slot
, face
->size
,
631 load_flags
| FT_LOAD_SBITS_ONLY
);
633 if ( !error
&& slot
->format
== FT_GLYPH_FORMAT_BITMAP
)
637 /* load auto-hinted outline */
638 hinting
= (FT_AutoHinter_Service
)hinter
->clazz
->module_interface
;
640 error
= hinting
->load_glyph( (FT_AutoHinter
)hinter
,
642 glyph_index
, load_flags
);
646 error
= driver
->clazz
->load_glyph( slot
,
653 if ( slot
->format
== FT_GLYPH_FORMAT_OUTLINE
)
655 /* check that the loaded outline is correct */
656 error
= FT_Outline_Check( &slot
->outline
);
660 #ifdef GRID_FIT_METRICS
661 if ( !( load_flags
& FT_LOAD_NO_HINTING
) )
662 ft_glyphslot_grid_fit_metrics( slot
,
663 FT_BOOL( load_flags
& FT_LOAD_VERTICAL_LAYOUT
) );
669 /* compute the advance */
670 if ( load_flags
& FT_LOAD_VERTICAL_LAYOUT
)
673 slot
->advance
.y
= slot
->metrics
.vertAdvance
;
677 slot
->advance
.x
= slot
->metrics
.horiAdvance
;
681 /* compute the linear advance in 16.16 pixels */
682 if ( ( load_flags
& FT_LOAD_LINEAR_DESIGN
) == 0 &&
683 ( face
->face_flags
& FT_FACE_FLAG_SCALABLE
) )
685 FT_Size_Metrics
* metrics
= &face
->size
->metrics
;
689 slot
->linearHoriAdvance
= FT_MulDiv( slot
->linearHoriAdvance
,
690 metrics
->x_scale
, 64 );
692 slot
->linearVertAdvance
= FT_MulDiv( slot
->linearVertAdvance
,
693 metrics
->y_scale
, 64 );
696 if ( ( load_flags
& FT_LOAD_IGNORE_TRANSFORM
) == 0 )
698 FT_Face_Internal internal
= face
->internal
;
701 /* now, transform the glyph image if needed */
702 if ( internal
->transform_flags
)
705 FT_Renderer renderer
= ft_lookup_glyph_renderer( slot
);
709 error
= renderer
->clazz
->transform_glyph(
711 &internal
->transform_matrix
,
712 &internal
->transform_delta
);
713 /* transform advance */
714 FT_Vector_Transform( &slot
->advance
, &internal
->transform_matrix
);
718 /* do we need to render the image now? */
720 slot
->format
!= FT_GLYPH_FORMAT_BITMAP
&&
721 slot
->format
!= FT_GLYPH_FORMAT_COMPOSITE
&&
722 load_flags
& FT_LOAD_RENDER
)
724 FT_Render_Mode mode
= FT_LOAD_TARGET_MODE( load_flags
);
727 if ( mode
== FT_RENDER_MODE_NORMAL
&&
728 (load_flags
& FT_LOAD_MONOCHROME
) )
729 mode
= FT_RENDER_MODE_MONO
;
731 error
= FT_Render_Glyph( slot
, mode
);
739 /* documentation is in freetype.h */
741 FT_EXPORT_DEF( FT_Error
)
742 FT_Load_Char( FT_Face face
,
744 FT_Int32 load_flags
)
750 return FT_Err_Invalid_Face_Handle
;
752 glyph_index
= (FT_UInt
)char_code
;
754 glyph_index
= FT_Get_Char_Index( face
, char_code
);
756 return FT_Load_Glyph( face
, glyph_index
, load_flags
);
760 /* destructor for sizes list */
762 destroy_size( FT_Memory memory
,
766 /* finalize client-specific data */
767 if ( size
->generic
.finalizer
)
768 size
->generic
.finalizer( size
);
770 /* finalize format-specific stuff */
771 if ( driver
->clazz
->done_size
)
772 driver
->clazz
->done_size( size
);
774 FT_FREE( size
->internal
);
780 ft_cmap_done_internal( FT_CMap cmap
);
784 destroy_charmaps( FT_Face face
,
793 for ( n
= 0; n
< face
->num_charmaps
; n
++ )
795 FT_CMap cmap
= FT_CMAP( face
->charmaps
[n
] );
798 ft_cmap_done_internal( cmap
);
800 face
->charmaps
[n
] = NULL
;
803 FT_FREE( face
->charmaps
);
804 face
->num_charmaps
= 0;
808 /* destructor for faces list */
810 destroy_face( FT_Memory memory
,
814 FT_Driver_Class clazz
= driver
->clazz
;
817 /* discard auto-hinting data */
818 if ( face
->autohint
.finalizer
)
819 face
->autohint
.finalizer( face
->autohint
.data
);
821 /* Discard glyph slots for this face. */
822 /* Beware! FT_Done_GlyphSlot() changes the field `face->glyph' */
823 while ( face
->glyph
)
824 FT_Done_GlyphSlot( face
->glyph
);
826 /* discard all sizes for this face */
827 FT_List_Finalize( &face
->sizes_list
,
828 (FT_List_Destructor
)destroy_size
,
833 /* now discard client data */
834 if ( face
->generic
.finalizer
)
835 face
->generic
.finalizer( face
);
837 /* discard charmaps */
838 destroy_charmaps( face
, memory
);
840 /* finalize format-specific stuff */
841 if ( clazz
->done_face
)
842 clazz
->done_face( face
);
844 /* close the stream for this face if needed */
847 ( face
->face_flags
& FT_FACE_FLAG_EXTERNAL_STREAM
) != 0 );
852 if ( face
->internal
)
854 FT_FREE( face
->internal
);
861 Destroy_Driver( FT_Driver driver
)
863 FT_List_Finalize( &driver
->faces_list
,
864 (FT_List_Destructor
)destroy_face
,
868 /* check whether we need to drop the driver's glyph loader */
869 if ( FT_DRIVER_USES_OUTLINES( driver
) )
870 FT_GlyphLoader_Done( driver
->glyph_loader
);
874 /*************************************************************************/
877 /* find_unicode_charmap */
880 /* This function finds a Unicode charmap, if there is one. */
881 /* And if there is more than one, it tries to favour the more */
882 /* extensive one, i.e., one that supports UCS-4 against those which */
883 /* are limited to the BMP (said UCS-2 encoding.) */
885 /* This function is called from open_face() (just below), and also */
886 /* from FT_Select_Charmap( ..., FT_ENCODING_UNICODE). */
889 find_unicode_charmap( FT_Face face
)
893 FT_CharMap
* unicmap
= NULL
; /* some UCS-2 map, if we found it */
896 /* caller should have already checked that `face' is valid */
899 first
= face
->charmaps
;
902 return FT_Err_Invalid_CharMap_Handle
;
905 * The original TrueType specification(s) only specified charmap
906 * formats that are capable of mapping 8 or 16 bit character codes to
909 * However, recent updates to the Apple and OpenType specifications
910 * introduced new formats that are capable of mapping 32-bit character
911 * codes as well. And these are already used on some fonts, mainly to
912 * map non-BMP Asian ideographs as defined in Unicode.
914 * For compatibility purposes, these fonts generally come with
915 * *several* Unicode charmaps:
917 * - One of them in the "old" 16-bit format, that cannot access
918 * all glyphs in the font.
920 * - Another one in the "new" 32-bit format, that can access all
923 * This function has been written to always favor a 32-bit charmap
924 * when found. Otherwise, a 16-bit one is returned when found.
927 /* Since the `interesting' table, with IDs (3,10), is normally the */
928 /* last one, we loop backwards. This loses with type1 fonts with */
929 /* non-BMP characters (<.0001%), this wins with .ttf with non-BMP */
930 /* chars (.01% ?), and this is the same about 99.99% of the time! */
932 cur
= first
+ face
->num_charmaps
; /* points after the last one */
934 for ( ; --cur
>= first
; )
936 if ( cur
[0]->encoding
== FT_ENCODING_UNICODE
)
938 unicmap
= cur
; /* record we found a Unicode charmap */
940 /* XXX If some new encodings to represent UCS-4 are added, */
941 /* they should be added here. */
942 if ( ( cur
[0]->platform_id
== TT_PLATFORM_MICROSOFT
&&
943 cur
[0]->encoding_id
== TT_MS_ID_UCS_4
) ||
944 ( cur
[0]->platform_id
== TT_PLATFORM_APPLE_UNICODE
&&
945 cur
[0]->encoding_id
== TT_APPLE_ID_UNICODE_32
) )
947 /* Hurray! We found a UCS-4 charmap. We can stop the scan! */
949 face
->charmap
= cur
[0];
955 /* We do not have any UCS-4 charmap. Sigh. */
956 /* Let's see if we have some other kind of Unicode charmap, though. */
957 if ( unicmap
!= NULL
)
959 face
->charmap
= unicmap
[0];
964 return FT_Err_Invalid_CharMap_Handle
;
968 /*************************************************************************/
974 /* This function does some work for FT_Open_Face(). */
977 open_face( FT_Driver driver
,
981 FT_Parameter
* params
,
985 FT_Driver_Class clazz
;
987 FT_Error error
, error2
;
988 FT_Face_Internal internal
= NULL
;
991 clazz
= driver
->clazz
;
992 memory
= driver
->root
.memory
;
994 /* allocate the face object and perform basic initialization */
995 if ( FT_ALLOC( face
, clazz
->face_object_size
) )
998 if ( FT_NEW( internal
) )
1001 face
->internal
= internal
;
1003 face
->driver
= driver
;
1004 face
->memory
= memory
;
1005 face
->stream
= stream
;
1007 #ifdef FT_CONFIG_OPTION_INCREMENTAL
1012 face
->internal
->incremental_interface
= 0;
1013 for ( i
= 0; i
< num_params
&& !face
->internal
->incremental_interface
;
1015 if ( params
[i
].tag
== FT_PARAM_TAG_INCREMENTAL
)
1016 face
->internal
->incremental_interface
= params
[i
].data
;
1020 error
= clazz
->init_face( stream
,
1028 /* select Unicode charmap by default */
1029 error2
= find_unicode_charmap( face
);
1031 /* if no Unicode charmap can be found, FT_Err_Invalid_CharMap_Handle */
1034 /* no error should happen, but we want to play safe */
1035 if ( error2
&& error2
!= FT_Err_Invalid_CharMap_Handle
)
1046 destroy_charmaps( face
, memory
);
1047 clazz
->done_face( face
);
1048 FT_FREE( internal
);
1057 /* there's a Mac-specific extended implementation of FT_New_Face() */
1058 /* in src/base/ftmac.c */
1060 #ifndef FT_MACINTOSH
1062 /* documentation is in freetype.h */
1064 FT_EXPORT_DEF( FT_Error
)
1065 FT_New_Face( FT_Library library
,
1066 const char* pathname
,
1073 /* test for valid `library' and `aface' delayed to FT_Open_Face() */
1075 return FT_Err_Invalid_Argument
;
1077 args
.flags
= FT_OPEN_PATHNAME
;
1078 args
.pathname
= (char*)pathname
;
1080 return FT_Open_Face( library
, &args
, face_index
, aface
);
1083 #endif /* !FT_MACINTOSH */
1086 /* documentation is in freetype.h */
1088 FT_EXPORT_DEF( FT_Error
)
1089 FT_New_Memory_Face( FT_Library library
,
1090 const FT_Byte
* file_base
,
1098 /* test for valid `library' and `face' delayed to FT_Open_Face() */
1100 return FT_Err_Invalid_Argument
;
1102 args
.flags
= FT_OPEN_MEMORY
;
1103 args
.memory_base
= file_base
;
1104 args
.memory_size
= file_size
;
1106 return FT_Open_Face( library
, &args
, face_index
, aface
);
1110 #if !defined( FT_MACINTOSH ) && defined( FT_CONFIG_OPTION_MAC_FONTS )
1112 /* The behavior here is very similar to that in base/ftmac.c, but it */
1113 /* is designed to work on non-mac systems, so no mac specific calls. */
1115 /* We look at the file and determine if it is a mac dfont file or a mac */
1116 /* resource file, or a macbinary file containing a mac resource file. */
1118 /* Unlike ftmac I'm not going to look at a `FOND'. I don't really see */
1119 /* the point, especially since there may be multiple `FOND' resources. */
1120 /* Instead I'll just look for `sfnt' and `POST' resources, ordered as */
1121 /* they occur in the file. */
1123 /* Note that multiple `POST' resources do not mean multiple postscript */
1124 /* fonts; they all get jammed together to make what is essentially a */
1127 /* We aren't interested in `NFNT' or `FONT' bitmap resources. */
1129 /* As soon as we get an `sfnt' load it into memory and pass it off to */
1132 /* If we have a (set of) `POST' resources, massage them into a (memory) */
1133 /* pfb file and pass that to FT_Open_Face. (As with ftmac.c I'm not */
1134 /* going to try to save the kerning info. After all that lives in the */
1135 /* `FOND' which isn't in the file containing the `POST' resources so */
1136 /* we don't really have access to it. */
1139 /* Finalizer for a memory stream; gets called by FT_Done_Face().
1140 It frees the memory it uses. */
1143 memory_stream_close( FT_Stream stream
)
1145 FT_Memory memory
= stream
->memory
;
1148 FT_FREE( stream
->base
);
1156 /* Create a new memory stream from a buffer and a size. */
1159 new_memory_stream( FT_Library library
,
1162 FT_Stream_CloseFunc close
,
1163 FT_Stream
*astream
)
1171 return FT_Err_Invalid_Library_Handle
;
1174 return FT_Err_Invalid_Argument
;
1177 memory
= library
->memory
;
1178 if ( FT_NEW( stream
) )
1181 FT_Stream_OpenMemory( stream
, base
, size
);
1183 stream
->close
= close
;
1192 /* Create a new FT_Face given a buffer and a driver name. */
1195 open_face_from_buffer( FT_Library library
,
1199 const char* driver_name
,
1204 FT_Stream stream
= NULL
;
1205 FT_Memory memory
= library
->memory
;
1208 error
= new_memory_stream( library
,
1211 memory_stream_close
,
1219 args
.flags
= FT_OPEN_STREAM
;
1220 args
.stream
= stream
;
1223 args
.flags
= args
.flags
| FT_OPEN_DRIVER
;
1224 args
.driver
= FT_Get_Module( library
, driver_name
);
1227 error
= FT_Open_Face( library
, &args
, face_index
, aface
);
1229 if ( error
== FT_Err_Ok
)
1230 (*aface
)->face_flags
&= ~FT_FACE_FLAG_EXTERNAL_STREAM
;
1233 FT_Stream_Close( stream
);
1241 /* The resource header says we've got resource_cnt `POST' (type1) */
1242 /* resources in this file. They all need to be coalesced into */
1243 /* one lump which gets passed on to the type1 driver. */
1244 /* Here can be only one PostScript font in a file so face_index */
1245 /* must be 0 (or -1). */
1248 Mac_Read_POST_Resource( FT_Library library
,
1251 FT_Long resource_cnt
,
1255 FT_Error error
= FT_Err_Cannot_Open_Resource
;
1256 FT_Memory memory
= library
->memory
;
1260 FT_Long pfb_len
, pfb_pos
, pfb_lenpos
;
1264 if ( face_index
== -1 )
1266 if ( face_index
!= 0 )
1269 /* Find the length of all the POST resources, concatenated. Assume */
1270 /* worst case (each resource in its own section). */
1272 for ( i
= 0; i
< resource_cnt
; ++i
)
1274 error
= FT_Stream_Seek( stream
, offsets
[i
] );
1277 if ( FT_READ_LONG( temp
) )
1279 pfb_len
+= temp
+ 6;
1282 if ( FT_ALLOC( pfb_data
, (FT_Long
)pfb_len
+ 2 ) )
1286 pfb_data
[1] = 1; /* Ascii section */
1287 pfb_data
[2] = 0; /* 4-byte length, fill in later */
1296 for ( i
= 0; i
< resource_cnt
; ++i
)
1298 error
= FT_Stream_Seek( stream
, offsets
[i
] );
1301 if ( FT_READ_LONG( rlen
) )
1303 if ( FT_READ_USHORT( flags
) )
1305 rlen
-= 2; /* the flags are part of the resource */
1306 if ( ( flags
>> 8 ) == type
)
1310 pfb_data
[pfb_lenpos
] = (FT_Byte
)( len
);
1311 pfb_data
[pfb_lenpos
+ 1] = (FT_Byte
)( len
>> 8 );
1312 pfb_data
[pfb_lenpos
+ 2] = (FT_Byte
)( len
>> 16 );
1313 pfb_data
[pfb_lenpos
+ 3] = (FT_Byte
)( len
>> 24 );
1315 if ( ( flags
>> 8 ) == 5 ) /* End of font mark */
1318 pfb_data
[pfb_pos
++] = 0x80;
1323 pfb_data
[pfb_pos
++] = (FT_Byte
)type
;
1324 pfb_lenpos
= pfb_pos
;
1325 pfb_data
[pfb_pos
++] = 0; /* 4-byte length, fill in later */
1326 pfb_data
[pfb_pos
++] = 0;
1327 pfb_data
[pfb_pos
++] = 0;
1328 pfb_data
[pfb_pos
++] = 0;
1331 error
= FT_Stream_Read( stream
, (FT_Byte
*)pfb_data
+ pfb_pos
, rlen
);
1335 pfb_data
[pfb_pos
++] = 0x80;
1336 pfb_data
[pfb_pos
++] = 3;
1338 pfb_data
[pfb_lenpos
] = (FT_Byte
)( len
);
1339 pfb_data
[pfb_lenpos
+ 1] = (FT_Byte
)( len
>> 8 );
1340 pfb_data
[pfb_lenpos
+ 2] = (FT_Byte
)( len
>> 16 );
1341 pfb_data
[pfb_lenpos
+ 3] = (FT_Byte
)( len
>> 24 );
1343 return open_face_from_buffer( library
,
1351 FT_FREE( pfb_data
);
1358 /* The resource header says we've got resource_cnt `sfnt' */
1359 /* (TrueType/OpenType) resources in this file. Look through */
1360 /* them for the one indicated by face_index, load it into mem, */
1361 /* pass it on the the truetype driver and return it. */
1364 Mac_Read_sfnt_Resource( FT_Library library
,
1367 FT_Long resource_cnt
,
1371 FT_Memory memory
= library
->memory
;
1374 FT_Long flag_offset
;
1377 FT_Long face_index_in_resource
= 0;
1380 if ( face_index
== -1 )
1382 if ( face_index
>= resource_cnt
)
1383 return FT_Err_Cannot_Open_Resource
;
1385 flag_offset
= offsets
[face_index
];
1386 error
= FT_Stream_Seek( stream
, flag_offset
);
1390 if ( FT_READ_LONG( rlen
) )
1393 return FT_Err_Cannot_Open_Resource
;
1395 if ( FT_ALLOC( sfnt_data
, (FT_Long
)rlen
) )
1397 error
= FT_Stream_Read( stream
, (FT_Byte
*)sfnt_data
, rlen
);
1401 is_cff
= rlen
> 4 && sfnt_data
[0] == 'O' &&
1402 sfnt_data
[1] == 'T' &&
1403 sfnt_data
[2] == 'T' &&
1404 sfnt_data
[3] == 'O';
1406 error
= open_face_from_buffer( library
,
1409 face_index_in_resource
,
1410 is_cff
? "cff" : "truetype",
1418 /* Check for a valid resource fork header, or a valid dfont */
1419 /* header. In a resource fork the first 16 bytes are repeated */
1420 /* at the location specified by bytes 4-7. In a dfont bytes */
1421 /* 4-7 point to 16 bytes of zeroes instead. */
1424 IsMacResource( FT_Library library
,
1426 FT_Long resource_offset
,
1430 FT_Memory memory
= library
->memory
;
1432 FT_Long map_offset
, rdara_pos
;
1433 FT_Long
*data_offsets
;
1437 error
= FT_Raccess_Get_HeaderInfo( library
, stream
, resource_offset
,
1438 &map_offset
, &rdara_pos
);
1442 error
= FT_Raccess_Get_DataOffsets( library
, stream
,
1443 map_offset
, rdara_pos
,
1444 FT_MAKE_TAG( 'P', 'O', 'S', 'T' ),
1445 &data_offsets
, &count
);
1448 error
= Mac_Read_POST_Resource( library
, stream
, data_offsets
, count
,
1449 face_index
, aface
);
1450 FT_FREE( data_offsets
);
1451 /* POST exists in an LWFN providing a single face */
1453 (*aface
)->num_faces
= 1;
1457 error
= FT_Raccess_Get_DataOffsets( library
, stream
,
1458 map_offset
, rdara_pos
,
1459 FT_MAKE_TAG( 's', 'f', 'n', 't' ),
1460 &data_offsets
, &count
);
1463 FT_Long face_index_internal
= face_index
% count
;
1466 error
= Mac_Read_sfnt_Resource( library
, stream
, data_offsets
, count
,
1467 face_index_internal
, aface
);
1468 FT_FREE( data_offsets
);
1470 (*aface
)->num_faces
= count
;
1477 /* Check for a valid macbinary header, and if we find one */
1478 /* check that the (flattened) resource fork in it is valid. */
1481 IsMacBinary( FT_Library library
,
1486 unsigned char header
[128];
1488 FT_Long dlen
, offset
;
1491 error
= FT_Stream_Seek( stream
, 0 );
1495 error
= FT_Stream_Read( stream
, (FT_Byte
*)header
, 128 );
1499 if ( header
[ 0] != 0 ||
1505 header
[2 + header
[1]] != 0 )
1506 return FT_Err_Unknown_File_Format
;
1508 dlen
= ( header
[0x53] << 24 ) |
1509 ( header
[0x54] << 16 ) |
1510 ( header
[0x55] << 8 ) |
1513 rlen
= ( header
[0x57] << 24 ) |
1514 ( header
[0x58] << 16 ) |
1515 ( header
[0x59] << 8 ) |
1518 offset
= 128 + ( ( dlen
+ 127 ) & ~127 );
1520 return IsMacResource( library
, stream
, offset
, face_index
, aface
);
1528 load_face_in_embedded_rfork( FT_Library library
,
1532 const FT_Open_Args
*args
)
1536 #define FT_COMPONENT trace_raccess
1538 FT_Memory memory
= library
->memory
;
1539 FT_Error error
= FT_Err_Unknown_File_Format
;
1542 char * file_names
[FT_RACCESS_N_RULES
];
1543 FT_Long offsets
[FT_RACCESS_N_RULES
];
1544 FT_Error errors
[FT_RACCESS_N_RULES
];
1550 FT_Raccess_Guess( library
, stream
,
1551 args
->pathname
, file_names
, offsets
, errors
);
1553 for ( i
= 0; i
< FT_RACCESS_N_RULES
; i
++ )
1557 FT_TRACE3(( "Error[%d] has occurred in rule %d\n", errors
[i
], i
));
1561 args2
.flags
= FT_OPEN_PATHNAME
;
1562 args2
.pathname
= file_names
[i
] ? file_names
[i
] : args
->pathname
;
1564 FT_TRACE3(( "Try rule %d: %s (offset=%d) ...",
1565 i
, args2
.pathname
, offsets
[i
] ));
1567 error
= FT_Stream_New( library
, &args2
, &stream2
);
1570 FT_TRACE3(( "failed\n" ));
1574 error
= IsMacResource( library
, stream2
, offsets
[i
],
1575 face_index
, aface
);
1576 FT_Stream_Free( stream2
, 0 );
1578 FT_TRACE3(( "%s\n", error
? "failed": "successful" ));
1584 for (i
= 0; i
< FT_RACCESS_N_RULES
; i
++)
1586 if ( file_names
[i
] )
1587 FT_FREE( file_names
[i
] );
1590 /* Caller (load_mac_face) requires FT_Err_Unknown_File_Format. */
1592 error
= FT_Err_Unknown_File_Format
;
1597 #define FT_COMPONENT trace_objs
1602 /* Check for some macintosh formats. */
1603 /* Is this a macbinary file? If so look at the resource fork. */
1604 /* Is this a mac dfont file? */
1605 /* Is this an old style resource fork? (in data) */
1606 /* Else call load_face_in_embedded_rfork to try extra rules */
1607 /* (defined in `ftrfork.c'). */
1610 load_mac_face( FT_Library library
,
1614 const FT_Open_Args
*args
)
1620 error
= IsMacBinary( library
, stream
, face_index
, aface
);
1621 if ( FT_ERROR_BASE( error
) == FT_Err_Unknown_File_Format
)
1625 #define FT_COMPONENT trace_raccess
1627 FT_TRACE3(( "Try as dfont: %s ...", args
->pathname
));
1629 error
= IsMacResource( library
, stream
, 0, face_index
, aface
);
1631 FT_TRACE3(( "%s\n", error
? "failed" : "successful" ));
1634 #define FT_COMPONENT trace_objs
1638 if ( ( FT_ERROR_BASE( error
) == FT_Err_Unknown_File_Format
||
1639 FT_ERROR_BASE( error
) == FT_Err_Invalid_Stream_Operation
) &&
1640 ( args
->flags
& FT_OPEN_PATHNAME
) )
1641 error
= load_face_in_embedded_rfork( library
, stream
,
1642 face_index
, aface
, args
);
1646 #endif /* !FT_MACINTOSH && FT_CONFIG_OPTION_MAC_FONTS */
1649 /* documentation is in freetype.h */
1651 FT_EXPORT_DEF( FT_Error
)
1652 FT_Open_Face( FT_Library library
,
1653 const FT_Open_Args
* args
,
1662 FT_ListNode node
= 0;
1663 FT_Bool external_stream
;
1666 /* test for valid `library' delayed to */
1667 /* FT_Stream_New() */
1669 if ( ( !aface
&& face_index
>= 0 ) || !args
)
1670 return FT_Err_Invalid_Argument
;
1672 external_stream
= FT_BOOL( ( args
->flags
& FT_OPEN_STREAM
) &&
1675 /* create input stream */
1676 error
= FT_Stream_New( library
, args
, &stream
);
1680 memory
= library
->memory
;
1682 /* If the font driver is specified in the `args' structure, use */
1683 /* it. Otherwise, we scan the list of registered drivers. */
1684 if ( ( args
->flags
& FT_OPEN_DRIVER
) && args
->driver
)
1686 driver
= FT_DRIVER( args
->driver
);
1688 /* not all modules are drivers, so check... */
1689 if ( FT_MODULE_IS_DRIVER( driver
) )
1691 FT_Int num_params
= 0;
1692 FT_Parameter
* params
= 0;
1695 if ( args
->flags
& FT_OPEN_PARAMS
)
1697 num_params
= args
->num_params
;
1698 params
= args
->params
;
1701 error
= open_face( driver
, stream
, face_index
,
1702 num_params
, params
, &face
);
1707 error
= FT_Err_Invalid_Handle
;
1709 FT_Stream_Free( stream
, external_stream
);
1714 /* check each font driver for an appropriate format */
1715 FT_Module
* cur
= library
->modules
;
1716 FT_Module
* limit
= cur
+ library
->num_modules
;
1719 for ( ; cur
< limit
; cur
++ )
1721 /* not all modules are font drivers, so check... */
1722 if ( FT_MODULE_IS_DRIVER( cur
[0] ) )
1724 FT_Int num_params
= 0;
1725 FT_Parameter
* params
= 0;
1728 driver
= FT_DRIVER( cur
[0] );
1730 if ( args
->flags
& FT_OPEN_PARAMS
)
1732 num_params
= args
->num_params
;
1733 params
= args
->params
;
1736 error
= open_face( driver
, stream
, face_index
,
1737 num_params
, params
, &face
);
1741 if ( FT_ERROR_BASE( error
) != FT_Err_Unknown_File_Format
)
1747 /* If we are on the mac, and we get an FT_Err_Invalid_Stream_Operation */
1748 /* it may be because we have an empty data fork, so we need to check */
1749 /* the resource fork. */
1750 if ( FT_ERROR_BASE( error
) != FT_Err_Unknown_File_Format
&&
1751 FT_ERROR_BASE( error
) != FT_Err_Invalid_Stream_Operation
)
1754 #if !defined( FT_MACINTOSH ) && defined( FT_CONFIG_OPTION_MAC_FONTS )
1755 error
= load_mac_face( library
, stream
, face_index
, aface
, args
);
1758 /* We don't want to go to Success here. We've already done that. */
1759 /* On the other hand, if we succeeded we still need to close this */
1760 /* stream (we opened a different stream which extracted the */
1761 /* interesting information out of this stream here. That stream */
1762 /* will still be open and the face will point to it). */
1763 FT_Stream_Free( stream
, external_stream
);
1767 if ( FT_ERROR_BASE( error
) != FT_Err_Unknown_File_Format
)
1769 #endif /* !FT_MACINTOSH && FT_CONFIG_OPTION_MAC_FONTS */
1771 /* no driver is able to handle this format */
1772 error
= FT_Err_Unknown_File_Format
;
1775 FT_Stream_Free( stream
, external_stream
);
1780 FT_TRACE4(( "FT_Open_Face: New face object, adding to list\n" ));
1782 /* set the FT_FACE_FLAG_EXTERNAL_STREAM bit for FT_Done_Face */
1783 if ( external_stream
)
1784 face
->face_flags
|= FT_FACE_FLAG_EXTERNAL_STREAM
;
1786 /* add the face object to its driver's list */
1787 if ( FT_NEW( node
) )
1791 /* don't assume driver is the same as face->driver, so use */
1792 /* face->driver instead. */
1793 FT_List_Add( &face
->driver
->faces_list
, node
);
1795 /* now allocate a glyph slot object for the face */
1796 FT_TRACE4(( "FT_Open_Face: Creating glyph slot\n" ));
1798 if ( face_index
>= 0 )
1800 error
= FT_New_GlyphSlot( face
, NULL
);
1804 /* finally, allocate a size object for the face */
1809 FT_TRACE4(( "FT_Open_Face: Creating size object\n" ));
1811 error
= FT_New_Size( face
, &size
);
1821 if ( FT_IS_SCALABLE( face
) )
1823 if ( face
->height
< 0 )
1824 face
->height
= (FT_Short
)-face
->height
;
1826 if ( !FT_HAS_VERTICAL( face
) )
1827 face
->max_advance_height
= (FT_Short
)face
->height
;
1830 if ( FT_HAS_FIXED_SIZES( face
) )
1835 for ( i
= 0; i
< face
->num_fixed_sizes
; i
++ )
1837 FT_Bitmap_Size
* bsize
= face
->available_sizes
+ i
;
1840 if ( bsize
->height
< 0 )
1841 bsize
->height
= (FT_Short
)-bsize
->height
;
1842 if ( bsize
->x_ppem
< 0 )
1843 bsize
->x_ppem
= (FT_Short
)-bsize
->x_ppem
;
1844 if ( bsize
->y_ppem
< 0 )
1845 bsize
->y_ppem
= -bsize
->y_ppem
;
1849 /* initialize internal face data */
1851 FT_Face_Internal internal
= face
->internal
;
1854 internal
->transform_matrix
.xx
= 0x10000L
;
1855 internal
->transform_matrix
.xy
= 0;
1856 internal
->transform_matrix
.yx
= 0;
1857 internal
->transform_matrix
.yy
= 0x10000L
;
1859 internal
->transform_delta
.x
= 0;
1860 internal
->transform_delta
.y
= 0;
1866 FT_Done_Face( face
);
1871 FT_Done_Face( face
);
1874 FT_TRACE4(( "FT_Open_Face: Return %d\n", error
));
1880 /* documentation is in freetype.h */
1882 FT_EXPORT_DEF( FT_Error
)
1883 FT_Attach_File( FT_Face face
,
1884 const char* filepathname
)
1889 /* test for valid `face' delayed to FT_Attach_Stream() */
1891 if ( !filepathname
)
1892 return FT_Err_Invalid_Argument
;
1895 open
.flags
= FT_OPEN_PATHNAME
;
1896 open
.pathname
= (char*)filepathname
;
1898 return FT_Attach_Stream( face
, &open
);
1902 /* documentation is in freetype.h */
1904 FT_EXPORT_DEF( FT_Error
)
1905 FT_Attach_Stream( FT_Face face
,
1906 FT_Open_Args
* parameters
)
1912 FT_Driver_Class clazz
;
1915 /* test for valid `parameters' delayed to FT_Stream_New() */
1918 return FT_Err_Invalid_Face_Handle
;
1920 driver
= face
->driver
;
1922 return FT_Err_Invalid_Driver_Handle
;
1924 error
= FT_Stream_New( driver
->root
.library
, parameters
, &stream
);
1928 /* we implement FT_Attach_Stream in each driver through the */
1929 /* `attach_file' interface */
1931 error
= FT_Err_Unimplemented_Feature
;
1932 clazz
= driver
->clazz
;
1933 if ( clazz
->attach_file
)
1934 error
= clazz
->attach_file( face
, stream
);
1936 /* close the attached stream */
1937 FT_Stream_Free( stream
,
1938 (FT_Bool
)( parameters
->stream
&&
1939 ( parameters
->flags
& FT_OPEN_STREAM
) ) );
1946 /* documentation is in freetype.h */
1948 FT_EXPORT_DEF( FT_Error
)
1949 FT_Done_Face( FT_Face face
)
1957 error
= FT_Err_Invalid_Face_Handle
;
1958 if ( face
&& face
->driver
)
1960 driver
= face
->driver
;
1961 memory
= driver
->root
.memory
;
1963 /* find face in driver's list */
1964 node
= FT_List_Find( &driver
->faces_list
, face
);
1967 /* remove face object from the driver's list */
1968 FT_List_Remove( &driver
->faces_list
, node
);
1971 /* now destroy the object proper */
1972 destroy_face( memory
, face
, driver
);
1980 /* documentation is in ftobjs.h */
1982 FT_EXPORT_DEF( FT_Error
)
1983 FT_New_Size( FT_Face face
,
1989 FT_Driver_Class clazz
;
1992 FT_ListNode node
= 0;
1996 return FT_Err_Invalid_Face_Handle
;
1999 return FT_Err_Invalid_Size_Handle
;
2001 if ( !face
->driver
)
2002 return FT_Err_Invalid_Driver_Handle
;
2006 driver
= face
->driver
;
2007 clazz
= driver
->clazz
;
2008 memory
= face
->memory
;
2010 /* Allocate new size object and perform basic initialisation */
2011 if ( FT_ALLOC( size
, clazz
->size_object_size
) || FT_NEW( node
) )
2016 /* for now, do not use any internal fields in size objects */
2019 if ( clazz
->init_size
)
2020 error
= clazz
->init_size( size
);
2022 /* in case of success, add to the face's list */
2027 FT_List_Add( &face
->sizes_list
, node
);
2041 /* documentation is in ftobjs.h */
2043 FT_EXPORT_DEF( FT_Error
)
2044 FT_Done_Size( FT_Size size
)
2054 return FT_Err_Invalid_Size_Handle
;
2058 return FT_Err_Invalid_Face_Handle
;
2060 driver
= face
->driver
;
2062 return FT_Err_Invalid_Driver_Handle
;
2064 memory
= driver
->root
.memory
;
2067 node
= FT_List_Find( &face
->sizes_list
, size
);
2070 FT_List_Remove( &face
->sizes_list
, node
);
2073 if ( face
->size
== size
)
2076 if ( face
->sizes_list
.head
)
2077 face
->size
= (FT_Size
)(face
->sizes_list
.head
->data
);
2080 destroy_size( memory
, size
, driver
);
2083 error
= FT_Err_Invalid_Size_Handle
;
2089 /* documentation is in ftobjs.h */
2091 FT_BASE_DEF( FT_Error
)
2092 FT_Match_Size( FT_Face face
,
2093 FT_Size_Request req
,
2094 FT_Bool ignore_width
,
2095 FT_ULong
* size_index
)
2101 if ( !FT_HAS_FIXED_SIZES( face
) )
2102 return FT_Err_Invalid_Face_Handle
;
2104 /* FT_Bitmap_Size doesn't provide enough info... */
2105 if ( req
->type
!= FT_SIZE_REQUEST_TYPE_NOMINAL
)
2106 return FT_Err_Unimplemented_Feature
;
2108 w
= FT_REQUEST_WIDTH ( req
);
2109 h
= FT_REQUEST_HEIGHT( req
);
2111 if ( req
->width
&& !req
->height
)
2113 else if ( !req
->width
&& req
->height
)
2116 w
= FT_PIX_ROUND( w
);
2117 h
= FT_PIX_ROUND( h
);
2119 for ( i
= 0; i
< face
->num_fixed_sizes
; i
++ )
2121 FT_Bitmap_Size
* bsize
= face
->available_sizes
+ i
;
2124 if ( h
!= FT_PIX_ROUND( bsize
->y_ppem
) )
2127 if ( w
== FT_PIX_ROUND( bsize
->x_ppem
) || ignore_width
)
2130 *size_index
= (FT_ULong
)i
;
2136 return FT_Err_Invalid_Pixel_Size
;
2140 /* documentation is in ftobjs.h */
2143 ft_synthesize_vertical_metrics( FT_Glyph_Metrics
* metrics
,
2146 /* the factor 1.2 is a heuristical value */
2148 advance
= metrics
->height
* 12 / 10;
2150 metrics
->vertBearingX
= -( metrics
->width
/ 2 );
2151 metrics
->vertBearingY
= ( advance
- metrics
->height
) / 2;
2152 metrics
->vertAdvance
= advance
;
2157 ft_recompute_scaled_metrics( FT_Face face
,
2158 FT_Size_Metrics
* metrics
)
2160 /* Compute root ascender, descender, test height, and max_advance */
2162 #ifdef GRID_FIT_METRICS
2163 metrics
->ascender
= FT_PIX_CEIL( FT_MulFix( face
->ascender
,
2164 metrics
->y_scale
) );
2166 metrics
->descender
= FT_PIX_FLOOR( FT_MulFix( face
->descender
,
2167 metrics
->y_scale
) );
2169 metrics
->height
= FT_PIX_ROUND( FT_MulFix( face
->height
,
2170 metrics
->y_scale
) );
2172 metrics
->max_advance
= FT_PIX_ROUND( FT_MulFix( face
->max_advance_width
,
2173 metrics
->x_scale
) );
2174 #else /* !GRID_FIT_METRICS */
2175 metrics
->ascender
= FT_MulFix( face
->ascender
,
2178 metrics
->descender
= FT_MulFix( face
->descender
,
2181 metrics
->height
= FT_MulFix( face
->height
,
2184 metrics
->max_advance
= FT_MulFix( face
->max_advance_width
,
2186 #endif /* !GRID_FIT_METRICS */
2191 FT_Select_Metrics( FT_Face face
,
2192 FT_ULong strike_index
)
2194 FT_Size_Metrics
* metrics
;
2195 FT_Bitmap_Size
* bsize
;
2198 metrics
= &face
->size
->metrics
;
2199 bsize
= face
->available_sizes
+ strike_index
;
2201 metrics
->x_ppem
= (FT_UShort
)( ( bsize
->x_ppem
+ 32 ) >> 6 );
2202 metrics
->y_ppem
= (FT_UShort
)( ( bsize
->y_ppem
+ 32 ) >> 6 );
2204 if ( FT_IS_SCALABLE( face
) )
2206 metrics
->x_scale
= FT_DivFix( bsize
->x_ppem
,
2207 face
->units_per_EM
);
2208 metrics
->y_scale
= FT_DivFix( bsize
->y_ppem
,
2209 face
->units_per_EM
);
2211 ft_recompute_scaled_metrics( face
, metrics
);
2215 metrics
->x_scale
= 1L << 22;
2216 metrics
->y_scale
= 1L << 22;
2217 metrics
->ascender
= bsize
->y_ppem
;
2218 metrics
->descender
= 0;
2219 metrics
->height
= bsize
->height
<< 6;
2220 metrics
->max_advance
= bsize
->x_ppem
;
2226 FT_Request_Metrics( FT_Face face
,
2227 FT_Size_Request req
)
2229 FT_Size_Metrics
* metrics
;
2232 metrics
= &face
->size
->metrics
;
2234 if ( FT_IS_SCALABLE( face
) )
2236 FT_Long w
= 0, h
= 0, scaled_w
= 0, scaled_h
= 0;
2239 switch ( req
->type
)
2241 case FT_SIZE_REQUEST_TYPE_NOMINAL
:
2242 w
= h
= face
->units_per_EM
;
2245 case FT_SIZE_REQUEST_TYPE_REAL_DIM
:
2246 w
= h
= face
->ascender
- face
->descender
;
2249 case FT_SIZE_REQUEST_TYPE_BBOX
:
2250 w
= face
->bbox
.xMax
- face
->bbox
.xMin
;
2251 h
= face
->bbox
.yMax
- face
->bbox
.yMin
;
2254 case FT_SIZE_REQUEST_TYPE_CELL
:
2255 w
= face
->max_advance_width
;
2256 h
= face
->ascender
- face
->descender
;
2259 case FT_SIZE_REQUEST_TYPE_SCALES
:
2260 metrics
->x_scale
= (FT_Fixed
)req
->width
;
2261 metrics
->y_scale
= (FT_Fixed
)req
->height
;
2262 if ( !metrics
->x_scale
)
2263 metrics
->x_scale
= metrics
->y_scale
;
2264 else if ( !metrics
->y_scale
)
2265 metrics
->y_scale
= metrics
->x_scale
;
2266 goto Calculate_Ppem
;
2268 case FT_SIZE_REQUEST_TYPE_MAX
:
2272 /* to be on the safe side */
2279 scaled_w
= FT_REQUEST_WIDTH ( req
);
2280 scaled_h
= FT_REQUEST_HEIGHT( req
);
2282 /* determine scales */
2285 metrics
->x_scale
= FT_DivFix( scaled_w
, w
);
2289 metrics
->y_scale
= FT_DivFix( scaled_h
, h
);
2291 if ( req
->type
== FT_SIZE_REQUEST_TYPE_CELL
)
2293 if ( metrics
->y_scale
> metrics
->x_scale
)
2294 metrics
->y_scale
= metrics
->x_scale
;
2296 metrics
->x_scale
= metrics
->y_scale
;
2301 metrics
->y_scale
= metrics
->x_scale
;
2302 scaled_h
= FT_MulDiv( scaled_w
, h
, w
);
2307 metrics
->x_scale
= metrics
->y_scale
= FT_DivFix( scaled_h
, h
);
2308 scaled_w
= FT_MulDiv( scaled_h
, w
, h
);
2312 /* calculate the ppems */
2313 if ( req
->type
!= FT_SIZE_REQUEST_TYPE_NOMINAL
)
2315 scaled_w
= FT_MulFix( face
->units_per_EM
, metrics
->x_scale
);
2316 scaled_h
= FT_MulFix( face
->units_per_EM
, metrics
->y_scale
);
2319 metrics
->x_ppem
= (FT_UShort
)( ( scaled_w
+ 32 ) >> 6 );
2320 metrics
->y_ppem
= (FT_UShort
)( ( scaled_h
+ 32 ) >> 6 );
2322 ft_recompute_scaled_metrics( face
, metrics
);
2327 metrics
->x_scale
= 1L << 22;
2328 metrics
->y_scale
= 1L << 22;
2333 /* documentation is in freetype.h */
2335 FT_EXPORT_DEF( FT_Error
)
2336 FT_Select_Size( FT_Face face
,
2337 FT_Int strike_index
)
2339 FT_Driver_Class clazz
;
2342 if ( !face
|| !FT_HAS_FIXED_SIZES( face
) )
2343 return FT_Err_Invalid_Face_Handle
;
2345 if ( strike_index
< 0 || strike_index
>= face
->num_fixed_sizes
)
2346 return FT_Err_Invalid_Argument
;
2348 clazz
= face
->driver
->clazz
;
2350 if ( clazz
->select_size
)
2351 return clazz
->select_size( face
->size
, (FT_ULong
)strike_index
);
2353 FT_Select_Metrics( face
, (FT_ULong
)strike_index
);
2359 /* documentation is in freetype.h */
2361 FT_EXPORT_DEF( FT_Error
)
2362 FT_Request_Size( FT_Face face
,
2363 FT_Size_Request req
)
2365 FT_Driver_Class clazz
;
2366 FT_ULong strike_index
;
2370 return FT_Err_Invalid_Face_Handle
;
2372 if ( !req
|| req
->width
< 0 || req
->height
< 0 ||
2373 req
->type
>= FT_SIZE_REQUEST_TYPE_MAX
)
2374 return FT_Err_Invalid_Argument
;
2376 clazz
= face
->driver
->clazz
;
2378 if ( clazz
->request_size
)
2379 return clazz
->request_size( face
->size
, req
);
2382 * The reason that a driver doesn't have `request_size' defined is
2383 * either that the scaling here suffices or that the supported formats
2384 * are bitmap-only and size matching is not implemented.
2386 * In the latter case, a simple size matching is done.
2388 if ( !FT_IS_SCALABLE( face
) && FT_HAS_FIXED_SIZES( face
) )
2393 error
= FT_Match_Size( face
, req
, 0, &strike_index
);
2397 FT_TRACE3(( "FT_Request_Size: bitmap strike %lu matched\n",
2400 return FT_Select_Size( face
, (FT_Int
)strike_index
);
2403 FT_Request_Metrics( face
, req
);
2409 /* documentation is in freetype.h */
2411 FT_EXPORT_DEF( FT_Error
)
2412 FT_Set_Char_Size( FT_Face face
,
2413 FT_F26Dot6 char_width
,
2414 FT_F26Dot6 char_height
,
2415 FT_UInt horz_resolution
,
2416 FT_UInt vert_resolution
)
2418 FT_Size_RequestRec req
;
2422 char_width
= char_height
;
2423 else if ( !char_height
)
2424 char_height
= char_width
;
2426 if ( !horz_resolution
)
2427 horz_resolution
= vert_resolution
;
2428 else if ( !vert_resolution
)
2429 vert_resolution
= horz_resolution
;
2431 if ( char_width
< 1 * 64 )
2432 char_width
= 1 * 64;
2433 if ( char_height
< 1 * 64 )
2434 char_height
= 1 * 64;
2436 if ( !horz_resolution
)
2437 horz_resolution
= vert_resolution
= 72;
2439 req
.type
= FT_SIZE_REQUEST_TYPE_NOMINAL
;
2440 req
.width
= char_width
;
2441 req
.height
= char_height
;
2442 req
.horiResolution
= horz_resolution
;
2443 req
.vertResolution
= vert_resolution
;
2445 return FT_Request_Size( face
, &req
);
2449 /* documentation is in freetype.h */
2451 FT_EXPORT_DEF( FT_Error
)
2452 FT_Set_Pixel_Sizes( FT_Face face
,
2453 FT_UInt pixel_width
,
2454 FT_UInt pixel_height
)
2456 FT_Size_RequestRec req
;
2459 if ( pixel_width
== 0 )
2460 pixel_width
= pixel_height
;
2461 else if ( pixel_height
== 0 )
2462 pixel_height
= pixel_width
;
2464 if ( pixel_width
< 1 )
2466 if ( pixel_height
< 1 )
2469 /* use `>=' to avoid potential compiler warning on 16bit platforms */
2470 if ( pixel_width
>= 0xFFFFU
)
2471 pixel_width
= 0xFFFFU
;
2472 if ( pixel_height
>= 0xFFFFU
)
2473 pixel_height
= 0xFFFFU
;
2475 req
.type
= FT_SIZE_REQUEST_TYPE_NOMINAL
;
2476 req
.width
= pixel_width
<< 6;
2477 req
.height
= pixel_height
<< 6;
2478 req
.horiResolution
= 0;
2479 req
.vertResolution
= 0;
2481 return FT_Request_Size( face
, &req
);
2485 /* documentation is in freetype.h */
2487 FT_EXPORT_DEF( FT_Error
)
2488 FT_Get_Kerning( FT_Face face
,
2490 FT_UInt right_glyph
,
2492 FT_Vector
*akerning
)
2494 FT_Error error
= FT_Err_Ok
;
2499 return FT_Err_Invalid_Face_Handle
;
2502 return FT_Err_Invalid_Argument
;
2504 driver
= face
->driver
;
2509 if ( driver
->clazz
->get_kerning
)
2511 error
= driver
->clazz
->get_kerning( face
,
2517 if ( kern_mode
!= FT_KERNING_UNSCALED
)
2519 akerning
->x
= FT_MulFix( akerning
->x
, face
->size
->metrics
.x_scale
);
2520 akerning
->y
= FT_MulFix( akerning
->y
, face
->size
->metrics
.y_scale
);
2522 if ( kern_mode
!= FT_KERNING_UNFITTED
)
2524 /* we scale down kerning values for small ppem values */
2525 /* to avoid that rounding makes them too big. */
2526 /* `25' has been determined heuristically. */
2527 if ( face
->size
->metrics
.x_ppem
< 25 )
2528 akerning
->x
= FT_MulDiv( akerning
->x
,
2529 face
->size
->metrics
.x_ppem
, 25 );
2530 if ( face
->size
->metrics
.y_ppem
< 25 )
2531 akerning
->y
= FT_MulDiv( akerning
->y
,
2532 face
->size
->metrics
.y_ppem
, 25 );
2534 akerning
->x
= FT_PIX_ROUND( akerning
->x
);
2535 akerning
->y
= FT_PIX_ROUND( akerning
->y
);
2545 /* documentation is in freetype.h */
2547 FT_EXPORT_DEF( FT_Error
)
2548 FT_Get_Track_Kerning( FT_Face face
,
2549 FT_Fixed point_size
,
2551 FT_Fixed
* akerning
)
2553 FT_Service_Kerning service
;
2554 FT_Error error
= FT_Err_Ok
;
2558 return FT_Err_Invalid_Face_Handle
;
2561 return FT_Err_Invalid_Argument
;
2563 FT_FACE_FIND_SERVICE( face
, service
, KERNING
);
2565 return FT_Err_Unimplemented_Feature
;
2567 error
= service
->get_track( face
,
2576 /* documentation is in freetype.h */
2578 FT_EXPORT_DEF( FT_Error
)
2579 FT_Select_Charmap( FT_Face face
,
2580 FT_Encoding encoding
)
2587 return FT_Err_Invalid_Face_Handle
;
2589 if ( encoding
== FT_ENCODING_NONE
)
2590 return FT_Err_Invalid_Argument
;
2592 /* FT_ENCODING_UNICODE is special. We try to find the `best' Unicode */
2593 /* charmap available, i.e., one with UCS-4 characters, if possible. */
2595 /* This is done by find_unicode_charmap() above, to share code. */
2596 if ( encoding
== FT_ENCODING_UNICODE
)
2597 return find_unicode_charmap( face
);
2599 cur
= face
->charmaps
;
2601 return FT_Err_Invalid_CharMap_Handle
;
2603 limit
= cur
+ face
->num_charmaps
;
2605 for ( ; cur
< limit
; cur
++ )
2607 if ( cur
[0]->encoding
== encoding
)
2609 face
->charmap
= cur
[0];
2614 return FT_Err_Invalid_Argument
;
2618 /* documentation is in freetype.h */
2620 FT_EXPORT_DEF( FT_Error
)
2621 FT_Set_Charmap( FT_Face face
,
2622 FT_CharMap charmap
)
2629 return FT_Err_Invalid_Face_Handle
;
2631 cur
= face
->charmaps
;
2633 return FT_Err_Invalid_CharMap_Handle
;
2635 limit
= cur
+ face
->num_charmaps
;
2637 for ( ; cur
< limit
; cur
++ )
2639 if ( cur
[0] == charmap
)
2641 face
->charmap
= cur
[0];
2645 return FT_Err_Invalid_Argument
;
2649 /* documentation is in freetype.h */
2651 FT_EXPORT_DEF( FT_Int
)
2652 FT_Get_Charmap_Index( FT_CharMap charmap
)
2657 for ( i
= 0; i
< charmap
->face
->num_charmaps
; i
++ )
2658 if ( charmap
->face
->charmaps
[i
] == charmap
)
2661 FT_ASSERT( i
< charmap
->face
->num_charmaps
);
2668 ft_cmap_done_internal( FT_CMap cmap
)
2670 FT_CMap_Class clazz
= cmap
->clazz
;
2671 FT_Face face
= cmap
->charmap
.face
;
2672 FT_Memory memory
= FT_FACE_MEMORY(face
);
2676 clazz
->done( cmap
);
2683 FT_CMap_Done( FT_CMap cmap
)
2687 FT_Face face
= cmap
->charmap
.face
;
2688 FT_Memory memory
= FT_FACE_MEMORY( face
);
2693 for ( i
= 0; i
< face
->num_charmaps
; i
++ )
2695 if ( (FT_CMap
)face
->charmaps
[i
] == cmap
)
2697 FT_CharMap last_charmap
= face
->charmaps
[face
->num_charmaps
- 1];
2700 if ( FT_RENEW_ARRAY( face
->charmaps
,
2702 face
->num_charmaps
- 1 ) )
2705 /* remove it from our list of charmaps */
2706 for ( j
= i
+ 1; j
< face
->num_charmaps
; j
++ )
2708 if ( j
== face
->num_charmaps
- 1 )
2709 face
->charmaps
[j
- 1] = last_charmap
;
2711 face
->charmaps
[j
- 1] = face
->charmaps
[j
];
2714 face
->num_charmaps
--;
2716 if ( (FT_CMap
)face
->charmap
== cmap
)
2717 face
->charmap
= NULL
;
2719 ft_cmap_done_internal( cmap
);
2728 FT_BASE_DEF( FT_Error
)
2729 FT_CMap_New( FT_CMap_Class clazz
,
2730 FT_Pointer init_data
,
2734 FT_Error error
= FT_Err_Ok
;
2740 if ( clazz
== NULL
|| charmap
== NULL
|| charmap
->face
== NULL
)
2741 return FT_Err_Invalid_Argument
;
2743 face
= charmap
->face
;
2744 memory
= FT_FACE_MEMORY( face
);
2746 if ( !FT_ALLOC( cmap
, clazz
->size
) )
2748 cmap
->charmap
= *charmap
;
2749 cmap
->clazz
= clazz
;
2753 error
= clazz
->init( cmap
, init_data
);
2758 /* add it to our list of charmaps */
2759 if ( FT_RENEW_ARRAY( face
->charmaps
,
2761 face
->num_charmaps
+ 1 ) )
2764 face
->charmaps
[face
->num_charmaps
++] = (FT_CharMap
)cmap
;
2774 ft_cmap_done_internal( cmap
);
2780 /* documentation is in freetype.h */
2782 FT_EXPORT_DEF( FT_UInt
)
2783 FT_Get_Char_Index( FT_Face face
,
2789 if ( face
&& face
->charmap
)
2791 FT_CMap cmap
= FT_CMAP( face
->charmap
);
2794 result
= cmap
->clazz
->char_index( cmap
, charcode
);
2800 /* documentation is in freetype.h */
2802 FT_EXPORT_DEF( FT_ULong
)
2803 FT_Get_First_Char( FT_Face face
,
2806 FT_ULong result
= 0;
2810 if ( face
&& face
->charmap
)
2812 gindex
= FT_Get_Char_Index( face
, 0 );
2814 result
= FT_Get_Next_Char( face
, 0, &gindex
);
2824 /* documentation is in freetype.h */
2826 FT_EXPORT_DEF( FT_ULong
)
2827 FT_Get_Next_Char( FT_Face face
,
2831 FT_ULong result
= 0;
2835 if ( face
&& face
->charmap
)
2837 FT_UInt32 code
= (FT_UInt32
)charcode
;
2838 FT_CMap cmap
= FT_CMAP( face
->charmap
);
2841 gindex
= cmap
->clazz
->char_next( cmap
, &code
);
2842 result
= ( gindex
== 0 ) ? 0 : code
;
2852 /* documentation is in freetype.h */
2854 FT_EXPORT_DEF( FT_UInt
)
2855 FT_Get_Name_Index( FT_Face face
,
2856 FT_String
* glyph_name
)
2861 if ( face
&& FT_HAS_GLYPH_NAMES( face
) )
2863 FT_Service_GlyphDict service
;
2866 FT_FACE_LOOKUP_SERVICE( face
,
2870 if ( service
&& service
->name_index
)
2871 result
= service
->name_index( face
, glyph_name
);
2878 /* documentation is in freetype.h */
2880 FT_EXPORT_DEF( FT_Error
)
2881 FT_Get_Glyph_Name( FT_Face face
,
2882 FT_UInt glyph_index
,
2884 FT_UInt buffer_max
)
2886 FT_Error error
= FT_Err_Invalid_Argument
;
2889 /* clean up buffer */
2890 if ( buffer
&& buffer_max
> 0 )
2891 ((FT_Byte
*)buffer
)[0] = 0;
2894 glyph_index
<= (FT_UInt
)face
->num_glyphs
&&
2895 FT_HAS_GLYPH_NAMES( face
) )
2897 FT_Service_GlyphDict service
;
2900 FT_FACE_LOOKUP_SERVICE( face
,
2904 if ( service
&& service
->get_name
)
2905 error
= service
->get_name( face
, glyph_index
, buffer
, buffer_max
);
2912 /* documentation is in freetype.h */
2914 FT_EXPORT_DEF( const char* )
2915 FT_Get_Postscript_Name( FT_Face face
)
2917 const char* result
= NULL
;
2925 FT_Service_PsFontName service
;
2928 FT_FACE_LOOKUP_SERVICE( face
,
2930 POSTSCRIPT_FONT_NAME
);
2932 if ( service
&& service
->get_ps_font_name
)
2933 result
= service
->get_ps_font_name( face
);
2941 /* documentation is in tttables.h */
2943 FT_EXPORT_DEF( void* )
2944 FT_Get_Sfnt_Table( FT_Face face
,
2948 FT_Service_SFNT_Table service
;
2951 if ( face
&& FT_IS_SFNT( face
) )
2953 FT_FACE_FIND_SERVICE( face
, service
, SFNT_TABLE
);
2954 if ( service
!= NULL
)
2955 table
= service
->get_table( face
, tag
);
2962 /* documentation is in tttables.h */
2964 FT_EXPORT_DEF( FT_Error
)
2965 FT_Load_Sfnt_Table( FT_Face face
,
2971 FT_Service_SFNT_Table service
;
2974 if ( !face
|| !FT_IS_SFNT( face
) )
2975 return FT_Err_Invalid_Face_Handle
;
2977 FT_FACE_FIND_SERVICE( face
, service
, SFNT_TABLE
);
2978 if ( service
== NULL
)
2979 return FT_Err_Unimplemented_Feature
;
2981 return service
->load_table( face
, tag
, offset
, buffer
, length
);
2985 /* documentation is in tttables.h */
2987 FT_EXPORT_DEF( FT_Error
)
2988 FT_Sfnt_Table_Info( FT_Face face
,
2989 FT_UInt table_index
,
2993 FT_Service_SFNT_Table service
;
2996 if ( !face
|| !FT_IS_SFNT( face
) )
2997 return FT_Err_Invalid_Face_Handle
;
2999 FT_FACE_FIND_SERVICE( face
, service
, SFNT_TABLE
);
3000 if ( service
== NULL
)
3001 return FT_Err_Unimplemented_Feature
;
3003 return service
->table_info( face
, table_index
, tag
, length
);
3007 /* documentation is in tttables.h */
3009 FT_EXPORT_DEF( FT_ULong
)
3010 FT_Get_CMap_Language_ID( FT_CharMap charmap
)
3012 FT_Service_TTCMaps service
;
3014 TT_CMapInfo cmap_info
;
3017 if ( !charmap
|| !charmap
->face
)
3020 face
= charmap
->face
;
3021 FT_FACE_FIND_SERVICE( face
, service
, TT_CMAP
);
3022 if ( service
== NULL
)
3024 if ( service
->get_cmap_info( charmap
, &cmap_info
))
3027 return cmap_info
.language
;
3031 /* documentation is in tttables.h */
3033 FT_EXPORT_DEF( FT_Long
)
3034 FT_Get_CMap_Format( FT_CharMap charmap
)
3036 FT_Service_TTCMaps service
;
3038 TT_CMapInfo cmap_info
;
3041 if ( !charmap
|| !charmap
->face
)
3044 face
= charmap
->face
;
3045 FT_FACE_FIND_SERVICE( face
, service
, TT_CMAP
);
3046 if ( service
== NULL
)
3048 if ( service
->get_cmap_info( charmap
, &cmap_info
))
3051 return cmap_info
.format
;
3055 /* documentation is in ftsizes.h */
3057 FT_EXPORT_DEF( FT_Error
)
3058 FT_Activate_Size( FT_Size size
)
3064 return FT_Err_Bad_Argument
;
3067 if ( face
== NULL
|| face
->driver
== NULL
)
3068 return FT_Err_Bad_Argument
;
3070 /* we don't need anything more complex than that; all size objects */
3071 /* are already listed by the face */
3078 /*************************************************************************/
3079 /*************************************************************************/
3080 /*************************************************************************/
3083 /**** R E N D E R E R S ****/
3086 /*************************************************************************/
3087 /*************************************************************************/
3088 /*************************************************************************/
3090 /* lookup a renderer by glyph format in the library's list */
3091 FT_BASE_DEF( FT_Renderer
)
3092 FT_Lookup_Renderer( FT_Library library
,
3093 FT_Glyph_Format format
,
3097 FT_Renderer result
= 0;
3103 cur
= library
->renderers
.head
;
3108 cur
= (*node
)->next
;
3114 FT_Renderer renderer
= FT_RENDERER( cur
->data
);
3117 if ( renderer
->glyph_format
== format
)
3134 ft_lookup_glyph_renderer( FT_GlyphSlot slot
)
3136 FT_Face face
= slot
->face
;
3137 FT_Library library
= FT_FACE_LIBRARY( face
);
3138 FT_Renderer result
= library
->cur_renderer
;
3141 if ( !result
|| result
->glyph_format
!= slot
->format
)
3142 result
= FT_Lookup_Renderer( library
, slot
->format
, 0 );
3149 ft_set_current_renderer( FT_Library library
)
3151 FT_Renderer renderer
;
3154 renderer
= FT_Lookup_Renderer( library
, FT_GLYPH_FORMAT_OUTLINE
, 0 );
3155 library
->cur_renderer
= renderer
;
3160 ft_add_renderer( FT_Module module
)
3162 FT_Library library
= module
->library
;
3163 FT_Memory memory
= library
->memory
;
3168 if ( FT_NEW( node
) )
3172 FT_Renderer render
= FT_RENDERER( module
);
3173 FT_Renderer_Class
* clazz
= (FT_Renderer_Class
*)module
->clazz
;
3176 render
->clazz
= clazz
;
3177 render
->glyph_format
= clazz
->glyph_format
;
3179 /* allocate raster object if needed */
3180 if ( clazz
->glyph_format
== FT_GLYPH_FORMAT_OUTLINE
&&
3181 clazz
->raster_class
->raster_new
)
3183 error
= clazz
->raster_class
->raster_new( memory
, &render
->raster
);
3187 render
->raster_render
= clazz
->raster_class
->raster_render
;
3188 render
->render
= clazz
->render_glyph
;
3192 node
->data
= module
;
3193 FT_List_Add( &library
->renderers
, node
);
3195 ft_set_current_renderer( library
);
3208 ft_remove_renderer( FT_Module module
)
3210 FT_Library library
= module
->library
;
3211 FT_Memory memory
= library
->memory
;
3215 node
= FT_List_Find( &library
->renderers
, module
);
3218 FT_Renderer render
= FT_RENDERER( module
);
3221 /* release raster object, if any */
3222 if ( render
->raster
)
3223 render
->clazz
->raster_class
->raster_done( render
->raster
);
3225 /* remove from list */
3226 FT_List_Remove( &library
->renderers
, node
);
3229 ft_set_current_renderer( library
);
3234 /* documentation is in ftrender.h */
3236 FT_EXPORT_DEF( FT_Renderer
)
3237 FT_Get_Renderer( FT_Library library
,
3238 FT_Glyph_Format format
)
3240 /* test for valid `library' delayed to FT_Lookup_Renderer() */
3242 return FT_Lookup_Renderer( library
, format
, 0 );
3246 /* documentation is in ftrender.h */
3248 FT_EXPORT_DEF( FT_Error
)
3249 FT_Set_Renderer( FT_Library library
,
3250 FT_Renderer renderer
,
3252 FT_Parameter
* parameters
)
3255 FT_Error error
= FT_Err_Ok
;
3259 return FT_Err_Invalid_Library_Handle
;
3262 return FT_Err_Invalid_Argument
;
3264 node
= FT_List_Find( &library
->renderers
, renderer
);
3267 error
= FT_Err_Invalid_Argument
;
3271 FT_List_Up( &library
->renderers
, node
);
3273 if ( renderer
->glyph_format
== FT_GLYPH_FORMAT_OUTLINE
)
3274 library
->cur_renderer
= renderer
;
3276 if ( num_params
> 0 )
3278 FT_Renderer_SetModeFunc set_mode
= renderer
->clazz
->set_mode
;
3281 for ( ; num_params
> 0; num_params
-- )
3283 error
= set_mode( renderer
, parameters
->tag
, parameters
->data
);
3294 FT_BASE_DEF( FT_Error
)
3295 FT_Render_Glyph_Internal( FT_Library library
,
3297 FT_Render_Mode render_mode
)
3299 FT_Error error
= FT_Err_Ok
;
3300 FT_Renderer renderer
;
3303 /* if it is already a bitmap, no need to do anything */
3304 switch ( slot
->format
)
3306 case FT_GLYPH_FORMAT_BITMAP
: /* already a bitmap, don't do anything */
3311 FT_ListNode node
= 0;
3315 /* small shortcut for the very common case */
3316 if ( slot
->format
== FT_GLYPH_FORMAT_OUTLINE
)
3318 renderer
= library
->cur_renderer
;
3319 node
= library
->renderers
.head
;
3322 renderer
= FT_Lookup_Renderer( library
, slot
->format
, &node
);
3324 error
= FT_Err_Unimplemented_Feature
;
3327 error
= renderer
->render( renderer
, slot
, render_mode
, NULL
);
3329 FT_ERROR_BASE( error
) != FT_Err_Cannot_Render_Glyph
)
3332 /* FT_Err_Cannot_Render_Glyph is returned if the render mode */
3333 /* is unsupported by the current renderer for this glyph image */
3336 /* now, look for another renderer that supports the same */
3338 renderer
= FT_Lookup_Renderer( library
, slot
->format
, &node
);
3342 /* if we changed the current renderer for the glyph image format */
3343 /* we need to select it as the next current one */
3344 if ( !error
&& update
&& renderer
)
3345 FT_Set_Renderer( library
, renderer
, 0, 0 );
3353 /* documentation is in freetype.h */
3355 FT_EXPORT_DEF( FT_Error
)
3356 FT_Render_Glyph( FT_GlyphSlot slot
,
3357 FT_Render_Mode render_mode
)
3363 return FT_Err_Invalid_Argument
;
3365 library
= FT_FACE_LIBRARY( slot
->face
);
3367 return FT_Render_Glyph_Internal( library
, slot
, render_mode
);
3371 /*************************************************************************/
3372 /*************************************************************************/
3373 /*************************************************************************/
3376 /**** M O D U L E S ****/
3379 /*************************************************************************/
3380 /*************************************************************************/
3381 /*************************************************************************/
3384 /*************************************************************************/
3387 /* Destroy_Module */
3390 /* Destroys a given module object. For drivers, this also destroys */
3391 /* all child faces. */
3394 /* module :: A handle to the target driver object. */
3397 /* The driver _must_ be LOCKED! */
3400 Destroy_Module( FT_Module module
)
3402 FT_Memory memory
= module
->memory
;
3403 FT_Module_Class
* clazz
= module
->clazz
;
3404 FT_Library library
= module
->library
;
3407 /* finalize client-data - before anything else */
3408 if ( module
->generic
.finalizer
)
3409 module
->generic
.finalizer( module
);
3411 if ( library
&& library
->auto_hinter
== module
)
3412 library
->auto_hinter
= 0;
3414 /* if the module is a renderer */
3415 if ( FT_MODULE_IS_RENDERER( module
) )
3416 ft_remove_renderer( module
);
3418 /* if the module is a font driver, add some steps */
3419 if ( FT_MODULE_IS_DRIVER( module
) )
3420 Destroy_Driver( FT_DRIVER( module
) );
3422 /* finalize the module object */
3423 if ( clazz
->module_done
)
3424 clazz
->module_done( module
);
3431 /* documentation is in ftmodapi.h */
3433 FT_EXPORT_DEF( FT_Error
)
3434 FT_Add_Module( FT_Library library
,
3435 const FT_Module_Class
* clazz
)
3443 #define FREETYPE_VER_FIXED ( ( (FT_Long)FREETYPE_MAJOR << 16 ) | \
3447 return FT_Err_Invalid_Library_Handle
;
3450 return FT_Err_Invalid_Argument
;
3452 /* check freetype version */
3453 if ( clazz
->module_requires
> FREETYPE_VER_FIXED
)
3454 return FT_Err_Invalid_Version
;
3456 /* look for a module with the same name in the library's table */
3457 for ( nn
= 0; nn
< library
->num_modules
; nn
++ )
3459 module
= library
->modules
[nn
];
3460 if ( ft_strcmp( module
->clazz
->module_name
, clazz
->module_name
) == 0 )
3462 /* this installed module has the same name, compare their versions */
3463 if ( clazz
->module_version
<= module
->clazz
->module_version
)
3464 return FT_Err_Lower_Module_Version
;
3466 /* remove the module from our list, then exit the loop to replace */
3467 /* it by our new version.. */
3468 FT_Remove_Module( library
, module
);
3473 memory
= library
->memory
;
3476 if ( library
->num_modules
>= FT_MAX_MODULES
)
3478 error
= FT_Err_Too_Many_Drivers
;
3482 /* allocate module object */
3483 if ( FT_ALLOC( module
, clazz
->module_size
) )
3486 /* base initialization */
3487 module
->library
= library
;
3488 module
->memory
= memory
;
3489 module
->clazz
= (FT_Module_Class
*)clazz
;
3491 /* check whether the module is a renderer - this must be performed */
3492 /* before the normal module initialization */
3493 if ( FT_MODULE_IS_RENDERER( module
) )
3495 /* add to the renderers list */
3496 error
= ft_add_renderer( module
);
3501 /* is the module a auto-hinter? */
3502 if ( FT_MODULE_IS_HINTER( module
) )
3503 library
->auto_hinter
= module
;
3505 /* if the module is a font driver */
3506 if ( FT_MODULE_IS_DRIVER( module
) )
3508 /* allocate glyph loader if needed */
3509 FT_Driver driver
= FT_DRIVER( module
);
3512 driver
->clazz
= (FT_Driver_Class
)module
->clazz
;
3513 if ( FT_DRIVER_USES_OUTLINES( driver
) )
3515 error
= FT_GlyphLoader_New( memory
, &driver
->glyph_loader
);
3521 if ( clazz
->module_init
)
3523 error
= clazz
->module_init( module
);
3528 /* add module to the library's table */
3529 library
->modules
[library
->num_modules
++] = module
;
3535 if ( FT_MODULE_IS_DRIVER( module
) )
3537 FT_Driver driver
= FT_DRIVER( module
);
3540 if ( FT_DRIVER_USES_OUTLINES( driver
) )
3541 FT_GlyphLoader_Done( driver
->glyph_loader
);
3544 if ( FT_MODULE_IS_RENDERER( module
) )
3546 FT_Renderer renderer
= FT_RENDERER( module
);
3549 if ( renderer
->raster
)
3550 renderer
->clazz
->raster_class
->raster_done( renderer
->raster
);
3558 /* documentation is in ftmodapi.h */
3560 FT_EXPORT_DEF( FT_Module
)
3561 FT_Get_Module( FT_Library library
,
3562 const char* module_name
)
3564 FT_Module result
= 0;
3569 if ( !library
|| !module_name
)
3572 cur
= library
->modules
;
3573 limit
= cur
+ library
->num_modules
;
3575 for ( ; cur
< limit
; cur
++ )
3576 if ( ft_strcmp( cur
[0]->clazz
->module_name
, module_name
) == 0 )
3586 /* documentation is in ftobjs.h */
3588 FT_BASE_DEF( const void* )
3589 FT_Get_Module_Interface( FT_Library library
,
3590 const char* mod_name
)
3595 /* test for valid `library' delayed to FT_Get_Module() */
3597 module
= FT_Get_Module( library
, mod_name
);
3599 return module
? module
->clazz
->module_interface
: 0;
3603 FT_BASE_DEF( FT_Pointer
)
3604 ft_module_get_service( FT_Module module
,
3605 const char* service_id
)
3607 FT_Pointer result
= NULL
;
3611 FT_ASSERT( module
->clazz
&& module
->clazz
->get_interface
);
3613 /* first, look for the service in the module
3615 if ( module
->clazz
->get_interface
)
3616 result
= module
->clazz
->get_interface( module
, service_id
);
3618 if ( result
== NULL
)
3620 /* we didn't find it, look in all other modules then
3622 FT_Library library
= module
->library
;
3623 FT_Module
* cur
= library
->modules
;
3624 FT_Module
* limit
= cur
+ library
->num_modules
;
3626 for ( ; cur
< limit
; cur
++ )
3628 if ( cur
[0] != module
)
3630 FT_ASSERT( cur
[0]->clazz
);
3632 if ( cur
[0]->clazz
->get_interface
)
3634 result
= cur
[0]->clazz
->get_interface( cur
[0], service_id
);
3635 if ( result
!= NULL
)
3647 /* documentation is in ftmodapi.h */
3649 FT_EXPORT_DEF( FT_Error
)
3650 FT_Remove_Module( FT_Library library
,
3653 /* try to find the module from the table, then remove it from there */
3656 return FT_Err_Invalid_Library_Handle
;
3660 FT_Module
* cur
= library
->modules
;
3661 FT_Module
* limit
= cur
+ library
->num_modules
;
3664 for ( ; cur
< limit
; cur
++ )
3666 if ( cur
[0] == module
)
3668 /* remove it from the table */
3669 library
->num_modules
--;
3671 while ( cur
< limit
)
3678 /* destroy the module */
3679 Destroy_Module( module
);
3685 return FT_Err_Invalid_Driver_Handle
;
3689 /*************************************************************************/
3690 /*************************************************************************/
3691 /*************************************************************************/
3694 /**** L I B R A R Y ****/
3697 /*************************************************************************/
3698 /*************************************************************************/
3699 /*************************************************************************/
3702 /* documentation is in ftmodapi.h */
3704 FT_EXPORT_DEF( FT_Error
)
3705 FT_New_Library( FT_Memory memory
,
3706 FT_Library
*alibrary
)
3708 FT_Library library
= 0;
3713 return FT_Err_Invalid_Argument
;
3715 #ifdef FT_DEBUG_LEVEL_ERROR
3716 /* init debugging support */
3720 /* first of all, allocate the library object */
3721 if ( FT_NEW( library
) )
3724 library
->memory
= memory
;
3726 /* allocate the render pool */
3727 library
->raster_pool_size
= FT_RENDER_POOL_SIZE
;
3728 if ( FT_RENDER_POOL_SIZE
> 0 )
3729 if ( FT_ALLOC( library
->raster_pool
, FT_RENDER_POOL_SIZE
) )
3733 *alibrary
= library
;
3743 /* documentation is in freetype.h */
3745 FT_EXPORT_DEF( void )
3746 FT_Library_Version( FT_Library library
,
3758 major
= library
->version_major
;
3759 minor
= library
->version_minor
;
3760 patch
= library
->version_patch
;
3774 /* documentation is in ftmodapi.h */
3776 FT_EXPORT_DEF( FT_Error
)
3777 FT_Done_Library( FT_Library library
)
3783 return FT_Err_Invalid_Library_Handle
;
3785 memory
= library
->memory
;
3787 /* Discard client-data */
3788 if ( library
->generic
.finalizer
)
3789 library
->generic
.finalizer( library
);
3791 /* Close all faces in the library. If we don't do
3792 * this, we can have some subtle memory leaks.
3795 * - the cff font driver uses the pshinter module in cff_size_done
3796 * - if the pshinter module is destroyed before the cff font driver,
3797 * opened FT_Face objects managed by the driver are not properly
3798 * destroyed, resulting in a memory leak
3804 for ( n
= 0; n
< library
->num_modules
; n
++ )
3806 FT_Module module
= library
->modules
[n
];
3810 if ( ( module
->clazz
->module_flags
& FT_MODULE_FONT_DRIVER
) == 0 )
3813 faces
= &FT_DRIVER(module
)->faces_list
;
3814 while ( faces
->head
)
3815 FT_Done_Face( FT_FACE( faces
->head
->data
) );
3819 /* Close all other modules in the library */
3821 /* XXX Modules are removed in the reversed order so that */
3822 /* type42 module is removed before truetype module. This */
3823 /* avoids double free in some occasions. It is a hack. */
3824 while ( library
->num_modules
> 0 )
3825 FT_Remove_Module( library
,
3826 library
->modules
[library
->num_modules
- 1] );
3832 for ( n
= 0; n
< library
->num_modules
; n
++ )
3834 FT_Module module
= library
->modules
[n
];
3839 Destroy_Module( module
);
3840 library
->modules
[n
] = 0;
3846 /* Destroy raster objects */
3847 FT_FREE( library
->raster_pool
);
3848 library
->raster_pool_size
= 0;
3855 /* documentation is in ftmodapi.h */
3857 FT_EXPORT_DEF( void )
3858 FT_Set_Debug_Hook( FT_Library library
,
3860 FT_DebugHook_Func debug_hook
)
3862 if ( library
&& debug_hook
&&
3864 ( sizeof ( library
->debug_hooks
) / sizeof ( void* ) ) )
3865 library
->debug_hooks
[hook_index
] = debug_hook
;
3869 /* documentation is in ftmodapi.h */
3871 FT_EXPORT_DEF( FT_TrueTypeEngineType
)
3872 FT_Get_TrueType_Engine_Type( FT_Library library
)
3874 FT_TrueTypeEngineType result
= FT_TRUETYPE_ENGINE_TYPE_NONE
;
3879 FT_Module module
= FT_Get_Module( library
, "truetype" );
3884 FT_Service_TrueTypeEngine service
;
3887 service
= (FT_Service_TrueTypeEngine
)
3888 ft_module_get_service( module
,
3889 FT_SERVICE_ID_TRUETYPE_ENGINE
);
3891 result
= service
->engine_type
;
3899 #ifdef FT_CONFIG_OPTION_OLD_INTERNALS
3901 FT_BASE_DEF( FT_Error
)
3902 ft_stub_set_char_sizes( FT_Size size
,
3908 FT_Size_RequestRec req
;
3909 FT_Driver driver
= size
->face
->driver
;
3912 if ( driver
->clazz
->request_size
)
3914 req
.type
= FT_SIZE_REQUEST_TYPE_NOMINAL
;
3916 req
.height
= height
;
3918 if ( horz_res
== 0 )
3919 horz_res
= vert_res
;
3921 if ( vert_res
== 0 )
3922 vert_res
= horz_res
;
3924 if ( horz_res
== 0 )
3925 horz_res
= vert_res
= 72;
3927 req
.horiResolution
= horz_res
;
3928 req
.vertResolution
= vert_res
;
3930 return driver
->clazz
->request_size( size
, &req
);
3937 FT_BASE_DEF( FT_Error
)
3938 ft_stub_set_pixel_sizes( FT_Size size
,
3942 FT_Size_RequestRec req
;
3943 FT_Driver driver
= size
->face
->driver
;
3946 if ( driver
->clazz
->request_size
)
3948 req
.type
= FT_SIZE_REQUEST_TYPE_NOMINAL
;
3949 req
.width
= width
<< 6;
3950 req
.height
= height
<< 6;
3951 req
.horiResolution
= 0;
3952 req
.vertResolution
= 0;
3954 return driver
->clazz
->request_size( size
, &req
);
3960 #endif /* FT_CONFIG_OPTION_OLD_INTERNALS */
3963 FT_EXPORT_DEF( FT_Error
)
3964 FT_Get_SubGlyph_Info( FT_GlyphSlot glyph
,
3970 FT_Matrix
*p_transform
)
3972 FT_Error error
= FT_Err_Invalid_Argument
;
3975 if ( glyph
!= NULL
&&
3976 glyph
->format
== FT_GLYPH_FORMAT_COMPOSITE
&&
3977 sub_index
< glyph
->num_subglyphs
)
3979 FT_SubGlyph subg
= glyph
->subglyphs
+ sub_index
;
3982 *p_index
= subg
->index
;
3983 *p_flags
= subg
->flags
;
3984 *p_arg1
= subg
->arg1
;
3985 *p_arg2
= subg
->arg2
;
3986 *p_transform
= subg
->transform
;