1 /***************************************************************************/
5 /* The FreeType private base classes (body). */
7 /* Copyright 1996-2014 by */
8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
10 /* This file is part of the FreeType project, and may only be used, */
11 /* modified, and distributed under the terms of the FreeType project */
12 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */
13 /* this file you indicate that you have read the license and */
14 /* understand and accept it fully. */
16 /***************************************************************************/
22 #include FT_INTERNAL_VALIDATE_H
23 #include FT_INTERNAL_OBJECTS_H
24 #include FT_INTERNAL_DEBUG_H
25 #include FT_INTERNAL_RFORK_H
26 #include FT_INTERNAL_STREAM_H
27 #include FT_INTERNAL_SFNT_H /* for SFNT_Load_Table_Func */
28 #include FT_TRUETYPE_TABLES_H
29 #include FT_TRUETYPE_TAGS_H
30 #include FT_TRUETYPE_IDS_H
32 #include FT_SERVICE_PROPERTIES_H
33 #include FT_SERVICE_SFNT_H
34 #include FT_SERVICE_POSTSCRIPT_NAME_H
35 #include FT_SERVICE_GLYPH_DICT_H
36 #include FT_SERVICE_TT_CMAP_H
37 #include FT_SERVICE_KERNING_H
38 #include FT_SERVICE_TRUETYPE_ENGINE_H
40 #ifdef FT_CONFIG_OPTION_MAC_FONTS
45 #ifdef FT_DEBUG_LEVEL_TRACE
49 #if defined( _MSC_VER ) /* Visual C++ (and Intel C++) */
50 /* We disable the warning `conversion from XXX to YYY, */
51 /* possible loss of data' in order to compile cleanly with */
52 /* the maximum level of warnings: `md5.c' is non-FreeType */
53 /* code, and it gets used during development builds only. */
54 #pragma warning( push )
55 #pragma warning( disable : 4244 )
58 /* it's easiest to include `md5.c' directly */
61 #if defined( _MSC_VER )
62 #pragma warning( pop )
65 #endif /* FT_DEBUG_LEVEL_TRACE */
68 #define GRID_FIT_METRICS
71 FT_BASE_DEF( FT_Pointer )
72 ft_service_list_lookup( FT_ServiceDesc service_descriptors,
73 const char* service_id )
75 FT_Pointer result = NULL;
76 FT_ServiceDesc desc = service_descriptors;
79 if ( desc && service_id )
81 for ( ; desc->serv_id != NULL; desc++ )
83 if ( ft_strcmp( desc->serv_id, service_id ) == 0 )
85 result = (FT_Pointer)desc->serv_data;
96 ft_validator_init( FT_Validator valid,
99 FT_ValidationLevel level )
102 valid->limit = limit;
103 valid->level = level;
104 valid->error = FT_Err_Ok;
108 FT_BASE_DEF( FT_Int )
109 ft_validator_run( FT_Validator valid )
111 /* This function doesn't work! None should call it. */
119 ft_validator_error( FT_Validator valid,
122 /* since the cast below also disables the compiler's */
123 /* type check, we introduce a dummy variable, which */
124 /* will be optimized away */
125 volatile ft_jmp_buf* jump_buffer = &valid->jump_buffer;
128 valid->error = error;
130 /* throw away volatileness; use `jump_buffer' or the */
131 /* compiler may warn about an unused local variable */
132 ft_longjmp( *(ft_jmp_buf*) jump_buffer, 1 );
136 /*************************************************************************/
137 /*************************************************************************/
138 /*************************************************************************/
141 /**** S T R E A M ****/
144 /*************************************************************************/
145 /*************************************************************************/
146 /*************************************************************************/
149 /* create a new input stream from an FT_Open_Args structure */
151 FT_BASE_DEF( FT_Error )
152 FT_Stream_New( FT_Library library,
153 const FT_Open_Args* args,
158 FT_Stream stream = NULL;
164 return FT_THROW( Invalid_Library_Handle );
167 return FT_THROW( Invalid_Argument );
169 memory = library->memory;
171 if ( FT_NEW( stream ) )
174 stream->memory = memory;
176 if ( args->flags & FT_OPEN_MEMORY )
178 /* create a memory-based stream */
179 FT_Stream_OpenMemory( stream,
180 (const FT_Byte*)args->memory_base,
184 #ifndef FT_CONFIG_OPTION_DISABLE_STREAM_SUPPORT
186 else if ( args->flags & FT_OPEN_PATHNAME )
188 /* create a normal system stream */
189 error = FT_Stream_Open( stream, args->pathname );
190 stream->pathname.pointer = args->pathname;
192 else if ( ( args->flags & FT_OPEN_STREAM ) && args->stream )
194 /* use an existing, user-provided stream */
196 /* in this case, we do not need to allocate a new stream object */
197 /* since the caller is responsible for closing it himself */
199 stream = args->stream;
205 error = FT_THROW( Invalid_Argument );
210 stream->memory = memory; /* just to be certain */
220 FT_Stream_Free( FT_Stream stream,
225 FT_Memory memory = stream->memory;
228 FT_Stream_Close( stream );
236 /*************************************************************************/
238 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
239 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
240 /* messages during execution. */
243 #define FT_COMPONENT trace_objs
246 /*************************************************************************/
247 /*************************************************************************/
248 /*************************************************************************/
251 /**** FACE, SIZE & GLYPH SLOT OBJECTS ****/
254 /*************************************************************************/
255 /*************************************************************************/
256 /*************************************************************************/
260 ft_glyphslot_init( FT_GlyphSlot slot )
262 FT_Driver driver = slot->face->driver;
263 FT_Driver_Class clazz = driver->clazz;
264 FT_Memory memory = driver->root.memory;
265 FT_Error error = FT_Err_Ok;
266 FT_Slot_Internal internal = NULL;
269 slot->library = driver->root.library;
271 if ( FT_NEW( internal ) )
274 slot->internal = internal;
276 if ( FT_DRIVER_USES_OUTLINES( driver ) )
277 error = FT_GlyphLoader_New( memory, &internal->loader );
279 if ( !error && clazz->init_slot )
280 error = clazz->init_slot( slot );
288 ft_glyphslot_free_bitmap( FT_GlyphSlot slot )
290 if ( slot->internal && ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) )
292 FT_Memory memory = FT_FACE_MEMORY( slot->face );
295 FT_FREE( slot->bitmap.buffer );
296 slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
300 /* assume that the bitmap buffer was stolen or not */
301 /* allocated from the heap */
302 slot->bitmap.buffer = NULL;
308 ft_glyphslot_set_bitmap( FT_GlyphSlot slot,
311 ft_glyphslot_free_bitmap( slot );
313 slot->bitmap.buffer = buffer;
315 FT_ASSERT( (slot->internal->flags & FT_GLYPH_OWN_BITMAP) == 0 );
319 FT_BASE_DEF( FT_Error )
320 ft_glyphslot_alloc_bitmap( FT_GlyphSlot slot,
323 FT_Memory memory = FT_FACE_MEMORY( slot->face );
327 if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
328 FT_FREE( slot->bitmap.buffer );
330 slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
332 (void)FT_ALLOC( slot->bitmap.buffer, size );
338 ft_glyphslot_clear( FT_GlyphSlot slot )
340 /* free bitmap if needed */
341 ft_glyphslot_free_bitmap( slot );
343 /* clear all public fields in the glyph slot */
344 FT_ZERO( &slot->metrics );
345 FT_ZERO( &slot->outline );
347 slot->bitmap.width = 0;
348 slot->bitmap.rows = 0;
349 slot->bitmap.pitch = 0;
350 slot->bitmap.pixel_mode = 0;
351 /* `slot->bitmap.buffer' has been handled by ft_glyphslot_free_bitmap */
353 slot->bitmap_left = 0;
354 slot->bitmap_top = 0;
355 slot->num_subglyphs = 0;
357 slot->control_data = 0;
358 slot->control_len = 0;
360 slot->format = FT_GLYPH_FORMAT_NONE;
362 slot->linearHoriAdvance = 0;
363 slot->linearVertAdvance = 0;
370 ft_glyphslot_done( FT_GlyphSlot slot )
372 FT_Driver driver = slot->face->driver;
373 FT_Driver_Class clazz = driver->clazz;
374 FT_Memory memory = driver->root.memory;
377 if ( clazz->done_slot )
378 clazz->done_slot( slot );
380 /* free bitmap buffer if needed */
381 ft_glyphslot_free_bitmap( slot );
383 /* slot->internal might be NULL in out-of-memory situations */
384 if ( slot->internal )
386 /* free glyph loader */
387 if ( FT_DRIVER_USES_OUTLINES( driver ) )
389 FT_GlyphLoader_Done( slot->internal->loader );
390 slot->internal->loader = 0;
393 FT_FREE( slot->internal );
398 /* documentation is in ftobjs.h */
400 FT_BASE_DEF( FT_Error )
401 FT_New_GlyphSlot( FT_Face face,
402 FT_GlyphSlot *aslot )
406 FT_Driver_Class clazz;
408 FT_GlyphSlot slot = NULL;
412 return FT_THROW( Invalid_Face_Handle );
415 return FT_THROW( Invalid_Argument );
417 driver = face->driver;
418 clazz = driver->clazz;
419 memory = driver->root.memory;
421 FT_TRACE4(( "FT_New_GlyphSlot: Creating new slot object\n" ));
422 if ( !FT_ALLOC( slot, clazz->slot_object_size ) )
426 error = ft_glyphslot_init( slot );
429 ft_glyphslot_done( slot );
434 slot->next = face->glyph;
445 FT_TRACE4(( "FT_New_GlyphSlot: Return %d\n", error ));
450 /* documentation is in ftobjs.h */
453 FT_Done_GlyphSlot( FT_GlyphSlot slot )
457 FT_Driver driver = slot->face->driver;
458 FT_Memory memory = driver->root.memory;
463 /* Remove slot from its parent face's list */
465 cur = slot->face->glyph;
472 slot->face->glyph = cur->next;
474 prev->next = cur->next;
476 /* finalize client-specific data */
477 if ( slot->generic.finalizer )
478 slot->generic.finalizer( slot );
480 ft_glyphslot_done( slot );
491 /* documentation is in freetype.h */
493 FT_EXPORT_DEF( void )
494 FT_Set_Transform( FT_Face face,
498 FT_Face_Internal internal;
504 internal = face->internal;
506 internal->transform_flags = 0;
510 internal->transform_matrix.xx = 0x10000L;
511 internal->transform_matrix.xy = 0;
512 internal->transform_matrix.yx = 0;
513 internal->transform_matrix.yy = 0x10000L;
515 matrix = &internal->transform_matrix;
518 internal->transform_matrix = *matrix;
520 /* set transform_flags bit flag 0 if `matrix' isn't the identity */
521 if ( ( matrix->xy | matrix->yx ) ||
522 matrix->xx != 0x10000L ||
523 matrix->yy != 0x10000L )
524 internal->transform_flags |= 1;
528 internal->transform_delta.x = 0;
529 internal->transform_delta.y = 0;
531 delta = &internal->transform_delta;
534 internal->transform_delta = *delta;
536 /* set transform_flags bit flag 1 if `delta' isn't the null vector */
537 if ( delta->x | delta->y )
538 internal->transform_flags |= 2;
543 ft_lookup_glyph_renderer( FT_GlyphSlot slot );
546 #ifdef GRID_FIT_METRICS
548 ft_glyphslot_grid_fit_metrics( FT_GlyphSlot slot,
551 FT_Glyph_Metrics* metrics = &slot->metrics;
552 FT_Pos right, bottom;
557 metrics->horiBearingX = FT_PIX_FLOOR( metrics->horiBearingX );
558 metrics->horiBearingY = FT_PIX_CEIL ( metrics->horiBearingY );
560 right = FT_PIX_CEIL( metrics->vertBearingX + metrics->width );
561 bottom = FT_PIX_CEIL( metrics->vertBearingY + metrics->height );
563 metrics->vertBearingX = FT_PIX_FLOOR( metrics->vertBearingX );
564 metrics->vertBearingY = FT_PIX_FLOOR( metrics->vertBearingY );
566 metrics->width = right - metrics->vertBearingX;
567 metrics->height = bottom - metrics->vertBearingY;
571 metrics->vertBearingX = FT_PIX_FLOOR( metrics->vertBearingX );
572 metrics->vertBearingY = FT_PIX_FLOOR( metrics->vertBearingY );
574 right = FT_PIX_CEIL ( metrics->horiBearingX + metrics->width );
575 bottom = FT_PIX_FLOOR( metrics->horiBearingY - metrics->height );
577 metrics->horiBearingX = FT_PIX_FLOOR( metrics->horiBearingX );
578 metrics->horiBearingY = FT_PIX_CEIL ( metrics->horiBearingY );
580 metrics->width = right - metrics->horiBearingX;
581 metrics->height = metrics->horiBearingY - bottom;
584 metrics->horiAdvance = FT_PIX_ROUND( metrics->horiAdvance );
585 metrics->vertAdvance = FT_PIX_ROUND( metrics->vertAdvance );
587 #endif /* GRID_FIT_METRICS */
590 /* documentation is in freetype.h */
592 FT_EXPORT_DEF( FT_Error )
593 FT_Load_Glyph( FT_Face face,
595 FT_Int32 load_flags )
601 FT_Bool autohint = FALSE;
603 TT_Face ttface = (TT_Face)face;
606 if ( !face || !face->size || !face->glyph )
607 return FT_THROW( Invalid_Face_Handle );
609 /* The validity test for `glyph_index' is performed by the */
613 ft_glyphslot_clear( slot );
615 driver = face->driver;
616 library = driver->root.library;
617 hinter = library->auto_hinter;
619 /* resolve load flags dependencies */
621 if ( load_flags & FT_LOAD_NO_RECURSE )
622 load_flags |= FT_LOAD_NO_SCALE |
623 FT_LOAD_IGNORE_TRANSFORM;
625 if ( load_flags & FT_LOAD_NO_SCALE )
627 load_flags |= FT_LOAD_NO_HINTING |
630 load_flags &= ~FT_LOAD_RENDER;
634 * Determine whether we need to auto-hint or not.
635 * The general rules are:
637 * - Do only auto-hinting if we have a hinter module, a scalable font
638 * format dealing with outlines, and no transforms except simple
639 * slants and/or rotations by integer multiples of 90 degrees.
641 * - Then, auto-hint if FT_LOAD_FORCE_AUTOHINT is set or if we don't
642 * have a native font hinter.
644 * - Otherwise, auto-hint for LIGHT hinting mode or if there isn't
645 * any hinting bytecode in the TrueType/OpenType font.
647 * - Exception: The font is `tricky' and requires the native hinter to
652 !( load_flags & FT_LOAD_NO_HINTING ) &&
653 !( load_flags & FT_LOAD_NO_AUTOHINT ) &&
654 FT_DRIVER_IS_SCALABLE( driver ) &&
655 FT_DRIVER_USES_OUTLINES( driver ) &&
656 !FT_IS_TRICKY( face ) &&
657 ( ( load_flags & FT_LOAD_IGNORE_TRANSFORM ) ||
658 ( face->internal->transform_matrix.yx == 0 &&
659 face->internal->transform_matrix.xx != 0 ) ||
660 ( face->internal->transform_matrix.xx == 0 &&
661 face->internal->transform_matrix.yx != 0 ) ) )
663 if ( ( load_flags & FT_LOAD_FORCE_AUTOHINT ) ||
664 !FT_DRIVER_HAS_HINTER( driver ) )
668 FT_Render_Mode mode = FT_LOAD_TARGET_MODE( load_flags );
671 /* the check for `num_locations' assures that we actually */
672 /* test for instructions in a TTF and not in a CFF-based OTF */
674 /* since `maxSizeOfInstructions' might be unreliable, we */
675 /* check the size of the `fpgm' and `prep' tables, too -- */
676 /* the assumption is that there don't exist real TTFs where */
677 /* both `fpgm' and `prep' tables are missing */
678 if ( mode == FT_RENDER_MODE_LIGHT ||
679 face->internal->ignore_unpatented_hinter ||
680 ( FT_IS_SFNT( face ) &&
681 ttface->num_locations &&
682 ttface->max_profile.maxSizeOfInstructions == 0 &&
683 ttface->font_program_size == 0 &&
684 ttface->cvt_program_size == 0 ) )
691 FT_AutoHinter_Interface hinting;
694 /* try to load embedded bitmaps first if available */
696 /* XXX: This is really a temporary hack that should disappear */
697 /* promptly with FreeType 2.1! */
699 if ( FT_HAS_FIXED_SIZES( face ) &&
700 ( load_flags & FT_LOAD_NO_BITMAP ) == 0 )
702 error = driver->clazz->load_glyph( slot, face->size,
704 load_flags | FT_LOAD_SBITS_ONLY );
706 if ( !error && slot->format == FT_GLYPH_FORMAT_BITMAP )
711 FT_Face_Internal internal = face->internal;
712 FT_Int transform_flags = internal->transform_flags;
715 /* since the auto-hinter calls FT_Load_Glyph by itself, */
716 /* make sure that glyphs aren't transformed */
717 internal->transform_flags = 0;
719 /* load auto-hinted outline */
720 hinting = (FT_AutoHinter_Interface)hinter->clazz->module_interface;
722 error = hinting->load_glyph( (FT_AutoHinter)hinter,
724 glyph_index, load_flags );
726 internal->transform_flags = transform_flags;
731 error = driver->clazz->load_glyph( slot,
738 if ( slot->format == FT_GLYPH_FORMAT_OUTLINE )
740 /* check that the loaded outline is correct */
741 error = FT_Outline_Check( &slot->outline );
745 #ifdef GRID_FIT_METRICS
746 if ( !( load_flags & FT_LOAD_NO_HINTING ) )
747 ft_glyphslot_grid_fit_metrics( slot,
748 FT_BOOL( load_flags & FT_LOAD_VERTICAL_LAYOUT ) );
754 /* compute the advance */
755 if ( load_flags & FT_LOAD_VERTICAL_LAYOUT )
758 slot->advance.y = slot->metrics.vertAdvance;
762 slot->advance.x = slot->metrics.horiAdvance;
766 /* compute the linear advance in 16.16 pixels */
767 if ( ( load_flags & FT_LOAD_LINEAR_DESIGN ) == 0 &&
768 ( FT_IS_SCALABLE( face ) ) )
770 FT_Size_Metrics* metrics = &face->size->metrics;
774 slot->linearHoriAdvance = FT_MulDiv( slot->linearHoriAdvance,
775 metrics->x_scale, 64 );
777 slot->linearVertAdvance = FT_MulDiv( slot->linearVertAdvance,
778 metrics->y_scale, 64 );
781 if ( ( load_flags & FT_LOAD_IGNORE_TRANSFORM ) == 0 )
783 FT_Face_Internal internal = face->internal;
786 /* now, transform the glyph image if needed */
787 if ( internal->transform_flags )
790 FT_Renderer renderer = ft_lookup_glyph_renderer( slot );
794 error = renderer->clazz->transform_glyph(
796 &internal->transform_matrix,
797 &internal->transform_delta );
798 else if ( slot->format == FT_GLYPH_FORMAT_OUTLINE )
800 /* apply `standard' transformation if no renderer is available */
801 if ( internal->transform_flags & 1 )
802 FT_Outline_Transform( &slot->outline,
803 &internal->transform_matrix );
805 if ( internal->transform_flags & 2 )
806 FT_Outline_Translate( &slot->outline,
807 internal->transform_delta.x,
808 internal->transform_delta.y );
811 /* transform advance */
812 FT_Vector_Transform( &slot->advance, &internal->transform_matrix );
816 FT_TRACE5(( " x advance: %d\n" , slot->advance.x ));
817 FT_TRACE5(( " y advance: %d\n" , slot->advance.y ));
819 FT_TRACE5(( " linear x advance: %d\n" , slot->linearHoriAdvance ));
820 FT_TRACE5(( " linear y advance: %d\n" , slot->linearVertAdvance ));
822 /* do we need to render the image now? */
824 slot->format != FT_GLYPH_FORMAT_BITMAP &&
825 slot->format != FT_GLYPH_FORMAT_COMPOSITE &&
826 load_flags & FT_LOAD_RENDER )
828 FT_Render_Mode mode = FT_LOAD_TARGET_MODE( load_flags );
831 if ( mode == FT_RENDER_MODE_NORMAL &&
832 (load_flags & FT_LOAD_MONOCHROME ) )
833 mode = FT_RENDER_MODE_MONO;
835 error = FT_Render_Glyph( slot, mode );
843 /* documentation is in freetype.h */
845 FT_EXPORT_DEF( FT_Error )
846 FT_Load_Char( FT_Face face,
848 FT_Int32 load_flags )
854 return FT_THROW( Invalid_Face_Handle );
856 glyph_index = (FT_UInt)char_code;
858 glyph_index = FT_Get_Char_Index( face, char_code );
860 return FT_Load_Glyph( face, glyph_index, load_flags );
864 /* destructor for sizes list */
866 destroy_size( FT_Memory memory,
870 /* finalize client-specific data */
871 if ( size->generic.finalizer )
872 size->generic.finalizer( size );
874 /* finalize format-specific stuff */
875 if ( driver->clazz->done_size )
876 driver->clazz->done_size( size );
878 FT_FREE( size->internal );
884 ft_cmap_done_internal( FT_CMap cmap );
888 destroy_charmaps( FT_Face face,
897 for ( n = 0; n < face->num_charmaps; n++ )
899 FT_CMap cmap = FT_CMAP( face->charmaps[n] );
902 ft_cmap_done_internal( cmap );
904 face->charmaps[n] = NULL;
907 FT_FREE( face->charmaps );
908 face->num_charmaps = 0;
912 /* destructor for faces list */
914 destroy_face( FT_Memory memory,
918 FT_Driver_Class clazz = driver->clazz;
921 /* discard auto-hinting data */
922 if ( face->autohint.finalizer )
923 face->autohint.finalizer( face->autohint.data );
925 /* Discard glyph slots for this face. */
926 /* Beware! FT_Done_GlyphSlot() changes the field `face->glyph' */
927 while ( face->glyph )
928 FT_Done_GlyphSlot( face->glyph );
930 /* discard all sizes for this face */
931 FT_List_Finalize( &face->sizes_list,
932 (FT_List_Destructor)destroy_size,
937 /* now discard client data */
938 if ( face->generic.finalizer )
939 face->generic.finalizer( face );
941 /* discard charmaps */
942 destroy_charmaps( face, memory );
944 /* finalize format-specific stuff */
945 if ( clazz->done_face )
946 clazz->done_face( face );
948 /* close the stream for this face if needed */
951 ( face->face_flags & FT_FACE_FLAG_EXTERNAL_STREAM ) != 0 );
956 if ( face->internal )
958 FT_FREE( face->internal );
965 Destroy_Driver( FT_Driver driver )
967 FT_List_Finalize( &driver->faces_list,
968 (FT_List_Destructor)destroy_face,
972 /* check whether we need to drop the driver's glyph loader */
973 if ( FT_DRIVER_USES_OUTLINES( driver ) )
974 FT_GlyphLoader_Done( driver->glyph_loader );
978 /*************************************************************************/
981 /* find_unicode_charmap */
984 /* This function finds a Unicode charmap, if there is one. */
985 /* And if there is more than one, it tries to favour the more */
986 /* extensive one, i.e., one that supports UCS-4 against those which */
987 /* are limited to the BMP (said UCS-2 encoding.) */
989 /* This function is called from open_face() (just below), and also */
990 /* from FT_Select_Charmap( ..., FT_ENCODING_UNICODE ). */
993 find_unicode_charmap( FT_Face face )
999 /* caller should have already checked that `face' is valid */
1002 first = face->charmaps;
1005 return FT_THROW( Invalid_CharMap_Handle );
1008 * The original TrueType specification(s) only specified charmap
1009 * formats that are capable of mapping 8 or 16 bit character codes to
1012 * However, recent updates to the Apple and OpenType specifications
1013 * introduced new formats that are capable of mapping 32-bit character
1014 * codes as well. And these are already used on some fonts, mainly to
1015 * map non-BMP Asian ideographs as defined in Unicode.
1017 * For compatibility purposes, these fonts generally come with
1018 * *several* Unicode charmaps:
1020 * - One of them in the "old" 16-bit format, that cannot access
1021 * all glyphs in the font.
1023 * - Another one in the "new" 32-bit format, that can access all
1026 * This function has been written to always favor a 32-bit charmap
1027 * when found. Otherwise, a 16-bit one is returned when found.
1030 /* Since the `interesting' table, with IDs (3,10), is normally the */
1031 /* last one, we loop backwards. This loses with type1 fonts with */
1032 /* non-BMP characters (<.0001%), this wins with .ttf with non-BMP */
1033 /* chars (.01% ?), and this is the same about 99.99% of the time! */
1035 cur = first + face->num_charmaps; /* points after the last one */
1037 for ( ; --cur >= first; )
1039 if ( cur[0]->encoding == FT_ENCODING_UNICODE )
1041 /* XXX If some new encodings to represent UCS-4 are added, */
1042 /* they should be added here. */
1043 if ( ( cur[0]->platform_id == TT_PLATFORM_MICROSOFT &&
1044 cur[0]->encoding_id == TT_MS_ID_UCS_4 ) ||
1045 ( cur[0]->platform_id == TT_PLATFORM_APPLE_UNICODE &&
1046 cur[0]->encoding_id == TT_APPLE_ID_UNICODE_32 ) )
1048 face->charmap = cur[0];
1054 /* We do not have any UCS-4 charmap. */
1055 /* Do the loop again and search for UCS-2 charmaps. */
1056 cur = first + face->num_charmaps;
1058 for ( ; --cur >= first; )
1060 if ( cur[0]->encoding == FT_ENCODING_UNICODE )
1062 face->charmap = cur[0];
1067 return FT_THROW( Invalid_CharMap_Handle );
1071 /*************************************************************************/
1074 /* find_variant_selector_charmap */
1077 /* This function finds the variant selector charmap, if there is one. */
1078 /* There can only be one (platform=0, specific=5, format=14). */
1081 find_variant_selector_charmap( FT_Face face )
1088 /* caller should have already checked that `face' is valid */
1091 first = face->charmaps;
1096 end = first + face->num_charmaps; /* points after the last one */
1098 for ( cur = first; cur < end; ++cur )
1100 if ( cur[0]->platform_id == TT_PLATFORM_APPLE_UNICODE &&
1101 cur[0]->encoding_id == TT_APPLE_ID_VARIANT_SELECTOR &&
1102 FT_Get_CMap_Format( cur[0] ) == 14 )
1110 /*************************************************************************/
1116 /* This function does some work for FT_Open_Face(). */
1119 open_face( FT_Driver driver,
1121 FT_Bool external_stream,
1124 FT_Parameter* params,
1128 FT_Driver_Class clazz;
1129 FT_Face face = NULL;
1130 FT_Face_Internal internal = NULL;
1132 FT_Error error, error2;
1135 clazz = driver->clazz;
1136 memory = driver->root.memory;
1138 /* allocate the face object and perform basic initialization */
1139 if ( FT_ALLOC( face, clazz->face_object_size ) )
1142 face->driver = driver;
1143 face->memory = memory;
1144 face->stream = *astream;
1146 /* set the FT_FACE_FLAG_EXTERNAL_STREAM bit for FT_Done_Face */
1147 if ( external_stream )
1148 face->face_flags |= FT_FACE_FLAG_EXTERNAL_STREAM;
1150 if ( FT_NEW( internal ) )
1153 face->internal = internal;
1155 #ifdef FT_CONFIG_OPTION_INCREMENTAL
1160 face->internal->incremental_interface = 0;
1161 for ( i = 0; i < num_params && !face->internal->incremental_interface;
1163 if ( params[i].tag == FT_PARAM_TAG_INCREMENTAL )
1164 face->internal->incremental_interface =
1165 (FT_Incremental_Interface)params[i].data;
1169 if ( clazz->init_face )
1170 error = clazz->init_face( *astream,
1175 *astream = face->stream; /* Stream may have been changed. */
1179 /* select Unicode charmap by default */
1180 error2 = find_unicode_charmap( face );
1182 /* if no Unicode charmap can be found, FT_Err_Invalid_CharMap_Handle */
1185 /* no error should happen, but we want to play safe */
1186 if ( error2 && FT_ERR_NEQ( error2, Invalid_CharMap_Handle ) )
1197 destroy_charmaps( face, memory );
1198 if ( clazz->done_face )
1199 clazz->done_face( face );
1200 FT_FREE( internal );
1209 /* there's a Mac-specific extended implementation of FT_New_Face() */
1210 /* in src/base/ftmac.c */
1212 #ifndef FT_MACINTOSH
1214 /* documentation is in freetype.h */
1216 FT_EXPORT_DEF( FT_Error )
1217 FT_New_Face( FT_Library library,
1218 const char* pathname,
1225 /* test for valid `library' and `aface' delayed to `FT_Open_Face' */
1227 return FT_THROW( Invalid_Argument );
1229 args.flags = FT_OPEN_PATHNAME;
1230 args.pathname = (char*)pathname;
1233 return FT_Open_Face( library, &args, face_index, aface );
1239 /* documentation is in freetype.h */
1241 FT_EXPORT_DEF( FT_Error )
1242 FT_New_Memory_Face( FT_Library library,
1243 const FT_Byte* file_base,
1251 /* test for valid `library' and `face' delayed to `FT_Open_Face' */
1253 return FT_THROW( Invalid_Argument );
1255 args.flags = FT_OPEN_MEMORY;
1256 args.memory_base = file_base;
1257 args.memory_size = file_size;
1260 return FT_Open_Face( library, &args, face_index, aface );
1264 #ifdef FT_CONFIG_OPTION_MAC_FONTS
1266 /* The behavior here is very similar to that in base/ftmac.c, but it */
1267 /* is designed to work on non-mac systems, so no mac specific calls. */
1269 /* We look at the file and determine if it is a mac dfont file or a mac */
1270 /* resource file, or a macbinary file containing a mac resource file. */
1272 /* Unlike ftmac I'm not going to look at a `FOND'. I don't really see */
1273 /* the point, especially since there may be multiple `FOND' resources. */
1274 /* Instead I'll just look for `sfnt' and `POST' resources, ordered as */
1275 /* they occur in the file. */
1277 /* Note that multiple `POST' resources do not mean multiple postscript */
1278 /* fonts; they all get jammed together to make what is essentially a */
1281 /* We aren't interested in `NFNT' or `FONT' bitmap resources. */
1283 /* As soon as we get an `sfnt' load it into memory and pass it off to */
1286 /* If we have a (set of) `POST' resources, massage them into a (memory) */
1287 /* pfb file and pass that to FT_Open_Face. (As with ftmac.c I'm not */
1288 /* going to try to save the kerning info. After all that lives in the */
1289 /* `FOND' which isn't in the file containing the `POST' resources so */
1290 /* we don't really have access to it. */
1293 /* Finalizer for a memory stream; gets called by FT_Done_Face(). */
1294 /* It frees the memory it uses. */
1297 memory_stream_close( FT_Stream stream )
1299 FT_Memory memory = stream->memory;
1302 FT_FREE( stream->base );
1310 /* Create a new memory stream from a buffer and a size. */
1313 new_memory_stream( FT_Library library,
1316 FT_Stream_CloseFunc close,
1317 FT_Stream *astream )
1321 FT_Stream stream = NULL;
1325 return FT_THROW( Invalid_Library_Handle );
1328 return FT_THROW( Invalid_Argument );
1331 memory = library->memory;
1332 if ( FT_NEW( stream ) )
1335 FT_Stream_OpenMemory( stream, base, size );
1337 stream->close = close;
1346 /* Create a new FT_Face given a buffer and a driver name. */
1348 FT_LOCAL_DEF( FT_Error )
1349 open_face_from_buffer( FT_Library library,
1353 const char* driver_name,
1358 FT_Stream stream = NULL;
1359 FT_Memory memory = library->memory;
1362 error = new_memory_stream( library,
1365 memory_stream_close,
1373 args.flags = FT_OPEN_STREAM;
1374 args.stream = stream;
1377 args.flags = args.flags | FT_OPEN_DRIVER;
1378 args.driver = FT_Get_Module( library, driver_name );
1382 /* At this point, face_index has served its purpose; */
1383 /* whoever calls this function has already used it to */
1384 /* locate the correct font data. We should not propagate */
1385 /* this index to FT_Open_Face() (unless it is negative). */
1387 if ( face_index > 0 )
1391 error = FT_Open_Face( library, &args, face_index, aface );
1393 if ( error == FT_Err_Ok )
1394 (*aface)->face_flags &= ~FT_FACE_FLAG_EXTERNAL_STREAM;
1397 FT_Stream_Free( stream, 0 );
1400 FT_Stream_Close( stream );
1409 /* Look up `TYP1' or `CID ' table from sfnt table directory. */
1410 /* `offset' and `length' must exclude the binary header in tables. */
1412 /* Type 1 and CID-keyed font drivers should recognize sfnt-wrapped */
1413 /* format too. Here, since we can't expect that the TrueType font */
1414 /* driver is loaded unconditially, we must parse the font by */
1415 /* ourselves. We are only interested in the name of the table and */
1419 ft_lookup_PS_in_sfnt_stream( FT_Stream stream,
1423 FT_Bool* is_sfnt_cid )
1426 FT_UShort numTables;
1427 FT_Long pstable_index;
1434 *is_sfnt_cid = FALSE;
1436 /* TODO: support for sfnt-wrapped PS/CID in TTC format */
1438 /* version check for 'typ1' (should be ignored?) */
1439 if ( FT_READ_ULONG( tag ) )
1441 if ( tag != TTAG_typ1 )
1442 return FT_THROW( Unknown_File_Format );
1444 if ( FT_READ_USHORT( numTables ) )
1446 if ( FT_STREAM_SKIP( 2 * 3 ) ) /* skip binary search header */
1450 *is_sfnt_cid = FALSE;
1452 for ( i = 0; i < numTables; i++ )
1454 if ( FT_READ_ULONG( tag ) || FT_STREAM_SKIP( 4 ) ||
1455 FT_READ_ULONG( *offset ) || FT_READ_ULONG( *length ) )
1458 if ( tag == TTAG_CID )
1463 *is_sfnt_cid = TRUE;
1464 if ( face_index < 0 )
1467 else if ( tag == TTAG_TYP1 )
1472 *is_sfnt_cid = FALSE;
1473 if ( face_index < 0 )
1476 if ( face_index >= 0 && pstable_index == face_index )
1479 return FT_THROW( Table_Missing );
1483 FT_LOCAL_DEF( FT_Error )
1484 open_face_PS_from_sfnt_stream( FT_Library library,
1488 FT_Parameter *params,
1492 FT_Memory memory = library->memory;
1493 FT_ULong offset, length;
1495 FT_Bool is_sfnt_cid;
1496 FT_Byte* sfnt_ps = NULL;
1498 FT_UNUSED( num_params );
1499 FT_UNUSED( params );
1502 pos = FT_Stream_Pos( stream );
1504 error = ft_lookup_PS_in_sfnt_stream( stream,
1512 if ( FT_Stream_Seek( stream, pos + offset ) )
1515 if ( FT_ALLOC( sfnt_ps, (FT_Long)length ) )
1518 error = FT_Stream_Read( stream, (FT_Byte *)sfnt_ps, length );
1522 error = open_face_from_buffer( library,
1525 FT_MIN( face_index, 0 ),
1526 is_sfnt_cid ? "cid" : "type1",
1533 if ( FT_ERR_EQ( error, Unknown_File_Format ) )
1535 error1 = FT_Stream_Seek( stream, pos );
1545 #ifndef FT_MACINTOSH
1547 /* The resource header says we've got resource_cnt `POST' (type1) */
1548 /* resources in this file. They all need to be coalesced into */
1549 /* one lump which gets passed on to the type1 driver. */
1550 /* Here can be only one PostScript font in a file so face_index */
1551 /* must be 0 (or -1). */
1554 Mac_Read_POST_Resource( FT_Library library,
1557 FT_Long resource_cnt,
1561 FT_Error error = FT_ERR( Cannot_Open_Resource );
1562 FT_Memory memory = library->memory;
1563 FT_Byte* pfb_data = NULL;
1566 FT_ULong pfb_len, pfb_pos, pfb_lenpos;
1567 FT_ULong rlen, temp;
1570 if ( face_index == -1 )
1572 if ( face_index != 0 )
1575 /* Find the length of all the POST resources, concatenated. Assume */
1576 /* worst case (each resource in its own section). */
1578 for ( i = 0; i < resource_cnt; ++i )
1580 error = FT_Stream_Seek( stream, offsets[i] );
1583 if ( FT_READ_ULONG( temp ) )
1586 /* FT2 allocator takes signed long buffer length,
1587 * too large value causing overflow should be checked
1589 FT_TRACE4(( " POST fragment #%d: length=0x%08x\n",
1591 if ( 0x7FFFFFFFUL < temp || pfb_len + temp + 6 < pfb_len )
1593 FT_TRACE2(( " too long fragment length makes"
1594 " pfb_len confused: temp=0x%08x\n", temp ));
1595 error = FT_THROW( Invalid_Offset );
1599 pfb_len += temp + 6;
1602 FT_TRACE2(( " total buffer size to concatenate %d"
1603 " POST fragments: 0x%08x\n",
1604 resource_cnt, pfb_len + 2));
1605 if ( pfb_len + 2 < 6 ) {
1606 FT_TRACE2(( " too long fragment length makes"
1607 " pfb_len confused: pfb_len=0x%08x\n", pfb_len ));
1608 error = FT_THROW( Array_Too_Large );
1611 if ( FT_ALLOC( pfb_data, (FT_Long)pfb_len + 2 ) )
1615 pfb_data[1] = 1; /* Ascii section */
1616 pfb_data[2] = 0; /* 4-byte length, fill in later */
1625 for ( i = 0; i < resource_cnt; ++i )
1627 error = FT_Stream_Seek( stream, offsets[i] );
1630 if ( FT_READ_ULONG( rlen ) )
1633 /* FT2 allocator takes signed long buffer length,
1634 * too large fragment length causing overflow should be checked
1636 if ( 0x7FFFFFFFUL < rlen )
1638 error = FT_THROW( Invalid_Offset );
1642 if ( FT_READ_USHORT( flags ) )
1644 FT_TRACE3(( "POST fragment[%d]: offsets=0x%08x, rlen=0x%08x, flags=0x%04x\n",
1645 i, offsets[i], rlen, flags ));
1647 error = FT_ERR( Array_Too_Large );
1648 /* postpone the check of rlen longer than buffer until FT_Stream_Read() */
1649 if ( ( flags >> 8 ) == 0 ) /* Comment, should not be loaded */
1651 FT_TRACE3(( " Skip POST fragment #%d because it is a comment\n", i ));
1655 /* the flags are part of the resource, so rlen >= 2. */
1656 /* but some fonts declare rlen = 0 for empty fragment */
1662 if ( ( flags >> 8 ) == type )
1666 FT_TRACE3(( " Write POST fragment #%d header (4-byte) to buffer"
1667 " 0x%p + 0x%08x\n", i, pfb_data, pfb_lenpos ));
1668 if ( pfb_lenpos + 3 > pfb_len + 2 )
1670 pfb_data[pfb_lenpos ] = (FT_Byte)( len );
1671 pfb_data[pfb_lenpos + 1] = (FT_Byte)( len >> 8 );
1672 pfb_data[pfb_lenpos + 2] = (FT_Byte)( len >> 16 );
1673 pfb_data[pfb_lenpos + 3] = (FT_Byte)( len >> 24 );
1675 if ( ( flags >> 8 ) == 5 ) /* End of font mark */
1678 FT_TRACE3(( " Write POST fragment #%d header (6-byte) to buffer"
1679 " 0x%p + 0x%08x\n", i, pfb_data, pfb_pos ));
1680 if ( pfb_pos + 6 > pfb_len + 2 )
1682 pfb_data[pfb_pos++] = 0x80;
1687 pfb_data[pfb_pos++] = (FT_Byte)type;
1688 pfb_lenpos = pfb_pos;
1689 pfb_data[pfb_pos++] = 0; /* 4-byte length, fill in later */
1690 pfb_data[pfb_pos++] = 0;
1691 pfb_data[pfb_pos++] = 0;
1692 pfb_data[pfb_pos++] = 0;
1695 if ( pfb_pos > pfb_len || pfb_pos + rlen > pfb_len )
1698 FT_TRACE3(( " Load POST fragment #%d (%d byte) to buffer"
1699 " 0x%p + 0x%08x\n", i, rlen, pfb_data, pfb_pos ));
1700 error = FT_Stream_Read( stream, (FT_Byte *)pfb_data + pfb_pos, rlen );
1706 error = FT_ERR( Array_Too_Large );
1707 if ( pfb_pos + 2 > pfb_len + 2 )
1709 pfb_data[pfb_pos++] = 0x80;
1710 pfb_data[pfb_pos++] = 3;
1712 if ( pfb_lenpos + 3 > pfb_len + 2 )
1714 pfb_data[pfb_lenpos ] = (FT_Byte)( len );
1715 pfb_data[pfb_lenpos + 1] = (FT_Byte)( len >> 8 );
1716 pfb_data[pfb_lenpos + 2] = (FT_Byte)( len >> 16 );
1717 pfb_data[pfb_lenpos + 3] = (FT_Byte)( len >> 24 );
1719 return open_face_from_buffer( library,
1727 if ( error == FT_ERR( Array_Too_Large ) )
1728 FT_TRACE2(( " Abort due to too-short buffer to store"
1729 " all POST fragments\n" ));
1730 else if ( error == FT_ERR( Invalid_Offset ) )
1731 FT_TRACE2(( " Abort due to invalid offset in a POST fragment\n" ));
1733 error = FT_ERR( Cannot_Open_Resource );
1734 FT_FREE( pfb_data );
1741 /* The resource header says we've got resource_cnt `sfnt' */
1742 /* (TrueType/OpenType) resources in this file. Look through */
1743 /* them for the one indicated by face_index, load it into mem, */
1744 /* pass it on the the truetype driver and return it. */
1747 Mac_Read_sfnt_Resource( FT_Library library,
1750 FT_Long resource_cnt,
1754 FT_Memory memory = library->memory;
1755 FT_Byte* sfnt_data = NULL;
1757 FT_Long flag_offset;
1760 FT_Long face_index_in_resource = 0;
1763 if ( face_index == -1 )
1765 if ( face_index >= resource_cnt )
1766 return FT_THROW( Cannot_Open_Resource );
1768 flag_offset = offsets[face_index];
1769 error = FT_Stream_Seek( stream, flag_offset );
1773 if ( FT_READ_LONG( rlen ) )
1776 return FT_THROW( Cannot_Open_Resource );
1778 error = open_face_PS_from_sfnt_stream( library,
1786 /* rewind sfnt stream before open_face_PS_from_sfnt_stream() */
1787 if ( FT_Stream_Seek( stream, flag_offset + 4 ) )
1790 if ( FT_ALLOC( sfnt_data, (FT_Long)rlen ) )
1792 error = FT_Stream_Read( stream, (FT_Byte *)sfnt_data, rlen );
1796 is_cff = rlen > 4 && !ft_memcmp( sfnt_data, "OTTO", 4 );
1797 error = open_face_from_buffer( library,
1800 face_index_in_resource,
1801 is_cff ? "cff" : "truetype",
1809 /* Check for a valid resource fork header, or a valid dfont */
1810 /* header. In a resource fork the first 16 bytes are repeated */
1811 /* at the location specified by bytes 4-7. In a dfont bytes */
1812 /* 4-7 point to 16 bytes of zeroes instead. */
1815 IsMacResource( FT_Library library,
1817 FT_Long resource_offset,
1821 FT_Memory memory = library->memory;
1823 FT_Long map_offset, rdara_pos;
1824 FT_Long *data_offsets;
1828 error = FT_Raccess_Get_HeaderInfo( library, stream, resource_offset,
1829 &map_offset, &rdara_pos );
1833 /* POST resources must be sorted to concatenate properly */
1834 error = FT_Raccess_Get_DataOffsets( library, stream,
1835 map_offset, rdara_pos,
1837 &data_offsets, &count );
1840 error = Mac_Read_POST_Resource( library, stream, data_offsets, count,
1841 face_index, aface );
1842 FT_FREE( data_offsets );
1843 /* POST exists in an LWFN providing a single face */
1845 (*aface)->num_faces = 1;
1849 /* sfnt resources should not be sorted to preserve the face order by
1851 error = FT_Raccess_Get_DataOffsets( library, stream,
1852 map_offset, rdara_pos,
1854 &data_offsets, &count );
1857 FT_Long face_index_internal = face_index % count;
1860 error = Mac_Read_sfnt_Resource( library, stream, data_offsets, count,
1861 face_index_internal, aface );
1862 FT_FREE( data_offsets );
1864 (*aface)->num_faces = count;
1871 /* Check for a valid macbinary header, and if we find one */
1872 /* check that the (flattened) resource fork in it is valid. */
1875 IsMacBinary( FT_Library library,
1880 unsigned char header[128];
1882 FT_Long dlen, offset;
1885 if ( NULL == stream )
1886 return FT_THROW( Invalid_Stream_Operation );
1888 error = FT_Stream_Seek( stream, 0 );
1892 error = FT_Stream_Read( stream, (FT_Byte*)header, 128 );
1896 if ( header[ 0] != 0 ||
1902 header[2 + header[1]] != 0 )
1903 return FT_THROW( Unknown_File_Format );
1905 dlen = ( header[0x53] << 24 ) |
1906 ( header[0x54] << 16 ) |
1907 ( header[0x55] << 8 ) |
1910 rlen = ( header[0x57] << 24 ) |
1911 ( header[0x58] << 16 ) |
1912 ( header[0x59] << 8 ) |
1915 offset = 128 + ( ( dlen + 127 ) & ~127 );
1917 return IsMacResource( library, stream, offset, face_index, aface );
1925 load_face_in_embedded_rfork( FT_Library library,
1929 const FT_Open_Args *args )
1933 #define FT_COMPONENT trace_raccess
1935 FT_Memory memory = library->memory;
1936 FT_Error error = FT_ERR( Unknown_File_Format );
1939 char * file_names[FT_RACCESS_N_RULES];
1940 FT_Long offsets[FT_RACCESS_N_RULES];
1941 FT_Error errors[FT_RACCESS_N_RULES];
1942 FT_Bool is_darwin_vfs, vfs_rfork_has_no_font = FALSE; /* not tested */
1945 FT_Stream stream2 = 0;
1948 FT_Raccess_Guess( library, stream,
1949 args->pathname, file_names, offsets, errors );
1951 for ( i = 0; i < FT_RACCESS_N_RULES; i++ )
1953 is_darwin_vfs = ft_raccess_rule_by_darwin_vfs( library, i );
1954 if ( is_darwin_vfs && vfs_rfork_has_no_font )
1956 FT_TRACE3(( "Skip rule %d: darwin vfs resource fork"
1957 " is already checked and"
1958 " no font is found\n", i ));
1964 FT_TRACE3(( "Error[%d] has occurred in rule %d\n", errors[i], i ));
1968 args2.flags = FT_OPEN_PATHNAME;
1969 args2.pathname = file_names[i] ? file_names[i] : args->pathname;
1971 FT_TRACE3(( "Try rule %d: %s (offset=%d) ...",
1972 i, args2.pathname, offsets[i] ));
1974 error = FT_Stream_New( library, &args2, &stream2 );
1975 if ( is_darwin_vfs && FT_ERR_EQ( error, Cannot_Open_Stream ) )
1976 vfs_rfork_has_no_font = TRUE;
1980 FT_TRACE3(( "failed\n" ));
1984 error = IsMacResource( library, stream2, offsets[i],
1985 face_index, aface );
1986 FT_Stream_Free( stream2, 0 );
1988 FT_TRACE3(( "%s\n", error ? "failed": "successful" ));
1992 else if ( is_darwin_vfs )
1993 vfs_rfork_has_no_font = TRUE;
1996 for (i = 0; i < FT_RACCESS_N_RULES; i++)
1998 if ( file_names[i] )
1999 FT_FREE( file_names[i] );
2002 /* Caller (load_mac_face) requires FT_Err_Unknown_File_Format. */
2004 error = FT_ERR( Unknown_File_Format );
2009 #define FT_COMPONENT trace_objs
2014 /* Check for some macintosh formats without Carbon framework. */
2015 /* Is this a macbinary file? If so look at the resource fork. */
2016 /* Is this a mac dfont file? */
2017 /* Is this an old style resource fork? (in data) */
2018 /* Else call load_face_in_embedded_rfork to try extra rules */
2019 /* (defined in `ftrfork.c'). */
2022 load_mac_face( FT_Library library,
2026 const FT_Open_Args *args )
2032 error = IsMacBinary( library, stream, face_index, aface );
2033 if ( FT_ERR_EQ( error, Unknown_File_Format ) )
2037 #define FT_COMPONENT trace_raccess
2039 FT_TRACE3(( "Try as dfont: %s ...", args->pathname ));
2041 error = IsMacResource( library, stream, 0, face_index, aface );
2043 FT_TRACE3(( "%s\n", error ? "failed" : "successful" ));
2046 #define FT_COMPONENT trace_objs
2050 if ( ( FT_ERR_EQ( error, Unknown_File_Format ) ||
2051 FT_ERR_EQ( error, Invalid_Stream_Operation ) ) &&
2052 ( args->flags & FT_OPEN_PATHNAME ) )
2053 error = load_face_in_embedded_rfork( library, stream,
2054 face_index, aface, args );
2059 #endif /* !FT_MACINTOSH && FT_CONFIG_OPTION_MAC_FONTS */
2062 /* documentation is in freetype.h */
2064 FT_EXPORT_DEF( FT_Error )
2065 FT_Open_Face( FT_Library library,
2066 const FT_Open_Args* args,
2071 FT_Driver driver = NULL;
2072 FT_Memory memory = NULL;
2073 FT_Stream stream = NULL;
2074 FT_Face face = NULL;
2075 FT_ListNode node = NULL;
2076 FT_Bool external_stream;
2081 /* test for valid `library' delayed to `FT_Stream_New' */
2083 if ( ( !aface && face_index >= 0 ) || !args )
2084 return FT_THROW( Invalid_Argument );
2086 external_stream = FT_BOOL( ( args->flags & FT_OPEN_STREAM ) &&
2089 /* create input stream */
2090 error = FT_Stream_New( library, args, &stream );
2094 memory = library->memory;
2096 /* If the font driver is specified in the `args' structure, use */
2097 /* it. Otherwise, we scan the list of registered drivers. */
2098 if ( ( args->flags & FT_OPEN_DRIVER ) && args->driver )
2100 driver = FT_DRIVER( args->driver );
2102 /* not all modules are drivers, so check... */
2103 if ( FT_MODULE_IS_DRIVER( driver ) )
2105 FT_Int num_params = 0;
2106 FT_Parameter* params = 0;
2109 if ( args->flags & FT_OPEN_PARAMS )
2111 num_params = args->num_params;
2112 params = args->params;
2115 error = open_face( driver, &stream, external_stream, face_index,
2116 num_params, params, &face );
2121 error = FT_THROW( Invalid_Handle );
2123 FT_Stream_Free( stream, external_stream );
2128 error = FT_ERR( Missing_Module );
2130 /* check each font driver for an appropriate format */
2131 cur = library->modules;
2132 limit = cur + library->num_modules;
2134 for ( ; cur < limit; cur++ )
2136 /* not all modules are font drivers, so check... */
2137 if ( FT_MODULE_IS_DRIVER( cur[0] ) )
2139 FT_Int num_params = 0;
2140 FT_Parameter* params = 0;
2143 driver = FT_DRIVER( cur[0] );
2145 if ( args->flags & FT_OPEN_PARAMS )
2147 num_params = args->num_params;
2148 params = args->params;
2151 error = open_face( driver, &stream, external_stream, face_index,
2152 num_params, params, &face );
2156 #ifdef FT_CONFIG_OPTION_MAC_FONTS
2157 if ( ft_strcmp( cur[0]->clazz->module_name, "truetype" ) == 0 &&
2158 FT_ERR_EQ( error, Table_Missing ) )
2160 /* TrueType but essential tables are missing */
2161 if ( FT_Stream_Seek( stream, 0 ) )
2164 error = open_face_PS_from_sfnt_stream( library,
2172 FT_Stream_Free( stream, external_stream );
2178 if ( FT_ERR_NEQ( error, Unknown_File_Format ) )
2184 /* If we are on the mac, and we get an */
2185 /* FT_Err_Invalid_Stream_Operation it may be because we have an */
2186 /* empty data fork, so we need to check the resource fork. */
2187 if ( FT_ERR_NEQ( error, Cannot_Open_Stream ) &&
2188 FT_ERR_NEQ( error, Unknown_File_Format ) &&
2189 FT_ERR_NEQ( error, Invalid_Stream_Operation ) )
2192 #if !defined( FT_MACINTOSH ) && defined( FT_CONFIG_OPTION_MAC_FONTS )
2193 error = load_mac_face( library, stream, face_index, aface, args );
2196 /* We don't want to go to Success here. We've already done that. */
2197 /* On the other hand, if we succeeded we still need to close this */
2198 /* stream (we opened a different stream which extracted the */
2199 /* interesting information out of this stream here. That stream */
2200 /* will still be open and the face will point to it). */
2201 FT_Stream_Free( stream, external_stream );
2205 if ( FT_ERR_NEQ( error, Unknown_File_Format ) )
2207 #endif /* !FT_MACINTOSH && FT_CONFIG_OPTION_MAC_FONTS */
2209 /* no driver is able to handle this format */
2210 error = FT_THROW( Unknown_File_Format );
2213 FT_Stream_Free( stream, external_stream );
2218 FT_TRACE4(( "FT_Open_Face: New face object, adding to list\n" ));
2220 /* add the face object to its driver's list */
2221 if ( FT_NEW( node ) )
2225 /* don't assume driver is the same as face->driver, so use */
2226 /* face->driver instead. */
2227 FT_List_Add( &face->driver->faces_list, node );
2229 /* now allocate a glyph slot object for the face */
2230 FT_TRACE4(( "FT_Open_Face: Creating glyph slot\n" ));
2232 if ( face_index >= 0 )
2234 error = FT_New_GlyphSlot( face, NULL );
2238 /* finally, allocate a size object for the face */
2243 FT_TRACE4(( "FT_Open_Face: Creating size object\n" ));
2245 error = FT_New_Size( face, &size );
2255 if ( FT_IS_SCALABLE( face ) )
2257 if ( face->height < 0 )
2258 face->height = (FT_Short)-face->height;
2260 if ( !FT_HAS_VERTICAL( face ) )
2261 face->max_advance_height = (FT_Short)face->height;
2264 if ( FT_HAS_FIXED_SIZES( face ) )
2269 for ( i = 0; i < face->num_fixed_sizes; i++ )
2271 FT_Bitmap_Size* bsize = face->available_sizes + i;
2274 if ( bsize->height < 0 )
2275 bsize->height = (FT_Short)-bsize->height;
2276 if ( bsize->x_ppem < 0 )
2277 bsize->x_ppem = (FT_Short)-bsize->x_ppem;
2278 if ( bsize->y_ppem < 0 )
2279 bsize->y_ppem = -bsize->y_ppem;
2283 /* initialize internal face data */
2285 FT_Face_Internal internal = face->internal;
2288 internal->transform_matrix.xx = 0x10000L;
2289 internal->transform_matrix.xy = 0;
2290 internal->transform_matrix.yx = 0;
2291 internal->transform_matrix.yy = 0x10000L;
2293 internal->transform_delta.x = 0;
2294 internal->transform_delta.y = 0;
2296 internal->refcount = 1;
2302 FT_Done_Face( face );
2308 FT_Done_Face( face ); /* face must be in the driver's list */
2310 destroy_face( memory, face, driver );
2313 FT_TRACE4(( "FT_Open_Face: Return %d\n", error ));
2319 /* documentation is in freetype.h */
2321 FT_EXPORT_DEF( FT_Error )
2322 FT_Attach_File( FT_Face face,
2323 const char* filepathname )
2328 /* test for valid `face' delayed to `FT_Attach_Stream' */
2330 if ( !filepathname )
2331 return FT_THROW( Invalid_Argument );
2334 open.flags = FT_OPEN_PATHNAME;
2335 open.pathname = (char*)filepathname;
2337 return FT_Attach_Stream( face, &open );
2341 /* documentation is in freetype.h */
2343 FT_EXPORT_DEF( FT_Error )
2344 FT_Attach_Stream( FT_Face face,
2345 FT_Open_Args* parameters )
2351 FT_Driver_Class clazz;
2354 /* test for valid `parameters' delayed to `FT_Stream_New' */
2357 return FT_THROW( Invalid_Face_Handle );
2359 driver = face->driver;
2361 return FT_THROW( Invalid_Driver_Handle );
2363 error = FT_Stream_New( driver->root.library, parameters, &stream );
2367 /* we implement FT_Attach_Stream in each driver through the */
2368 /* `attach_file' interface */
2370 error = FT_ERR( Unimplemented_Feature );
2371 clazz = driver->clazz;
2372 if ( clazz->attach_file )
2373 error = clazz->attach_file( face, stream );
2375 /* close the attached stream */
2376 FT_Stream_Free( stream,
2377 (FT_Bool)( parameters->stream &&
2378 ( parameters->flags & FT_OPEN_STREAM ) ) );
2385 /* documentation is in freetype.h */
2387 FT_EXPORT_DEF( FT_Error )
2388 FT_Reference_Face( FT_Face face )
2391 return FT_THROW( Invalid_Face_Handle );
2393 face->internal->refcount++;
2399 /* documentation is in freetype.h */
2401 FT_EXPORT_DEF( FT_Error )
2402 FT_Done_Face( FT_Face face )
2410 error = FT_ERR( Invalid_Face_Handle );
2411 if ( face && face->driver )
2413 face->internal->refcount--;
2414 if ( face->internal->refcount > 0 )
2418 driver = face->driver;
2419 memory = driver->root.memory;
2421 /* find face in driver's list */
2422 node = FT_List_Find( &driver->faces_list, face );
2425 /* remove face object from the driver's list */
2426 FT_List_Remove( &driver->faces_list, node );
2429 /* now destroy the object proper */
2430 destroy_face( memory, face, driver );
2440 /* documentation is in ftobjs.h */
2442 FT_EXPORT_DEF( FT_Error )
2443 FT_New_Size( FT_Face face,
2449 FT_Driver_Class clazz;
2452 FT_ListNode node = 0;
2456 return FT_THROW( Invalid_Face_Handle );
2459 return FT_THROW( Invalid_Argument );
2461 if ( !face->driver )
2462 return FT_THROW( Invalid_Driver_Handle );
2466 driver = face->driver;
2467 clazz = driver->clazz;
2468 memory = face->memory;
2470 /* Allocate new size object and perform basic initialisation */
2471 if ( FT_ALLOC( size, clazz->size_object_size ) || FT_NEW( node ) )
2476 /* for now, do not use any internal fields in size objects */
2479 if ( clazz->init_size )
2480 error = clazz->init_size( size );
2482 /* in case of success, add to the face's list */
2487 FT_List_Add( &face->sizes_list, node );
2501 /* documentation is in ftobjs.h */
2503 FT_EXPORT_DEF( FT_Error )
2504 FT_Done_Size( FT_Size size )
2514 return FT_THROW( Invalid_Size_Handle );
2518 return FT_THROW( Invalid_Face_Handle );
2520 driver = face->driver;
2522 return FT_THROW( Invalid_Driver_Handle );
2524 memory = driver->root.memory;
2527 node = FT_List_Find( &face->sizes_list, size );
2530 FT_List_Remove( &face->sizes_list, node );
2533 if ( face->size == size )
2536 if ( face->sizes_list.head )
2537 face->size = (FT_Size)(face->sizes_list.head->data);
2540 destroy_size( memory, size, driver );
2543 error = FT_THROW( Invalid_Size_Handle );
2549 /* documentation is in ftobjs.h */
2551 FT_BASE_DEF( FT_Error )
2552 FT_Match_Size( FT_Face face,
2553 FT_Size_Request req,
2554 FT_Bool ignore_width,
2555 FT_ULong* size_index )
2561 if ( !FT_HAS_FIXED_SIZES( face ) )
2562 return FT_THROW( Invalid_Face_Handle );
2564 /* FT_Bitmap_Size doesn't provide enough info... */
2565 if ( req->type != FT_SIZE_REQUEST_TYPE_NOMINAL )
2566 return FT_THROW( Unimplemented_Feature );
2568 w = FT_REQUEST_WIDTH ( req );
2569 h = FT_REQUEST_HEIGHT( req );
2571 if ( req->width && !req->height )
2573 else if ( !req->width && req->height )
2576 w = FT_PIX_ROUND( w );
2577 h = FT_PIX_ROUND( h );
2579 for ( i = 0; i < face->num_fixed_sizes; i++ )
2581 FT_Bitmap_Size* bsize = face->available_sizes + i;
2584 if ( h != FT_PIX_ROUND( bsize->y_ppem ) )
2587 if ( w == FT_PIX_ROUND( bsize->x_ppem ) || ignore_width )
2589 FT_TRACE3(( "FT_Match_Size: bitmap strike %d matches\n", i ));
2592 *size_index = (FT_ULong)i;
2598 return FT_THROW( Invalid_Pixel_Size );
2602 /* documentation is in ftobjs.h */
2605 ft_synthesize_vertical_metrics( FT_Glyph_Metrics* metrics,
2608 FT_Pos height = metrics->height;
2611 /* compensate for glyph with bbox above/below the baseline */
2612 if ( metrics->horiBearingY < 0 )
2614 if ( height < metrics->horiBearingY )
2615 height = metrics->horiBearingY;
2617 else if ( metrics->horiBearingY > 0 )
2618 height -= metrics->horiBearingY;
2620 /* the factor 1.2 is a heuristical value */
2622 advance = height * 12 / 10;
2624 metrics->vertBearingX = metrics->horiBearingX - metrics->horiAdvance / 2;
2625 metrics->vertBearingY = ( advance - height ) / 2;
2626 metrics->vertAdvance = advance;
2631 ft_recompute_scaled_metrics( FT_Face face,
2632 FT_Size_Metrics* metrics )
2634 /* Compute root ascender, descender, test height, and max_advance */
2636 #ifdef GRID_FIT_METRICS
2637 metrics->ascender = FT_PIX_CEIL( FT_MulFix( face->ascender,
2638 metrics->y_scale ) );
2640 metrics->descender = FT_PIX_FLOOR( FT_MulFix( face->descender,
2641 metrics->y_scale ) );
2643 metrics->height = FT_PIX_ROUND( FT_MulFix( face->height,
2644 metrics->y_scale ) );
2646 metrics->max_advance = FT_PIX_ROUND( FT_MulFix( face->max_advance_width,
2647 metrics->x_scale ) );
2648 #else /* !GRID_FIT_METRICS */
2649 metrics->ascender = FT_MulFix( face->ascender,
2652 metrics->descender = FT_MulFix( face->descender,
2655 metrics->height = FT_MulFix( face->height,
2658 metrics->max_advance = FT_MulFix( face->max_advance_width,
2660 #endif /* !GRID_FIT_METRICS */
2665 FT_Select_Metrics( FT_Face face,
2666 FT_ULong strike_index )
2668 FT_Size_Metrics* metrics;
2669 FT_Bitmap_Size* bsize;
2672 metrics = &face->size->metrics;
2673 bsize = face->available_sizes + strike_index;
2675 metrics->x_ppem = (FT_UShort)( ( bsize->x_ppem + 32 ) >> 6 );
2676 metrics->y_ppem = (FT_UShort)( ( bsize->y_ppem + 32 ) >> 6 );
2678 if ( FT_IS_SCALABLE( face ) )
2680 metrics->x_scale = FT_DivFix( bsize->x_ppem,
2681 face->units_per_EM );
2682 metrics->y_scale = FT_DivFix( bsize->y_ppem,
2683 face->units_per_EM );
2685 ft_recompute_scaled_metrics( face, metrics );
2689 metrics->x_scale = 1L << 16;
2690 metrics->y_scale = 1L << 16;
2691 metrics->ascender = bsize->y_ppem;
2692 metrics->descender = 0;
2693 metrics->height = bsize->height << 6;
2694 metrics->max_advance = bsize->x_ppem;
2697 FT_TRACE5(( "FT_Select_Metrics:\n" ));
2698 FT_TRACE5(( " x scale: %d (%f)\n",
2699 metrics->x_scale, metrics->x_scale / 65536.0 ));
2700 FT_TRACE5(( " y scale: %d (%f)\n",
2701 metrics->y_scale, metrics->y_scale / 65536.0 ));
2702 FT_TRACE5(( " ascender: %f\n", metrics->ascender / 64.0 ));
2703 FT_TRACE5(( " descender: %f\n", metrics->descender / 64.0 ));
2704 FT_TRACE5(( " height: %f\n", metrics->height / 64.0 ));
2705 FT_TRACE5(( " max advance: %f\n", metrics->max_advance / 64.0 ));
2706 FT_TRACE5(( " x ppem: %d\n", metrics->x_ppem ));
2707 FT_TRACE5(( " y ppem: %d\n", metrics->y_ppem ));
2712 FT_Request_Metrics( FT_Face face,
2713 FT_Size_Request req )
2715 FT_Size_Metrics* metrics;
2718 metrics = &face->size->metrics;
2720 if ( FT_IS_SCALABLE( face ) )
2722 FT_Long w = 0, h = 0, scaled_w = 0, scaled_h = 0;
2725 switch ( req->type )
2727 case FT_SIZE_REQUEST_TYPE_NOMINAL:
2728 w = h = face->units_per_EM;
2731 case FT_SIZE_REQUEST_TYPE_REAL_DIM:
2732 w = h = face->ascender - face->descender;
2735 case FT_SIZE_REQUEST_TYPE_BBOX:
2736 w = face->bbox.xMax - face->bbox.xMin;
2737 h = face->bbox.yMax - face->bbox.yMin;
2740 case FT_SIZE_REQUEST_TYPE_CELL:
2741 w = face->max_advance_width;
2742 h = face->ascender - face->descender;
2745 case FT_SIZE_REQUEST_TYPE_SCALES:
2746 metrics->x_scale = (FT_Fixed)req->width;
2747 metrics->y_scale = (FT_Fixed)req->height;
2748 if ( !metrics->x_scale )
2749 metrics->x_scale = metrics->y_scale;
2750 else if ( !metrics->y_scale )
2751 metrics->y_scale = metrics->x_scale;
2752 goto Calculate_Ppem;
2754 case FT_SIZE_REQUEST_TYPE_MAX:
2758 /* to be on the safe side */
2765 scaled_w = FT_REQUEST_WIDTH ( req );
2766 scaled_h = FT_REQUEST_HEIGHT( req );
2768 /* determine scales */
2771 metrics->x_scale = FT_DivFix( scaled_w, w );
2775 metrics->y_scale = FT_DivFix( scaled_h, h );
2777 if ( req->type == FT_SIZE_REQUEST_TYPE_CELL )
2779 if ( metrics->y_scale > metrics->x_scale )
2780 metrics->y_scale = metrics->x_scale;
2782 metrics->x_scale = metrics->y_scale;
2787 metrics->y_scale = metrics->x_scale;
2788 scaled_h = FT_MulDiv( scaled_w, h, w );
2793 metrics->x_scale = metrics->y_scale = FT_DivFix( scaled_h, h );
2794 scaled_w = FT_MulDiv( scaled_h, w, h );
2798 /* calculate the ppems */
2799 if ( req->type != FT_SIZE_REQUEST_TYPE_NOMINAL )
2801 scaled_w = FT_MulFix( face->units_per_EM, metrics->x_scale );
2802 scaled_h = FT_MulFix( face->units_per_EM, metrics->y_scale );
2805 metrics->x_ppem = (FT_UShort)( ( scaled_w + 32 ) >> 6 );
2806 metrics->y_ppem = (FT_UShort)( ( scaled_h + 32 ) >> 6 );
2808 ft_recompute_scaled_metrics( face, metrics );
2813 metrics->x_scale = 1L << 16;
2814 metrics->y_scale = 1L << 16;
2817 FT_TRACE5(( "FT_Request_Metrics:\n" ));
2818 FT_TRACE5(( " x scale: %d (%f)\n",
2819 metrics->x_scale, metrics->x_scale / 65536.0 ));
2820 FT_TRACE5(( " y scale: %d (%f)\n",
2821 metrics->y_scale, metrics->y_scale / 65536.0 ));
2822 FT_TRACE5(( " ascender: %f\n", metrics->ascender / 64.0 ));
2823 FT_TRACE5(( " descender: %f\n", metrics->descender / 64.0 ));
2824 FT_TRACE5(( " height: %f\n", metrics->height / 64.0 ));
2825 FT_TRACE5(( " max advance: %f\n", metrics->max_advance / 64.0 ));
2826 FT_TRACE5(( " x ppem: %d\n", metrics->x_ppem ));
2827 FT_TRACE5(( " y ppem: %d\n", metrics->y_ppem ));
2831 /* documentation is in freetype.h */
2833 FT_EXPORT_DEF( FT_Error )
2834 FT_Select_Size( FT_Face face,
2835 FT_Int strike_index )
2837 FT_Driver_Class clazz;
2840 if ( !face || !FT_HAS_FIXED_SIZES( face ) )
2841 return FT_THROW( Invalid_Face_Handle );
2843 if ( strike_index < 0 || strike_index >= face->num_fixed_sizes )
2844 return FT_THROW( Invalid_Argument );
2846 clazz = face->driver->clazz;
2848 if ( clazz->select_size )
2853 error = clazz->select_size( face->size, (FT_ULong)strike_index );
2855 #ifdef FT_DEBUG_LEVEL_TRACE
2857 FT_Size_Metrics* metrics = &face->size->metrics;
2860 FT_TRACE5(( "FT_Select_Size (font driver's `select_size'):\n" ));
2861 FT_TRACE5(( " x scale: %d (%f)\n",
2862 metrics->x_scale, metrics->x_scale / 65536.0 ));
2863 FT_TRACE5(( " y scale: %d (%f)\n",
2864 metrics->y_scale, metrics->y_scale / 65536.0 ));
2865 FT_TRACE5(( " ascender: %f\n", metrics->ascender / 64.0 ));
2866 FT_TRACE5(( " descender: %f\n", metrics->descender / 64.0 ));
2867 FT_TRACE5(( " height: %f\n", metrics->height / 64.0 ));
2868 FT_TRACE5(( " max advance: %f\n", metrics->max_advance / 64.0 ));
2869 FT_TRACE5(( " x ppem: %d\n", metrics->x_ppem ));
2870 FT_TRACE5(( " y ppem: %d\n", metrics->y_ppem ));
2877 FT_Select_Metrics( face, (FT_ULong)strike_index );
2883 /* documentation is in freetype.h */
2885 FT_EXPORT_DEF( FT_Error )
2886 FT_Request_Size( FT_Face face,
2887 FT_Size_Request req )
2889 FT_Driver_Class clazz;
2890 FT_ULong strike_index;
2894 return FT_THROW( Invalid_Face_Handle );
2896 if ( !req || req->width < 0 || req->height < 0 ||
2897 req->type >= FT_SIZE_REQUEST_TYPE_MAX )
2898 return FT_THROW( Invalid_Argument );
2900 clazz = face->driver->clazz;
2902 if ( clazz->request_size )
2907 error = clazz->request_size( face->size, req );
2909 #ifdef FT_DEBUG_LEVEL_TRACE
2911 FT_Size_Metrics* metrics = &face->size->metrics;
2914 FT_TRACE5(( "FT_Request_Size (font driver's `request_size'):\n" ));
2915 FT_TRACE5(( " x scale: %d (%f)\n",
2916 metrics->x_scale, metrics->x_scale / 65536.0 ));
2917 FT_TRACE5(( " y scale: %d (%f)\n",
2918 metrics->y_scale, metrics->y_scale / 65536.0 ));
2919 FT_TRACE5(( " ascender: %f\n", metrics->ascender / 64.0 ));
2920 FT_TRACE5(( " descender: %f\n", metrics->descender / 64.0 ));
2921 FT_TRACE5(( " height: %f\n", metrics->height / 64.0 ));
2922 FT_TRACE5(( " max advance: %f\n", metrics->max_advance / 64.0 ));
2923 FT_TRACE5(( " x ppem: %d\n", metrics->x_ppem ));
2924 FT_TRACE5(( " y ppem: %d\n", metrics->y_ppem ));
2932 * The reason that a driver doesn't have `request_size' defined is
2933 * either that the scaling here suffices or that the supported formats
2934 * are bitmap-only and size matching is not implemented.
2936 * In the latter case, a simple size matching is done.
2938 if ( !FT_IS_SCALABLE( face ) && FT_HAS_FIXED_SIZES( face ) )
2943 error = FT_Match_Size( face, req, 0, &strike_index );
2947 return FT_Select_Size( face, (FT_Int)strike_index );
2950 FT_Request_Metrics( face, req );
2956 /* documentation is in freetype.h */
2958 FT_EXPORT_DEF( FT_Error )
2959 FT_Set_Char_Size( FT_Face face,
2960 FT_F26Dot6 char_width,
2961 FT_F26Dot6 char_height,
2962 FT_UInt horz_resolution,
2963 FT_UInt vert_resolution )
2965 FT_Size_RequestRec req;
2968 /* check of `face' delayed to `FT_Request_Size' */
2971 char_width = char_height;
2972 else if ( !char_height )
2973 char_height = char_width;
2975 if ( !horz_resolution )
2976 horz_resolution = vert_resolution;
2977 else if ( !vert_resolution )
2978 vert_resolution = horz_resolution;
2980 if ( char_width < 1 * 64 )
2981 char_width = 1 * 64;
2982 if ( char_height < 1 * 64 )
2983 char_height = 1 * 64;
2985 if ( !horz_resolution )
2986 horz_resolution = vert_resolution = 72;
2988 req.type = FT_SIZE_REQUEST_TYPE_NOMINAL;
2989 req.width = char_width;
2990 req.height = char_height;
2991 req.horiResolution = horz_resolution;
2992 req.vertResolution = vert_resolution;
2994 return FT_Request_Size( face, &req );
2998 /* documentation is in freetype.h */
3000 FT_EXPORT_DEF( FT_Error )
3001 FT_Set_Pixel_Sizes( FT_Face face,
3002 FT_UInt pixel_width,
3003 FT_UInt pixel_height )
3005 FT_Size_RequestRec req;
3008 /* check of `face' delayed to `FT_Request_Size' */
3010 if ( pixel_width == 0 )
3011 pixel_width = pixel_height;
3012 else if ( pixel_height == 0 )
3013 pixel_height = pixel_width;
3015 if ( pixel_width < 1 )
3017 if ( pixel_height < 1 )
3020 /* use `>=' to avoid potential compiler warning on 16bit platforms */
3021 if ( pixel_width >= 0xFFFFU )
3022 pixel_width = 0xFFFFU;
3023 if ( pixel_height >= 0xFFFFU )
3024 pixel_height = 0xFFFFU;
3026 req.type = FT_SIZE_REQUEST_TYPE_NOMINAL;
3027 req.width = pixel_width << 6;
3028 req.height = pixel_height << 6;
3029 req.horiResolution = 0;
3030 req.vertResolution = 0;
3032 return FT_Request_Size( face, &req );
3036 /* documentation is in freetype.h */
3038 FT_EXPORT_DEF( FT_Error )
3039 FT_Get_Kerning( FT_Face face,
3041 FT_UInt right_glyph,
3043 FT_Vector *akerning )
3045 FT_Error error = FT_Err_Ok;
3050 return FT_THROW( Invalid_Face_Handle );
3053 return FT_THROW( Invalid_Argument );
3055 driver = face->driver;
3060 if ( driver->clazz->get_kerning )
3062 error = driver->clazz->get_kerning( face,
3068 if ( kern_mode != FT_KERNING_UNSCALED )
3070 akerning->x = FT_MulFix( akerning->x, face->size->metrics.x_scale );
3071 akerning->y = FT_MulFix( akerning->y, face->size->metrics.y_scale );
3073 if ( kern_mode != FT_KERNING_UNFITTED )
3075 /* we scale down kerning values for small ppem values */
3076 /* to avoid that rounding makes them too big. */
3077 /* `25' has been determined heuristically. */
3078 if ( face->size->metrics.x_ppem < 25 )
3079 akerning->x = FT_MulDiv( akerning->x,
3080 face->size->metrics.x_ppem, 25 );
3081 if ( face->size->metrics.y_ppem < 25 )
3082 akerning->y = FT_MulDiv( akerning->y,
3083 face->size->metrics.y_ppem, 25 );
3085 akerning->x = FT_PIX_ROUND( akerning->x );
3086 akerning->y = FT_PIX_ROUND( akerning->y );
3096 /* documentation is in freetype.h */
3098 FT_EXPORT_DEF( FT_Error )
3099 FT_Get_Track_Kerning( FT_Face face,
3100 FT_Fixed point_size,
3102 FT_Fixed* akerning )
3104 FT_Service_Kerning service;
3105 FT_Error error = FT_Err_Ok;
3109 return FT_THROW( Invalid_Face_Handle );
3112 return FT_THROW( Invalid_Argument );
3114 FT_FACE_FIND_SERVICE( face, service, KERNING );
3116 return FT_THROW( Unimplemented_Feature );
3118 error = service->get_track( face,
3127 /* documentation is in freetype.h */
3129 FT_EXPORT_DEF( FT_Error )
3130 FT_Select_Charmap( FT_Face face,
3131 FT_Encoding encoding )
3138 return FT_THROW( Invalid_Face_Handle );
3140 if ( encoding == FT_ENCODING_NONE )
3141 return FT_THROW( Invalid_Argument );
3143 /* FT_ENCODING_UNICODE is special. We try to find the `best' Unicode */
3144 /* charmap available, i.e., one with UCS-4 characters, if possible. */
3146 /* This is done by find_unicode_charmap() above, to share code. */
3147 if ( encoding == FT_ENCODING_UNICODE )
3148 return find_unicode_charmap( face );
3150 cur = face->charmaps;
3152 return FT_THROW( Invalid_CharMap_Handle );
3154 limit = cur + face->num_charmaps;
3156 for ( ; cur < limit; cur++ )
3158 if ( cur[0]->encoding == encoding )
3160 face->charmap = cur[0];
3165 return FT_THROW( Invalid_Argument );
3169 /* documentation is in freetype.h */
3171 FT_EXPORT_DEF( FT_Error )
3172 FT_Set_Charmap( FT_Face face,
3173 FT_CharMap charmap )
3180 return FT_THROW( Invalid_Face_Handle );
3182 cur = face->charmaps;
3183 if ( !cur || !charmap )
3184 return FT_THROW( Invalid_CharMap_Handle );
3186 if ( FT_Get_CMap_Format( charmap ) == 14 )
3187 return FT_THROW( Invalid_Argument );
3189 limit = cur + face->num_charmaps;
3191 for ( ; cur < limit; cur++ )
3193 if ( cur[0] == charmap )
3195 face->charmap = cur[0];
3200 return FT_THROW( Invalid_Argument );
3204 /* documentation is in freetype.h */
3206 FT_EXPORT_DEF( FT_Int )
3207 FT_Get_Charmap_Index( FT_CharMap charmap )
3212 if ( !charmap || !charmap->face )
3215 for ( i = 0; i < charmap->face->num_charmaps; i++ )
3216 if ( charmap->face->charmaps[i] == charmap )
3219 FT_ASSERT( i < charmap->face->num_charmaps );
3226 ft_cmap_done_internal( FT_CMap cmap )
3228 FT_CMap_Class clazz = cmap->clazz;
3229 FT_Face face = cmap->charmap.face;
3230 FT_Memory memory = FT_FACE_MEMORY( face );
3234 clazz->done( cmap );
3241 FT_CMap_Done( FT_CMap cmap )
3245 FT_Face face = cmap->charmap.face;
3246 FT_Memory memory = FT_FACE_MEMORY( face );
3251 for ( i = 0; i < face->num_charmaps; i++ )
3253 if ( (FT_CMap)face->charmaps[i] == cmap )
3255 FT_CharMap last_charmap = face->charmaps[face->num_charmaps - 1];
3258 if ( FT_RENEW_ARRAY( face->charmaps,
3260 face->num_charmaps - 1 ) )
3263 /* remove it from our list of charmaps */
3264 for ( j = i + 1; j < face->num_charmaps; j++ )
3266 if ( j == face->num_charmaps - 1 )
3267 face->charmaps[j - 1] = last_charmap;
3269 face->charmaps[j - 1] = face->charmaps[j];
3272 face->num_charmaps--;
3274 if ( (FT_CMap)face->charmap == cmap )
3275 face->charmap = NULL;
3277 ft_cmap_done_internal( cmap );
3286 FT_BASE_DEF( FT_Error )
3287 FT_CMap_New( FT_CMap_Class clazz,
3288 FT_Pointer init_data,
3292 FT_Error error = FT_Err_Ok;
3295 FT_CMap cmap = NULL;
3298 if ( clazz == NULL || charmap == NULL || charmap->face == NULL )
3299 return FT_THROW( Invalid_Argument );
3301 face = charmap->face;
3302 memory = FT_FACE_MEMORY( face );
3304 if ( !FT_ALLOC( cmap, clazz->size ) )
3306 cmap->charmap = *charmap;
3307 cmap->clazz = clazz;
3311 error = clazz->init( cmap, init_data );
3316 /* add it to our list of charmaps */
3317 if ( FT_RENEW_ARRAY( face->charmaps,
3319 face->num_charmaps + 1 ) )
3322 face->charmaps[face->num_charmaps++] = (FT_CharMap)cmap;
3332 ft_cmap_done_internal( cmap );
3338 /* documentation is in freetype.h */
3340 FT_EXPORT_DEF( FT_UInt )
3341 FT_Get_Char_Index( FT_Face face,
3347 if ( face && face->charmap )
3349 FT_CMap cmap = FT_CMAP( face->charmap );
3352 if ( charcode > 0xFFFFFFFFUL )
3354 FT_TRACE1(( "FT_Get_Char_Index: too large charcode" ));
3355 FT_TRACE1(( " 0x%x is truncated\n", charcode ));
3357 result = cmap->clazz->char_index( cmap, (FT_UInt32)charcode );
3363 /* documentation is in freetype.h */
3365 FT_EXPORT_DEF( FT_ULong )
3366 FT_Get_First_Char( FT_Face face,
3369 FT_ULong result = 0;
3373 /* only do something if we have a charmap, and we have glyphs at all */
3374 if ( face && face->charmap && face->num_glyphs )
3376 gindex = FT_Get_Char_Index( face, 0 );
3377 if ( gindex == 0 || gindex >= (FT_UInt)face->num_glyphs )
3378 result = FT_Get_Next_Char( face, 0, &gindex );
3388 /* documentation is in freetype.h */
3390 FT_EXPORT_DEF( FT_ULong )
3391 FT_Get_Next_Char( FT_Face face,
3395 FT_ULong result = 0;
3399 if ( face && face->charmap && face->num_glyphs )
3401 FT_UInt32 code = (FT_UInt32)charcode;
3402 FT_CMap cmap = FT_CMAP( face->charmap );
3407 gindex = cmap->clazz->char_next( cmap, &code );
3409 } while ( gindex >= (FT_UInt)face->num_glyphs );
3411 result = ( gindex == 0 ) ? 0 : code;
3421 /* documentation is in freetype.h */
3423 FT_EXPORT_DEF( FT_UInt )
3424 FT_Face_GetCharVariantIndex( FT_Face face,
3426 FT_ULong variantSelector )
3433 face->charmap->encoding == FT_ENCODING_UNICODE )
3435 FT_CharMap charmap = find_variant_selector_charmap( face );
3436 FT_CMap ucmap = FT_CMAP( face->charmap );
3439 if ( charmap != NULL )
3441 FT_CMap vcmap = FT_CMAP( charmap );
3444 if ( charcode > 0xFFFFFFFFUL )
3446 FT_TRACE1(( "FT_Get_Char_Index: too large charcode" ));
3447 FT_TRACE1(( " 0x%x is truncated\n", charcode ));
3449 if ( variantSelector > 0xFFFFFFFFUL )
3451 FT_TRACE1(( "FT_Get_Char_Index: too large variantSelector" ));
3452 FT_TRACE1(( " 0x%x is truncated\n", variantSelector ));
3455 result = vcmap->clazz->char_var_index( vcmap, ucmap,
3456 (FT_UInt32)charcode,
3457 (FT_UInt32)variantSelector );
3465 /* documentation is in freetype.h */
3467 FT_EXPORT_DEF( FT_Int )
3468 FT_Face_GetCharVariantIsDefault( FT_Face face,
3470 FT_ULong variantSelector )
3477 FT_CharMap charmap = find_variant_selector_charmap( face );
3480 if ( charmap != NULL )
3482 FT_CMap vcmap = FT_CMAP( charmap );
3485 if ( charcode > 0xFFFFFFFFUL )
3487 FT_TRACE1(( "FT_Get_Char_Index: too large charcode" ));
3488 FT_TRACE1(( " 0x%x is truncated\n", charcode ));
3490 if ( variantSelector > 0xFFFFFFFFUL )
3492 FT_TRACE1(( "FT_Get_Char_Index: too large variantSelector" ));
3493 FT_TRACE1(( " 0x%x is truncated\n", variantSelector ));
3496 result = vcmap->clazz->char_var_default( vcmap,
3497 (FT_UInt32)charcode,
3498 (FT_UInt32)variantSelector );
3506 /* documentation is in freetype.h */
3508 FT_EXPORT_DEF( FT_UInt32* )
3509 FT_Face_GetVariantSelectors( FT_Face face )
3511 FT_UInt32 *result = NULL;
3516 FT_CharMap charmap = find_variant_selector_charmap( face );
3519 if ( charmap != NULL )
3521 FT_CMap vcmap = FT_CMAP( charmap );
3522 FT_Memory memory = FT_FACE_MEMORY( face );
3525 result = vcmap->clazz->variant_list( vcmap, memory );
3533 /* documentation is in freetype.h */
3535 FT_EXPORT_DEF( FT_UInt32* )
3536 FT_Face_GetVariantsOfChar( FT_Face face,
3539 FT_UInt32 *result = NULL;
3544 FT_CharMap charmap = find_variant_selector_charmap( face );
3547 if ( charmap != NULL )
3549 FT_CMap vcmap = FT_CMAP( charmap );
3550 FT_Memory memory = FT_FACE_MEMORY( face );
3553 if ( charcode > 0xFFFFFFFFUL )
3555 FT_TRACE1(( "FT_Get_Char_Index: too large charcode" ));
3556 FT_TRACE1(( " 0x%x is truncated\n", charcode ));
3559 result = vcmap->clazz->charvariant_list( vcmap, memory,
3560 (FT_UInt32)charcode );
3567 /* documentation is in freetype.h */
3569 FT_EXPORT_DEF( FT_UInt32* )
3570 FT_Face_GetCharsOfVariant( FT_Face face,
3571 FT_ULong variantSelector )
3573 FT_UInt32 *result = NULL;
3578 FT_CharMap charmap = find_variant_selector_charmap( face );
3581 if ( charmap != NULL )
3583 FT_CMap vcmap = FT_CMAP( charmap );
3584 FT_Memory memory = FT_FACE_MEMORY( face );
3587 if ( variantSelector > 0xFFFFFFFFUL )
3589 FT_TRACE1(( "FT_Get_Char_Index: too large variantSelector" ));
3590 FT_TRACE1(( " 0x%x is truncated\n", variantSelector ));
3593 result = vcmap->clazz->variantchar_list( vcmap, memory,
3594 (FT_UInt32)variantSelector );
3602 /* documentation is in freetype.h */
3604 FT_EXPORT_DEF( FT_UInt )
3605 FT_Get_Name_Index( FT_Face face,
3606 FT_String* glyph_name )
3612 FT_HAS_GLYPH_NAMES( face ) &&
3615 FT_Service_GlyphDict service;
3618 FT_FACE_LOOKUP_SERVICE( face,
3622 if ( service && service->name_index )
3623 result = service->name_index( face, glyph_name );
3630 /* documentation is in freetype.h */
3632 FT_EXPORT_DEF( FT_Error )
3633 FT_Get_Glyph_Name( FT_Face face,
3634 FT_UInt glyph_index,
3636 FT_UInt buffer_max )
3639 FT_Service_GlyphDict service;
3643 return FT_THROW( Invalid_Face_Handle );
3645 if ( !buffer || buffer_max == 0 )
3646 return FT_THROW( Invalid_Argument );
3648 /* clean up buffer */
3649 ((FT_Byte*)buffer)[0] = '\0';
3651 if ( (FT_Long)glyph_index >= face->num_glyphs )
3652 return FT_THROW( Invalid_Glyph_Index );
3654 if ( !FT_HAS_GLYPH_NAMES( face ) )
3655 return FT_THROW( Invalid_Argument );
3657 FT_FACE_LOOKUP_SERVICE( face, service, GLYPH_DICT );
3658 if ( service && service->get_name )
3659 error = service->get_name( face, glyph_index, buffer, buffer_max );
3661 error = FT_THROW( Invalid_Argument );
3667 /* documentation is in freetype.h */
3669 FT_EXPORT_DEF( const char* )
3670 FT_Get_Postscript_Name( FT_Face face )
3672 const char* result = NULL;
3680 FT_Service_PsFontName service;
3683 FT_FACE_LOOKUP_SERVICE( face,
3685 POSTSCRIPT_FONT_NAME );
3687 if ( service && service->get_ps_font_name )
3688 result = service->get_ps_font_name( face );
3696 /* documentation is in tttables.h */
3698 FT_EXPORT_DEF( void* )
3699 FT_Get_Sfnt_Table( FT_Face face,
3703 FT_Service_SFNT_Table service;
3706 if ( face && FT_IS_SFNT( face ) )
3708 FT_FACE_FIND_SERVICE( face, service, SFNT_TABLE );
3709 if ( service != NULL )
3710 table = service->get_table( face, tag );
3717 /* documentation is in tttables.h */
3719 FT_EXPORT_DEF( FT_Error )
3720 FT_Load_Sfnt_Table( FT_Face face,
3726 FT_Service_SFNT_Table service;
3729 if ( !face || !FT_IS_SFNT( face ) )
3730 return FT_THROW( Invalid_Face_Handle );
3732 FT_FACE_FIND_SERVICE( face, service, SFNT_TABLE );
3733 if ( service == NULL )
3734 return FT_THROW( Unimplemented_Feature );
3736 return service->load_table( face, tag, offset, buffer, length );
3740 /* documentation is in tttables.h */
3742 FT_EXPORT_DEF( FT_Error )
3743 FT_Sfnt_Table_Info( FT_Face face,
3744 FT_UInt table_index,
3748 FT_Service_SFNT_Table service;
3752 /* test for valid `length' delayed to `service->table_info' */
3754 if ( !face || !FT_IS_SFNT( face ) )
3755 return FT_THROW( Invalid_Face_Handle );
3757 FT_FACE_FIND_SERVICE( face, service, SFNT_TABLE );
3758 if ( service == NULL )
3759 return FT_THROW( Unimplemented_Feature );
3761 return service->table_info( face, table_index, tag, &offset, length );
3765 /* documentation is in tttables.h */
3767 FT_EXPORT_DEF( FT_ULong )
3768 FT_Get_CMap_Language_ID( FT_CharMap charmap )
3770 FT_Service_TTCMaps service;
3772 TT_CMapInfo cmap_info;
3775 if ( !charmap || !charmap->face )
3778 face = charmap->face;
3779 FT_FACE_FIND_SERVICE( face, service, TT_CMAP );
3780 if ( service == NULL )
3782 if ( service->get_cmap_info( charmap, &cmap_info ))
3785 return cmap_info.language;
3789 /* documentation is in tttables.h */
3791 FT_EXPORT_DEF( FT_Long )
3792 FT_Get_CMap_Format( FT_CharMap charmap )
3794 FT_Service_TTCMaps service;
3796 TT_CMapInfo cmap_info;
3799 if ( !charmap || !charmap->face )
3802 face = charmap->face;
3803 FT_FACE_FIND_SERVICE( face, service, TT_CMAP );
3804 if ( service == NULL )
3806 if ( service->get_cmap_info( charmap, &cmap_info ))
3809 return cmap_info.format;
3813 /* documentation is in ftsizes.h */
3815 FT_EXPORT_DEF( FT_Error )
3816 FT_Activate_Size( FT_Size size )
3822 return FT_THROW( Invalid_Size_Handle );
3825 if ( !face || !face->driver )
3826 return FT_THROW( Invalid_Face_Handle );
3828 /* we don't need anything more complex than that; all size objects */
3829 /* are already listed by the face */
3836 /*************************************************************************/
3837 /*************************************************************************/
3838 /*************************************************************************/
3841 /**** R E N D E R E R S ****/
3844 /*************************************************************************/
3845 /*************************************************************************/
3846 /*************************************************************************/
3848 /* lookup a renderer by glyph format in the library's list */
3849 FT_BASE_DEF( FT_Renderer )
3850 FT_Lookup_Renderer( FT_Library library,
3851 FT_Glyph_Format format,
3855 FT_Renderer result = 0;
3861 cur = library->renderers.head;
3866 cur = (*node)->next;
3872 FT_Renderer renderer = FT_RENDERER( cur->data );
3875 if ( renderer->glyph_format == format )
3892 ft_lookup_glyph_renderer( FT_GlyphSlot slot )
3894 FT_Face face = slot->face;
3895 FT_Library library = FT_FACE_LIBRARY( face );
3896 FT_Renderer result = library->cur_renderer;
3899 if ( !result || result->glyph_format != slot->format )
3900 result = FT_Lookup_Renderer( library, slot->format, 0 );
3907 ft_set_current_renderer( FT_Library library )
3909 FT_Renderer renderer;
3912 renderer = FT_Lookup_Renderer( library, FT_GLYPH_FORMAT_OUTLINE, 0 );
3913 library->cur_renderer = renderer;
3918 ft_add_renderer( FT_Module module )
3920 FT_Library library = module->library;
3921 FT_Memory memory = library->memory;
3923 FT_ListNode node = NULL;
3926 if ( FT_NEW( node ) )
3930 FT_Renderer render = FT_RENDERER( module );
3931 FT_Renderer_Class* clazz = (FT_Renderer_Class*)module->clazz;
3934 render->clazz = clazz;
3935 render->glyph_format = clazz->glyph_format;
3937 /* allocate raster object if needed */
3938 if ( clazz->glyph_format == FT_GLYPH_FORMAT_OUTLINE &&
3939 clazz->raster_class->raster_new )
3941 error = clazz->raster_class->raster_new( memory, &render->raster );
3945 render->raster_render = clazz->raster_class->raster_render;
3946 render->render = clazz->render_glyph;
3950 node->data = module;
3951 FT_List_Add( &library->renderers, node );
3953 ft_set_current_renderer( library );
3966 ft_remove_renderer( FT_Module module )
3973 library = module->library;
3977 memory = library->memory;
3979 node = FT_List_Find( &library->renderers, module );
3982 FT_Renderer render = FT_RENDERER( module );
3985 /* release raster object, if any */
3986 if ( render->clazz->glyph_format == FT_GLYPH_FORMAT_OUTLINE &&
3988 render->clazz->raster_class->raster_done( render->raster );
3990 /* remove from list */
3991 FT_List_Remove( &library->renderers, node );
3994 ft_set_current_renderer( library );
3999 /* documentation is in ftrender.h */
4001 FT_EXPORT_DEF( FT_Renderer )
4002 FT_Get_Renderer( FT_Library library,
4003 FT_Glyph_Format format )
4005 /* test for valid `library' delayed to `FT_Lookup_Renderer' */
4007 return FT_Lookup_Renderer( library, format, 0 );
4011 /* documentation is in ftrender.h */
4013 FT_EXPORT_DEF( FT_Error )
4014 FT_Set_Renderer( FT_Library library,
4015 FT_Renderer renderer,
4017 FT_Parameter* parameters )
4020 FT_Error error = FT_Err_Ok;
4022 FT_Renderer_SetModeFunc set_mode;
4027 error = FT_THROW( Invalid_Library_Handle );
4033 error = FT_THROW( Invalid_Argument );
4037 if ( num_params > 0 && !parameters )
4039 error = FT_THROW( Invalid_Argument );
4043 node = FT_List_Find( &library->renderers, renderer );
4046 error = FT_THROW( Invalid_Argument );
4050 FT_List_Up( &library->renderers, node );
4052 if ( renderer->glyph_format == FT_GLYPH_FORMAT_OUTLINE )
4053 library->cur_renderer = renderer;
4055 set_mode = renderer->clazz->set_mode;
4057 for ( ; num_params > 0; num_params-- )
4059 error = set_mode( renderer, parameters->tag, parameters->data );
4070 FT_BASE_DEF( FT_Error )
4071 FT_Render_Glyph_Internal( FT_Library library,
4073 FT_Render_Mode render_mode )
4075 FT_Error error = FT_Err_Ok;
4076 FT_Renderer renderer;
4079 /* if it is already a bitmap, no need to do anything */
4080 switch ( slot->format )
4082 case FT_GLYPH_FORMAT_BITMAP: /* already a bitmap, don't do anything */
4087 FT_ListNode node = 0;
4091 /* small shortcut for the very common case */
4092 if ( slot->format == FT_GLYPH_FORMAT_OUTLINE )
4094 renderer = library->cur_renderer;
4095 node = library->renderers.head;
4098 renderer = FT_Lookup_Renderer( library, slot->format, &node );
4100 error = FT_ERR( Unimplemented_Feature );
4103 error = renderer->render( renderer, slot, render_mode, NULL );
4105 FT_ERR_NEQ( error, Cannot_Render_Glyph ) )
4108 /* FT_Err_Cannot_Render_Glyph is returned if the render mode */
4109 /* is unsupported by the current renderer for this glyph image */
4112 /* now, look for another renderer that supports the same */
4114 renderer = FT_Lookup_Renderer( library, slot->format, &node );
4118 /* if we changed the current renderer for the glyph image format */
4119 /* we need to select it as the next current one */
4120 if ( !error && update && renderer )
4122 error = FT_Set_Renderer( library, renderer, 0, 0 );
4129 #ifdef FT_DEBUG_LEVEL_TRACE
4132 #define FT_COMPONENT trace_bitmap
4134 /* we convert to a single bitmap format for computing the checksum */
4141 FT_Bitmap_New( &bitmap );
4143 /* this also converts the bitmap flow to `down' (i.e., pitch > 0) */
4144 err = FT_Bitmap_Convert( library, &slot->bitmap, &bitmap, 1 );
4148 unsigned char md5[16];
4153 MD5_Update( &ctx, bitmap.buffer, bitmap.rows * bitmap.pitch );
4154 MD5_Final( md5, &ctx );
4156 FT_TRACE3(( "MD5 checksum for %dx%d bitmap:\n"
4158 bitmap.rows, bitmap.pitch ));
4159 for ( i = 0; i < 16; i++ )
4160 FT_TRACE3(( "%02X", md5[i] ));
4161 FT_TRACE3(( "\n" ));
4164 FT_Bitmap_Done( library, &bitmap );
4168 #define FT_COMPONENT trace_objs
4170 #endif /* FT_DEBUG_LEVEL_TRACE */
4176 /* documentation is in freetype.h */
4178 FT_EXPORT_DEF( FT_Error )
4179 FT_Render_Glyph( FT_GlyphSlot slot,
4180 FT_Render_Mode render_mode )
4185 if ( !slot || !slot->face )
4186 return FT_THROW( Invalid_Argument );
4188 library = FT_FACE_LIBRARY( slot->face );
4190 return FT_Render_Glyph_Internal( library, slot, render_mode );
4194 /*************************************************************************/
4195 /*************************************************************************/
4196 /*************************************************************************/
4199 /**** M O D U L E S ****/
4202 /*************************************************************************/
4203 /*************************************************************************/
4204 /*************************************************************************/
4207 /*************************************************************************/
4210 /* Destroy_Module */
4213 /* Destroys a given module object. For drivers, this also destroys */
4214 /* all child faces. */
4217 /* module :: A handle to the target driver object. */
4220 /* The driver _must_ be LOCKED! */
4223 Destroy_Module( FT_Module module )
4225 FT_Memory memory = module->memory;
4226 FT_Module_Class* clazz = module->clazz;
4227 FT_Library library = module->library;
4230 if ( library && library->auto_hinter == module )
4231 library->auto_hinter = 0;
4233 /* if the module is a renderer */
4234 if ( FT_MODULE_IS_RENDERER( module ) )
4235 ft_remove_renderer( module );
4237 /* if the module is a font driver, add some steps */
4238 if ( FT_MODULE_IS_DRIVER( module ) )
4239 Destroy_Driver( FT_DRIVER( module ) );
4241 /* finalize the module object */
4242 if ( clazz->module_done )
4243 clazz->module_done( module );
4250 /* documentation is in ftmodapi.h */
4252 FT_EXPORT_DEF( FT_Error )
4253 FT_Add_Module( FT_Library library,
4254 const FT_Module_Class* clazz )
4262 #define FREETYPE_VER_FIXED ( ( (FT_Long)FREETYPE_MAJOR << 16 ) | \
4266 return FT_THROW( Invalid_Library_Handle );
4269 return FT_THROW( Invalid_Argument );
4271 /* check freetype version */
4272 if ( clazz->module_requires > FREETYPE_VER_FIXED )
4273 return FT_THROW( Invalid_Version );
4275 /* look for a module with the same name in the library's table */
4276 for ( nn = 0; nn < library->num_modules; nn++ )
4278 module = library->modules[nn];
4279 if ( ft_strcmp( module->clazz->module_name, clazz->module_name ) == 0 )
4281 /* this installed module has the same name, compare their versions */
4282 if ( clazz->module_version <= module->clazz->module_version )
4283 return FT_THROW( Lower_Module_Version );
4285 /* remove the module from our list, then exit the loop to replace */
4286 /* it by our new version.. */
4287 FT_Remove_Module( library, module );
4292 memory = library->memory;
4295 if ( library->num_modules >= FT_MAX_MODULES )
4297 error = FT_THROW( Too_Many_Drivers );
4301 /* allocate module object */
4302 if ( FT_ALLOC( module, clazz->module_size ) )
4305 /* base initialization */
4306 module->library = library;
4307 module->memory = memory;
4308 module->clazz = (FT_Module_Class*)clazz;
4310 /* check whether the module is a renderer - this must be performed */
4311 /* before the normal module initialization */
4312 if ( FT_MODULE_IS_RENDERER( module ) )
4314 /* add to the renderers list */
4315 error = ft_add_renderer( module );
4320 /* is the module a auto-hinter? */
4321 if ( FT_MODULE_IS_HINTER( module ) )
4322 library->auto_hinter = module;
4324 /* if the module is a font driver */
4325 if ( FT_MODULE_IS_DRIVER( module ) )
4327 /* allocate glyph loader if needed */
4328 FT_Driver driver = FT_DRIVER( module );
4331 driver->clazz = (FT_Driver_Class)module->clazz;
4332 if ( FT_DRIVER_USES_OUTLINES( driver ) )
4334 error = FT_GlyphLoader_New( memory, &driver->glyph_loader );
4340 if ( clazz->module_init )
4342 error = clazz->module_init( module );
4347 /* add module to the library's table */
4348 library->modules[library->num_modules++] = module;
4354 if ( FT_MODULE_IS_DRIVER( module ) )
4356 FT_Driver driver = FT_DRIVER( module );
4359 if ( FT_DRIVER_USES_OUTLINES( driver ) )
4360 FT_GlyphLoader_Done( driver->glyph_loader );
4363 if ( FT_MODULE_IS_RENDERER( module ) )
4365 FT_Renderer renderer = FT_RENDERER( module );
4368 if ( renderer->clazz &&
4369 renderer->clazz->glyph_format == FT_GLYPH_FORMAT_OUTLINE &&
4371 renderer->clazz->raster_class->raster_done( renderer->raster );
4379 /* documentation is in ftmodapi.h */
4381 FT_EXPORT_DEF( FT_Module )
4382 FT_Get_Module( FT_Library library,
4383 const char* module_name )
4385 FT_Module result = NULL;
4390 if ( !library || !module_name )
4393 cur = library->modules;
4394 limit = cur + library->num_modules;
4396 for ( ; cur < limit; cur++ )
4397 if ( ft_strcmp( cur[0]->clazz->module_name, module_name ) == 0 )
4407 /* documentation is in ftobjs.h */
4409 FT_BASE_DEF( const void* )
4410 FT_Get_Module_Interface( FT_Library library,
4411 const char* mod_name )
4416 /* test for valid `library' delayed to FT_Get_Module() */
4418 module = FT_Get_Module( library, mod_name );
4420 return module ? module->clazz->module_interface : 0;
4424 FT_BASE_DEF( FT_Pointer )
4425 ft_module_get_service( FT_Module module,
4426 const char* service_id )
4428 FT_Pointer result = NULL;
4433 FT_ASSERT( module->clazz && module->clazz->get_interface );
4435 /* first, look for the service in the module */
4436 if ( module->clazz->get_interface )
4437 result = module->clazz->get_interface( module, service_id );
4439 if ( result == NULL )
4441 /* we didn't find it, look in all other modules then */
4442 FT_Library library = module->library;
4443 FT_Module* cur = library->modules;
4444 FT_Module* limit = cur + library->num_modules;
4447 for ( ; cur < limit; cur++ )
4449 if ( cur[0] != module )
4451 FT_ASSERT( cur[0]->clazz );
4453 if ( cur[0]->clazz->get_interface )
4455 result = cur[0]->clazz->get_interface( cur[0], service_id );
4456 if ( result != NULL )
4468 /* documentation is in ftmodapi.h */
4470 FT_EXPORT_DEF( FT_Error )
4471 FT_Remove_Module( FT_Library library,
4474 /* try to find the module from the table, then remove it from there */
4477 return FT_THROW( Invalid_Library_Handle );
4481 FT_Module* cur = library->modules;
4482 FT_Module* limit = cur + library->num_modules;
4485 for ( ; cur < limit; cur++ )
4487 if ( cur[0] == module )
4489 /* remove it from the table */
4490 library->num_modules--;
4492 while ( cur < limit )
4499 /* destroy the module */
4500 Destroy_Module( module );
4506 return FT_THROW( Invalid_Driver_Handle );
4511 ft_property_do( FT_Library library,
4512 const FT_String* module_name,
4513 const FT_String* property_name,
4519 FT_Module_Interface interface;
4521 FT_Service_Properties service;
4523 #ifdef FT_DEBUG_LEVEL_ERROR
4524 const FT_String* set_name = "FT_Property_Set";
4525 const FT_String* get_name = "FT_Property_Get";
4526 const FT_String* func_name = set ? set_name : get_name;
4529 FT_Bool missing_func;
4533 return FT_THROW( Invalid_Library_Handle );
4535 if ( !module_name || !property_name || !value )
4536 return FT_THROW( Invalid_Argument );
4538 cur = library->modules;
4539 limit = cur + library->num_modules;
4542 for ( ; cur < limit; cur++ )
4543 if ( !ft_strcmp( cur[0]->clazz->module_name, module_name ) )
4548 FT_ERROR(( "%s: can't find module `%s'\n",
4549 func_name, module_name ));
4550 return FT_THROW( Missing_Module );
4553 /* check whether we have a service interface */
4554 if ( !cur[0]->clazz->get_interface )
4556 FT_ERROR(( "%s: module `%s' doesn't support properties\n",
4557 func_name, module_name ));
4558 return FT_THROW( Unimplemented_Feature );
4561 /* search property service */
4562 interface = cur[0]->clazz->get_interface( cur[0],
4563 FT_SERVICE_ID_PROPERTIES );
4566 FT_ERROR(( "%s: module `%s' doesn't support properties\n",
4567 func_name, module_name ));
4568 return FT_THROW( Unimplemented_Feature );
4571 service = (FT_Service_Properties)interface;
4574 missing_func = (FT_Bool)( !service->set_property );
4576 missing_func = (FT_Bool)( !service->get_property );
4580 FT_ERROR(( "%s: property service of module `%s' is broken\n",
4581 func_name, module_name ));
4582 return FT_THROW( Unimplemented_Feature );
4585 return set ? service->set_property( cur[0], property_name, value )
4586 : service->get_property( cur[0], property_name, value );
4590 /* documentation is in ftmodapi.h */
4592 FT_EXPORT_DEF( FT_Error )
4593 FT_Property_Set( FT_Library library,
4594 const FT_String* module_name,
4595 const FT_String* property_name,
4598 return ft_property_do( library,
4606 /* documentation is in ftmodapi.h */
4608 FT_EXPORT_DEF( FT_Error )
4609 FT_Property_Get( FT_Library library,
4610 const FT_String* module_name,
4611 const FT_String* property_name,
4614 return ft_property_do( library,
4622 /*************************************************************************/
4623 /*************************************************************************/
4624 /*************************************************************************/
4627 /**** L I B R A R Y ****/
4630 /*************************************************************************/
4631 /*************************************************************************/
4632 /*************************************************************************/
4635 /* documentation is in ftmodapi.h */
4637 FT_EXPORT_DEF( FT_Error )
4638 FT_Reference_Library( FT_Library library )
4641 return FT_THROW( Invalid_Library_Handle );
4643 library->refcount++;
4649 /* documentation is in ftmodapi.h */
4651 FT_EXPORT_DEF( FT_Error )
4652 FT_New_Library( FT_Memory memory,
4653 FT_Library *alibrary )
4655 FT_Library library = NULL;
4659 if ( !memory || !alibrary )
4660 return FT_THROW( Invalid_Argument );
4662 #ifdef FT_DEBUG_LEVEL_ERROR
4663 /* init debugging support */
4667 /* first of all, allocate the library object */
4668 if ( FT_NEW( library ) )
4671 library->memory = memory;
4673 #ifdef FT_CONFIG_OPTION_PIC
4674 /* initialize position independent code containers */
4675 error = ft_pic_container_init( library );
4680 /* allocate the render pool */
4681 library->raster_pool_size = FT_RENDER_POOL_SIZE;
4682 #if FT_RENDER_POOL_SIZE > 0
4683 if ( FT_ALLOC( library->raster_pool, FT_RENDER_POOL_SIZE ) )
4687 library->version_major = FREETYPE_MAJOR;
4688 library->version_minor = FREETYPE_MINOR;
4689 library->version_patch = FREETYPE_PATCH;
4691 library->refcount = 1;
4694 *alibrary = library;
4699 #ifdef FT_CONFIG_OPTION_PIC
4700 ft_pic_container_destroy( library );
4707 /* documentation is in freetype.h */
4709 FT_EXPORT_DEF( void )
4710 FT_Library_Version( FT_Library library,
4722 major = library->version_major;
4723 minor = library->version_minor;
4724 patch = library->version_patch;
4738 /* documentation is in ftmodapi.h */
4740 FT_EXPORT_DEF( FT_Error )
4741 FT_Done_Library( FT_Library library )
4747 return FT_THROW( Invalid_Library_Handle );
4749 library->refcount--;
4750 if ( library->refcount > 0 )
4753 memory = library->memory;
4756 * Close all faces in the library. If we don't do this, we can have
4757 * some subtle memory leaks.
4761 * - the cff font driver uses the pshinter module in cff_size_done
4762 * - if the pshinter module is destroyed before the cff font driver,
4763 * opened FT_Face objects managed by the driver are not properly
4764 * destroyed, resulting in a memory leak
4766 * Some faces are dependent on other faces, like Type42 faces that
4767 * depend on TrueType faces synthesized internally.
4769 * The order of drivers should be specified in driver_name[].
4773 const char* driver_name[] = { "type42", NULL };
4777 m < sizeof ( driver_name ) / sizeof ( driver_name[0] );
4780 for ( n = 0; n < library->num_modules; n++ )
4782 FT_Module module = library->modules[n];
4783 const char* module_name = module->clazz->module_name;
4787 if ( driver_name[m] &&
4788 ft_strcmp( module_name, driver_name[m] ) != 0 )
4791 if ( ( module->clazz->module_flags & FT_MODULE_FONT_DRIVER ) == 0 )
4794 FT_TRACE7(( "FT_Done_Library: close faces for %s\n", module_name ));
4796 faces = &FT_DRIVER( module )->faces_list;
4797 while ( faces->head )
4799 FT_Done_Face( FT_FACE( faces->head->data ) );
4801 FT_TRACE0(( "FT_Done_Library: failed to free some faces\n" ));
4807 /* Close all other modules in the library */
4809 /* XXX Modules are removed in the reversed order so that */
4810 /* type42 module is removed before truetype module. This */
4811 /* avoids double free in some occasions. It is a hack. */
4812 while ( library->num_modules > 0 )
4813 FT_Remove_Module( library,
4814 library->modules[library->num_modules - 1] );
4820 for ( n = 0; n < library->num_modules; n++ )
4822 FT_Module module = library->modules[n];
4827 Destroy_Module( module );
4828 library->modules[n] = 0;
4834 /* Destroy raster objects */
4835 FT_FREE( library->raster_pool );
4836 library->raster_pool_size = 0;
4838 #ifdef FT_CONFIG_OPTION_PIC
4839 /* Destroy pic container contents */
4840 ft_pic_container_destroy( library );
4850 /* documentation is in ftmodapi.h */
4852 FT_EXPORT_DEF( void )
4853 FT_Set_Debug_Hook( FT_Library library,
4855 FT_DebugHook_Func debug_hook )
4857 if ( library && debug_hook &&
4859 ( sizeof ( library->debug_hooks ) / sizeof ( void* ) ) )
4860 library->debug_hooks[hook_index] = debug_hook;
4864 /* documentation is in ftmodapi.h */
4866 FT_EXPORT_DEF( FT_TrueTypeEngineType )
4867 FT_Get_TrueType_Engine_Type( FT_Library library )
4869 FT_TrueTypeEngineType result = FT_TRUETYPE_ENGINE_TYPE_NONE;
4874 FT_Module module = FT_Get_Module( library, "truetype" );
4879 FT_Service_TrueTypeEngine service;
4882 service = (FT_Service_TrueTypeEngine)
4883 ft_module_get_service( module,
4884 FT_SERVICE_ID_TRUETYPE_ENGINE );
4886 result = service->engine_type;
4894 /* documentation is in freetype.h */
4896 FT_EXPORT_DEF( FT_Error )
4897 FT_Get_SubGlyph_Info( FT_GlyphSlot glyph,
4903 FT_Matrix *p_transform )
4905 FT_Error error = FT_ERR( Invalid_Argument );
4910 glyph->format == FT_GLYPH_FORMAT_COMPOSITE &&
4911 sub_index < glyph->num_subglyphs )
4913 FT_SubGlyph subg = glyph->subglyphs + sub_index;
4916 *p_index = subg->index;
4917 *p_flags = subg->flags;
4918 *p_arg1 = subg->arg1;
4919 *p_arg2 = subg->arg2;
4920 *p_transform = subg->transform;