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