/* */
/* The FreeType private base classes (body). */
/* */
-/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007 by */
+/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, */
+/* 2010 by */
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
/* */
/* This file is part of the FreeType project, and may only be used, */
#include FT_INTERNAL_STREAM_H
#include FT_INTERNAL_SFNT_H /* for SFNT_Load_Table_Func */
#include FT_TRUETYPE_TABLES_H
+#include FT_TRUETYPE_TAGS_H
#include FT_TRUETYPE_IDS_H
-#include FT_OUTLINE_H
#include FT_SERVICE_SFNT_H
#include FT_SERVICE_POSTSCRIPT_NAME_H
#include FT_SERVICE_KERNING_H
#include FT_SERVICE_TRUETYPE_ENGINE_H
+#ifdef FT_CONFIG_OPTION_MAC_FONTS
+#include "ftbase.h"
+#endif
+
#define GRID_FIT_METRICS
+
FT_BASE_DEF( FT_Pointer )
ft_service_list_lookup( FT_ServiceDesc service_descriptors,
const char* service_id )
FT_Stream stream;
+ *astream = 0;
+
if ( !library )
return FT_Err_Invalid_Library_Handle;
if ( !args )
return FT_Err_Invalid_Argument;
- *astream = 0;
- memory = library->memory;
+ memory = library->memory;
if ( FT_NEW( stream ) )
goto Exit;
}
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
#undef FT_COMPONENT
#define FT_COMPONENT trace_objs
static FT_Error
ft_glyphslot_init( FT_GlyphSlot slot )
{
- FT_Driver driver = slot->face->driver;
- FT_Driver_Class clazz = driver->clazz;
- FT_Memory memory = driver->root.memory;
- FT_Error error = FT_Err_Ok;
- FT_Slot_Internal internal;
+ FT_Driver driver = slot->face->driver;
+ FT_Driver_Class clazz = driver->clazz;
+ FT_Memory memory = driver->root.memory;
+ FT_Error error = FT_Err_Ok;
+ FT_Slot_Internal internal = NULL;
slot->library = driver->root.library;
FT_BASE_DEF( void )
ft_glyphslot_free_bitmap( FT_GlyphSlot slot )
{
- if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
+ if ( slot->internal && ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) )
{
FT_Memory memory = FT_FACE_MEMORY( slot->face );
/* free bitmap buffer if needed */
ft_glyphslot_free_bitmap( slot );
- /* free glyph loader */
- if ( FT_DRIVER_USES_OUTLINES( driver ) )
+ /* slot->internal might be NULL in out-of-memory situations */
+ if ( slot->internal )
{
- FT_GlyphLoader_Done( slot->internal->loader );
- slot->internal->loader = 0;
- }
+ /* free glyph loader */
+ if ( FT_DRIVER_USES_OUTLINES( driver ) )
+ {
+ FT_GlyphLoader_Done( slot->internal->loader );
+ slot->internal->loader = 0;
+ }
- FT_FREE( slot->internal );
+ FT_FREE( slot->internal );
+ }
}
FT_Driver driver;
FT_GlyphSlot slot;
FT_Library library;
- FT_Bool autohint = 0;
+ FT_Bool autohint = FALSE;
FT_Module hinter;
* Determine whether we need to auto-hint or not.
* The general rules are:
*
- * - Do only auto-hinting if we have a hinter module,
- * a scalable font format dealing with outlines,
- * and no transforms except simple slants.
+ * - Do only auto-hinting if we have a hinter module, a scalable font
+ * format dealing with outlines, and no transforms except simple
+ * slants and/or rotations by integer multiples of 90 degrees.
*
- * - Then, autohint if FT_LOAD_FORCE_AUTOHINT is set
- * or if we don't have a native font hinter.
+ * - Then, auto-hint if FT_LOAD_FORCE_AUTOHINT is set or if we don't
+ * have a native font hinter.
*
* - Otherwise, auto-hint for LIGHT hinting mode.
*
- * - Exception: The font requires the unpatented
- * bytecode interpreter to load properly.
+ * - Exception: The font is `tricky' and requires the native hinter to
+ * load properly.
*/
- autohint = 0;
- if ( hinter &&
- ( load_flags & FT_LOAD_NO_HINTING ) == 0 &&
- ( load_flags & FT_LOAD_NO_AUTOHINT ) == 0 &&
- FT_DRIVER_IS_SCALABLE( driver ) &&
- FT_DRIVER_USES_OUTLINES( driver ) &&
- face->internal->transform_matrix.yy > 0 &&
- face->internal->transform_matrix.yx == 0 )
- {
- if ( ( load_flags & FT_LOAD_FORCE_AUTOHINT ) != 0 ||
- !FT_DRIVER_HAS_HINTER( driver ) )
- autohint = 1;
+ if ( hinter &&
+ !( load_flags & FT_LOAD_NO_HINTING ) &&
+ !( load_flags & FT_LOAD_NO_AUTOHINT ) &&
+ FT_DRIVER_IS_SCALABLE( driver ) &&
+ FT_DRIVER_USES_OUTLINES( driver ) &&
+ !FT_IS_TRICKY( face ) &&
+ ( ( face->internal->transform_matrix.yx == 0 &&
+ face->internal->transform_matrix.xx != 0 ) ||
+ ( face->internal->transform_matrix.xx == 0 &&
+ face->internal->transform_matrix.yx != 0 ) ) )
+ {
+ if ( ( load_flags & FT_LOAD_FORCE_AUTOHINT ) ||
+ !FT_DRIVER_HAS_HINTER( driver ) )
+ autohint = TRUE;
else
{
FT_Render_Mode mode = FT_LOAD_TARGET_MODE( load_flags );
if ( mode == FT_RENDER_MODE_LIGHT ||
face->internal->ignore_unpatented_hinter )
- autohint = 1;
+ autohint = TRUE;
}
}
goto Load_Ok;
}
- /* load auto-hinted outline */
- hinting = (FT_AutoHinter_Service)hinter->clazz->module_interface;
+ {
+ FT_Face_Internal internal = face->internal;
+ FT_Int transform_flags = internal->transform_flags;
+
+
+ /* since the auto-hinter calls FT_Load_Glyph by itself, */
+ /* make sure that glyphs aren't transformed */
+ internal->transform_flags = 0;
+
+ /* load auto-hinted outline */
+ hinting = (FT_AutoHinter_Service)hinter->clazz->module_interface;
+
+ error = hinting->load_glyph( (FT_AutoHinter)hinter,
+ slot, face->size,
+ glyph_index, load_flags );
- error = hinting->load_glyph( (FT_AutoHinter)hinter,
- slot, face->size,
- glyph_index, load_flags );
+ internal->transform_flags = transform_flags;
+ }
}
else
{
}
/* compute the linear advance in 16.16 pixels */
- if ( ( load_flags & FT_LOAD_LINEAR_DESIGN ) == 0 &&
- ( face->face_flags & FT_FACE_FLAG_SCALABLE ) )
+ if ( ( load_flags & FT_LOAD_LINEAR_DESIGN ) == 0 &&
+ ( FT_IS_SCALABLE( face ) ) )
{
FT_Size_Metrics* metrics = &face->size->metrics;
renderer, slot,
&internal->transform_matrix,
&internal->transform_delta );
+ else if ( slot->format == FT_GLYPH_FORMAT_OUTLINE )
+ {
+ /* apply `standard' transformation if no renderer is available */
+ if ( &internal->transform_matrix )
+ FT_Outline_Transform( &slot->outline,
+ &internal->transform_matrix );
+
+ if ( &internal->transform_delta )
+ FT_Outline_Translate( &slot->outline,
+ internal->transform_delta.x,
+ internal->transform_delta.y );
+ }
+
/* transform advance */
FT_Vector_Transform( &slot->advance, &internal->transform_matrix );
}
}
+ FT_TRACE5(( " x advance: %d\n" , slot->advance.x ));
+ FT_TRACE5(( " y advance: %d\n" , slot->advance.y ));
+
+ FT_TRACE5(( " linear x advance: %d\n" , slot->linearHoriAdvance ));
+ FT_TRACE5(( " linear y advance: %d\n" , slot->linearVertAdvance ));
+
/* do we need to render the image now? */
if ( !error &&
slot->format != FT_GLYPH_FORMAT_BITMAP &&
/* are limited to the BMP (said UCS-2 encoding.) */
/* */
/* This function is called from open_face() (just below), and also */
- /* from FT_Select_Charmap( ..., FT_ENCODING_UNICODE). */
+ /* from FT_Select_Charmap( ..., FT_ENCODING_UNICODE ). */
/* */
static FT_Error
find_unicode_charmap( FT_Face face )
{
FT_CharMap* first;
FT_CharMap* cur;
- FT_CharMap* unicmap = NULL; /* some UCS-2 map, if we found it */
/* caller should have already checked that `face' is valid */
{
if ( cur[0]->encoding == FT_ENCODING_UNICODE )
{
- unicmap = cur; /* record we found a Unicode charmap */
-
- /* XXX If some new encodings to represent UCS-4 are added, */
- /* they should be added here. */
+ /* XXX If some new encodings to represent UCS-4 are added, */
+ /* they should be added here. */
if ( ( cur[0]->platform_id == TT_PLATFORM_MICROSOFT &&
- cur[0]->encoding_id == TT_MS_ID_UCS_4 ) ||
+ cur[0]->encoding_id == TT_MS_ID_UCS_4 ) ||
( cur[0]->platform_id == TT_PLATFORM_APPLE_UNICODE &&
- cur[0]->encoding_id == TT_APPLE_ID_UNICODE_32 ) )
-
- /* Hurray! We found a UCS-4 charmap. We can stop the scan! */
+ cur[0]->encoding_id == TT_APPLE_ID_UNICODE_32 ) )
{
+#ifdef FT_MAX_CHARMAP_CACHEABLE
+ if ( cur - first > FT_MAX_CHARMAP_CACHEABLE )
+ {
+ FT_ERROR(( "find_unicode_charmap: UCS-4 cmap is found "
+ "at too late position (%d)\n", cur - first ));
+ continue;
+ }
+#endif
face->charmap = cur[0];
- return 0;
+ return FT_Err_Ok;
}
}
}
- /* We do not have any UCS-4 charmap. Sigh. */
- /* Let's see if we have some other kind of Unicode charmap, though. */
- if ( unicmap != NULL )
+ /* We do not have any UCS-4 charmap. */
+ /* Do the loop again and search for UCS-2 charmaps. */
+ cur = first + face->num_charmaps;
+
+ for ( ; --cur >= first; )
{
- face->charmap = unicmap[0];
- return 0;
+ if ( cur[0]->encoding == FT_ENCODING_UNICODE )
+ {
+#ifdef FT_MAX_CHARMAP_CACHEABLE
+ if ( cur - first > FT_MAX_CHARMAP_CACHEABLE )
+ {
+ FT_ERROR(( "find_unicode_charmap: UCS-2 cmap is found "
+ "at too late position (%d)\n", cur - first ));
+ continue;
+ }
+#endif
+ face->charmap = cur[0];
+ return FT_Err_Ok;
+ }
}
- /* Chou blanc! */
return FT_Err_Invalid_CharMap_Handle;
}
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* find_variant_selector_charmap */
+ /* */
+ /* <Description> */
+ /* This function finds the variant selector charmap, if there is one. */
+ /* There can only be one (platform=0, specific=5, format=14). */
+ /* */
+ static FT_CharMap
+ find_variant_selector_charmap( FT_Face face )
+ {
+ FT_CharMap* first;
+ FT_CharMap* end;
+ FT_CharMap* cur;
+
+
+ /* caller should have already checked that `face' is valid */
+ FT_ASSERT( face );
+
+ first = face->charmaps;
+
+ if ( !first )
+ return NULL;
+
+ end = first + face->num_charmaps; /* points after the last one */
+
+ for ( cur = first; cur < end; ++cur )
+ {
+ if ( cur[0]->platform_id == TT_PLATFORM_APPLE_UNICODE &&
+ cur[0]->encoding_id == TT_APPLE_ID_VARIANT_SELECTOR &&
+ FT_Get_CMap_Format( cur[0] ) == 14 )
+ {
+#ifdef FT_MAX_CHARMAP_CACHEABLE
+ if ( cur - first > FT_MAX_CHARMAP_CACHEABLE )
+ {
+ FT_ERROR(( "find_unicode_charmap: UVS cmap is found "
+ "at too late position (%d)\n", cur - first ));
+ continue;
+ }
+#endif
+ return cur[0];
+ }
+ }
+
+ return NULL;
+ }
+
+
/*************************************************************************/
/* */
/* <Function> */
for ( i = 0; i < num_params && !face->internal->incremental_interface;
i++ )
if ( params[i].tag == FT_PARAM_TAG_INCREMENTAL )
- face->internal->incremental_interface = params[i].data;
+ face->internal->incremental_interface =
+ (FT_Incremental_Interface)params[i].data;
}
#endif
- error = clazz->init_face( stream,
- face,
- (FT_Int)face_index,
- num_params,
- params );
+ if ( clazz->init_face )
+ error = clazz->init_face( stream,
+ face,
+ (FT_Int)face_index,
+ num_params,
+ params );
if ( error )
goto Fail;
if ( error )
{
destroy_charmaps( face, memory );
- clazz->done_face( face );
+ if ( clazz->done_face )
+ clazz->done_face( face );
FT_FREE( internal );
FT_FREE( face );
*aface = 0;
/* there's a Mac-specific extended implementation of FT_New_Face() */
/* in src/base/ftmac.c */
-#ifndef FT_MACINTOSH
+#if !defined( FT_MACINTOSH ) || defined( DARWIN_NO_CARBON )
/* documentation is in freetype.h */
args.flags = FT_OPEN_PATHNAME;
args.pathname = (char*)pathname;
+ args.stream = NULL;
return FT_Open_Face( library, &args, face_index, aface );
}
-#endif /* !FT_MACINTOSH */
+#endif /* defined( FT_MACINTOSH ) && !defined( DARWIN_NO_CARBON ) */
/* documentation is in freetype.h */
args.flags = FT_OPEN_MEMORY;
args.memory_base = file_base;
args.memory_size = file_size;
+ args.stream = NULL;
return FT_Open_Face( library, &args, face_index, aface );
}
-#if !defined( FT_MACINTOSH ) && defined( FT_CONFIG_OPTION_MAC_FONTS )
+#ifdef FT_CONFIG_OPTION_MAC_FONTS
/* The behavior here is very similar to that in base/ftmac.c, but it */
/* is designed to work on non-mac systems, so no mac specific calls. */
/* we don't really have access to it. */
- /* Finalizer for a memory stream; gets called by FT_Done_Face().
- It frees the memory it uses. */
- /* from ftmac.c */
+ /* Finalizer for a memory stream; gets called by FT_Done_Face(). */
+ /* It frees the memory it uses. */
+ /* From ftmac.c. */
static void
memory_stream_close( FT_Stream stream )
{
/* Create a new memory stream from a buffer and a size. */
- /* from ftmac.c */
+ /* From ftmac.c. */
static FT_Error
new_memory_stream( FT_Library library,
FT_Byte* base,
/* Create a new FT_Face given a buffer and a driver name. */
/* from ftmac.c */
- static FT_Error
+ FT_LOCAL_DEF( FT_Error )
open_face_from_buffer( FT_Library library,
FT_Byte* base,
FT_ULong size,
args.driver = FT_Get_Module( library, driver_name );
}
+#ifdef FT_MACINTOSH
+ /* At this point, face_index has served its purpose; */
+ /* whoever calls this function has already used it to */
+ /* locate the correct font data. We should not propagate */
+ /* this index to FT_Open_Face() (unless it is negative). */
+
+ if ( face_index > 0 )
+ face_index = 0;
+#endif
+
error = FT_Open_Face( library, &args, face_index, aface );
if ( error == FT_Err_Ok )
(*aface)->face_flags &= ~FT_FACE_FLAG_EXTERNAL_STREAM;
else
+#ifdef FT_MACINTOSH
+ FT_Stream_Free( stream, 0 );
+#else
{
FT_Stream_Close( stream );
FT_FREE( stream );
}
+#endif
return error;
}
+ /* Look up `TYP1' or `CID ' table from sfnt table directory. */
+ /* `offset' and `length' must exclude the binary header in tables. */
+
+ /* Type 1 and CID-keyed font drivers should recognize sfnt-wrapped */
+ /* format too. Here, since we can't expect that the TrueType font */
+ /* driver is loaded unconditially, we must parse the font by */
+ /* ourselves. We are only interested in the name of the table and */
+ /* the offset. */
+
+ static FT_Error
+ ft_lookup_PS_in_sfnt_stream( FT_Stream stream,
+ FT_Long face_index,
+ FT_ULong* offset,
+ FT_ULong* length,
+ FT_Bool* is_sfnt_cid )
+ {
+ FT_Error error;
+ FT_UShort numTables;
+ FT_Long pstable_index;
+ FT_ULong tag;
+ int i;
+
+
+ *offset = 0;
+ *length = 0;
+ *is_sfnt_cid = FALSE;
+
+ /* TODO: support for sfnt-wrapped PS/CID in TTC format */
+
+ /* version check for 'typ1' (should be ignored?) */
+ if ( FT_READ_ULONG( tag ) )
+ return error;
+ if ( tag != TTAG_typ1 )
+ return FT_Err_Unknown_File_Format;
+
+ if ( FT_READ_USHORT( numTables ) )
+ return error;
+ if ( FT_STREAM_SKIP( 2 * 3 ) ) /* skip binary search header */
+ return error;
+
+ pstable_index = -1;
+ *is_sfnt_cid = FALSE;
+
+ for ( i = 0; i < numTables; i++ )
+ {
+ if ( FT_READ_ULONG( tag ) || FT_STREAM_SKIP( 4 ) ||
+ FT_READ_ULONG( *offset ) || FT_READ_ULONG( *length ) )
+ return error;
+
+ if ( tag == TTAG_CID )
+ {
+ pstable_index++;
+ *offset += 22;
+ *length -= 22;
+ *is_sfnt_cid = TRUE;
+ if ( face_index < 0 )
+ return FT_Err_Ok;
+ }
+ else if ( tag == TTAG_TYP1 )
+ {
+ pstable_index++;
+ *offset += 24;
+ *length -= 24;
+ *is_sfnt_cid = FALSE;
+ if ( face_index < 0 )
+ return FT_Err_Ok;
+ }
+ if ( face_index >= 0 && pstable_index == face_index )
+ return FT_Err_Ok;
+ }
+ return FT_Err_Table_Missing;
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ open_face_PS_from_sfnt_stream( FT_Library library,
+ FT_Stream stream,
+ FT_Long face_index,
+ FT_Int num_params,
+ FT_Parameter *params,
+ FT_Face *aface )
+ {
+ FT_Error error;
+ FT_Memory memory = library->memory;
+ FT_ULong offset, length;
+ FT_Long pos;
+ FT_Bool is_sfnt_cid;
+ FT_Byte* sfnt_ps;
+
+ FT_UNUSED( num_params );
+ FT_UNUSED( params );
+
+
+ pos = FT_Stream_Pos( stream );
+
+ error = ft_lookup_PS_in_sfnt_stream( stream,
+ face_index,
+ &offset,
+ &length,
+ &is_sfnt_cid );
+ if ( error )
+ goto Exit;
+
+ if ( FT_Stream_Seek( stream, pos + offset ) )
+ goto Exit;
+
+ if ( FT_ALLOC( sfnt_ps, (FT_Long)length ) )
+ goto Exit;
+
+ error = FT_Stream_Read( stream, (FT_Byte *)sfnt_ps, length );
+ if ( error )
+ goto Exit;
+
+ error = open_face_from_buffer( library,
+ sfnt_ps,
+ length,
+ face_index < 0 ? face_index : 0,
+ is_sfnt_cid ? "cid" : "type1",
+ aface );
+ Exit:
+ {
+ FT_Error error1;
+
+
+ if ( error == FT_Err_Unknown_File_Format )
+ {
+ error1 = FT_Stream_Seek( stream, pos );
+ if ( error1 )
+ return error1;
+ }
+
+ return error;
+ }
+ }
+
+
+#if !defined( FT_MACINTOSH ) || defined( DARWIN_NO_CARBON )
+
/* The resource header says we've got resource_cnt `POST' (type1) */
/* resources in this file. They all need to be coalesced into */
/* one lump which gets passed on to the type1 driver. */
goto Exit;
if ( FT_READ_USHORT( flags ) )
goto Exit;
- rlen -= 2; /* the flags are part of the resource */
+ FT_TRACE3(( "POST fragment[%d]: offsets=0x%08x, rlen=0x%08x, flags=0x%04x\n",
+ i, offsets[i], rlen, flags ));
+
+ /* postpone the check of rlen longer than buffer until FT_Stream_Read() */
+ if ( ( flags >> 8 ) == 0 ) /* Comment, should not be loaded */
+ continue;
+
+ /* the flags are part of the resource, so rlen >= 2. */
+ /* but some fonts declare rlen = 0 for empty fragment */
+ if ( rlen > 2 )
+ rlen -= 2;
+ else
+ rlen = 0;
+
if ( ( flags >> 8 ) == type )
len += rlen;
else
{
+ if ( pfb_lenpos + 3 > pfb_len + 2 )
+ goto Exit2;
pfb_data[pfb_lenpos ] = (FT_Byte)( len );
pfb_data[pfb_lenpos + 1] = (FT_Byte)( len >> 8 );
pfb_data[pfb_lenpos + 2] = (FT_Byte)( len >> 16 );
if ( ( flags >> 8 ) == 5 ) /* End of font mark */
break;
+ if ( pfb_pos + 6 > pfb_len + 2 )
+ goto Exit2;
pfb_data[pfb_pos++] = 0x80;
type = flags >> 8;
pfb_data[pfb_pos++] = 0;
}
+ error = FT_Err_Cannot_Open_Resource;
+ if ( pfb_pos > pfb_len || pfb_pos + rlen > pfb_len )
+ goto Exit2;
+
error = FT_Stream_Read( stream, (FT_Byte *)pfb_data + pfb_pos, rlen );
+ if ( error )
+ goto Exit2;
pfb_pos += rlen;
}
+ if ( pfb_pos + 2 > pfb_len + 2 )
+ goto Exit2;
pfb_data[pfb_pos++] = 0x80;
pfb_data[pfb_pos++] = 3;
+ if ( pfb_lenpos + 3 > pfb_len + 2 )
+ goto Exit2;
pfb_data[pfb_lenpos ] = (FT_Byte)( len );
pfb_data[pfb_lenpos + 1] = (FT_Byte)( len >> 8 );
pfb_data[pfb_lenpos + 2] = (FT_Byte)( len >> 16 );
if ( rlen == -1 )
return FT_Err_Cannot_Open_Resource;
+ error = open_face_PS_from_sfnt_stream( library,
+ stream,
+ face_index,
+ 0, NULL,
+ aface );
+ if ( !error )
+ goto Exit;
+
+ /* rewind sfnt stream before open_face_PS_from_sfnt_stream() */
+ if ( FT_Stream_Seek( stream, flag_offset + 4 ) )
+ goto Exit;
+
if ( FT_ALLOC( sfnt_data, (FT_Long)rlen ) )
return error;
error = FT_Stream_Read( stream, (FT_Byte *)sfnt_data, rlen );
if ( error )
goto Exit;
- is_cff = rlen > 4 && sfnt_data[0] == 'O' &&
- sfnt_data[1] == 'T' &&
- sfnt_data[2] == 'T' &&
- sfnt_data[3] == 'O';
-
+ is_cff = rlen > 4 && !ft_memcmp( sfnt_data, "OTTO", 4 );
error = open_face_from_buffer( library,
sfnt_data,
rlen,
error = FT_Raccess_Get_DataOffsets( library, stream,
map_offset, rdara_pos,
- FT_MAKE_TAG( 'P', 'O', 'S', 'T' ),
+ TTAG_POST,
&data_offsets, &count );
if ( !error )
{
error = FT_Raccess_Get_DataOffsets( library, stream,
map_offset, rdara_pos,
- FT_MAKE_TAG( 's', 'f', 'n', 't' ),
+ TTAG_sfnt,
&data_offsets, &count );
if ( !error )
{
FT_Long dlen, offset;
+ if ( NULL == stream )
+ return FT_Err_Invalid_Stream_Operation;
+
error = FT_Stream_Seek( stream, 0 );
if ( error )
goto Exit;
char * file_names[FT_RACCESS_N_RULES];
FT_Long offsets[FT_RACCESS_N_RULES];
FT_Error errors[FT_RACCESS_N_RULES];
+ FT_Bool is_darwin_vfs, vfs_rfork_has_no_font = FALSE; /* not tested */
FT_Open_Args args2;
- FT_Stream stream2;
+ FT_Stream stream2 = 0;
FT_Raccess_Guess( library, stream,
for ( i = 0; i < FT_RACCESS_N_RULES; i++ )
{
+ is_darwin_vfs = raccess_rule_by_darwin_vfs( i );
+ if ( is_darwin_vfs && vfs_rfork_has_no_font )
+ {
+ FT_TRACE3(( "Skip rule %d: darwin vfs resource fork"
+ " is already checked and"
+ " no font is found\n", i ));
+ continue;
+ }
+
if ( errors[i] )
{
FT_TRACE3(( "Error[%d] has occurred in rule %d\n", errors[i], i ));
i, args2.pathname, offsets[i] ));
error = FT_Stream_New( library, &args2, &stream2 );
+ if ( is_darwin_vfs && error == FT_Err_Cannot_Open_Stream )
+ vfs_rfork_has_no_font = TRUE;
+
if ( error )
{
FT_TRACE3(( "failed\n" ));
if ( !error )
break;
+ else if ( is_darwin_vfs )
+ vfs_rfork_has_no_font = TRUE;
}
for (i = 0; i < FT_RACCESS_N_RULES; i++)
}
- /* Check for some macintosh formats. */
+ /* Check for some macintosh formats without Carbon framework. */
/* Is this a macbinary file? If so look at the resource fork. */
/* Is this a mac dfont file? */
/* Is this an old style resource fork? (in data) */
face_index, aface, args );
return error;
}
+#endif
#endif /* !FT_MACINTOSH && FT_CONFIG_OPTION_MAC_FONTS */
FT_Error error;
FT_Driver driver;
FT_Memory memory;
- FT_Stream stream;
- FT_Face face = 0;
- FT_ListNode node = 0;
+ FT_Stream stream = NULL;
+ FT_Face face = NULL;
+ FT_ListNode node = NULL;
FT_Bool external_stream;
+ FT_Module* cur;
+ FT_Module* limit;
/* test for valid `library' delayed to */
/* create input stream */
error = FT_Stream_New( library, args, &stream );
if ( error )
- goto Exit;
+ goto Fail3;
memory = library->memory;
else
{
/* check each font driver for an appropriate format */
- FT_Module* cur = library->modules;
- FT_Module* limit = cur + library->num_modules;
+ cur = library->modules;
+ limit = cur + library->num_modules;
for ( ; cur < limit; cur++ )
if ( !error )
goto Success;
+#ifdef FT_CONFIG_OPTION_MAC_FONTS
+ if ( ft_strcmp( cur[0]->clazz->module_name, "truetype" ) == 0 &&
+ FT_ERROR_BASE( error ) == FT_Err_Table_Missing )
+ {
+ /* TrueType but essential tables are missing */
+ if ( FT_Stream_Seek( stream, 0 ) )
+ break;
+
+ error = open_face_PS_from_sfnt_stream( library,
+ stream,
+ face_index,
+ num_params,
+ params,
+ aface );
+ if ( !error )
+ {
+ FT_Stream_Free( stream, external_stream );
+ return error;
+ }
+ }
+#endif
+
if ( FT_ERROR_BASE( error ) != FT_Err_Unknown_File_Format )
goto Fail3;
}
/* If we are on the mac, and we get an FT_Err_Invalid_Stream_Operation */
/* it may be because we have an empty data fork, so we need to check */
/* the resource fork. */
- if ( FT_ERROR_BASE( error ) != FT_Err_Unknown_File_Format &&
+ if ( FT_ERROR_BASE( error ) != FT_Err_Cannot_Open_Stream &&
+ FT_ERROR_BASE( error ) != FT_Err_Unknown_File_Format &&
FT_ERROR_BASE( error ) != FT_Err_Invalid_Stream_Operation )
goto Fail2;
internal->transform_delta.x = 0;
internal->transform_delta.y = 0;
+
+ internal->refcount = 1;
}
if ( aface )
}
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Reference_Face( FT_Face face )
+ {
+ face->internal->refcount++;
+
+ return FT_Err_Ok;
+ }
+
+
/* documentation is in freetype.h */
FT_EXPORT_DEF( FT_Error )
error = FT_Err_Invalid_Face_Handle;
if ( face && face->driver )
{
- driver = face->driver;
- memory = driver->root.memory;
-
- /* find face in driver's list */
- node = FT_List_Find( &driver->faces_list, face );
- if ( node )
+ face->internal->refcount--;
+ if ( face->internal->refcount > 0 )
+ error = FT_Err_Ok;
+ else
{
- /* remove face object from the driver's list */
- FT_List_Remove( &driver->faces_list, node );
- FT_FREE( node );
+ driver = face->driver;
+ memory = driver->root.memory;
- /* now destroy the object proper */
- destroy_face( memory, face, driver );
- error = FT_Err_Ok;
+ /* find face in driver's list */
+ node = FT_List_Find( &driver->faces_list, face );
+ if ( node )
+ {
+ /* remove face object from the driver's list */
+ FT_List_Remove( &driver->faces_list, node );
+ FT_FREE( node );
+
+ /* now destroy the object proper */
+ destroy_face( memory, face, driver );
+ error = FT_Err_Ok;
+ }
}
}
+
return error;
}
ft_synthesize_vertical_metrics( FT_Glyph_Metrics* metrics,
FT_Pos advance )
{
+ FT_Pos height = metrics->height;
+
+
+ /* compensate for glyph with bbox above/below the baseline */
+ if ( metrics->horiBearingY < 0 )
+ {
+ if ( height < metrics->horiBearingY )
+ height = metrics->horiBearingY;
+ }
+ else if ( metrics->horiBearingY > 0 )
+ height -= metrics->horiBearingY;
+
/* the factor 1.2 is a heuristical value */
if ( !advance )
- advance = metrics->height * 12 / 10;
+ advance = height * 12 / 10;
- metrics->vertBearingX = -( metrics->width / 2 );
- metrics->vertBearingY = ( advance - metrics->height ) / 2;
+ metrics->vertBearingX = metrics->horiBearingX - metrics->horiAdvance / 2;
+ metrics->vertBearingY = ( advance - height ) / 2;
metrics->vertAdvance = advance;
}
}
else
{
- metrics->x_scale = 1L << 22;
- metrics->y_scale = 1L << 22;
+ metrics->x_scale = 1L << 16;
+ metrics->y_scale = 1L << 16;
metrics->ascender = bsize->y_ppem;
metrics->descender = 0;
metrics->height = bsize->height << 6;
else
{
FT_ZERO( metrics );
- metrics->x_scale = 1L << 22;
- metrics->y_scale = 1L << 22;
+ metrics->x_scale = 1L << 16;
+ metrics->y_scale = 1L << 16;
}
}
{
if ( cur[0]->encoding == encoding )
{
+#ifdef FT_MAX_CHARMAP_CACHEABLE
+ if ( cur - face->charmaps > FT_MAX_CHARMAP_CACHEABLE )
+ {
+ FT_ERROR(( "FT_Select_Charmap: requested charmap is found (%d), "
+ "but in too late position to cache\n",
+ cur - face->charmaps ));
+ continue;
+ }
+#endif
face->charmap = cur[0];
return 0;
}
cur = face->charmaps;
if ( !cur )
return FT_Err_Invalid_CharMap_Handle;
+ if ( FT_Get_CMap_Format( charmap ) == 14 )
+ return FT_Err_Invalid_Argument;
limit = cur + face->num_charmaps;
{
if ( cur[0] == charmap )
{
+#ifdef FT_MAX_CHARMAP_CACHEABLE
+ if ( cur - face->charmaps > FT_MAX_CHARMAP_CACHEABLE )
+ {
+ FT_ERROR(( "FT_Set_Charmap: requested charmap is found (%d), "
+ "but in too late position to cache\n",
+ cur - face->charmaps ));
+ continue;
+ }
+#endif
face->charmap = cur[0];
return 0;
}
FT_Int i;
+ if ( !charmap || !charmap->face )
+ return -1;
+
for ( i = 0; i < charmap->face->num_charmaps; i++ )
if ( charmap->face->charmaps[i] == charmap )
break;
FT_ASSERT( i < charmap->face->num_charmaps );
+#ifdef FT_MAX_CHARMAP_CACHEABLE
+ if ( i > FT_MAX_CHARMAP_CACHEABLE )
+ {
+ FT_ERROR(( "FT_Get_Charmap_Index: requested charmap is found (%d), "
+ "but in too late position to cache\n",
+ i ));
+ return -i;
+ }
+#endif
return i;
}
FT_CMap cmap = FT_CMAP( face->charmap );
- result = cmap->clazz->char_index( cmap, charcode );
+ if ( charcode > 0xFFFFFFFFUL )
+ {
+ FT_TRACE1(( "FT_Get_Char_Index: too large charcode" ));
+ FT_TRACE1(( " 0x%x is truncated\n", charcode ));
+ }
+ result = cmap->clazz->char_index( cmap, (FT_UInt32)charcode );
}
- return result;
+ return result;
}
FT_UInt gindex = 0;
- if ( face && face->charmap )
+ if ( face && face->charmap && face->num_glyphs )
{
gindex = FT_Get_Char_Index( face, 0 );
- if ( gindex == 0 )
+ if ( gindex == 0 || gindex >= (FT_UInt)face->num_glyphs )
result = FT_Get_Next_Char( face, 0, &gindex );
}
- if ( agindex )
+ if ( agindex )
*agindex = gindex;
return result;
FT_UInt gindex = 0;
- if ( face && face->charmap )
+ if ( face && face->charmap && face->num_glyphs )
{
FT_UInt32 code = (FT_UInt32)charcode;
FT_CMap cmap = FT_CMAP( face->charmap );
- gindex = cmap->clazz->char_next( cmap, &code );
+ do {
+ gindex = cmap->clazz->char_next( cmap, &code );
+ } while ( gindex >= (FT_UInt)face->num_glyphs );
+
result = ( gindex == 0 ) ? 0 : code;
}
}
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_UInt )
+ FT_Face_GetCharVariantIndex( FT_Face face,
+ FT_ULong charcode,
+ FT_ULong variantSelector )
+ {
+ FT_UInt result = 0;
+
+
+ if ( face && face->charmap &&
+ face->charmap->encoding == FT_ENCODING_UNICODE )
+ {
+ FT_CharMap charmap = find_variant_selector_charmap( face );
+ FT_CMap ucmap = FT_CMAP( face->charmap );
+
+
+ if ( charmap != NULL )
+ {
+ FT_CMap vcmap = FT_CMAP( charmap );
+
+
+ if ( charcode > 0xFFFFFFFFUL )
+ {
+ FT_TRACE1(( "FT_Get_Char_Index: too large charcode" ));
+ FT_TRACE1(( " 0x%x is truncated\n", charcode ));
+ }
+ if ( variantSelector > 0xFFFFFFFFUL )
+ {
+ FT_TRACE1(( "FT_Get_Char_Index: too large variantSelector" ));
+ FT_TRACE1(( " 0x%x is truncated\n", variantSelector ));
+ }
+
+ result = vcmap->clazz->char_var_index( vcmap, ucmap,
+ (FT_UInt32)charcode,
+ (FT_UInt32)variantSelector );
+ }
+ }
+
+ return result;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Int )
+ FT_Face_GetCharVariantIsDefault( FT_Face face,
+ FT_ULong charcode,
+ FT_ULong variantSelector )
+ {
+ FT_Int result = -1;
+
+
+ if ( face )
+ {
+ FT_CharMap charmap = find_variant_selector_charmap( face );
+
+
+ if ( charmap != NULL )
+ {
+ FT_CMap vcmap = FT_CMAP( charmap );
+
+
+ if ( charcode > 0xFFFFFFFFUL )
+ {
+ FT_TRACE1(( "FT_Get_Char_Index: too large charcode" ));
+ FT_TRACE1(( " 0x%x is truncated\n", charcode ));
+ }
+ if ( variantSelector > 0xFFFFFFFFUL )
+ {
+ FT_TRACE1(( "FT_Get_Char_Index: too large variantSelector" ));
+ FT_TRACE1(( " 0x%x is truncated\n", variantSelector ));
+ }
+
+ result = vcmap->clazz->char_var_default( vcmap,
+ (FT_UInt32)charcode,
+ (FT_UInt32)variantSelector );
+ }
+ }
+
+ return result;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_UInt32* )
+ FT_Face_GetVariantSelectors( FT_Face face )
+ {
+ FT_UInt32 *result = NULL;
+
+
+ if ( face )
+ {
+ FT_CharMap charmap = find_variant_selector_charmap( face );
+
+
+ if ( charmap != NULL )
+ {
+ FT_CMap vcmap = FT_CMAP( charmap );
+ FT_Memory memory = FT_FACE_MEMORY( face );
+
+
+ result = vcmap->clazz->variant_list( vcmap, memory );
+ }
+ }
+
+ return result;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_UInt32* )
+ FT_Face_GetVariantsOfChar( FT_Face face,
+ FT_ULong charcode )
+ {
+ FT_UInt32 *result = NULL;
+
+
+ if ( face )
+ {
+ FT_CharMap charmap = find_variant_selector_charmap( face );
+
+
+ if ( charmap != NULL )
+ {
+ FT_CMap vcmap = FT_CMAP( charmap );
+ FT_Memory memory = FT_FACE_MEMORY( face );
+
+
+ if ( charcode > 0xFFFFFFFFUL )
+ {
+ FT_TRACE1(( "FT_Get_Char_Index: too large charcode" ));
+ FT_TRACE1(( " 0x%x is truncated\n", charcode ));
+ }
+
+ result = vcmap->clazz->charvariant_list( vcmap, memory,
+ (FT_UInt32)charcode );
+ }
+ }
+ return result;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_UInt32* )
+ FT_Face_GetCharsOfVariant( FT_Face face,
+ FT_ULong variantSelector )
+ {
+ FT_UInt32 *result = NULL;
+
+
+ if ( face )
+ {
+ FT_CharMap charmap = find_variant_selector_charmap( face );
+
+
+ if ( charmap != NULL )
+ {
+ FT_CMap vcmap = FT_CMAP( charmap );
+ FT_Memory memory = FT_FACE_MEMORY( face );
+
+
+ if ( variantSelector > 0xFFFFFFFFUL )
+ {
+ FT_TRACE1(( "FT_Get_Char_Index: too large variantSelector" ));
+ FT_TRACE1(( " 0x%x is truncated\n", variantSelector ));
+ }
+
+ result = vcmap->clazz->variantchar_list( vcmap, memory,
+ (FT_UInt32)variantSelector );
+ }
+ }
+
+ return result;
+ }
+
+
/* documentation is in freetype.h */
FT_EXPORT_DEF( FT_UInt )
((FT_Byte*)buffer)[0] = 0;
if ( face &&
- glyph_index <= (FT_UInt)face->num_glyphs &&
+ (FT_Long)glyph_index <= face->num_glyphs &&
FT_HAS_GLYPH_NAMES( face ) )
{
FT_Service_GlyphDict service;
FT_ULong *length )
{
FT_Service_SFNT_Table service;
+ FT_ULong offset;
if ( !face || !FT_IS_SFNT( face ) )
if ( service == NULL )
return FT_Err_Unimplemented_Feature;
- return service->table_info( face, table_index, tag, length );
+ return service->table_info( face, table_index, tag, &offset, length );
}
if ( size == NULL )
- return FT_Err_Bad_Argument;
+ return FT_Err_Invalid_Argument;
face = size->face;
if ( face == NULL || face->driver == NULL )
- return FT_Err_Bad_Argument;
+ return FT_Err_Invalid_Argument;
/* we don't need anything more complex than that; all size objects */
/* are already listed by the face */
FT_Library library = module->library;
FT_Memory memory = library->memory;
FT_Error error;
- FT_ListNode node;
+ FT_ListNode node = NULL;
if ( FT_NEW( node ) )
/* allocate raster object if needed */
if ( clazz->glyph_format == FT_GLYPH_FORMAT_OUTLINE &&
- clazz->raster_class->raster_new )
+ clazz->raster_class->raster_new )
{
error = clazz->raster_class->raster_new( memory, &render->raster );
if ( error )
/* release raster object, if any */
- if ( render->raster )
+ if ( render->clazz->glyph_format == FT_GLYPH_FORMAT_OUTLINE &&
+ render->raster )
render->clazz->raster_class->raster_done( render->raster );
/* remove from list */
while ( renderer )
{
error = renderer->render( renderer, slot, render_mode, NULL );
- if ( !error ||
+ if ( !error ||
FT_ERROR_BASE( error ) != FT_Err_Cannot_Render_Glyph )
break;
FT_Library library;
- if ( !slot )
+ if ( !slot || !slot->face )
return FT_Err_Invalid_Argument;
library = FT_FACE_LIBRARY( slot->face );
FT_Renderer renderer = FT_RENDERER( module );
- if ( renderer->raster )
+ if ( renderer->clazz->glyph_format == FT_GLYPH_FORMAT_OUTLINE &&
+ renderer->raster )
renderer->clazz->raster_class->raster_done( renderer->raster );
}
/*************************************************************************/
+ /* documentation is in ftmodapi.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Reference_Library( FT_Library library )
+ {
+ library->refcount++;
+
+ return FT_Err_Ok;
+ }
+
+
/* documentation is in ftmodapi.h */
FT_EXPORT_DEF( FT_Error )
FT_New_Library( FT_Memory memory,
FT_Library *alibrary )
{
- FT_Library library = 0;
+ FT_Library library = NULL;
FT_Error error;
library->memory = memory;
+#ifdef FT_CONFIG_OPTION_PIC
+ /* initialize position independent code containers */
+ error = ft_pic_container_init( library );
+ if ( error )
+ goto Fail;
+#endif
+
/* allocate the render pool */
library->raster_pool_size = FT_RENDER_POOL_SIZE;
- if ( FT_RENDER_POOL_SIZE > 0 )
- if ( FT_ALLOC( library->raster_pool, FT_RENDER_POOL_SIZE ) )
- goto Fail;
+#if FT_RENDER_POOL_SIZE > 0
+ if ( FT_ALLOC( library->raster_pool, FT_RENDER_POOL_SIZE ) )
+ goto Fail;
+#endif
+
+ library->version_major = FREETYPE_MAJOR;
+ library->version_minor = FREETYPE_MINOR;
+ library->version_patch = FREETYPE_PATCH;
+
+ library->refcount = 1;
/* That's ok now */
*alibrary = library;
return FT_Err_Ok;
Fail:
+#ifdef FT_CONFIG_OPTION_PIC
+ ft_pic_container_destroy( library );
+#endif
FT_FREE( library );
return error;
}
if ( !library )
return FT_Err_Invalid_Library_Handle;
+ library->refcount--;
+ if ( library->refcount > 0 )
+ goto Exit;
+
memory = library->memory;
/* Discard client-data */
if ( library->generic.finalizer )
library->generic.finalizer( library );
- /* Close all faces in the library. If we don't do
- * this, we can have some subtle memory leaks.
+ /*
+ * Close all faces in the library. If we don't do this, we can have
+ * some subtle memory leaks.
+ *
* Example:
*
* - the cff font driver uses the pshinter module in cff_size_done
* - if the pshinter module is destroyed before the cff font driver,
* opened FT_Face objects managed by the driver are not properly
* destroyed, resulting in a memory leak
+ *
+ * Some faces are dependent on other faces, like Type42 faces that
+ * depend on TrueType faces synthesized internally.
+ *
+ * The order of drivers should be specified in driver_name[].
*/
{
- FT_UInt n;
+ FT_UInt m, n;
+ const char* driver_name[] = { "type42", NULL };
- for ( n = 0; n < library->num_modules; n++ )
+ for ( m = 0;
+ m < sizeof ( driver_name ) / sizeof ( driver_name[0] );
+ m++ )
{
- FT_Module module = library->modules[n];
- FT_List faces;
+ for ( n = 0; n < library->num_modules; n++ )
+ {
+ FT_Module module = library->modules[n];
+ const char* module_name = module->clazz->module_name;
+ FT_List faces;
- if ( ( module->clazz->module_flags & FT_MODULE_FONT_DRIVER ) == 0 )
- continue;
+ if ( driver_name[m] &&
+ ft_strcmp( module_name, driver_name[m] ) != 0 )
+ continue;
- faces = &FT_DRIVER(module)->faces_list;
- while ( faces->head )
- FT_Done_Face( FT_FACE( faces->head->data ) );
+ if ( ( module->clazz->module_flags & FT_MODULE_FONT_DRIVER ) == 0 )
+ continue;
+
+ FT_TRACE7(( "FT_Done_Library: close faces for %s\n", module_name ));
+
+ faces = &FT_DRIVER( module )->faces_list;
+ while ( faces->head )
+ {
+ FT_Done_Face( FT_FACE( faces->head->data ) );
+ if ( faces->head )
+ FT_TRACE0(( "FT_Done_Library: failed to free some faces\n" ));
+ }
+ }
}
}
FT_FREE( library->raster_pool );
library->raster_pool_size = 0;
+#ifdef FT_CONFIG_OPTION_PIC
+ /* Destroy pic container contents */
+ ft_pic_container_destroy( library );
+#endif
+
FT_FREE( library );
+
+ Exit:
return FT_Err_Ok;
}
#endif /* FT_CONFIG_OPTION_OLD_INTERNALS */
+ /* documentation is in freetype.h */
+
FT_EXPORT_DEF( FT_Error )
FT_Get_SubGlyph_Info( FT_GlyphSlot glyph,
FT_UInt sub_index,
FT_Error error = FT_Err_Invalid_Argument;
- if ( glyph != NULL &&
+ if ( glyph &&
+ glyph->subglyphs &&
glyph->format == FT_GLYPH_FORMAT_COMPOSITE &&
sub_index < glyph->num_subglyphs )
{