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 */
61 #if defined( _MSC_VER )
62 #pragma warning( pop )
65 #endif /* FT_DEBUG_LEVEL_TRACE */
68 #define GRID_FIT_METRICS
71 FT_BASE_DEF( FT_Pointer
)
72 ft_service_list_lookup( FT_ServiceDesc service_descriptors
,
73 const char* service_id
)
75 FT_Pointer result
= NULL
;
76 FT_ServiceDesc desc
= service_descriptors
;
79 if ( desc
&& service_id
)
81 for ( ; desc
->serv_id
!= NULL
; desc
++ )
83 if ( ft_strcmp( desc
->serv_id
, service_id
) == 0 )
85 result
= (FT_Pointer
)desc
->serv_data
;
96 ft_validator_init( FT_Validator valid
,
99 FT_ValidationLevel level
)
102 valid
->limit
= limit
;
103 valid
->level
= level
;
104 valid
->error
= FT_Err_Ok
;
108 FT_BASE_DEF( FT_Int
)
109 ft_validator_run( FT_Validator valid
)
111 /* This function doesn't work! None should call it. */
119 ft_validator_error( FT_Validator valid
,
122 /* since the cast below also disables the compiler's */
123 /* type check, we introduce a dummy variable, which */
124 /* will be optimized away */
125 volatile ft_jmp_buf
* jump_buffer
= &valid
->jump_buffer
;
128 valid
->error
= error
;
130 /* throw away volatileness; use `jump_buffer' or the */
131 /* compiler may warn about an unused local variable */
132 ft_longjmp( *(ft_jmp_buf
*) jump_buffer
, 1 );
136 /*************************************************************************/
137 /*************************************************************************/
138 /*************************************************************************/
141 /**** S T R E A M ****/
144 /*************************************************************************/
145 /*************************************************************************/
146 /*************************************************************************/
149 /* create a new input stream from an FT_Open_Args structure */
151 FT_BASE_DEF( FT_Error
)
152 FT_Stream_New( FT_Library library
,
153 const FT_Open_Args
* args
,
158 FT_Stream stream
= NULL
;
164 return FT_THROW( Invalid_Library_Handle
);
167 return FT_THROW( Invalid_Argument
);
169 memory
= library
->memory
;
171 if ( FT_NEW( stream
) )
174 stream
->memory
= memory
;
176 if ( args
->flags
& FT_OPEN_MEMORY
)
178 /* create a memory-based stream */
179 FT_Stream_OpenMemory( stream
,
180 (const FT_Byte
*)args
->memory_base
,
184 #ifndef FT_CONFIG_OPTION_DISABLE_STREAM_SUPPORT
186 else if ( args
->flags
& FT_OPEN_PATHNAME
)
188 /* create a normal system stream */
189 error
= FT_Stream_Open( stream
, args
->pathname
);
190 stream
->pathname
.pointer
= args
->pathname
;
192 else if ( ( args
->flags
& FT_OPEN_STREAM
) && args
->stream
)
194 /* use an existing, user-provided stream */
196 /* in this case, we do not need to allocate a new stream object */
197 /* since the caller is responsible for closing it himself */
199 stream
= args
->stream
;
205 error
= FT_THROW( Invalid_Argument
);
210 stream
->memory
= memory
; /* just to be certain */
220 FT_Stream_Free( FT_Stream stream
,
225 FT_Memory memory
= stream
->memory
;
228 FT_Stream_Close( stream
);
236 /*************************************************************************/
238 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
239 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
240 /* messages during execution. */
243 #define FT_COMPONENT trace_objs
246 /*************************************************************************/
247 /*************************************************************************/
248 /*************************************************************************/
251 /**** FACE, SIZE & GLYPH SLOT OBJECTS ****/
254 /*************************************************************************/
255 /*************************************************************************/
256 /*************************************************************************/
260 ft_glyphslot_init( FT_GlyphSlot slot
)
262 FT_Driver driver
= slot
->face
->driver
;
263 FT_Driver_Class clazz
= driver
->clazz
;
264 FT_Memory memory
= driver
->root
.memory
;
265 FT_Error error
= FT_Err_Ok
;
266 FT_Slot_Internal internal
= NULL
;
269 slot
->library
= driver
->root
.library
;
271 if ( FT_NEW( internal
) )
274 slot
->internal
= internal
;
276 if ( FT_DRIVER_USES_OUTLINES( driver
) )
277 error
= FT_GlyphLoader_New( memory
, &internal
->loader
);
279 if ( !error
&& clazz
->init_slot
)
280 error
= clazz
->init_slot( slot
);
288 ft_glyphslot_free_bitmap( FT_GlyphSlot slot
)
290 if ( slot
->internal
&& ( slot
->internal
->flags
& FT_GLYPH_OWN_BITMAP
) )
292 FT_Memory memory
= FT_FACE_MEMORY( slot
->face
);
295 FT_FREE( slot
->bitmap
.buffer
);
296 slot
->internal
->flags
&= ~FT_GLYPH_OWN_BITMAP
;
300 /* assume that the bitmap buffer was stolen or not */
301 /* allocated from the heap */
302 slot
->bitmap
.buffer
= NULL
;
308 ft_glyphslot_set_bitmap( FT_GlyphSlot slot
,
311 ft_glyphslot_free_bitmap( slot
);
313 slot
->bitmap
.buffer
= buffer
;
315 FT_ASSERT( (slot
->internal
->flags
& FT_GLYPH_OWN_BITMAP
) == 0 );
319 FT_BASE_DEF( FT_Error
)
320 ft_glyphslot_alloc_bitmap( FT_GlyphSlot slot
,
323 FT_Memory memory
= FT_FACE_MEMORY( slot
->face
);
327 if ( slot
->internal
->flags
& FT_GLYPH_OWN_BITMAP
)
328 FT_FREE( slot
->bitmap
.buffer
);
330 slot
->internal
->flags
|= FT_GLYPH_OWN_BITMAP
;
332 (void)FT_ALLOC( slot
->bitmap
.buffer
, size
);
338 ft_glyphslot_clear( FT_GlyphSlot slot
)
340 /* free bitmap if needed */
341 ft_glyphslot_free_bitmap( slot
);
343 /* clear all public fields in the glyph slot */
344 FT_ZERO( &slot
->metrics
);
345 FT_ZERO( &slot
->outline
);
347 slot
->bitmap
.width
= 0;
348 slot
->bitmap
.rows
= 0;
349 slot
->bitmap
.pitch
= 0;
350 slot
->bitmap
.pixel_mode
= 0;
351 /* `slot->bitmap.buffer' has been handled by ft_glyphslot_free_bitmap */
353 slot
->bitmap_left
= 0;
354 slot
->bitmap_top
= 0;
355 slot
->num_subglyphs
= 0;
357 slot
->control_data
= 0;
358 slot
->control_len
= 0;
360 slot
->format
= FT_GLYPH_FORMAT_NONE
;
362 slot
->linearHoriAdvance
= 0;
363 slot
->linearVertAdvance
= 0;
370 ft_glyphslot_done( FT_GlyphSlot slot
)
372 FT_Driver driver
= slot
->face
->driver
;
373 FT_Driver_Class clazz
= driver
->clazz
;
374 FT_Memory memory
= driver
->root
.memory
;
377 if ( clazz
->done_slot
)
378 clazz
->done_slot( slot
);
380 /* free bitmap buffer if needed */
381 ft_glyphslot_free_bitmap( slot
);
383 /* slot->internal might be NULL in out-of-memory situations */
384 if ( slot
->internal
)
386 /* free glyph loader */
387 if ( FT_DRIVER_USES_OUTLINES( driver
) )
389 FT_GlyphLoader_Done( slot
->internal
->loader
);
390 slot
->internal
->loader
= 0;
393 FT_FREE( slot
->internal
);
398 /* documentation is in ftobjs.h */
400 FT_BASE_DEF( FT_Error
)
401 FT_New_GlyphSlot( FT_Face face
,
402 FT_GlyphSlot
*aslot
)
406 FT_Driver_Class clazz
;
408 FT_GlyphSlot slot
= NULL
;
411 if ( !face
|| !face
->driver
)
412 return FT_THROW( Invalid_Argument
);
414 driver
= face
->driver
;
415 clazz
= driver
->clazz
;
416 memory
= driver
->root
.memory
;
418 FT_TRACE4(( "FT_New_GlyphSlot: Creating new slot object\n" ));
419 if ( !FT_ALLOC( slot
, clazz
->slot_object_size
) )
423 error
= ft_glyphslot_init( slot
);
426 ft_glyphslot_done( slot
);
431 slot
->next
= face
->glyph
;
442 FT_TRACE4(( "FT_New_GlyphSlot: Return %d\n", error
));
447 /* documentation is in ftobjs.h */
450 FT_Done_GlyphSlot( FT_GlyphSlot slot
)
454 FT_Driver driver
= slot
->face
->driver
;
455 FT_Memory memory
= driver
->root
.memory
;
460 /* Remove slot from its parent face's list */
462 cur
= slot
->face
->glyph
;
469 slot
->face
->glyph
= cur
->next
;
471 prev
->next
= cur
->next
;
473 /* finalize client-specific data */
474 if ( slot
->generic
.finalizer
)
475 slot
->generic
.finalizer( slot
);
477 ft_glyphslot_done( slot
);
488 /* documentation is in freetype.h */
490 FT_EXPORT_DEF( void )
491 FT_Set_Transform( FT_Face face
,
495 FT_Face_Internal internal
;
501 internal
= face
->internal
;
503 internal
->transform_flags
= 0;
507 internal
->transform_matrix
.xx
= 0x10000L
;
508 internal
->transform_matrix
.xy
= 0;
509 internal
->transform_matrix
.yx
= 0;
510 internal
->transform_matrix
.yy
= 0x10000L
;
511 matrix
= &internal
->transform_matrix
;
514 internal
->transform_matrix
= *matrix
;
516 /* set transform_flags bit flag 0 if `matrix' isn't the identity */
517 if ( ( matrix
->xy
| matrix
->yx
) ||
518 matrix
->xx
!= 0x10000L
||
519 matrix
->yy
!= 0x10000L
)
520 internal
->transform_flags
|= 1;
524 internal
->transform_delta
.x
= 0;
525 internal
->transform_delta
.y
= 0;
526 delta
= &internal
->transform_delta
;
529 internal
->transform_delta
= *delta
;
531 /* set transform_flags bit flag 1 if `delta' isn't the null vector */
532 if ( delta
->x
| delta
->y
)
533 internal
->transform_flags
|= 2;
538 ft_lookup_glyph_renderer( FT_GlyphSlot slot
);
541 #ifdef GRID_FIT_METRICS
543 ft_glyphslot_grid_fit_metrics( FT_GlyphSlot slot
,
546 FT_Glyph_Metrics
* metrics
= &slot
->metrics
;
547 FT_Pos right
, bottom
;
552 metrics
->horiBearingX
= FT_PIX_FLOOR( metrics
->horiBearingX
);
553 metrics
->horiBearingY
= FT_PIX_CEIL ( metrics
->horiBearingY
);
555 right
= FT_PIX_CEIL( metrics
->vertBearingX
+ metrics
->width
);
556 bottom
= FT_PIX_CEIL( metrics
->vertBearingY
+ metrics
->height
);
558 metrics
->vertBearingX
= FT_PIX_FLOOR( metrics
->vertBearingX
);
559 metrics
->vertBearingY
= FT_PIX_FLOOR( metrics
->vertBearingY
);
561 metrics
->width
= right
- metrics
->vertBearingX
;
562 metrics
->height
= bottom
- metrics
->vertBearingY
;
566 metrics
->vertBearingX
= FT_PIX_FLOOR( metrics
->vertBearingX
);
567 metrics
->vertBearingY
= FT_PIX_FLOOR( metrics
->vertBearingY
);
569 right
= FT_PIX_CEIL ( metrics
->horiBearingX
+ metrics
->width
);
570 bottom
= FT_PIX_FLOOR( metrics
->horiBearingY
- metrics
->height
);
572 metrics
->horiBearingX
= FT_PIX_FLOOR( metrics
->horiBearingX
);
573 metrics
->horiBearingY
= FT_PIX_CEIL ( metrics
->horiBearingY
);
575 metrics
->width
= right
- metrics
->horiBearingX
;
576 metrics
->height
= metrics
->horiBearingY
- bottom
;
579 metrics
->horiAdvance
= FT_PIX_ROUND( metrics
->horiAdvance
);
580 metrics
->vertAdvance
= FT_PIX_ROUND( metrics
->vertAdvance
);
582 #endif /* GRID_FIT_METRICS */
585 /* documentation is in freetype.h */
587 FT_EXPORT_DEF( FT_Error
)
588 FT_Load_Glyph( FT_Face face
,
590 FT_Int32 load_flags
)
596 FT_Bool autohint
= FALSE
;
598 TT_Face ttface
= (TT_Face
)face
;
601 if ( !face
|| !face
->size
|| !face
->glyph
)
602 return FT_THROW( Invalid_Face_Handle
);
604 /* The validity test for `glyph_index' is performed by the */
608 ft_glyphslot_clear( slot
);
610 driver
= face
->driver
;
611 library
= driver
->root
.library
;
612 hinter
= library
->auto_hinter
;
614 /* resolve load flags dependencies */
616 if ( load_flags
& FT_LOAD_NO_RECURSE
)
617 load_flags
|= FT_LOAD_NO_SCALE
|
618 FT_LOAD_IGNORE_TRANSFORM
;
620 if ( load_flags
& FT_LOAD_NO_SCALE
)
622 load_flags
|= FT_LOAD_NO_HINTING
|
625 load_flags
&= ~FT_LOAD_RENDER
;
629 * Determine whether we need to auto-hint or not.
630 * The general rules are:
632 * - Do only auto-hinting if we have a hinter module, a scalable font
633 * format dealing with outlines, and no transforms except simple
634 * slants and/or rotations by integer multiples of 90 degrees.
636 * - Then, auto-hint if FT_LOAD_FORCE_AUTOHINT is set or if we don't
637 * have a native font hinter.
639 * - Otherwise, auto-hint for LIGHT hinting mode or if there isn't
640 * any hinting bytecode in the TrueType/OpenType font.
642 * - Exception: The font is `tricky' and requires the native hinter to
647 !( load_flags
& FT_LOAD_NO_HINTING
) &&
648 !( load_flags
& FT_LOAD_NO_AUTOHINT
) &&
649 FT_DRIVER_IS_SCALABLE( driver
) &&
650 FT_DRIVER_USES_OUTLINES( driver
) &&
651 !FT_IS_TRICKY( face
) &&
652 ( ( load_flags
& FT_LOAD_IGNORE_TRANSFORM
) ||
653 ( face
->internal
->transform_matrix
.yx
== 0 &&
654 face
->internal
->transform_matrix
.xx
!= 0 ) ||
655 ( face
->internal
->transform_matrix
.xx
== 0 &&
656 face
->internal
->transform_matrix
.yx
!= 0 ) ) )
658 if ( ( load_flags
& FT_LOAD_FORCE_AUTOHINT
) ||
659 !FT_DRIVER_HAS_HINTER( driver
) )
663 FT_Render_Mode mode
= FT_LOAD_TARGET_MODE( load_flags
);
666 /* the check for `num_locations' assures that we actually */
667 /* test for instructions in a TTF and not in a CFF-based OTF */
669 /* since `maxSizeOfInstructions' might be unreliable, we */
670 /* check the size of the `fpgm' and `prep' tables, too -- */
671 /* the assumption is that there don't exist real TTFs where */
672 /* both `fpgm' and `prep' tables are missing */
673 if ( mode
== FT_RENDER_MODE_LIGHT
||
674 face
->internal
->ignore_unpatented_hinter
||
675 ( FT_IS_SFNT( face
) &&
676 ttface
->num_locations
&&
677 ttface
->max_profile
.maxSizeOfInstructions
== 0 &&
678 ttface
->font_program_size
== 0 &&
679 ttface
->cvt_program_size
== 0 ) )
686 FT_AutoHinter_Interface hinting
;
689 /* try to load embedded bitmaps first if available */
691 /* XXX: This is really a temporary hack that should disappear */
692 /* promptly with FreeType 2.1! */
694 if ( FT_HAS_FIXED_SIZES( face
) &&
695 ( load_flags
& FT_LOAD_NO_BITMAP
) == 0 )
697 error
= driver
->clazz
->load_glyph( slot
, face
->size
,
699 load_flags
| FT_LOAD_SBITS_ONLY
);
701 if ( !error
&& slot
->format
== FT_GLYPH_FORMAT_BITMAP
)
706 FT_Face_Internal internal
= face
->internal
;
707 FT_Int transform_flags
= internal
->transform_flags
;
710 /* since the auto-hinter calls FT_Load_Glyph by itself, */
711 /* make sure that glyphs aren't transformed */
712 internal
->transform_flags
= 0;
714 /* load auto-hinted outline */
715 hinting
= (FT_AutoHinter_Interface
)hinter
->clazz
->module_interface
;
717 error
= hinting
->load_glyph( (FT_AutoHinter
)hinter
,
719 glyph_index
, load_flags
);
721 internal
->transform_flags
= transform_flags
;
726 error
= driver
->clazz
->load_glyph( slot
,
733 if ( slot
->format
== FT_GLYPH_FORMAT_OUTLINE
)
735 /* check that the loaded outline is correct */
736 error
= FT_Outline_Check( &slot
->outline
);
740 #ifdef GRID_FIT_METRICS
741 if ( !( load_flags
& FT_LOAD_NO_HINTING
) )
742 ft_glyphslot_grid_fit_metrics( slot
,
743 FT_BOOL( load_flags
& FT_LOAD_VERTICAL_LAYOUT
) );
749 /* compute the advance */
750 if ( load_flags
& FT_LOAD_VERTICAL_LAYOUT
)
753 slot
->advance
.y
= slot
->metrics
.vertAdvance
;
757 slot
->advance
.x
= slot
->metrics
.horiAdvance
;
761 /* compute the linear advance in 16.16 pixels */
762 if ( ( load_flags
& FT_LOAD_LINEAR_DESIGN
) == 0 &&
763 ( FT_IS_SCALABLE( face
) ) )
765 FT_Size_Metrics
* metrics
= &face
->size
->metrics
;
769 slot
->linearHoriAdvance
= FT_MulDiv( slot
->linearHoriAdvance
,
770 metrics
->x_scale
, 64 );
772 slot
->linearVertAdvance
= FT_MulDiv( slot
->linearVertAdvance
,
773 metrics
->y_scale
, 64 );
776 if ( ( load_flags
& FT_LOAD_IGNORE_TRANSFORM
) == 0 )
778 FT_Face_Internal internal
= face
->internal
;
781 /* now, transform the glyph image if needed */
782 if ( internal
->transform_flags
)
785 FT_Renderer renderer
= ft_lookup_glyph_renderer( slot
);
789 error
= renderer
->clazz
->transform_glyph(
791 &internal
->transform_matrix
,
792 &internal
->transform_delta
);
793 else if ( slot
->format
== FT_GLYPH_FORMAT_OUTLINE
)
795 /* apply `standard' transformation if no renderer is available */
796 if ( internal
->transform_flags
& 1 )
797 FT_Outline_Transform( &slot
->outline
,
798 &internal
->transform_matrix
);
800 if ( internal
->transform_flags
& 2 )
801 FT_Outline_Translate( &slot
->outline
,
802 internal
->transform_delta
.x
,
803 internal
->transform_delta
.y
);
806 /* transform advance */
807 FT_Vector_Transform( &slot
->advance
, &internal
->transform_matrix
);
811 FT_TRACE5(( " x advance: %d\n" , slot
->advance
.x
));
812 FT_TRACE5(( " y advance: %d\n" , slot
->advance
.y
));
814 FT_TRACE5(( " linear x advance: %d\n" , slot
->linearHoriAdvance
));
815 FT_TRACE5(( " linear y advance: %d\n" , slot
->linearVertAdvance
));
817 /* do we need to render the image now? */
819 slot
->format
!= FT_GLYPH_FORMAT_BITMAP
&&
820 slot
->format
!= FT_GLYPH_FORMAT_COMPOSITE
&&
821 load_flags
& FT_LOAD_RENDER
)
823 FT_Render_Mode mode
= FT_LOAD_TARGET_MODE( load_flags
);
826 if ( mode
== FT_RENDER_MODE_NORMAL
&&
827 (load_flags
& FT_LOAD_MONOCHROME
) )
828 mode
= FT_RENDER_MODE_MONO
;
830 error
= FT_Render_Glyph( slot
, mode
);
838 /* documentation is in freetype.h */
840 FT_EXPORT_DEF( FT_Error
)
841 FT_Load_Char( FT_Face face
,
843 FT_Int32 load_flags
)
849 return FT_THROW( Invalid_Face_Handle
);
851 glyph_index
= (FT_UInt
)char_code
;
853 glyph_index
= FT_Get_Char_Index( face
, char_code
);
855 return FT_Load_Glyph( face
, glyph_index
, load_flags
);
859 /* destructor for sizes list */
861 destroy_size( FT_Memory memory
,
865 /* finalize client-specific data */
866 if ( size
->generic
.finalizer
)
867 size
->generic
.finalizer( size
);
869 /* finalize format-specific stuff */
870 if ( driver
->clazz
->done_size
)
871 driver
->clazz
->done_size( size
);
873 FT_FREE( size
->internal
);
879 ft_cmap_done_internal( FT_CMap cmap
);
883 destroy_charmaps( FT_Face face
,
892 for ( n
= 0; n
< face
->num_charmaps
; n
++ )
894 FT_CMap cmap
= FT_CMAP( face
->charmaps
[n
] );
897 ft_cmap_done_internal( cmap
);
899 face
->charmaps
[n
] = NULL
;
902 FT_FREE( face
->charmaps
);
903 face
->num_charmaps
= 0;
907 /* destructor for faces list */
909 destroy_face( FT_Memory memory
,
913 FT_Driver_Class clazz
= driver
->clazz
;
916 /* discard auto-hinting data */
917 if ( face
->autohint
.finalizer
)
918 face
->autohint
.finalizer( face
->autohint
.data
);
920 /* Discard glyph slots for this face. */
921 /* Beware! FT_Done_GlyphSlot() changes the field `face->glyph' */
922 while ( face
->glyph
)
923 FT_Done_GlyphSlot( face
->glyph
);
925 /* discard all sizes for this face */
926 FT_List_Finalize( &face
->sizes_list
,
927 (FT_List_Destructor
)destroy_size
,
932 /* now discard client data */
933 if ( face
->generic
.finalizer
)
934 face
->generic
.finalizer( face
);
936 /* discard charmaps */
937 destroy_charmaps( face
, memory
);
939 /* finalize format-specific stuff */
940 if ( clazz
->done_face
)
941 clazz
->done_face( face
);
943 /* close the stream for this face if needed */
946 ( face
->face_flags
& FT_FACE_FLAG_EXTERNAL_STREAM
) != 0 );
951 if ( face
->internal
)
953 FT_FREE( face
->internal
);
960 Destroy_Driver( FT_Driver driver
)
962 FT_List_Finalize( &driver
->faces_list
,
963 (FT_List_Destructor
)destroy_face
,
967 /* check whether we need to drop the driver's glyph loader */
968 if ( FT_DRIVER_USES_OUTLINES( driver
) )
969 FT_GlyphLoader_Done( driver
->glyph_loader
);
973 /*************************************************************************/
976 /* find_unicode_charmap */
979 /* This function finds a Unicode charmap, if there is one. */
980 /* And if there is more than one, it tries to favour the more */
981 /* extensive one, i.e., one that supports UCS-4 against those which */
982 /* are limited to the BMP (said UCS-2 encoding.) */
984 /* This function is called from open_face() (just below), and also */
985 /* from FT_Select_Charmap( ..., FT_ENCODING_UNICODE ). */
988 find_unicode_charmap( FT_Face face
)
994 /* caller should have already checked that `face' is valid */
997 first
= face
->charmaps
;
1000 return FT_THROW( Invalid_CharMap_Handle
);
1003 * The original TrueType specification(s) only specified charmap
1004 * formats that are capable of mapping 8 or 16 bit character codes to
1007 * However, recent updates to the Apple and OpenType specifications
1008 * introduced new formats that are capable of mapping 32-bit character
1009 * codes as well. And these are already used on some fonts, mainly to
1010 * map non-BMP Asian ideographs as defined in Unicode.
1012 * For compatibility purposes, these fonts generally come with
1013 * *several* Unicode charmaps:
1015 * - One of them in the "old" 16-bit format, that cannot access
1016 * all glyphs in the font.
1018 * - Another one in the "new" 32-bit format, that can access all
1021 * This function has been written to always favor a 32-bit charmap
1022 * when found. Otherwise, a 16-bit one is returned when found.
1025 /* Since the `interesting' table, with IDs (3,10), is normally the */
1026 /* last one, we loop backwards. This loses with type1 fonts with */
1027 /* non-BMP characters (<.0001%), this wins with .ttf with non-BMP */
1028 /* chars (.01% ?), and this is the same about 99.99% of the time! */
1030 cur
= first
+ face
->num_charmaps
; /* points after the last one */
1032 for ( ; --cur
>= first
; )
1034 if ( cur
[0]->encoding
== FT_ENCODING_UNICODE
)
1036 /* XXX If some new encodings to represent UCS-4 are added, */
1037 /* they should be added here. */
1038 if ( ( cur
[0]->platform_id
== TT_PLATFORM_MICROSOFT
&&
1039 cur
[0]->encoding_id
== TT_MS_ID_UCS_4
) ||
1040 ( cur
[0]->platform_id
== TT_PLATFORM_APPLE_UNICODE
&&
1041 cur
[0]->encoding_id
== TT_APPLE_ID_UNICODE_32
) )
1043 #ifdef FT_MAX_CHARMAP_CACHEABLE
1044 if ( cur
- first
> FT_MAX_CHARMAP_CACHEABLE
)
1046 FT_ERROR(( "find_unicode_charmap: UCS-4 cmap is found "
1047 "at too late position (%d)\n", cur
- first
));
1051 face
->charmap
= cur
[0];
1057 /* We do not have any UCS-4 charmap. */
1058 /* Do the loop again and search for UCS-2 charmaps. */
1059 cur
= first
+ face
->num_charmaps
;
1061 for ( ; --cur
>= first
; )
1063 if ( cur
[0]->encoding
== FT_ENCODING_UNICODE
)
1065 #ifdef FT_MAX_CHARMAP_CACHEABLE
1066 if ( cur
- first
> FT_MAX_CHARMAP_CACHEABLE
)
1068 FT_ERROR(( "find_unicode_charmap: UCS-2 cmap is found "
1069 "at too late position (%d)\n", cur
- first
));
1073 face
->charmap
= cur
[0];
1078 return FT_THROW( Invalid_CharMap_Handle
);
1082 /*************************************************************************/
1085 /* find_variant_selector_charmap */
1088 /* This function finds the variant selector charmap, if there is one. */
1089 /* There can only be one (platform=0, specific=5, format=14). */
1092 find_variant_selector_charmap( FT_Face face
)
1099 /* caller should have already checked that `face' is valid */
1102 first
= face
->charmaps
;
1107 end
= first
+ face
->num_charmaps
; /* points after the last one */
1109 for ( cur
= first
; cur
< end
; ++cur
)
1111 if ( cur
[0]->platform_id
== TT_PLATFORM_APPLE_UNICODE
&&
1112 cur
[0]->encoding_id
== TT_APPLE_ID_VARIANT_SELECTOR
&&
1113 FT_Get_CMap_Format( cur
[0] ) == 14 )
1115 #ifdef FT_MAX_CHARMAP_CACHEABLE
1116 if ( cur
- first
> FT_MAX_CHARMAP_CACHEABLE
)
1118 FT_ERROR(( "find_unicode_charmap: UVS cmap is found "
1119 "at too late position (%d)\n", cur
- first
));
1131 /*************************************************************************/
1137 /* This function does some work for FT_Open_Face(). */
1140 open_face( FT_Driver driver
,
1142 FT_Bool external_stream
,
1145 FT_Parameter
* params
,
1149 FT_Driver_Class clazz
;
1150 FT_Face face
= NULL
;
1151 FT_Face_Internal internal
= NULL
;
1153 FT_Error error
, error2
;
1156 clazz
= driver
->clazz
;
1157 memory
= driver
->root
.memory
;
1159 /* allocate the face object and perform basic initialization */
1160 if ( FT_ALLOC( face
, clazz
->face_object_size
) )
1163 face
->driver
= driver
;
1164 face
->memory
= memory
;
1165 face
->stream
= *astream
;
1167 /* set the FT_FACE_FLAG_EXTERNAL_STREAM bit for FT_Done_Face */
1168 if ( external_stream
)
1169 face
->face_flags
|= FT_FACE_FLAG_EXTERNAL_STREAM
;
1171 if ( FT_NEW( internal
) )
1174 face
->internal
= internal
;
1176 #ifdef FT_CONFIG_OPTION_INCREMENTAL
1181 face
->internal
->incremental_interface
= 0;
1182 for ( i
= 0; i
< num_params
&& !face
->internal
->incremental_interface
;
1184 if ( params
[i
].tag
== FT_PARAM_TAG_INCREMENTAL
)
1185 face
->internal
->incremental_interface
=
1186 (FT_Incremental_Interface
)params
[i
].data
;
1190 if ( clazz
->init_face
)
1191 error
= clazz
->init_face( *astream
,
1196 *astream
= face
->stream
; /* Stream may have been changed. */
1200 /* select Unicode charmap by default */
1201 error2
= find_unicode_charmap( face
);
1203 /* if no Unicode charmap can be found, FT_Err_Invalid_CharMap_Handle */
1206 /* no error should happen, but we want to play safe */
1207 if ( error2
&& FT_ERR_NEQ( error2
, Invalid_CharMap_Handle
) )
1218 destroy_charmaps( face
, memory
);
1219 if ( clazz
->done_face
)
1220 clazz
->done_face( face
);
1221 FT_FREE( internal
);
1230 /* there's a Mac-specific extended implementation of FT_New_Face() */
1231 /* in src/base/ftmac.c */
1233 #ifndef FT_MACINTOSH
1235 /* documentation is in freetype.h */
1237 FT_EXPORT_DEF( FT_Error
)
1238 FT_New_Face( FT_Library library
,
1239 const char* pathname
,
1246 /* test for valid `library' and `aface' delayed to FT_Open_Face() */
1248 return FT_THROW( Invalid_Argument
);
1250 args
.flags
= FT_OPEN_PATHNAME
;
1251 args
.pathname
= (char*)pathname
;
1254 return FT_Open_Face( library
, &args
, face_index
, aface
);
1260 /* documentation is in freetype.h */
1262 FT_EXPORT_DEF( FT_Error
)
1263 FT_New_Memory_Face( FT_Library library
,
1264 const FT_Byte
* file_base
,
1272 /* test for valid `library' and `face' delayed to FT_Open_Face() */
1274 return FT_THROW( Invalid_Argument
);
1276 args
.flags
= FT_OPEN_MEMORY
;
1277 args
.memory_base
= file_base
;
1278 args
.memory_size
= file_size
;
1281 return FT_Open_Face( library
, &args
, face_index
, aface
);
1285 #ifdef FT_CONFIG_OPTION_MAC_FONTS
1287 /* The behavior here is very similar to that in base/ftmac.c, but it */
1288 /* is designed to work on non-mac systems, so no mac specific calls. */
1290 /* We look at the file and determine if it is a mac dfont file or a mac */
1291 /* resource file, or a macbinary file containing a mac resource file. */
1293 /* Unlike ftmac I'm not going to look at a `FOND'. I don't really see */
1294 /* the point, especially since there may be multiple `FOND' resources. */
1295 /* Instead I'll just look for `sfnt' and `POST' resources, ordered as */
1296 /* they occur in the file. */
1298 /* Note that multiple `POST' resources do not mean multiple postscript */
1299 /* fonts; they all get jammed together to make what is essentially a */
1302 /* We aren't interested in `NFNT' or `FONT' bitmap resources. */
1304 /* As soon as we get an `sfnt' load it into memory and pass it off to */
1307 /* If we have a (set of) `POST' resources, massage them into a (memory) */
1308 /* pfb file and pass that to FT_Open_Face. (As with ftmac.c I'm not */
1309 /* going to try to save the kerning info. After all that lives in the */
1310 /* `FOND' which isn't in the file containing the `POST' resources so */
1311 /* we don't really have access to it. */
1314 /* Finalizer for a memory stream; gets called by FT_Done_Face(). */
1315 /* It frees the memory it uses. */
1318 memory_stream_close( FT_Stream stream
)
1320 FT_Memory memory
= stream
->memory
;
1323 FT_FREE( stream
->base
);
1331 /* Create a new memory stream from a buffer and a size. */
1334 new_memory_stream( FT_Library library
,
1337 FT_Stream_CloseFunc close
,
1338 FT_Stream
*astream
)
1342 FT_Stream stream
= NULL
;
1346 return FT_THROW( Invalid_Library_Handle
);
1349 return FT_THROW( Invalid_Argument
);
1352 memory
= library
->memory
;
1353 if ( FT_NEW( stream
) )
1356 FT_Stream_OpenMemory( stream
, base
, size
);
1358 stream
->close
= close
;
1367 /* Create a new FT_Face given a buffer and a driver name. */
1369 FT_LOCAL_DEF( FT_Error
)
1370 open_face_from_buffer( FT_Library library
,
1374 const char* driver_name
,
1379 FT_Stream stream
= NULL
;
1380 FT_Memory memory
= library
->memory
;
1383 error
= new_memory_stream( library
,
1386 memory_stream_close
,
1394 args
.flags
= FT_OPEN_STREAM
;
1395 args
.stream
= stream
;
1398 args
.flags
= args
.flags
| FT_OPEN_DRIVER
;
1399 args
.driver
= FT_Get_Module( library
, driver_name
);
1403 /* At this point, face_index has served its purpose; */
1404 /* whoever calls this function has already used it to */
1405 /* locate the correct font data. We should not propagate */
1406 /* this index to FT_Open_Face() (unless it is negative). */
1408 if ( face_index
> 0 )
1412 error
= FT_Open_Face( library
, &args
, face_index
, aface
);
1414 if ( error
== FT_Err_Ok
)
1415 (*aface
)->face_flags
&= ~FT_FACE_FLAG_EXTERNAL_STREAM
;
1418 FT_Stream_Free( stream
, 0 );
1421 FT_Stream_Close( stream
);
1430 /* Look up `TYP1' or `CID ' table from sfnt table directory. */
1431 /* `offset' and `length' must exclude the binary header in tables. */
1433 /* Type 1 and CID-keyed font drivers should recognize sfnt-wrapped */
1434 /* format too. Here, since we can't expect that the TrueType font */
1435 /* driver is loaded unconditially, we must parse the font by */
1436 /* ourselves. We are only interested in the name of the table and */
1440 ft_lookup_PS_in_sfnt_stream( FT_Stream stream
,
1444 FT_Bool
* is_sfnt_cid
)
1447 FT_UShort numTables
;
1448 FT_Long pstable_index
;
1455 *is_sfnt_cid
= FALSE
;
1457 /* TODO: support for sfnt-wrapped PS/CID in TTC format */
1459 /* version check for 'typ1' (should be ignored?) */
1460 if ( FT_READ_ULONG( tag
) )
1462 if ( tag
!= TTAG_typ1
)
1463 return FT_THROW( Unknown_File_Format
);
1465 if ( FT_READ_USHORT( numTables
) )
1467 if ( FT_STREAM_SKIP( 2 * 3 ) ) /* skip binary search header */
1471 *is_sfnt_cid
= FALSE
;
1473 for ( i
= 0; i
< numTables
; i
++ )
1475 if ( FT_READ_ULONG( tag
) || FT_STREAM_SKIP( 4 ) ||
1476 FT_READ_ULONG( *offset
) || FT_READ_ULONG( *length
) )
1479 if ( tag
== TTAG_CID
)
1484 *is_sfnt_cid
= TRUE
;
1485 if ( face_index
< 0 )
1488 else if ( tag
== TTAG_TYP1
)
1493 *is_sfnt_cid
= FALSE
;
1494 if ( face_index
< 0 )
1497 if ( face_index
>= 0 && pstable_index
== face_index
)
1500 return FT_THROW( Table_Missing
);
1504 FT_LOCAL_DEF( FT_Error
)
1505 open_face_PS_from_sfnt_stream( FT_Library library
,
1509 FT_Parameter
*params
,
1513 FT_Memory memory
= library
->memory
;
1514 FT_ULong offset
, length
;
1516 FT_Bool is_sfnt_cid
;
1517 FT_Byte
* sfnt_ps
= NULL
;
1519 FT_UNUSED( num_params
);
1520 FT_UNUSED( params
);
1523 pos
= FT_Stream_Pos( stream
);
1525 error
= ft_lookup_PS_in_sfnt_stream( stream
,
1533 if ( FT_Stream_Seek( stream
, pos
+ offset
) )
1536 if ( FT_ALLOC( sfnt_ps
, (FT_Long
)length
) )
1539 error
= FT_Stream_Read( stream
, (FT_Byte
*)sfnt_ps
, length
);
1543 error
= open_face_from_buffer( library
,
1546 FT_MIN( face_index
, 0 ),
1547 is_sfnt_cid
? "cid" : "type1",
1554 if ( FT_ERR_EQ( error
, Unknown_File_Format
) )
1556 error1
= FT_Stream_Seek( stream
, pos
);
1566 #ifndef FT_MACINTOSH
1568 /* The resource header says we've got resource_cnt `POST' (type1) */
1569 /* resources in this file. They all need to be coalesced into */
1570 /* one lump which gets passed on to the type1 driver. */
1571 /* Here can be only one PostScript font in a file so face_index */
1572 /* must be 0 (or -1). */
1575 Mac_Read_POST_Resource( FT_Library library
,
1578 FT_Long resource_cnt
,
1582 FT_Error error
= FT_ERR( Cannot_Open_Resource
);
1583 FT_Memory memory
= library
->memory
;
1584 FT_Byte
* pfb_data
= NULL
;
1587 FT_Long pfb_len
, pfb_pos
, pfb_lenpos
;
1591 if ( face_index
== -1 )
1593 if ( face_index
!= 0 )
1596 /* Find the length of all the POST resources, concatenated. Assume */
1597 /* worst case (each resource in its own section). */
1599 for ( i
= 0; i
< resource_cnt
; ++i
)
1601 error
= FT_Stream_Seek( stream
, offsets
[i
] );
1604 if ( FT_READ_LONG( temp
) )
1606 pfb_len
+= temp
+ 6;
1609 if ( FT_ALLOC( pfb_data
, (FT_Long
)pfb_len
+ 2 ) )
1613 pfb_data
[1] = 1; /* Ascii section */
1614 pfb_data
[2] = 0; /* 4-byte length, fill in later */
1623 for ( i
= 0; i
< resource_cnt
; ++i
)
1625 error
= FT_Stream_Seek( stream
, offsets
[i
] );
1628 if ( FT_READ_LONG( rlen
) )
1630 if ( FT_READ_USHORT( flags
) )
1632 FT_TRACE3(( "POST fragment[%d]: offsets=0x%08x, rlen=0x%08x, flags=0x%04x\n",
1633 i
, offsets
[i
], rlen
, flags
));
1635 /* postpone the check of rlen longer than buffer until FT_Stream_Read() */
1636 if ( ( flags
>> 8 ) == 0 ) /* Comment, should not be loaded */
1639 /* the flags are part of the resource, so rlen >= 2. */
1640 /* but some fonts declare rlen = 0 for empty fragment */
1646 if ( ( flags
>> 8 ) == type
)
1650 if ( pfb_lenpos
+ 3 > pfb_len
+ 2 )
1652 pfb_data
[pfb_lenpos
] = (FT_Byte
)( len
);
1653 pfb_data
[pfb_lenpos
+ 1] = (FT_Byte
)( len
>> 8 );
1654 pfb_data
[pfb_lenpos
+ 2] = (FT_Byte
)( len
>> 16 );
1655 pfb_data
[pfb_lenpos
+ 3] = (FT_Byte
)( len
>> 24 );
1657 if ( ( flags
>> 8 ) == 5 ) /* End of font mark */
1660 if ( pfb_pos
+ 6 > pfb_len
+ 2 )
1662 pfb_data
[pfb_pos
++] = 0x80;
1667 pfb_data
[pfb_pos
++] = (FT_Byte
)type
;
1668 pfb_lenpos
= pfb_pos
;
1669 pfb_data
[pfb_pos
++] = 0; /* 4-byte length, fill in later */
1670 pfb_data
[pfb_pos
++] = 0;
1671 pfb_data
[pfb_pos
++] = 0;
1672 pfb_data
[pfb_pos
++] = 0;
1675 error
= FT_ERR( Cannot_Open_Resource
);
1676 if ( pfb_pos
> pfb_len
|| pfb_pos
+ rlen
> pfb_len
)
1679 error
= FT_Stream_Read( stream
, (FT_Byte
*)pfb_data
+ pfb_pos
, rlen
);
1685 if ( pfb_pos
+ 2 > pfb_len
+ 2 )
1687 pfb_data
[pfb_pos
++] = 0x80;
1688 pfb_data
[pfb_pos
++] = 3;
1690 if ( pfb_lenpos
+ 3 > pfb_len
+ 2 )
1692 pfb_data
[pfb_lenpos
] = (FT_Byte
)( len
);
1693 pfb_data
[pfb_lenpos
+ 1] = (FT_Byte
)( len
>> 8 );
1694 pfb_data
[pfb_lenpos
+ 2] = (FT_Byte
)( len
>> 16 );
1695 pfb_data
[pfb_lenpos
+ 3] = (FT_Byte
)( len
>> 24 );
1697 return open_face_from_buffer( library
,
1705 FT_FREE( pfb_data
);
1712 /* The resource header says we've got resource_cnt `sfnt' */
1713 /* (TrueType/OpenType) resources in this file. Look through */
1714 /* them for the one indicated by face_index, load it into mem, */
1715 /* pass it on the the truetype driver and return it. */
1718 Mac_Read_sfnt_Resource( FT_Library library
,
1721 FT_Long resource_cnt
,
1725 FT_Memory memory
= library
->memory
;
1726 FT_Byte
* sfnt_data
= NULL
;
1728 FT_Long flag_offset
;
1731 FT_Long face_index_in_resource
= 0;
1734 if ( face_index
== -1 )
1736 if ( face_index
>= resource_cnt
)
1737 return FT_THROW( Cannot_Open_Resource
);
1739 flag_offset
= offsets
[face_index
];
1740 error
= FT_Stream_Seek( stream
, flag_offset
);
1744 if ( FT_READ_LONG( rlen
) )
1747 return FT_THROW( Cannot_Open_Resource
);
1749 error
= open_face_PS_from_sfnt_stream( library
,
1757 /* rewind sfnt stream before open_face_PS_from_sfnt_stream() */
1758 if ( FT_Stream_Seek( stream
, flag_offset
+ 4 ) )
1761 if ( FT_ALLOC( sfnt_data
, (FT_Long
)rlen
) )
1763 error
= FT_Stream_Read( stream
, (FT_Byte
*)sfnt_data
, rlen
);
1767 is_cff
= rlen
> 4 && !ft_memcmp( sfnt_data
, "OTTO", 4 );
1768 error
= open_face_from_buffer( library
,
1771 face_index_in_resource
,
1772 is_cff
? "cff" : "truetype",
1780 /* Check for a valid resource fork header, or a valid dfont */
1781 /* header. In a resource fork the first 16 bytes are repeated */
1782 /* at the location specified by bytes 4-7. In a dfont bytes */
1783 /* 4-7 point to 16 bytes of zeroes instead. */
1786 IsMacResource( FT_Library library
,
1788 FT_Long resource_offset
,
1792 FT_Memory memory
= library
->memory
;
1794 FT_Long map_offset
, rdara_pos
;
1795 FT_Long
*data_offsets
;
1799 error
= FT_Raccess_Get_HeaderInfo( library
, stream
, resource_offset
,
1800 &map_offset
, &rdara_pos
);
1804 error
= FT_Raccess_Get_DataOffsets( library
, stream
,
1805 map_offset
, rdara_pos
,
1807 &data_offsets
, &count
);
1810 error
= Mac_Read_POST_Resource( library
, stream
, data_offsets
, count
,
1811 face_index
, aface
);
1812 FT_FREE( data_offsets
);
1813 /* POST exists in an LWFN providing a single face */
1815 (*aface
)->num_faces
= 1;
1819 error
= FT_Raccess_Get_DataOffsets( library
, stream
,
1820 map_offset
, rdara_pos
,
1822 &data_offsets
, &count
);
1825 FT_Long face_index_internal
= face_index
% count
;
1828 error
= Mac_Read_sfnt_Resource( library
, stream
, data_offsets
, count
,
1829 face_index_internal
, aface
);
1830 FT_FREE( data_offsets
);
1832 (*aface
)->num_faces
= count
;
1839 /* Check for a valid macbinary header, and if we find one */
1840 /* check that the (flattened) resource fork in it is valid. */
1843 IsMacBinary( FT_Library library
,
1848 unsigned char header
[128];
1850 FT_Long dlen
, offset
;
1853 if ( NULL
== stream
)
1854 return FT_THROW( Invalid_Stream_Operation
);
1856 error
= FT_Stream_Seek( stream
, 0 );
1860 error
= FT_Stream_Read( stream
, (FT_Byte
*)header
, 128 );
1864 if ( header
[ 0] != 0 ||
1870 header
[2 + header
[1]] != 0 )
1871 return FT_THROW( Unknown_File_Format
);
1873 dlen
= ( header
[0x53] << 24 ) |
1874 ( header
[0x54] << 16 ) |
1875 ( header
[0x55] << 8 ) |
1878 rlen
= ( header
[0x57] << 24 ) |
1879 ( header
[0x58] << 16 ) |
1880 ( header
[0x59] << 8 ) |
1883 offset
= 128 + ( ( dlen
+ 127 ) & ~127 );
1885 return IsMacResource( library
, stream
, offset
, face_index
, aface
);
1893 load_face_in_embedded_rfork( FT_Library library
,
1897 const FT_Open_Args
*args
)
1901 #define FT_COMPONENT trace_raccess
1903 FT_Memory memory
= library
->memory
;
1904 FT_Error error
= FT_ERR( Unknown_File_Format
);
1907 char * file_names
[FT_RACCESS_N_RULES
];
1908 FT_Long offsets
[FT_RACCESS_N_RULES
];
1909 FT_Error errors
[FT_RACCESS_N_RULES
];
1910 FT_Bool is_darwin_vfs
, vfs_rfork_has_no_font
= FALSE
; /* not tested */
1913 FT_Stream stream2
= 0;
1916 FT_Raccess_Guess( library
, stream
,
1917 args
->pathname
, file_names
, offsets
, errors
);
1919 for ( i
= 0; i
< FT_RACCESS_N_RULES
; i
++ )
1921 is_darwin_vfs
= ft_raccess_rule_by_darwin_vfs( library
, i
);
1922 if ( is_darwin_vfs
&& vfs_rfork_has_no_font
)
1924 FT_TRACE3(( "Skip rule %d: darwin vfs resource fork"
1925 " is already checked and"
1926 " no font is found\n", i
));
1932 FT_TRACE3(( "Error[%d] has occurred in rule %d\n", errors
[i
], i
));
1936 args2
.flags
= FT_OPEN_PATHNAME
;
1937 args2
.pathname
= file_names
[i
] ? file_names
[i
] : args
->pathname
;
1939 FT_TRACE3(( "Try rule %d: %s (offset=%d) ...",
1940 i
, args2
.pathname
, offsets
[i
] ));
1942 error
= FT_Stream_New( library
, &args2
, &stream2
);
1943 if ( is_darwin_vfs
&& FT_ERR_EQ( error
, Cannot_Open_Stream
) )
1944 vfs_rfork_has_no_font
= TRUE
;
1948 FT_TRACE3(( "failed\n" ));
1952 error
= IsMacResource( library
, stream2
, offsets
[i
],
1953 face_index
, aface
);
1954 FT_Stream_Free( stream2
, 0 );
1956 FT_TRACE3(( "%s\n", error
? "failed": "successful" ));
1960 else if ( is_darwin_vfs
)
1961 vfs_rfork_has_no_font
= TRUE
;
1964 for (i
= 0; i
< FT_RACCESS_N_RULES
; i
++)
1966 if ( file_names
[i
] )
1967 FT_FREE( file_names
[i
] );
1970 /* Caller (load_mac_face) requires FT_Err_Unknown_File_Format. */
1972 error
= FT_ERR( Unknown_File_Format
);
1977 #define FT_COMPONENT trace_objs
1982 /* Check for some macintosh formats without Carbon framework. */
1983 /* Is this a macbinary file? If so look at the resource fork. */
1984 /* Is this a mac dfont file? */
1985 /* Is this an old style resource fork? (in data) */
1986 /* Else call load_face_in_embedded_rfork to try extra rules */
1987 /* (defined in `ftrfork.c'). */
1990 load_mac_face( FT_Library library
,
1994 const FT_Open_Args
*args
)
2000 error
= IsMacBinary( library
, stream
, face_index
, aface
);
2001 if ( FT_ERR_EQ( error
, Unknown_File_Format
) )
2005 #define FT_COMPONENT trace_raccess
2007 FT_TRACE3(( "Try as dfont: %s ...", args
->pathname
));
2009 error
= IsMacResource( library
, stream
, 0, face_index
, aface
);
2011 FT_TRACE3(( "%s\n", error
? "failed" : "successful" ));
2014 #define FT_COMPONENT trace_objs
2018 if ( ( FT_ERR_EQ( error
, Unknown_File_Format
) ||
2019 FT_ERR_EQ( error
, Invalid_Stream_Operation
) ) &&
2020 ( args
->flags
& FT_OPEN_PATHNAME
) )
2021 error
= load_face_in_embedded_rfork( library
, stream
,
2022 face_index
, aface
, args
);
2027 #endif /* !FT_MACINTOSH && FT_CONFIG_OPTION_MAC_FONTS */
2030 /* documentation is in freetype.h */
2032 FT_EXPORT_DEF( FT_Error
)
2033 FT_Open_Face( FT_Library library
,
2034 const FT_Open_Args
* args
,
2039 FT_Driver driver
= NULL
;
2040 FT_Memory memory
= NULL
;
2041 FT_Stream stream
= NULL
;
2042 FT_Face face
= NULL
;
2043 FT_ListNode node
= NULL
;
2044 FT_Bool external_stream
;
2049 /* test for valid `library' delayed to */
2050 /* FT_Stream_New() */
2052 if ( ( !aface
&& face_index
>= 0 ) || !args
)
2053 return FT_THROW( Invalid_Argument
);
2055 external_stream
= FT_BOOL( ( args
->flags
& FT_OPEN_STREAM
) &&
2058 /* create input stream */
2059 error
= FT_Stream_New( library
, args
, &stream
);
2063 memory
= library
->memory
;
2065 /* If the font driver is specified in the `args' structure, use */
2066 /* it. Otherwise, we scan the list of registered drivers. */
2067 if ( ( args
->flags
& FT_OPEN_DRIVER
) && args
->driver
)
2069 driver
= FT_DRIVER( args
->driver
);
2071 /* not all modules are drivers, so check... */
2072 if ( FT_MODULE_IS_DRIVER( driver
) )
2074 FT_Int num_params
= 0;
2075 FT_Parameter
* params
= 0;
2078 if ( args
->flags
& FT_OPEN_PARAMS
)
2080 num_params
= args
->num_params
;
2081 params
= args
->params
;
2084 error
= open_face( driver
, &stream
, external_stream
, face_index
,
2085 num_params
, params
, &face
);
2090 error
= FT_THROW( Invalid_Handle
);
2092 FT_Stream_Free( stream
, external_stream
);
2097 error
= FT_ERR( Missing_Module
);
2099 /* check each font driver for an appropriate format */
2100 cur
= library
->modules
;
2101 limit
= cur
+ library
->num_modules
;
2103 for ( ; cur
< limit
; cur
++ )
2105 /* not all modules are font drivers, so check... */
2106 if ( FT_MODULE_IS_DRIVER( cur
[0] ) )
2108 FT_Int num_params
= 0;
2109 FT_Parameter
* params
= 0;
2112 driver
= FT_DRIVER( cur
[0] );
2114 if ( args
->flags
& FT_OPEN_PARAMS
)
2116 num_params
= args
->num_params
;
2117 params
= args
->params
;
2120 error
= open_face( driver
, &stream
, external_stream
, face_index
,
2121 num_params
, params
, &face
);
2125 #ifdef FT_CONFIG_OPTION_MAC_FONTS
2126 if ( ft_strcmp( cur
[0]->clazz
->module_name
, "truetype" ) == 0 &&
2127 FT_ERR_EQ( error
, Table_Missing
) )
2129 /* TrueType but essential tables are missing */
2130 if ( FT_Stream_Seek( stream
, 0 ) )
2133 error
= open_face_PS_from_sfnt_stream( library
,
2141 FT_Stream_Free( stream
, external_stream
);
2147 if ( FT_ERR_NEQ( error
, Unknown_File_Format
) )
2153 /* If we are on the mac, and we get an */
2154 /* FT_Err_Invalid_Stream_Operation it may be because we have an */
2155 /* empty data fork, so we need to check the resource fork. */
2156 if ( FT_ERR_NEQ( error
, Cannot_Open_Stream
) &&
2157 FT_ERR_NEQ( error
, Unknown_File_Format
) &&
2158 FT_ERR_NEQ( error
, Invalid_Stream_Operation
) )
2161 #if !defined( FT_MACINTOSH ) && defined( FT_CONFIG_OPTION_MAC_FONTS )
2162 error
= load_mac_face( library
, stream
, face_index
, aface
, args
);
2165 /* We don't want to go to Success here. We've already done that. */
2166 /* On the other hand, if we succeeded we still need to close this */
2167 /* stream (we opened a different stream which extracted the */
2168 /* interesting information out of this stream here. That stream */
2169 /* will still be open and the face will point to it). */
2170 FT_Stream_Free( stream
, external_stream
);
2174 if ( FT_ERR_NEQ( error
, Unknown_File_Format
) )
2176 #endif /* !FT_MACINTOSH && FT_CONFIG_OPTION_MAC_FONTS */
2178 /* no driver is able to handle this format */
2179 error
= FT_THROW( Unknown_File_Format
);
2182 FT_Stream_Free( stream
, external_stream
);
2187 FT_TRACE4(( "FT_Open_Face: New face object, adding to list\n" ));
2189 /* add the face object to its driver's list */
2190 if ( FT_NEW( node
) )
2194 /* don't assume driver is the same as face->driver, so use */
2195 /* face->driver instead. */
2196 FT_List_Add( &face
->driver
->faces_list
, node
);
2198 /* now allocate a glyph slot object for the face */
2199 FT_TRACE4(( "FT_Open_Face: Creating glyph slot\n" ));
2201 if ( face_index
>= 0 )
2203 error
= FT_New_GlyphSlot( face
, NULL
);
2207 /* finally, allocate a size object for the face */
2212 FT_TRACE4(( "FT_Open_Face: Creating size object\n" ));
2214 error
= FT_New_Size( face
, &size
);
2224 if ( FT_IS_SCALABLE( face
) )
2226 if ( face
->height
< 0 )
2227 face
->height
= (FT_Short
)-face
->height
;
2229 if ( !FT_HAS_VERTICAL( face
) )
2230 face
->max_advance_height
= (FT_Short
)face
->height
;
2233 if ( FT_HAS_FIXED_SIZES( face
) )
2238 for ( i
= 0; i
< face
->num_fixed_sizes
; i
++ )
2240 FT_Bitmap_Size
* bsize
= face
->available_sizes
+ i
;
2243 if ( bsize
->height
< 0 )
2244 bsize
->height
= (FT_Short
)-bsize
->height
;
2245 if ( bsize
->x_ppem
< 0 )
2246 bsize
->x_ppem
= (FT_Short
)-bsize
->x_ppem
;
2247 if ( bsize
->y_ppem
< 0 )
2248 bsize
->y_ppem
= -bsize
->y_ppem
;
2252 /* initialize internal face data */
2254 FT_Face_Internal internal
= face
->internal
;
2257 internal
->transform_matrix
.xx
= 0x10000L
;
2258 internal
->transform_matrix
.xy
= 0;
2259 internal
->transform_matrix
.yx
= 0;
2260 internal
->transform_matrix
.yy
= 0x10000L
;
2262 internal
->transform_delta
.x
= 0;
2263 internal
->transform_delta
.y
= 0;
2265 internal
->refcount
= 1;
2271 FT_Done_Face( face
);
2277 FT_Done_Face( face
); /* face must be in the driver's list */
2279 destroy_face( memory
, face
, driver
);
2282 FT_TRACE4(( "FT_Open_Face: Return %d\n", error
));
2288 /* documentation is in freetype.h */
2290 FT_EXPORT_DEF( FT_Error
)
2291 FT_Attach_File( FT_Face face
,
2292 const char* filepathname
)
2297 /* test for valid `face' delayed to FT_Attach_Stream() */
2299 if ( !filepathname
)
2300 return FT_THROW( Invalid_Argument
);
2303 open
.flags
= FT_OPEN_PATHNAME
;
2304 open
.pathname
= (char*)filepathname
;
2306 return FT_Attach_Stream( face
, &open
);
2310 /* documentation is in freetype.h */
2312 FT_EXPORT_DEF( FT_Error
)
2313 FT_Attach_Stream( FT_Face face
,
2314 FT_Open_Args
* parameters
)
2320 FT_Driver_Class clazz
;
2323 /* test for valid `parameters' delayed to FT_Stream_New() */
2326 return FT_THROW( Invalid_Face_Handle
);
2328 driver
= face
->driver
;
2330 return FT_THROW( Invalid_Driver_Handle
);
2332 error
= FT_Stream_New( driver
->root
.library
, parameters
, &stream
);
2336 /* we implement FT_Attach_Stream in each driver through the */
2337 /* `attach_file' interface */
2339 error
= FT_ERR( Unimplemented_Feature
);
2340 clazz
= driver
->clazz
;
2341 if ( clazz
->attach_file
)
2342 error
= clazz
->attach_file( face
, stream
);
2344 /* close the attached stream */
2345 FT_Stream_Free( stream
,
2346 (FT_Bool
)( parameters
->stream
&&
2347 ( parameters
->flags
& FT_OPEN_STREAM
) ) );
2354 /* documentation is in freetype.h */
2356 FT_EXPORT_DEF( FT_Error
)
2357 FT_Reference_Face( FT_Face face
)
2359 face
->internal
->refcount
++;
2365 /* documentation is in freetype.h */
2367 FT_EXPORT_DEF( FT_Error
)
2368 FT_Done_Face( FT_Face face
)
2376 error
= FT_ERR( Invalid_Face_Handle
);
2377 if ( face
&& face
->driver
)
2379 face
->internal
->refcount
--;
2380 if ( face
->internal
->refcount
> 0 )
2384 driver
= face
->driver
;
2385 memory
= driver
->root
.memory
;
2387 /* find face in driver's list */
2388 node
= FT_List_Find( &driver
->faces_list
, face
);
2391 /* remove face object from the driver's list */
2392 FT_List_Remove( &driver
->faces_list
, node
);
2395 /* now destroy the object proper */
2396 destroy_face( memory
, face
, driver
);
2406 /* documentation is in ftobjs.h */
2408 FT_EXPORT_DEF( FT_Error
)
2409 FT_New_Size( FT_Face face
,
2415 FT_Driver_Class clazz
;
2418 FT_ListNode node
= 0;
2422 return FT_THROW( Invalid_Face_Handle
);
2425 return FT_THROW( Invalid_Size_Handle
);
2427 if ( !face
->driver
)
2428 return FT_THROW( Invalid_Driver_Handle
);
2432 driver
= face
->driver
;
2433 clazz
= driver
->clazz
;
2434 memory
= face
->memory
;
2436 /* Allocate new size object and perform basic initialisation */
2437 if ( FT_ALLOC( size
, clazz
->size_object_size
) || FT_NEW( node
) )
2442 /* for now, do not use any internal fields in size objects */
2445 if ( clazz
->init_size
)
2446 error
= clazz
->init_size( size
);
2448 /* in case of success, add to the face's list */
2453 FT_List_Add( &face
->sizes_list
, node
);
2467 /* documentation is in ftobjs.h */
2469 FT_EXPORT_DEF( FT_Error
)
2470 FT_Done_Size( FT_Size size
)
2480 return FT_THROW( Invalid_Size_Handle
);
2484 return FT_THROW( Invalid_Face_Handle
);
2486 driver
= face
->driver
;
2488 return FT_THROW( Invalid_Driver_Handle
);
2490 memory
= driver
->root
.memory
;
2493 node
= FT_List_Find( &face
->sizes_list
, size
);
2496 FT_List_Remove( &face
->sizes_list
, node
);
2499 if ( face
->size
== size
)
2502 if ( face
->sizes_list
.head
)
2503 face
->size
= (FT_Size
)(face
->sizes_list
.head
->data
);
2506 destroy_size( memory
, size
, driver
);
2509 error
= FT_THROW( Invalid_Size_Handle
);
2515 /* documentation is in ftobjs.h */
2517 FT_BASE_DEF( FT_Error
)
2518 FT_Match_Size( FT_Face face
,
2519 FT_Size_Request req
,
2520 FT_Bool ignore_width
,
2521 FT_ULong
* size_index
)
2527 if ( !FT_HAS_FIXED_SIZES( face
) )
2528 return FT_THROW( Invalid_Face_Handle
);
2530 /* FT_Bitmap_Size doesn't provide enough info... */
2531 if ( req
->type
!= FT_SIZE_REQUEST_TYPE_NOMINAL
)
2532 return FT_THROW( Unimplemented_Feature
);
2534 w
= FT_REQUEST_WIDTH ( req
);
2535 h
= FT_REQUEST_HEIGHT( req
);
2537 if ( req
->width
&& !req
->height
)
2539 else if ( !req
->width
&& req
->height
)
2542 w
= FT_PIX_ROUND( w
);
2543 h
= FT_PIX_ROUND( h
);
2545 for ( i
= 0; i
< face
->num_fixed_sizes
; i
++ )
2547 FT_Bitmap_Size
* bsize
= face
->available_sizes
+ i
;
2550 if ( h
!= FT_PIX_ROUND( bsize
->y_ppem
) )
2553 if ( w
== FT_PIX_ROUND( bsize
->x_ppem
) || ignore_width
)
2555 FT_TRACE3(( "FT_Match_Size: bitmap strike %d matches\n", i
));
2558 *size_index
= (FT_ULong
)i
;
2564 return FT_THROW( Invalid_Pixel_Size
);
2568 /* documentation is in ftobjs.h */
2571 ft_synthesize_vertical_metrics( FT_Glyph_Metrics
* metrics
,
2574 FT_Pos height
= metrics
->height
;
2577 /* compensate for glyph with bbox above/below the baseline */
2578 if ( metrics
->horiBearingY
< 0 )
2580 if ( height
< metrics
->horiBearingY
)
2581 height
= metrics
->horiBearingY
;
2583 else if ( metrics
->horiBearingY
> 0 )
2584 height
-= metrics
->horiBearingY
;
2586 /* the factor 1.2 is a heuristical value */
2588 advance
= height
* 12 / 10;
2590 metrics
->vertBearingX
= metrics
->horiBearingX
- metrics
->horiAdvance
/ 2;
2591 metrics
->vertBearingY
= ( advance
- height
) / 2;
2592 metrics
->vertAdvance
= advance
;
2597 ft_recompute_scaled_metrics( FT_Face face
,
2598 FT_Size_Metrics
* metrics
)
2600 /* Compute root ascender, descender, test height, and max_advance */
2602 #ifdef GRID_FIT_METRICS
2603 metrics
->ascender
= FT_PIX_CEIL( FT_MulFix( face
->ascender
,
2604 metrics
->y_scale
) );
2606 metrics
->descender
= FT_PIX_FLOOR( FT_MulFix( face
->descender
,
2607 metrics
->y_scale
) );
2609 metrics
->height
= FT_PIX_ROUND( FT_MulFix( face
->height
,
2610 metrics
->y_scale
) );
2612 metrics
->max_advance
= FT_PIX_ROUND( FT_MulFix( face
->max_advance_width
,
2613 metrics
->x_scale
) );
2614 #else /* !GRID_FIT_METRICS */
2615 metrics
->ascender
= FT_MulFix( face
->ascender
,
2618 metrics
->descender
= FT_MulFix( face
->descender
,
2621 metrics
->height
= FT_MulFix( face
->height
,
2624 metrics
->max_advance
= FT_MulFix( face
->max_advance_width
,
2626 #endif /* !GRID_FIT_METRICS */
2631 FT_Select_Metrics( FT_Face face
,
2632 FT_ULong strike_index
)
2634 FT_Size_Metrics
* metrics
;
2635 FT_Bitmap_Size
* bsize
;
2638 metrics
= &face
->size
->metrics
;
2639 bsize
= face
->available_sizes
+ strike_index
;
2641 metrics
->x_ppem
= (FT_UShort
)( ( bsize
->x_ppem
+ 32 ) >> 6 );
2642 metrics
->y_ppem
= (FT_UShort
)( ( bsize
->y_ppem
+ 32 ) >> 6 );
2644 if ( FT_IS_SCALABLE( face
) )
2646 metrics
->x_scale
= FT_DivFix( bsize
->x_ppem
,
2647 face
->units_per_EM
);
2648 metrics
->y_scale
= FT_DivFix( bsize
->y_ppem
,
2649 face
->units_per_EM
);
2651 ft_recompute_scaled_metrics( face
, metrics
);
2655 metrics
->x_scale
= 1L << 16;
2656 metrics
->y_scale
= 1L << 16;
2657 metrics
->ascender
= bsize
->y_ppem
;
2658 metrics
->descender
= 0;
2659 metrics
->height
= bsize
->height
<< 6;
2660 metrics
->max_advance
= bsize
->x_ppem
;
2663 FT_TRACE5(( "FT_Select_Metrics:\n" ));
2664 FT_TRACE5(( " x scale: %d (%f)\n",
2665 metrics
->x_scale
, metrics
->x_scale
/ 65536.0 ));
2666 FT_TRACE5(( " y scale: %d (%f)\n",
2667 metrics
->y_scale
, metrics
->y_scale
/ 65536.0 ));
2668 FT_TRACE5(( " ascender: %f\n", metrics
->ascender
/ 64.0 ));
2669 FT_TRACE5(( " descender: %f\n", metrics
->descender
/ 64.0 ));
2670 FT_TRACE5(( " height: %f\n", metrics
->height
/ 64.0 ));
2671 FT_TRACE5(( " max advance: %f\n", metrics
->max_advance
/ 64.0 ));
2672 FT_TRACE5(( " x ppem: %d\n", metrics
->x_ppem
));
2673 FT_TRACE5(( " y ppem: %d\n", metrics
->y_ppem
));
2678 FT_Request_Metrics( FT_Face face
,
2679 FT_Size_Request req
)
2681 FT_Size_Metrics
* metrics
;
2684 metrics
= &face
->size
->metrics
;
2686 if ( FT_IS_SCALABLE( face
) )
2688 FT_Long w
= 0, h
= 0, scaled_w
= 0, scaled_h
= 0;
2691 switch ( req
->type
)
2693 case FT_SIZE_REQUEST_TYPE_NOMINAL
:
2694 w
= h
= face
->units_per_EM
;
2697 case FT_SIZE_REQUEST_TYPE_REAL_DIM
:
2698 w
= h
= face
->ascender
- face
->descender
;
2701 case FT_SIZE_REQUEST_TYPE_BBOX
:
2702 w
= face
->bbox
.xMax
- face
->bbox
.xMin
;
2703 h
= face
->bbox
.yMax
- face
->bbox
.yMin
;
2706 case FT_SIZE_REQUEST_TYPE_CELL
:
2707 w
= face
->max_advance_width
;
2708 h
= face
->ascender
- face
->descender
;
2711 case FT_SIZE_REQUEST_TYPE_SCALES
:
2712 metrics
->x_scale
= (FT_Fixed
)req
->width
;
2713 metrics
->y_scale
= (FT_Fixed
)req
->height
;
2714 if ( !metrics
->x_scale
)
2715 metrics
->x_scale
= metrics
->y_scale
;
2716 else if ( !metrics
->y_scale
)
2717 metrics
->y_scale
= metrics
->x_scale
;
2718 goto Calculate_Ppem
;
2720 case FT_SIZE_REQUEST_TYPE_MAX
:
2724 /* to be on the safe side */
2731 scaled_w
= FT_REQUEST_WIDTH ( req
);
2732 scaled_h
= FT_REQUEST_HEIGHT( req
);
2734 /* determine scales */
2737 metrics
->x_scale
= FT_DivFix( scaled_w
, w
);
2741 metrics
->y_scale
= FT_DivFix( scaled_h
, h
);
2743 if ( req
->type
== FT_SIZE_REQUEST_TYPE_CELL
)
2745 if ( metrics
->y_scale
> metrics
->x_scale
)
2746 metrics
->y_scale
= metrics
->x_scale
;
2748 metrics
->x_scale
= metrics
->y_scale
;
2753 metrics
->y_scale
= metrics
->x_scale
;
2754 scaled_h
= FT_MulDiv( scaled_w
, h
, w
);
2759 metrics
->x_scale
= metrics
->y_scale
= FT_DivFix( scaled_h
, h
);
2760 scaled_w
= FT_MulDiv( scaled_h
, w
, h
);
2764 /* calculate the ppems */
2765 if ( req
->type
!= FT_SIZE_REQUEST_TYPE_NOMINAL
)
2767 scaled_w
= FT_MulFix( face
->units_per_EM
, metrics
->x_scale
);
2768 scaled_h
= FT_MulFix( face
->units_per_EM
, metrics
->y_scale
);
2771 metrics
->x_ppem
= (FT_UShort
)( ( scaled_w
+ 32 ) >> 6 );
2772 metrics
->y_ppem
= (FT_UShort
)( ( scaled_h
+ 32 ) >> 6 );
2774 ft_recompute_scaled_metrics( face
, metrics
);
2779 metrics
->x_scale
= 1L << 16;
2780 metrics
->y_scale
= 1L << 16;
2783 FT_TRACE5(( "FT_Request_Metrics:\n" ));
2784 FT_TRACE5(( " x scale: %d (%f)\n",
2785 metrics
->x_scale
, metrics
->x_scale
/ 65536.0 ));
2786 FT_TRACE5(( " y scale: %d (%f)\n",
2787 metrics
->y_scale
, metrics
->y_scale
/ 65536.0 ));
2788 FT_TRACE5(( " ascender: %f\n", metrics
->ascender
/ 64.0 ));
2789 FT_TRACE5(( " descender: %f\n", metrics
->descender
/ 64.0 ));
2790 FT_TRACE5(( " height: %f\n", metrics
->height
/ 64.0 ));
2791 FT_TRACE5(( " max advance: %f\n", metrics
->max_advance
/ 64.0 ));
2792 FT_TRACE5(( " x ppem: %d\n", metrics
->x_ppem
));
2793 FT_TRACE5(( " y ppem: %d\n", metrics
->y_ppem
));
2797 /* documentation is in freetype.h */
2799 FT_EXPORT_DEF( FT_Error
)
2800 FT_Select_Size( FT_Face face
,
2801 FT_Int strike_index
)
2803 FT_Driver_Class clazz
;
2806 if ( !face
|| !FT_HAS_FIXED_SIZES( face
) )
2807 return FT_THROW( Invalid_Face_Handle
);
2809 if ( strike_index
< 0 || strike_index
>= face
->num_fixed_sizes
)
2810 return FT_THROW( Invalid_Argument
);
2812 clazz
= face
->driver
->clazz
;
2814 if ( clazz
->select_size
)
2819 error
= clazz
->select_size( face
->size
, (FT_ULong
)strike_index
);
2821 #ifdef FT_DEBUG_LEVEL_TRACE
2823 FT_Size_Metrics
* metrics
= &face
->size
->metrics
;
2826 FT_TRACE5(( "FT_Select_Size (font driver's `select_size'):\n" ));
2827 FT_TRACE5(( " x scale: %d (%f)\n",
2828 metrics
->x_scale
, metrics
->x_scale
/ 65536.0 ));
2829 FT_TRACE5(( " y scale: %d (%f)\n",
2830 metrics
->y_scale
, metrics
->y_scale
/ 65536.0 ));
2831 FT_TRACE5(( " ascender: %f\n", metrics
->ascender
/ 64.0 ));
2832 FT_TRACE5(( " descender: %f\n", metrics
->descender
/ 64.0 ));
2833 FT_TRACE5(( " height: %f\n", metrics
->height
/ 64.0 ));
2834 FT_TRACE5(( " max advance: %f\n", metrics
->max_advance
/ 64.0 ));
2835 FT_TRACE5(( " x ppem: %d\n", metrics
->x_ppem
));
2836 FT_TRACE5(( " y ppem: %d\n", metrics
->y_ppem
));
2843 FT_Select_Metrics( face
, (FT_ULong
)strike_index
);
2849 /* documentation is in freetype.h */
2851 FT_EXPORT_DEF( FT_Error
)
2852 FT_Request_Size( FT_Face face
,
2853 FT_Size_Request req
)
2855 FT_Driver_Class clazz
;
2856 FT_ULong strike_index
;
2860 return FT_THROW( Invalid_Face_Handle
);
2862 if ( !req
|| req
->width
< 0 || req
->height
< 0 ||
2863 req
->type
>= FT_SIZE_REQUEST_TYPE_MAX
)
2864 return FT_THROW( Invalid_Argument
);
2866 clazz
= face
->driver
->clazz
;
2868 if ( clazz
->request_size
)
2873 error
= clazz
->request_size( face
->size
, req
);
2875 #ifdef FT_DEBUG_LEVEL_TRACE
2877 FT_Size_Metrics
* metrics
= &face
->size
->metrics
;
2880 FT_TRACE5(( "FT_Request_Size (font driver's `request_size'):\n" ));
2881 FT_TRACE5(( " x scale: %d (%f)\n",
2882 metrics
->x_scale
, metrics
->x_scale
/ 65536.0 ));
2883 FT_TRACE5(( " y scale: %d (%f)\n",
2884 metrics
->y_scale
, metrics
->y_scale
/ 65536.0 ));
2885 FT_TRACE5(( " ascender: %f\n", metrics
->ascender
/ 64.0 ));
2886 FT_TRACE5(( " descender: %f\n", metrics
->descender
/ 64.0 ));
2887 FT_TRACE5(( " height: %f\n", metrics
->height
/ 64.0 ));
2888 FT_TRACE5(( " max advance: %f\n", metrics
->max_advance
/ 64.0 ));
2889 FT_TRACE5(( " x ppem: %d\n", metrics
->x_ppem
));
2890 FT_TRACE5(( " y ppem: %d\n", metrics
->y_ppem
));
2898 * The reason that a driver doesn't have `request_size' defined is
2899 * either that the scaling here suffices or that the supported formats
2900 * are bitmap-only and size matching is not implemented.
2902 * In the latter case, a simple size matching is done.
2904 if ( !FT_IS_SCALABLE( face
) && FT_HAS_FIXED_SIZES( face
) )
2909 error
= FT_Match_Size( face
, req
, 0, &strike_index
);
2913 return FT_Select_Size( face
, (FT_Int
)strike_index
);
2916 FT_Request_Metrics( face
, req
);
2922 /* documentation is in freetype.h */
2924 FT_EXPORT_DEF( FT_Error
)
2925 FT_Set_Char_Size( FT_Face face
,
2926 FT_F26Dot6 char_width
,
2927 FT_F26Dot6 char_height
,
2928 FT_UInt horz_resolution
,
2929 FT_UInt vert_resolution
)
2931 FT_Size_RequestRec req
;
2935 char_width
= char_height
;
2936 else if ( !char_height
)
2937 char_height
= char_width
;
2939 if ( !horz_resolution
)
2940 horz_resolution
= vert_resolution
;
2941 else if ( !vert_resolution
)
2942 vert_resolution
= horz_resolution
;
2944 if ( char_width
< 1 * 64 )
2945 char_width
= 1 * 64;
2946 if ( char_height
< 1 * 64 )
2947 char_height
= 1 * 64;
2949 if ( !horz_resolution
)
2950 horz_resolution
= vert_resolution
= 72;
2952 req
.type
= FT_SIZE_REQUEST_TYPE_NOMINAL
;
2953 req
.width
= char_width
;
2954 req
.height
= char_height
;
2955 req
.horiResolution
= horz_resolution
;
2956 req
.vertResolution
= vert_resolution
;
2958 return FT_Request_Size( face
, &req
);
2962 /* documentation is in freetype.h */
2964 FT_EXPORT_DEF( FT_Error
)
2965 FT_Set_Pixel_Sizes( FT_Face face
,
2966 FT_UInt pixel_width
,
2967 FT_UInt pixel_height
)
2969 FT_Size_RequestRec req
;
2972 if ( pixel_width
== 0 )
2973 pixel_width
= pixel_height
;
2974 else if ( pixel_height
== 0 )
2975 pixel_height
= pixel_width
;
2977 if ( pixel_width
< 1 )
2979 if ( pixel_height
< 1 )
2982 /* use `>=' to avoid potential compiler warning on 16bit platforms */
2983 if ( pixel_width
>= 0xFFFFU
)
2984 pixel_width
= 0xFFFFU
;
2985 if ( pixel_height
>= 0xFFFFU
)
2986 pixel_height
= 0xFFFFU
;
2988 req
.type
= FT_SIZE_REQUEST_TYPE_NOMINAL
;
2989 req
.width
= pixel_width
<< 6;
2990 req
.height
= pixel_height
<< 6;
2991 req
.horiResolution
= 0;
2992 req
.vertResolution
= 0;
2994 return FT_Request_Size( face
, &req
);
2998 /* documentation is in freetype.h */
3000 FT_EXPORT_DEF( FT_Error
)
3001 FT_Get_Kerning( FT_Face face
,
3003 FT_UInt right_glyph
,
3005 FT_Vector
*akerning
)
3007 FT_Error error
= FT_Err_Ok
;
3012 return FT_THROW( Invalid_Face_Handle
);
3015 return FT_THROW( Invalid_Argument
);
3017 driver
= face
->driver
;
3022 if ( driver
->clazz
->get_kerning
)
3024 error
= driver
->clazz
->get_kerning( face
,
3030 if ( kern_mode
!= FT_KERNING_UNSCALED
)
3032 akerning
->x
= FT_MulFix( akerning
->x
, face
->size
->metrics
.x_scale
);
3033 akerning
->y
= FT_MulFix( akerning
->y
, face
->size
->metrics
.y_scale
);
3035 if ( kern_mode
!= FT_KERNING_UNFITTED
)
3037 /* we scale down kerning values for small ppem values */
3038 /* to avoid that rounding makes them too big. */
3039 /* `25' has been determined heuristically. */
3040 if ( face
->size
->metrics
.x_ppem
< 25 )
3041 akerning
->x
= FT_MulDiv( akerning
->x
,
3042 face
->size
->metrics
.x_ppem
, 25 );
3043 if ( face
->size
->metrics
.y_ppem
< 25 )
3044 akerning
->y
= FT_MulDiv( akerning
->y
,
3045 face
->size
->metrics
.y_ppem
, 25 );
3047 akerning
->x
= FT_PIX_ROUND( akerning
->x
);
3048 akerning
->y
= FT_PIX_ROUND( akerning
->y
);
3058 /* documentation is in freetype.h */
3060 FT_EXPORT_DEF( FT_Error
)
3061 FT_Get_Track_Kerning( FT_Face face
,
3062 FT_Fixed point_size
,
3064 FT_Fixed
* akerning
)
3066 FT_Service_Kerning service
;
3067 FT_Error error
= FT_Err_Ok
;
3071 return FT_THROW( Invalid_Face_Handle
);
3074 return FT_THROW( Invalid_Argument
);
3076 FT_FACE_FIND_SERVICE( face
, service
, KERNING
);
3078 return FT_THROW( Unimplemented_Feature
);
3080 error
= service
->get_track( face
,
3089 /* documentation is in freetype.h */
3091 FT_EXPORT_DEF( FT_Error
)
3092 FT_Select_Charmap( FT_Face face
,
3093 FT_Encoding encoding
)
3100 return FT_THROW( Invalid_Face_Handle
);
3102 if ( encoding
== FT_ENCODING_NONE
)
3103 return FT_THROW( Invalid_Argument
);
3105 /* FT_ENCODING_UNICODE is special. We try to find the `best' Unicode */
3106 /* charmap available, i.e., one with UCS-4 characters, if possible. */
3108 /* This is done by find_unicode_charmap() above, to share code. */
3109 if ( encoding
== FT_ENCODING_UNICODE
)
3110 return find_unicode_charmap( face
);
3112 cur
= face
->charmaps
;
3114 return FT_THROW( Invalid_CharMap_Handle
);
3116 limit
= cur
+ face
->num_charmaps
;
3118 for ( ; cur
< limit
; cur
++ )
3120 if ( cur
[0]->encoding
== encoding
)
3122 #ifdef FT_MAX_CHARMAP_CACHEABLE
3123 if ( cur
- face
->charmaps
> FT_MAX_CHARMAP_CACHEABLE
)
3125 FT_ERROR(( "FT_Select_Charmap: requested charmap is found (%d), "
3126 "but in too late position to cache\n",
3127 cur
- face
->charmaps
));
3131 face
->charmap
= cur
[0];
3136 return FT_THROW( Invalid_Argument
);
3140 /* documentation is in freetype.h */
3142 FT_EXPORT_DEF( FT_Error
)
3143 FT_Set_Charmap( FT_Face face
,
3144 FT_CharMap charmap
)
3151 return FT_THROW( Invalid_Face_Handle
);
3153 cur
= face
->charmaps
;
3155 return FT_THROW( Invalid_CharMap_Handle
);
3156 if ( FT_Get_CMap_Format( charmap
) == 14 )
3157 return FT_THROW( Invalid_Argument
);
3159 limit
= cur
+ face
->num_charmaps
;
3161 for ( ; cur
< limit
; cur
++ )
3163 if ( cur
[0] == charmap
)
3165 #ifdef FT_MAX_CHARMAP_CACHEABLE
3166 if ( cur
- face
->charmaps
> FT_MAX_CHARMAP_CACHEABLE
)
3168 FT_ERROR(( "FT_Set_Charmap: requested charmap is found (%d), "
3169 "but in too late position to cache\n",
3170 cur
- face
->charmaps
));
3174 face
->charmap
= cur
[0];
3178 return FT_THROW( Invalid_Argument
);
3182 /* documentation is in freetype.h */
3184 FT_EXPORT_DEF( FT_Int
)
3185 FT_Get_Charmap_Index( FT_CharMap charmap
)
3190 if ( !charmap
|| !charmap
->face
)
3193 for ( i
= 0; i
< charmap
->face
->num_charmaps
; i
++ )
3194 if ( charmap
->face
->charmaps
[i
] == charmap
)
3197 FT_ASSERT( i
< charmap
->face
->num_charmaps
);
3199 #ifdef FT_MAX_CHARMAP_CACHEABLE
3200 if ( i
> FT_MAX_CHARMAP_CACHEABLE
)
3202 FT_ERROR(( "FT_Get_Charmap_Index: requested charmap is found (%d), "
3203 "but in too late position to cache\n",
3213 ft_cmap_done_internal( FT_CMap cmap
)
3215 FT_CMap_Class clazz
= cmap
->clazz
;
3216 FT_Face face
= cmap
->charmap
.face
;
3217 FT_Memory memory
= FT_FACE_MEMORY( face
);
3221 clazz
->done( cmap
);
3228 FT_CMap_Done( FT_CMap cmap
)
3232 FT_Face face
= cmap
->charmap
.face
;
3233 FT_Memory memory
= FT_FACE_MEMORY( face
);
3238 for ( i
= 0; i
< face
->num_charmaps
; i
++ )
3240 if ( (FT_CMap
)face
->charmaps
[i
] == cmap
)
3242 FT_CharMap last_charmap
= face
->charmaps
[face
->num_charmaps
- 1];
3245 if ( FT_RENEW_ARRAY( face
->charmaps
,
3247 face
->num_charmaps
- 1 ) )
3250 /* remove it from our list of charmaps */
3251 for ( j
= i
+ 1; j
< face
->num_charmaps
; j
++ )
3253 if ( j
== face
->num_charmaps
- 1 )
3254 face
->charmaps
[j
- 1] = last_charmap
;
3256 face
->charmaps
[j
- 1] = face
->charmaps
[j
];
3259 face
->num_charmaps
--;
3261 if ( (FT_CMap
)face
->charmap
== cmap
)
3262 face
->charmap
= NULL
;
3264 ft_cmap_done_internal( cmap
);
3273 FT_BASE_DEF( FT_Error
)
3274 FT_CMap_New( FT_CMap_Class clazz
,
3275 FT_Pointer init_data
,
3279 FT_Error error
= FT_Err_Ok
;
3282 FT_CMap cmap
= NULL
;
3285 if ( clazz
== NULL
|| charmap
== NULL
|| charmap
->face
== NULL
)
3286 return FT_THROW( Invalid_Argument
);
3288 face
= charmap
->face
;
3289 memory
= FT_FACE_MEMORY( face
);
3291 if ( !FT_ALLOC( cmap
, clazz
->size
) )
3293 cmap
->charmap
= *charmap
;
3294 cmap
->clazz
= clazz
;
3298 error
= clazz
->init( cmap
, init_data
);
3303 /* add it to our list of charmaps */
3304 if ( FT_RENEW_ARRAY( face
->charmaps
,
3306 face
->num_charmaps
+ 1 ) )
3309 face
->charmaps
[face
->num_charmaps
++] = (FT_CharMap
)cmap
;
3319 ft_cmap_done_internal( cmap
);
3325 /* documentation is in freetype.h */
3327 FT_EXPORT_DEF( FT_UInt
)
3328 FT_Get_Char_Index( FT_Face face
,
3334 if ( face
&& face
->charmap
)
3336 FT_CMap cmap
= FT_CMAP( face
->charmap
);
3339 if ( charcode
> 0xFFFFFFFFUL
)
3341 FT_TRACE1(( "FT_Get_Char_Index: too large charcode" ));
3342 FT_TRACE1(( " 0x%x is truncated\n", charcode
));
3344 result
= cmap
->clazz
->char_index( cmap
, (FT_UInt32
)charcode
);
3350 /* documentation is in freetype.h */
3352 FT_EXPORT_DEF( FT_ULong
)
3353 FT_Get_First_Char( FT_Face face
,
3356 FT_ULong result
= 0;
3360 if ( face
&& face
->charmap
&& face
->num_glyphs
)
3362 gindex
= FT_Get_Char_Index( face
, 0 );
3363 if ( gindex
== 0 || gindex
>= (FT_UInt
)face
->num_glyphs
)
3364 result
= FT_Get_Next_Char( face
, 0, &gindex
);
3374 /* documentation is in freetype.h */
3376 FT_EXPORT_DEF( FT_ULong
)
3377 FT_Get_Next_Char( FT_Face face
,
3381 FT_ULong result
= 0;
3385 if ( face
&& face
->charmap
&& face
->num_glyphs
)
3387 FT_UInt32 code
= (FT_UInt32
)charcode
;
3388 FT_CMap cmap
= FT_CMAP( face
->charmap
);
3393 gindex
= cmap
->clazz
->char_next( cmap
, &code
);
3395 } while ( gindex
>= (FT_UInt
)face
->num_glyphs
);
3397 result
= ( gindex
== 0 ) ? 0 : code
;
3407 /* documentation is in freetype.h */
3409 FT_EXPORT_DEF( FT_UInt
)
3410 FT_Face_GetCharVariantIndex( FT_Face face
,
3412 FT_ULong variantSelector
)
3417 if ( face
&& face
->charmap
&&
3418 face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
3420 FT_CharMap charmap
= find_variant_selector_charmap( face
);
3421 FT_CMap ucmap
= FT_CMAP( face
->charmap
);
3424 if ( charmap
!= NULL
)
3426 FT_CMap vcmap
= FT_CMAP( charmap
);
3429 if ( charcode
> 0xFFFFFFFFUL
)
3431 FT_TRACE1(( "FT_Get_Char_Index: too large charcode" ));
3432 FT_TRACE1(( " 0x%x is truncated\n", charcode
));
3434 if ( variantSelector
> 0xFFFFFFFFUL
)
3436 FT_TRACE1(( "FT_Get_Char_Index: too large variantSelector" ));
3437 FT_TRACE1(( " 0x%x is truncated\n", variantSelector
));
3440 result
= vcmap
->clazz
->char_var_index( vcmap
, ucmap
,
3441 (FT_UInt32
)charcode
,
3442 (FT_UInt32
)variantSelector
);
3450 /* documentation is in freetype.h */
3452 FT_EXPORT_DEF( FT_Int
)
3453 FT_Face_GetCharVariantIsDefault( FT_Face face
,
3455 FT_ULong variantSelector
)
3462 FT_CharMap charmap
= find_variant_selector_charmap( face
);
3465 if ( charmap
!= NULL
)
3467 FT_CMap vcmap
= FT_CMAP( charmap
);
3470 if ( charcode
> 0xFFFFFFFFUL
)
3472 FT_TRACE1(( "FT_Get_Char_Index: too large charcode" ));
3473 FT_TRACE1(( " 0x%x is truncated\n", charcode
));
3475 if ( variantSelector
> 0xFFFFFFFFUL
)
3477 FT_TRACE1(( "FT_Get_Char_Index: too large variantSelector" ));
3478 FT_TRACE1(( " 0x%x is truncated\n", variantSelector
));
3481 result
= vcmap
->clazz
->char_var_default( vcmap
,
3482 (FT_UInt32
)charcode
,
3483 (FT_UInt32
)variantSelector
);
3491 /* documentation is in freetype.h */
3493 FT_EXPORT_DEF( FT_UInt32
* )
3494 FT_Face_GetVariantSelectors( FT_Face face
)
3496 FT_UInt32
*result
= NULL
;
3501 FT_CharMap charmap
= find_variant_selector_charmap( face
);
3504 if ( charmap
!= NULL
)
3506 FT_CMap vcmap
= FT_CMAP( charmap
);
3507 FT_Memory memory
= FT_FACE_MEMORY( face
);
3510 result
= vcmap
->clazz
->variant_list( vcmap
, memory
);
3518 /* documentation is in freetype.h */
3520 FT_EXPORT_DEF( FT_UInt32
* )
3521 FT_Face_GetVariantsOfChar( FT_Face face
,
3524 FT_UInt32
*result
= NULL
;
3529 FT_CharMap charmap
= find_variant_selector_charmap( face
);
3532 if ( charmap
!= NULL
)
3534 FT_CMap vcmap
= FT_CMAP( charmap
);
3535 FT_Memory memory
= FT_FACE_MEMORY( face
);
3538 if ( charcode
> 0xFFFFFFFFUL
)
3540 FT_TRACE1(( "FT_Get_Char_Index: too large charcode" ));
3541 FT_TRACE1(( " 0x%x is truncated\n", charcode
));
3544 result
= vcmap
->clazz
->charvariant_list( vcmap
, memory
,
3545 (FT_UInt32
)charcode
);
3552 /* documentation is in freetype.h */
3554 FT_EXPORT_DEF( FT_UInt32
* )
3555 FT_Face_GetCharsOfVariant( FT_Face face
,
3556 FT_ULong variantSelector
)
3558 FT_UInt32
*result
= NULL
;
3563 FT_CharMap charmap
= find_variant_selector_charmap( face
);
3566 if ( charmap
!= NULL
)
3568 FT_CMap vcmap
= FT_CMAP( charmap
);
3569 FT_Memory memory
= FT_FACE_MEMORY( face
);
3572 if ( variantSelector
> 0xFFFFFFFFUL
)
3574 FT_TRACE1(( "FT_Get_Char_Index: too large variantSelector" ));
3575 FT_TRACE1(( " 0x%x is truncated\n", variantSelector
));
3578 result
= vcmap
->clazz
->variantchar_list( vcmap
, memory
,
3579 (FT_UInt32
)variantSelector
);
3587 /* documentation is in freetype.h */
3589 FT_EXPORT_DEF( FT_UInt
)
3590 FT_Get_Name_Index( FT_Face face
,
3591 FT_String
* glyph_name
)
3596 if ( face
&& FT_HAS_GLYPH_NAMES( face
) )
3598 FT_Service_GlyphDict service
;
3601 FT_FACE_LOOKUP_SERVICE( face
,
3605 if ( service
&& service
->name_index
)
3606 result
= service
->name_index( face
, glyph_name
);
3613 /* documentation is in freetype.h */
3615 FT_EXPORT_DEF( FT_Error
)
3616 FT_Get_Glyph_Name( FT_Face face
,
3617 FT_UInt glyph_index
,
3619 FT_UInt buffer_max
)
3621 FT_Error error
= FT_ERR( Invalid_Argument
);
3624 /* clean up buffer */
3625 if ( buffer
&& buffer_max
> 0 )
3626 ((FT_Byte
*)buffer
)[0] = 0;
3629 (FT_Long
)glyph_index
<= face
->num_glyphs
&&
3630 FT_HAS_GLYPH_NAMES( face
) )
3632 FT_Service_GlyphDict service
;
3635 FT_FACE_LOOKUP_SERVICE( face
,
3639 if ( service
&& service
->get_name
)
3640 error
= service
->get_name( face
, glyph_index
, buffer
, buffer_max
);
3647 /* documentation is in freetype.h */
3649 FT_EXPORT_DEF( const char* )
3650 FT_Get_Postscript_Name( FT_Face face
)
3652 const char* result
= NULL
;
3660 FT_Service_PsFontName service
;
3663 FT_FACE_LOOKUP_SERVICE( face
,
3665 POSTSCRIPT_FONT_NAME
);
3667 if ( service
&& service
->get_ps_font_name
)
3668 result
= service
->get_ps_font_name( face
);
3676 /* documentation is in tttables.h */
3678 FT_EXPORT_DEF( void* )
3679 FT_Get_Sfnt_Table( FT_Face face
,
3683 FT_Service_SFNT_Table service
;
3686 if ( face
&& FT_IS_SFNT( face
) )
3688 FT_FACE_FIND_SERVICE( face
, service
, SFNT_TABLE
);
3689 if ( service
!= NULL
)
3690 table
= service
->get_table( face
, tag
);
3697 /* documentation is in tttables.h */
3699 FT_EXPORT_DEF( FT_Error
)
3700 FT_Load_Sfnt_Table( FT_Face face
,
3706 FT_Service_SFNT_Table service
;
3709 if ( !face
|| !FT_IS_SFNT( face
) )
3710 return FT_THROW( Invalid_Face_Handle
);
3712 FT_FACE_FIND_SERVICE( face
, service
, SFNT_TABLE
);
3713 if ( service
== NULL
)
3714 return FT_THROW( Unimplemented_Feature
);
3716 return service
->load_table( face
, tag
, offset
, buffer
, length
);
3720 /* documentation is in tttables.h */
3722 FT_EXPORT_DEF( FT_Error
)
3723 FT_Sfnt_Table_Info( FT_Face face
,
3724 FT_UInt table_index
,
3728 FT_Service_SFNT_Table service
;
3732 if ( !face
|| !FT_IS_SFNT( face
) )
3733 return FT_THROW( Invalid_Face_Handle
);
3735 FT_FACE_FIND_SERVICE( face
, service
, SFNT_TABLE
);
3736 if ( service
== NULL
)
3737 return FT_THROW( Unimplemented_Feature
);
3739 return service
->table_info( face
, table_index
, tag
, &offset
, length
);
3743 /* documentation is in tttables.h */
3745 FT_EXPORT_DEF( FT_ULong
)
3746 FT_Get_CMap_Language_ID( FT_CharMap charmap
)
3748 FT_Service_TTCMaps service
;
3750 TT_CMapInfo cmap_info
;
3753 if ( !charmap
|| !charmap
->face
)
3756 face
= charmap
->face
;
3757 FT_FACE_FIND_SERVICE( face
, service
, TT_CMAP
);
3758 if ( service
== NULL
)
3760 if ( service
->get_cmap_info( charmap
, &cmap_info
))
3763 return cmap_info
.language
;
3767 /* documentation is in tttables.h */
3769 FT_EXPORT_DEF( FT_Long
)
3770 FT_Get_CMap_Format( FT_CharMap charmap
)
3772 FT_Service_TTCMaps service
;
3774 TT_CMapInfo cmap_info
;
3777 if ( !charmap
|| !charmap
->face
)
3780 face
= charmap
->face
;
3781 FT_FACE_FIND_SERVICE( face
, service
, TT_CMAP
);
3782 if ( service
== NULL
)
3784 if ( service
->get_cmap_info( charmap
, &cmap_info
))
3787 return cmap_info
.format
;
3791 /* documentation is in ftsizes.h */
3793 FT_EXPORT_DEF( FT_Error
)
3794 FT_Activate_Size( FT_Size size
)
3800 return FT_THROW( Invalid_Argument
);
3803 if ( face
== NULL
|| face
->driver
== NULL
)
3804 return FT_THROW( Invalid_Argument
);
3806 /* we don't need anything more complex than that; all size objects */
3807 /* are already listed by the face */
3814 /*************************************************************************/
3815 /*************************************************************************/
3816 /*************************************************************************/
3819 /**** R E N D E R E R S ****/
3822 /*************************************************************************/
3823 /*************************************************************************/
3824 /*************************************************************************/
3826 /* lookup a renderer by glyph format in the library's list */
3827 FT_BASE_DEF( FT_Renderer
)
3828 FT_Lookup_Renderer( FT_Library library
,
3829 FT_Glyph_Format format
,
3833 FT_Renderer result
= 0;
3839 cur
= library
->renderers
.head
;
3844 cur
= (*node
)->next
;
3850 FT_Renderer renderer
= FT_RENDERER( cur
->data
);
3853 if ( renderer
->glyph_format
== format
)
3870 ft_lookup_glyph_renderer( FT_GlyphSlot slot
)
3872 FT_Face face
= slot
->face
;
3873 FT_Library library
= FT_FACE_LIBRARY( face
);
3874 FT_Renderer result
= library
->cur_renderer
;
3877 if ( !result
|| result
->glyph_format
!= slot
->format
)
3878 result
= FT_Lookup_Renderer( library
, slot
->format
, 0 );
3885 ft_set_current_renderer( FT_Library library
)
3887 FT_Renderer renderer
;
3890 renderer
= FT_Lookup_Renderer( library
, FT_GLYPH_FORMAT_OUTLINE
, 0 );
3891 library
->cur_renderer
= renderer
;
3896 ft_add_renderer( FT_Module module
)
3898 FT_Library library
= module
->library
;
3899 FT_Memory memory
= library
->memory
;
3901 FT_ListNode node
= NULL
;
3904 if ( FT_NEW( node
) )
3908 FT_Renderer render
= FT_RENDERER( module
);
3909 FT_Renderer_Class
* clazz
= (FT_Renderer_Class
*)module
->clazz
;
3912 render
->clazz
= clazz
;
3913 render
->glyph_format
= clazz
->glyph_format
;
3915 /* allocate raster object if needed */
3916 if ( clazz
->glyph_format
== FT_GLYPH_FORMAT_OUTLINE
&&
3917 clazz
->raster_class
->raster_new
)
3919 error
= clazz
->raster_class
->raster_new( memory
, &render
->raster
);
3923 render
->raster_render
= clazz
->raster_class
->raster_render
;
3924 render
->render
= clazz
->render_glyph
;
3928 node
->data
= module
;
3929 FT_List_Add( &library
->renderers
, node
);
3931 ft_set_current_renderer( library
);
3944 ft_remove_renderer( FT_Module module
)
3946 FT_Library library
= module
->library
;
3947 FT_Memory memory
= library
->memory
;
3951 node
= FT_List_Find( &library
->renderers
, module
);
3954 FT_Renderer render
= FT_RENDERER( module
);
3957 /* release raster object, if any */
3958 if ( render
->clazz
->glyph_format
== FT_GLYPH_FORMAT_OUTLINE
&&
3960 render
->clazz
->raster_class
->raster_done( render
->raster
);
3962 /* remove from list */
3963 FT_List_Remove( &library
->renderers
, node
);
3966 ft_set_current_renderer( library
);
3971 /* documentation is in ftrender.h */
3973 FT_EXPORT_DEF( FT_Renderer
)
3974 FT_Get_Renderer( FT_Library library
,
3975 FT_Glyph_Format format
)
3977 /* test for valid `library' delayed to FT_Lookup_Renderer() */
3979 return FT_Lookup_Renderer( library
, format
, 0 );
3983 /* documentation is in ftrender.h */
3985 FT_EXPORT_DEF( FT_Error
)
3986 FT_Set_Renderer( FT_Library library
,
3987 FT_Renderer renderer
,
3989 FT_Parameter
* parameters
)
3992 FT_Error error
= FT_Err_Ok
;
3996 return FT_THROW( Invalid_Library_Handle
);
3999 return FT_THROW( Invalid_Argument
);
4001 node
= FT_List_Find( &library
->renderers
, renderer
);
4004 error
= FT_THROW( Invalid_Argument
);
4008 FT_List_Up( &library
->renderers
, node
);
4010 if ( renderer
->glyph_format
== FT_GLYPH_FORMAT_OUTLINE
)
4011 library
->cur_renderer
= renderer
;
4013 if ( num_params
> 0 )
4015 FT_Renderer_SetModeFunc set_mode
= renderer
->clazz
->set_mode
;
4018 for ( ; num_params
> 0; num_params
-- )
4020 error
= set_mode( renderer
, parameters
->tag
, parameters
->data
);
4032 FT_BASE_DEF( FT_Error
)
4033 FT_Render_Glyph_Internal( FT_Library library
,
4035 FT_Render_Mode render_mode
)
4037 FT_Error error
= FT_Err_Ok
;
4038 FT_Renderer renderer
;
4041 /* if it is already a bitmap, no need to do anything */
4042 switch ( slot
->format
)
4044 case FT_GLYPH_FORMAT_BITMAP
: /* already a bitmap, don't do anything */
4049 FT_ListNode node
= 0;
4053 /* small shortcut for the very common case */
4054 if ( slot
->format
== FT_GLYPH_FORMAT_OUTLINE
)
4056 renderer
= library
->cur_renderer
;
4057 node
= library
->renderers
.head
;
4060 renderer
= FT_Lookup_Renderer( library
, slot
->format
, &node
);
4062 error
= FT_ERR( Unimplemented_Feature
);
4065 error
= renderer
->render( renderer
, slot
, render_mode
, NULL
);
4067 FT_ERR_NEQ( error
, Cannot_Render_Glyph
) )
4070 /* FT_Err_Cannot_Render_Glyph is returned if the render mode */
4071 /* is unsupported by the current renderer for this glyph image */
4074 /* now, look for another renderer that supports the same */
4076 renderer
= FT_Lookup_Renderer( library
, slot
->format
, &node
);
4080 /* if we changed the current renderer for the glyph image format */
4081 /* we need to select it as the next current one */
4082 if ( !error
&& update
&& renderer
)
4083 FT_Set_Renderer( library
, renderer
, 0, 0 );
4087 #ifdef FT_DEBUG_LEVEL_TRACE
4090 #define FT_COMPONENT trace_bitmap
4092 /* we convert to a single bitmap format for computing the checksum */
4098 FT_Bitmap_New( &bitmap
);
4100 err
= FT_Bitmap_Convert( library
, &slot
->bitmap
, &bitmap
, 1 );
4104 unsigned char md5
[16];
4109 MD5_Update( &ctx
, bitmap
.buffer
, bitmap
.rows
* bitmap
.pitch
);
4110 MD5_Final( md5
, &ctx
);
4112 FT_TRACE3(( "MD5 checksum for %dx%d bitmap:\n"
4114 bitmap
.rows
, bitmap
.pitch
));
4115 for ( i
= 0; i
< 16; i
++ )
4116 FT_TRACE3(( "%02X", md5
[i
] ));
4117 FT_TRACE3(( "\n" ));
4120 FT_Bitmap_Done( library
, &bitmap
);
4124 #define FT_COMPONENT trace_objs
4126 #endif /* FT_DEBUG_LEVEL_TRACE */
4132 /* documentation is in freetype.h */
4134 FT_EXPORT_DEF( FT_Error
)
4135 FT_Render_Glyph( FT_GlyphSlot slot
,
4136 FT_Render_Mode render_mode
)
4141 if ( !slot
|| !slot
->face
)
4142 return FT_THROW( Invalid_Argument
);
4144 library
= FT_FACE_LIBRARY( slot
->face
);
4146 return FT_Render_Glyph_Internal( library
, slot
, render_mode
);
4150 /*************************************************************************/
4151 /*************************************************************************/
4152 /*************************************************************************/
4155 /**** M O D U L E S ****/
4158 /*************************************************************************/
4159 /*************************************************************************/
4160 /*************************************************************************/
4163 /*************************************************************************/
4166 /* Destroy_Module */
4169 /* Destroys a given module object. For drivers, this also destroys */
4170 /* all child faces. */
4173 /* module :: A handle to the target driver object. */
4176 /* The driver _must_ be LOCKED! */
4179 Destroy_Module( FT_Module module
)
4181 FT_Memory memory
= module
->memory
;
4182 FT_Module_Class
* clazz
= module
->clazz
;
4183 FT_Library library
= module
->library
;
4186 if ( library
&& library
->auto_hinter
== module
)
4187 library
->auto_hinter
= 0;
4189 /* if the module is a renderer */
4190 if ( FT_MODULE_IS_RENDERER( module
) )
4191 ft_remove_renderer( module
);
4193 /* if the module is a font driver, add some steps */
4194 if ( FT_MODULE_IS_DRIVER( module
) )
4195 Destroy_Driver( FT_DRIVER( module
) );
4197 /* finalize the module object */
4198 if ( clazz
->module_done
)
4199 clazz
->module_done( module
);
4206 /* documentation is in ftmodapi.h */
4208 FT_EXPORT_DEF( FT_Error
)
4209 FT_Add_Module( FT_Library library
,
4210 const FT_Module_Class
* clazz
)
4218 #define FREETYPE_VER_FIXED ( ( (FT_Long)FREETYPE_MAJOR << 16 ) | \
4222 return FT_THROW( Invalid_Library_Handle
);
4225 return FT_THROW( Invalid_Argument
);
4227 /* check freetype version */
4228 if ( clazz
->module_requires
> FREETYPE_VER_FIXED
)
4229 return FT_THROW( Invalid_Version
);
4231 /* look for a module with the same name in the library's table */
4232 for ( nn
= 0; nn
< library
->num_modules
; nn
++ )
4234 module
= library
->modules
[nn
];
4235 if ( ft_strcmp( module
->clazz
->module_name
, clazz
->module_name
) == 0 )
4237 /* this installed module has the same name, compare their versions */
4238 if ( clazz
->module_version
<= module
->clazz
->module_version
)
4239 return FT_THROW( Lower_Module_Version
);
4241 /* remove the module from our list, then exit the loop to replace */
4242 /* it by our new version.. */
4243 FT_Remove_Module( library
, module
);
4248 memory
= library
->memory
;
4251 if ( library
->num_modules
>= FT_MAX_MODULES
)
4253 error
= FT_THROW( Too_Many_Drivers
);
4257 /* allocate module object */
4258 if ( FT_ALLOC( module
, clazz
->module_size
) )
4261 /* base initialization */
4262 module
->library
= library
;
4263 module
->memory
= memory
;
4264 module
->clazz
= (FT_Module_Class
*)clazz
;
4266 /* check whether the module is a renderer - this must be performed */
4267 /* before the normal module initialization */
4268 if ( FT_MODULE_IS_RENDERER( module
) )
4270 /* add to the renderers list */
4271 error
= ft_add_renderer( module
);
4276 /* is the module a auto-hinter? */
4277 if ( FT_MODULE_IS_HINTER( module
) )
4278 library
->auto_hinter
= module
;
4280 /* if the module is a font driver */
4281 if ( FT_MODULE_IS_DRIVER( module
) )
4283 /* allocate glyph loader if needed */
4284 FT_Driver driver
= FT_DRIVER( module
);
4287 driver
->clazz
= (FT_Driver_Class
)module
->clazz
;
4288 if ( FT_DRIVER_USES_OUTLINES( driver
) )
4290 error
= FT_GlyphLoader_New( memory
, &driver
->glyph_loader
);
4296 if ( clazz
->module_init
)
4298 error
= clazz
->module_init( module
);
4303 /* add module to the library's table */
4304 library
->modules
[library
->num_modules
++] = module
;
4310 if ( FT_MODULE_IS_DRIVER( module
) )
4312 FT_Driver driver
= FT_DRIVER( module
);
4315 if ( FT_DRIVER_USES_OUTLINES( driver
) )
4316 FT_GlyphLoader_Done( driver
->glyph_loader
);
4319 if ( FT_MODULE_IS_RENDERER( module
) )
4321 FT_Renderer renderer
= FT_RENDERER( module
);
4324 if ( renderer
->clazz
&&
4325 renderer
->clazz
->glyph_format
== FT_GLYPH_FORMAT_OUTLINE
&&
4327 renderer
->clazz
->raster_class
->raster_done( renderer
->raster
);
4335 /* documentation is in ftmodapi.h */
4337 FT_EXPORT_DEF( FT_Module
)
4338 FT_Get_Module( FT_Library library
,
4339 const char* module_name
)
4341 FT_Module result
= 0;
4346 if ( !library
|| !module_name
)
4349 cur
= library
->modules
;
4350 limit
= cur
+ library
->num_modules
;
4352 for ( ; cur
< limit
; cur
++ )
4353 if ( ft_strcmp( cur
[0]->clazz
->module_name
, module_name
) == 0 )
4363 /* documentation is in ftobjs.h */
4365 FT_BASE_DEF( const void* )
4366 FT_Get_Module_Interface( FT_Library library
,
4367 const char* mod_name
)
4372 /* test for valid `library' delayed to FT_Get_Module() */
4374 module
= FT_Get_Module( library
, mod_name
);
4376 return module
? module
->clazz
->module_interface
: 0;
4380 FT_BASE_DEF( FT_Pointer
)
4381 ft_module_get_service( FT_Module module
,
4382 const char* service_id
)
4384 FT_Pointer result
= NULL
;
4389 FT_ASSERT( module
->clazz
&& module
->clazz
->get_interface
);
4391 /* first, look for the service in the module */
4392 if ( module
->clazz
->get_interface
)
4393 result
= module
->clazz
->get_interface( module
, service_id
);
4395 if ( result
== NULL
)
4397 /* we didn't find it, look in all other modules then */
4398 FT_Library library
= module
->library
;
4399 FT_Module
* cur
= library
->modules
;
4400 FT_Module
* limit
= cur
+ library
->num_modules
;
4403 for ( ; cur
< limit
; cur
++ )
4405 if ( cur
[0] != module
)
4407 FT_ASSERT( cur
[0]->clazz
);
4409 if ( cur
[0]->clazz
->get_interface
)
4411 result
= cur
[0]->clazz
->get_interface( cur
[0], service_id
);
4412 if ( result
!= NULL
)
4424 /* documentation is in ftmodapi.h */
4426 FT_EXPORT_DEF( FT_Error
)
4427 FT_Remove_Module( FT_Library library
,
4430 /* try to find the module from the table, then remove it from there */
4433 return FT_THROW( Invalid_Library_Handle
);
4437 FT_Module
* cur
= library
->modules
;
4438 FT_Module
* limit
= cur
+ library
->num_modules
;
4441 for ( ; cur
< limit
; cur
++ )
4443 if ( cur
[0] == module
)
4445 /* remove it from the table */
4446 library
->num_modules
--;
4448 while ( cur
< limit
)
4455 /* destroy the module */
4456 Destroy_Module( module
);
4462 return FT_THROW( Invalid_Driver_Handle
);
4467 ft_property_do( FT_Library library
,
4468 const FT_String
* module_name
,
4469 const FT_String
* property_name
,
4475 FT_Module_Interface interface
;
4477 FT_Service_Properties service
;
4479 #ifdef FT_DEBUG_LEVEL_ERROR
4480 const FT_String
* set_name
= "FT_Property_Set";
4481 const FT_String
* get_name
= "FT_Property_Get";
4482 const FT_String
* func_name
= set
? set_name
: get_name
;
4485 FT_Bool missing_func
;
4489 return FT_THROW( Invalid_Library_Handle
);
4491 if ( !module_name
|| !property_name
|| !value
)
4492 return FT_THROW( Invalid_Argument
);
4494 cur
= library
->modules
;
4495 limit
= cur
+ library
->num_modules
;
4498 for ( ; cur
< limit
; cur
++ )
4499 if ( !ft_strcmp( cur
[0]->clazz
->module_name
, module_name
) )
4504 FT_ERROR(( "%s: can't find module `%s'\n",
4505 func_name
, module_name
));
4506 return FT_THROW( Missing_Module
);
4509 /* check whether we have a service interface */
4510 if ( !cur
[0]->clazz
->get_interface
)
4512 FT_ERROR(( "%s: module `%s' doesn't support properties\n",
4513 func_name
, module_name
));
4514 return FT_THROW( Unimplemented_Feature
);
4517 /* search property service */
4518 interface
= cur
[0]->clazz
->get_interface( cur
[0],
4519 FT_SERVICE_ID_PROPERTIES
);
4522 FT_ERROR(( "%s: module `%s' doesn't support properties\n",
4523 func_name
, module_name
));
4524 return FT_THROW( Unimplemented_Feature
);
4527 service
= (FT_Service_Properties
)interface
;
4530 missing_func
= (FT_Bool
)( !service
->set_property
);
4532 missing_func
= (FT_Bool
)( !service
->get_property
);
4536 FT_ERROR(( "%s: property service of module `%s' is broken\n",
4537 func_name
, module_name
));
4538 return FT_THROW( Unimplemented_Feature
);
4541 return set
? service
->set_property( cur
[0], property_name
, value
)
4542 : service
->get_property( cur
[0], property_name
, value
);
4546 /* documentation is in ftmodapi.h */
4548 FT_EXPORT_DEF( FT_Error
)
4549 FT_Property_Set( FT_Library library
,
4550 const FT_String
* module_name
,
4551 const FT_String
* property_name
,
4554 return ft_property_do( library
,
4562 /* documentation is in ftmodapi.h */
4564 FT_EXPORT_DEF( FT_Error
)
4565 FT_Property_Get( FT_Library library
,
4566 const FT_String
* module_name
,
4567 const FT_String
* property_name
,
4570 return ft_property_do( library
,
4578 /*************************************************************************/
4579 /*************************************************************************/
4580 /*************************************************************************/
4583 /**** L I B R A R Y ****/
4586 /*************************************************************************/
4587 /*************************************************************************/
4588 /*************************************************************************/
4591 /* documentation is in ftmodapi.h */
4593 FT_EXPORT_DEF( FT_Error
)
4594 FT_Reference_Library( FT_Library library
)
4596 library
->refcount
++;
4602 /* documentation is in ftmodapi.h */
4604 FT_EXPORT_DEF( FT_Error
)
4605 FT_New_Library( FT_Memory memory
,
4606 FT_Library
*alibrary
)
4608 FT_Library library
= NULL
;
4613 return FT_THROW( Invalid_Argument
);
4615 #ifdef FT_DEBUG_LEVEL_ERROR
4616 /* init debugging support */
4620 /* first of all, allocate the library object */
4621 if ( FT_NEW( library
) )
4624 library
->memory
= memory
;
4626 #ifdef FT_CONFIG_OPTION_PIC
4627 /* initialize position independent code containers */
4628 error
= ft_pic_container_init( library
);
4633 /* allocate the render pool */
4634 library
->raster_pool_size
= FT_RENDER_POOL_SIZE
;
4635 #if FT_RENDER_POOL_SIZE > 0
4636 if ( FT_ALLOC( library
->raster_pool
, FT_RENDER_POOL_SIZE
) )
4640 library
->version_major
= FREETYPE_MAJOR
;
4641 library
->version_minor
= FREETYPE_MINOR
;
4642 library
->version_patch
= FREETYPE_PATCH
;
4644 library
->refcount
= 1;
4647 *alibrary
= library
;
4652 #ifdef FT_CONFIG_OPTION_PIC
4653 ft_pic_container_destroy( library
);
4660 /* documentation is in freetype.h */
4662 FT_EXPORT_DEF( void )
4663 FT_Library_Version( FT_Library library
,
4675 major
= library
->version_major
;
4676 minor
= library
->version_minor
;
4677 patch
= library
->version_patch
;
4691 /* documentation is in ftmodapi.h */
4693 FT_EXPORT_DEF( FT_Error
)
4694 FT_Done_Library( FT_Library library
)
4700 return FT_THROW( Invalid_Library_Handle
);
4702 library
->refcount
--;
4703 if ( library
->refcount
> 0 )
4706 memory
= library
->memory
;
4709 * Close all faces in the library. If we don't do this, we can have
4710 * some subtle memory leaks.
4714 * - the cff font driver uses the pshinter module in cff_size_done
4715 * - if the pshinter module is destroyed before the cff font driver,
4716 * opened FT_Face objects managed by the driver are not properly
4717 * destroyed, resulting in a memory leak
4719 * Some faces are dependent on other faces, like Type42 faces that
4720 * depend on TrueType faces synthesized internally.
4722 * The order of drivers should be specified in driver_name[].
4726 const char* driver_name
[] = { "type42", NULL
};
4730 m
< sizeof ( driver_name
) / sizeof ( driver_name
[0] );
4733 for ( n
= 0; n
< library
->num_modules
; n
++ )
4735 FT_Module module
= library
->modules
[n
];
4736 const char* module_name
= module
->clazz
->module_name
;
4740 if ( driver_name
[m
] &&
4741 ft_strcmp( module_name
, driver_name
[m
] ) != 0 )
4744 if ( ( module
->clazz
->module_flags
& FT_MODULE_FONT_DRIVER
) == 0 )
4747 FT_TRACE7(( "FT_Done_Library: close faces for %s\n", module_name
));
4749 faces
= &FT_DRIVER( module
)->faces_list
;
4750 while ( faces
->head
)
4752 FT_Done_Face( FT_FACE( faces
->head
->data
) );
4754 FT_TRACE0(( "FT_Done_Library: failed to free some faces\n" ));
4760 /* Close all other modules in the library */
4762 /* XXX Modules are removed in the reversed order so that */
4763 /* type42 module is removed before truetype module. This */
4764 /* avoids double free in some occasions. It is a hack. */
4765 while ( library
->num_modules
> 0 )
4766 FT_Remove_Module( library
,
4767 library
->modules
[library
->num_modules
- 1] );
4773 for ( n
= 0; n
< library
->num_modules
; n
++ )
4775 FT_Module module
= library
->modules
[n
];
4780 Destroy_Module( module
);
4781 library
->modules
[n
] = 0;
4787 /* Destroy raster objects */
4788 FT_FREE( library
->raster_pool
);
4789 library
->raster_pool_size
= 0;
4791 #ifdef FT_CONFIG_OPTION_PIC
4792 /* Destroy pic container contents */
4793 ft_pic_container_destroy( library
);
4803 /* documentation is in ftmodapi.h */
4805 FT_EXPORT_DEF( void )
4806 FT_Set_Debug_Hook( FT_Library library
,
4808 FT_DebugHook_Func debug_hook
)
4810 if ( library
&& debug_hook
&&
4812 ( sizeof ( library
->debug_hooks
) / sizeof ( void* ) ) )
4813 library
->debug_hooks
[hook_index
] = debug_hook
;
4817 /* documentation is in ftmodapi.h */
4819 FT_EXPORT_DEF( FT_TrueTypeEngineType
)
4820 FT_Get_TrueType_Engine_Type( FT_Library library
)
4822 FT_TrueTypeEngineType result
= FT_TRUETYPE_ENGINE_TYPE_NONE
;
4827 FT_Module module
= FT_Get_Module( library
, "truetype" );
4832 FT_Service_TrueTypeEngine service
;
4835 service
= (FT_Service_TrueTypeEngine
)
4836 ft_module_get_service( module
,
4837 FT_SERVICE_ID_TRUETYPE_ENGINE
);
4839 result
= service
->engine_type
;
4847 /* documentation is in freetype.h */
4849 FT_EXPORT_DEF( FT_Error
)
4850 FT_Get_SubGlyph_Info( FT_GlyphSlot glyph
,
4856 FT_Matrix
*p_transform
)
4858 FT_Error error
= FT_ERR( Invalid_Argument
);
4863 glyph
->format
== FT_GLYPH_FORMAT_COMPOSITE
&&
4864 sub_index
< glyph
->num_subglyphs
)
4866 FT_SubGlyph subg
= glyph
->subglyphs
+ sub_index
;
4869 *p_index
= subg
->index
;
4870 *p_flags
= subg
->flags
;
4871 *p_arg1
= subg
->arg1
;
4872 *p_arg2
= subg
->arg2
;
4873 *p_transform
= subg
->transform
;