// ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ #include namespace BxCore { namespace AddOn { void* _inout_ ForExtend_CreateTTF(); void* _inout_ ForExtend_ReleaseTTF(); void* _inout_ ForExtend_TTFToBMP(); void* _inout_ ForExtend_TTFToINFO(); } } local_func id_ttf CreateTTF(const byte* ttf, const int length); local_func void ReleaseTTF(id_ttf ttf); local_func const byte* TTFToBMP(id_ttf ttf, int height, uint code); local_func bool TTFToINFO(id_ttf ttf, int height, uint code, int* width, int* ascent); local_func bool BindingCore() { BxCore::AddOn::ForExtend_CreateTTF() = (void*) CreateTTF; BxCore::AddOn::ForExtend_ReleaseTTF() = (void*) ReleaseTTF; BxCore::AddOn::ForExtend_TTFToBMP() = (void*) TTFToBMP; BxCore::AddOn::ForExtend_TTFToINFO() = (void*) TTFToINFO; return true; } local_data bool Unknown = BindingCore(); // ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ #include #define ft_ptrdiff_t ptrdiff_t #include #define FT_CHAR_BIT CHAR_BIT #define FT_USHORT_MAX USHRT_MAX #define FT_INT_MAX INT_MAX #define FT_INT_MIN INT_MIN #define FT_UINT_MAX UINT_MAX #define FT_ULONG_MAX ULONG_MAX #include #define ft_memchr memchr #define ft_memcmp memcmp #define ft_memcpy memcpy #define ft_memmove memmove #define ft_memset memset #define ft_strcat strcat #define ft_strcmp strcmp #define ft_strcpy strcpy #define ft_strlen strlen #define ft_strncmp strncmp #define ft_strncpy strncpy #define ft_strrchr strrchr #define ft_strstr strstr #include #define ft_sprintf sprintf #include #define ft_qsort qsort #define ft_scalloc calloc #define ft_sfree free #define ft_smalloc malloc #define ft_srealloc realloc #define ft_atol atol #define ft_labs labs #include #define ft_jmp_buf jmp_buf #define ft_longjmp longjmp #define ft_setjmp( b ) setjmp( *(ft_jmp_buf*) &(b) ) /* same thing here */ #include #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif #ifndef NULL #define NULL (void*)0 #endif #define FT_CONFIG_OPTION_INLINE_MULFIX #define FT_CONFIG_OPTION_USE_LZW #define FT_CONFIG_OPTION_USE_ZLIB #define FT_CONFIG_OPTION_DISABLE_STREAM_SUPPORT #define FT_CONFIG_OPTION_POSTSCRIPT_NAMES #define FT_CONFIG_OPTION_ADOBE_GLYPH_LIST #define FT_CONFIG_OPTION_MAC_FONTS #define FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK #define FT_CONFIG_OPTION_INCREMENTAL #define FT_CONFIG_OPTION_FORCE_INT64 #define AF_CONFIG_OPTION_CJK #define AF_CONFIG_OPTION_INDIC #define TT_CONFIG_OPTION_EMBEDDED_BITMAPS #define TT_CONFIG_OPTION_POSTSCRIPT_NAMES #define TT_CONFIG_OPTION_SFNT_NAMES #define TT_CONFIG_OPTION_BYTECODE_INTERPRETER #define TT_CONFIG_OPTION_INTERPRETER_SWITCH #define TT_CONFIG_OPTION_GX_VAR_SUPPORT //#define TT_CONFIG_OPTION_BDF #define TT_CONFIG_CMAP_FORMAT_0 #define TT_CONFIG_CMAP_FORMAT_2 #define TT_CONFIG_CMAP_FORMAT_4 #define TT_CONFIG_CMAP_FORMAT_6 #define TT_CONFIG_CMAP_FORMAT_8 #define TT_CONFIG_CMAP_FORMAT_10 #define TT_CONFIG_CMAP_FORMAT_12 #define TT_CONFIG_CMAP_FORMAT_13 #define TT_CONFIG_CMAP_FORMAT_14 // ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ #define FT_MIN( a, b ) ( (a) < (b) ? (a) : (b) ) #define FT_MAX( a, b ) ( (a) > (b) ? (a) : (b) ) #define FT_ABS( a ) ( (a) < 0 ? -(a) : (a) ) #define FT_PAD_FLOOR( x, n ) ( (x) & ~((n)-1) ) #define FT_PAD_ROUND( x, n ) FT_PAD_FLOOR( (x) + ((n)/2), n ) #define FT_PAD_CEIL( x, n ) FT_PAD_FLOOR( (x) + ((n)-1), n ) #define FT_PIX_FLOOR( x ) ( (x) & ~63 ) #define FT_PIX_ROUND( x ) FT_PIX_FLOOR( (x) + 32 ) #define FT_PIX_CEIL( x ) FT_PIX_FLOOR( (x) + 63 ) #define FREETYPE_MAJOR 2 #define FREETYPE_MINOR 5 #define FREETYPE_PATCH 3 #define FT_OPEN_MEMORY 0x1 #define FT_OPEN_STREAM 0x2 #define FT_OPEN_PATHNAME 0x4 #define FT_OPEN_DRIVER 0x8 #define FT_OPEN_PARAMS 0x10 #define ft_open_memory FT_OPEN_MEMORY /* deprecated */ #define ft_open_stream FT_OPEN_STREAM /* deprecated */ #define ft_open_pathname FT_OPEN_PATHNAME /* deprecated */ #define ft_open_driver FT_OPEN_DRIVER /* deprecated */ #define ft_open_params FT_OPEN_PARAMS /* deprecated */ #define FT_LOAD_DEFAULT 0x0 #define FT_LOAD_NO_SCALE ( 1L << 0 ) #define FT_LOAD_NO_HINTING ( 1L << 1 ) #define FT_LOAD_RENDER ( 1L << 2 ) #define FT_LOAD_NO_BITMAP ( 1L << 3 ) #define FT_LOAD_VERTICAL_LAYOUT ( 1L << 4 ) #define FT_LOAD_FORCE_AUTOHINT ( 1L << 5 ) #define FT_LOAD_CROP_BITMAP ( 1L << 6 ) #define FT_LOAD_PEDANTIC ( 1L << 7 ) #define FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH ( 1L << 9 ) #define FT_LOAD_NO_RECURSE ( 1L << 10 ) #define FT_LOAD_IGNORE_TRANSFORM ( 1L << 11 ) #define FT_LOAD_MONOCHROME ( 1L << 12 ) #define FT_LOAD_LINEAR_DESIGN ( 1L << 13 ) #define FT_LOAD_NO_AUTOHINT ( 1L << 15 ) #define FT_LOAD_COLOR ( 1L << 20 ) #define FT_LOAD_ADVANCE_ONLY ( 1L << 8 ) #define FT_LOAD_SBITS_ONLY ( 1L << 14 ) #define FT_ADVANCE_FLAG_FAST_ONLY 0x20000000UL #define FT_LOAD_TARGET_(x) ( (FT_Int32)( (x) & 15 ) << 16 ) #define FT_LOAD_TARGET_NORMAL FT_LOAD_TARGET_( FT_RENDER_MODE_NORMAL ) #define FT_LOAD_TARGET_LIGHT FT_LOAD_TARGET_( FT_RENDER_MODE_LIGHT ) #define FT_LOAD_TARGET_MONO FT_LOAD_TARGET_( FT_RENDER_MODE_MONO ) #define FT_LOAD_TARGET_LCD FT_LOAD_TARGET_( FT_RENDER_MODE_LCD ) #define FT_LOAD_TARGET_LCD_V FT_LOAD_TARGET_( FT_RENDER_MODE_LCD_V ) #define FT_LOAD_TARGET_MODE(x) ( (FT_Render_Mode)( ( (x) >> 16 ) & 15 ) ) #define ft_render_mode_normal FT_RENDER_MODE_NORMAL #define ft_render_mode_mono FT_RENDER_MODE_MONO #define ft_kerning_default FT_KERNING_DEFAULT #define ft_kerning_unfitted FT_KERNING_UNFITTED #define ft_kerning_unscaled FT_KERNING_UNSCALED #define FT_SUBGLYPH_FLAG_ARGS_ARE_WORDS 1 #define FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES 2 #define FT_SUBGLYPH_FLAG_ROUND_XY_TO_GRID 4 #define FT_SUBGLYPH_FLAG_SCALE 8 #define FT_SUBGLYPH_FLAG_XY_SCALE 0x40 #define FT_SUBGLYPH_FLAG_2X2 0x80 #define FT_SUBGLYPH_FLAG_USE_MY_METRICS 0x200 #define FT_FSTYPE_INSTALLABLE_EMBEDDING 0x0000 #define FT_FSTYPE_RESTRICTED_LICENSE_EMBEDDING 0x0002 #define FT_FSTYPE_PREVIEW_AND_PRINT_EMBEDDING 0x0004 #define FT_FSTYPE_EDITABLE_EMBEDDING 0x0008 #define FT_FSTYPE_NO_SUBSETTING 0x0100 #define FT_FSTYPE_BITMAP_EMBEDDING_ONLY 0x0200 #define FT_IS_SCALABLE( face ) ( face->face_flags & FT_FACE_FLAG_SCALABLE ) #define FT_HAS_VERTICAL( face ) ( face->face_flags & FT_FACE_FLAG_VERTICAL ) #define FT_HAS_FIXED_SIZES( face ) ( face->face_flags & FT_FACE_FLAG_FIXED_SIZES ) #define FT_BEGIN_STMNT do { #define FT_END_STMNT } while ( 0 ) #define FT_DUMMY_STMNT FT_BEGIN_STMNT FT_END_STMNT #define FT_BASE_DEF(x) x #define FT_CALLBACK_DEF( x ) extern "C" x #define FT_EXPORT_DEF( x ) extern "C" x extern "C++" template inline T* cplusplus_typeof( T*, void *v ) { return static_cast ( v ); } #define FT_RENDER_POOL_SIZE 16384L #define FT_ASSIGNP( p, val ) (p) = cplusplus_typeof( (p), (val) ) #define FT_DEBUG_INNER( exp ) (exp) #define FT_ASSIGNP_INNER( p, exp ) FT_ASSIGNP( p, exp ) #define FT_MEM_ALLOC( ptr, size ) FT_ASSIGNP_INNER( ptr, ft_mem_alloc( memory, (FT_Long)(size), &error ) ) #define FT_MEM_FREE( ptr ) FT_BEGIN_STMNT ft_mem_free( memory, (ptr) ); (ptr) = NULL; FT_END_STMNT #define FT_MEM_NEW( ptr ) FT_MEM_ALLOC( ptr, sizeof ( *(ptr) ) ) #define FT_MEM_SET_ERROR( cond ) ( (cond), error != 0 ) #define FT_MEM_SET( dest, byte, count ) ft_memset( dest, byte, count ) #define FT_MEM_COPY( dest, source, count ) ft_memcpy( dest, source, count ) #define FT_MEM_MOVE( dest, source, count ) ft_memmove( dest, source, count ) #define FT_MEM_ZERO( dest, count ) FT_MEM_SET( dest, 0, count ) #define FT_ZERO( p ) FT_MEM_ZERO( p, sizeof ( *(p) ) ) #define FT_ARRAY_ZERO( dest, count ) FT_MEM_ZERO( dest, (count) * sizeof ( *(dest) ) ) #define FT_ARRAY_COPY( dest, source, count ) FT_MEM_COPY( dest, source, (count) * sizeof ( *(dest) ) ) #define FT_ARRAY_MOVE( dest, source, count ) FT_MEM_MOVE( dest, source, (count) * sizeof ( *(dest) ) ) #define FT_ALLOC( ptr, size ) FT_MEM_SET_ERROR( FT_MEM_ALLOC( ptr, size ) ) #define FT_REALLOC( ptr, cursz, newsz ) FT_MEM_SET_ERROR( FT_MEM_REALLOC( ptr, cursz, newsz ) ) #define FT_ALLOC_MULT( ptr, count, item_size ) FT_MEM_SET_ERROR( FT_MEM_ALLOC_MULT( ptr, count, item_size ) ) #define FT_FREE( ptr ) FT_MEM_FREE( ptr ) #define FT_NEW( ptr ) FT_MEM_SET_ERROR( FT_MEM_NEW( ptr ) ) #define FT_NEW_ARRAY( ptr, count ) \ FT_MEM_SET_ERROR( FT_MEM_NEW_ARRAY( ptr, count ) ) #define FT_RENEW_ARRAY( ptr, curcnt, newcnt ) \ FT_MEM_SET_ERROR( FT_MEM_RENEW_ARRAY( ptr, curcnt, newcnt ) ) #define FT_QNEW( ptr ) \ FT_MEM_SET_ERROR( FT_MEM_QNEW( ptr ) ) #define FT_QNEW_ARRAY( ptr, count ) \ FT_MEM_SET_ERROR( FT_MEM_NEW_ARRAY( ptr, count ) ) #define FT_QRENEW_ARRAY( ptr, curcnt, newcnt ) \ FT_MEM_SET_ERROR( FT_MEM_RENEW_ARRAY( ptr, curcnt, newcnt ) ) #define FT_QALLOC( ptr, size ) \ FT_MEM_SET_ERROR( FT_MEM_QALLOC( ptr, size ) ) #define FT_QREALLOC( ptr, cursz, newsz ) \ FT_MEM_SET_ERROR( FT_MEM_QREALLOC( ptr, cursz, newsz ) ) #define FT_MEM_QALLOC( ptr, size ) \ FT_ASSIGNP_INNER( ptr, ft_mem_qalloc( memory, \ (FT_Long)(size), \ &error ) ) #define FT_MEM_QREALLOC( ptr, cursz, newsz ) \ FT_ASSIGNP_INNER( ptr, ft_mem_qrealloc( memory, \ 1, \ (FT_Long)(cursz), \ (FT_Long)(newsz), \ (ptr), \ &error ) ) #define FT_MEM_ALLOC_MULT( ptr, count, item_size ) \ FT_ASSIGNP_INNER( ptr, ft_mem_realloc( memory, \ (FT_Long)(item_size), \ 0, \ (FT_Long)(count), \ NULL, \ &error ) ) #define FT_MEM_NEW_ARRAY( ptr, count ) \ FT_ASSIGNP_INNER( ptr, ft_mem_realloc( memory, \ sizeof ( *(ptr) ), \ 0, \ (FT_Long)(count), \ NULL, \ &error ) ) #define FT_MEM_RENEW_ARRAY( ptr, cursz, newsz ) \ FT_ASSIGNP_INNER( ptr, ft_mem_realloc( memory, \ sizeof ( *(ptr) ), \ (FT_Long)(cursz), \ (FT_Long)(newsz), \ (ptr), \ &error ) ) #define FT_NEW_ARRAY( ptr, count ) \ FT_MEM_SET_ERROR( FT_MEM_NEW_ARRAY( ptr, count ) ) #define FT_RENEW_ARRAY( ptr, curcnt, newcnt ) \ FT_MEM_SET_ERROR( FT_MEM_RENEW_ARRAY( ptr, curcnt, newcnt ) ) #define FT_IS_EMPTY(list) ( (list).head == 0 ) #define FT_BOOL(x) ( (FT_Bool)( x ) ) #define FT_ERR_XCAT(x, y) x ## y #define FT_ERR_CAT(x, y) FT_ERR_XCAT( x, y ) #define FT_ERR(e) FT_ERR_CAT( FT_ERR_PREFIX, e ) #define FT_ERROR_BASE(x) ( (x) & 0xFF ) #define FT_ERROR_MODULE(x) ( (x) & 0xFF00U ) #define FT_ERR_EQ(x, e) ( FT_ERROR_BASE( x ) == FT_ERROR_BASE( FT_ERR( e ) ) ) #define FT_ERR_NEQ(x, e) ( FT_ERROR_BASE( x ) != FT_ERROR_BASE( FT_ERR( e ) ) ) #define FT_SERVICE_UNAVAILABLE ((FT_Pointer)~(FT_PtrDist)1) #define FT_DEFINE_SERVICE( name ) \ typedef struct FT_Service_ ## name ## Rec_ \ FT_Service_ ## name ## Rec ; \ typedef struct FT_Service_ ## name ## Rec_ \ const * FT_Service_ ## name ; \ struct FT_Service_ ## name ## Rec_ #define FT_FACE_FIND_SERVICE( face, ptr, id ) \ FT_BEGIN_STMNT \ FT_Module module = FT_MODULE( FT_FACE( face )->driver ); \ FT_Pointer _tm__ = NULL; \ FT_Pointer* _pptr_ = (FT_Pointer*)&(ptr); \ \ \ if ( module->clazz->get_interface ) \ _tm__ = module->clazz->get_interface( module, FT_SERVICE_ID_ ## id ); \ *_pptr_ = _tm__; \ FT_END_STMNT #define FT_FACE_LOOKUP_SERVICE( face, ptr, id ) \ FT_BEGIN_STMNT \ FT_Pointer svc; \ FT_Pointer* Pptr = (FT_Pointer*)&(ptr); \ \ \ svc = FT_FACE( face )->internal->services. service_ ## id; \ if ( svc == FT_SERVICE_UNAVAILABLE ) \ svc = NULL; \ else if ( svc == NULL ) \ { \ FT_FACE_FIND_SERVICE( face, svc, id ); \ \ FT_FACE( face )->internal->services. service_ ## id = \ (FT_Pointer)( svc != NULL ? svc \ : FT_SERVICE_UNAVAILABLE ); \ } \ *Pptr = svc; \ FT_END_STMNT #define FT_HAS_GLYPH_NAMES( face ) ( face->face_flags & FT_FACE_FLAG_GLYPH_NAMES ) #define FT_MAKE_TAG(_x1, _x2, _x3, _x4) (FT_Tag) (((FT_ULong) _x1 << 24) | ((FT_ULong) _x2 << 16) | ((FT_ULong) _x3 << 8) | (FT_ULong) _x4) #define FT_ENC_TAG(value, a, b, c, d) value = (((FT_UInt32)(a) << 24) | ((FT_UInt32)(b) << 16) | ((FT_UInt32)(c) << 8) | (FT_UInt32)(d)) #define FT_IMAGE_TAG( value, _x1, _x2, _x3, _x4 ) value = ( ( (unsigned long)_x1 << 24 ) | ( (unsigned long)_x2 << 16 ) | ( (unsigned long)_x3 << 8 ) | (unsigned long)_x4 ) #define FT_ERR_PREFIX FT_Err_ #define FT_ERR_BASE 0 #define FT_ERRORDEF( e, v, s ) e = v, #define FT_ERRORDEF_( e, v, s ) FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v + FT_ERR_BASE, s ) #define FT_NOERRORDEF_( e, v, s ) FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v, s ) #define FT_ERROR_ASSERT( varformat, ... ) BxASSERT( varformat, false ) #define FT_ERROR( m ) FT_ERROR_ASSERT m #define FT_THROW( e ) ( FT_Throw( FT_ERR_CAT( FT_ERR_PREFIX, e ), __LINE__, __FILE__ ) | FT_ERR_CAT( FT_ERR_PREFIX, e ) ) #define FT_ASSERT( condition ) BxASSERT( "BxCore::AddOn", condition ) #define FT_READ_MACRO( func, type, var ) \ ( var = (type)func( stream, &error ), \ error != FT_Err_Ok ) #define FT_READ_BYTE( var ) FT_READ_MACRO( FT_Stream_ReadChar, FT_Byte, var ) #define FT_READ_CHAR( var ) FT_READ_MACRO( FT_Stream_ReadChar, FT_Char, var ) #define FT_READ_SHORT( var ) FT_READ_MACRO( FT_Stream_ReadUShort, FT_Short, var ) #define FT_READ_USHORT( var ) FT_READ_MACRO( FT_Stream_ReadUShort, FT_UShort, var ) #define FT_READ_OFF3( var ) FT_READ_MACRO( FT_Stream_ReadUOffset, FT_Long, var ) #define FT_READ_UOFF3( var ) FT_READ_MACRO( FT_Stream_ReadUOffset, FT_ULong, var ) #define FT_READ_LONG( var ) FT_READ_MACRO( FT_Stream_ReadULong, FT_Long, var ) #define FT_READ_ULONG( var ) FT_READ_MACRO( FT_Stream_ReadULong, FT_ULong, var ) #define FT_READ_SHORT_LE( var ) FT_READ_MACRO( FT_Stream_ReadUShortLE, FT_Short, var ) #define FT_READ_USHORT_LE( var ) FT_READ_MACRO( FT_Stream_ReadUShortLE, FT_UShort, var ) #define FT_READ_LONG_LE( var ) FT_READ_MACRO( FT_Stream_ReadULongLE, FT_Long, var ) #define FT_READ_ULONG_LE( var ) FT_READ_MACRO( FT_Stream_ReadULongLE, FT_ULong, var ) #define FT_BYTE_( p, i ) ( ((const FT_Byte*)(p))[(i)] ) #define FT_INT16( x ) ( (FT_Int16)(x) ) #define FT_UINT16( x ) ( (FT_UInt16)(x) ) #define FT_INT32( x ) ( (FT_Int32)(x) ) #define FT_UINT32( x ) ( (FT_UInt32)(x) ) #define FT_BYTE_U16( p, i, s ) ( FT_UINT16( FT_BYTE_( p, i ) ) << (s) ) #define FT_BYTE_U32( p, i, s ) ( FT_UINT32( FT_BYTE_( p, i ) ) << (s) ) #define FT_PEEK_LONG( p ) FT_INT32( FT_BYTE_U32( p, 0, 24 ) | \ FT_BYTE_U32( p, 1, 16 ) | \ FT_BYTE_U32( p, 2, 8 ) | \ FT_BYTE_U32( p, 3, 0 ) ) #define FT_PEEK_ULONG( p ) FT_UINT32( FT_BYTE_U32( p, 0, 24 ) | \ FT_BYTE_U32( p, 1, 16 ) | \ FT_BYTE_U32( p, 2, 8 ) | \ FT_BYTE_U32( p, 3, 0 ) ) #define FT_PEEK_SHORT( p ) FT_INT16( FT_BYTE_U16( p, 0, 8) | \ FT_BYTE_U16( p, 1, 0) ) #define FT_PEEK_USHORT( p ) FT_UINT16( FT_BYTE_U16( p, 0, 8 ) | \ FT_BYTE_U16( p, 1, 0 ) ) #define FT_NEXT_LONG( buffer ) \ ( (long)( buffer += 4, FT_PEEK_LONG( buffer - 4 ) ) ) #define FT_NEXT_ULONG( buffer ) \ ( (unsigned long)( buffer += 4, FT_PEEK_ULONG( buffer - 4 ) ) ) #define FT_NEXT_SHORT( buffer ) \ ( (short)( buffer += 2, FT_PEEK_SHORT( buffer - 2 ) ) ) #define FT_NEXT_USHORT( buffer ) \ ( (unsigned short)( buffer += 2, FT_PEEK_USHORT( buffer - 2 ) ) ) #define FT_NEXT_CHAR( buffer ) \ ( (signed char)*buffer++ ) #define FT_NEXT_BYTE( buffer ) \ ( (unsigned char)*buffer++ ) #define FT_PEEK_SHORT( p ) FT_INT16( FT_BYTE_U16( p, 0, 8) | \ FT_BYTE_U16( p, 1, 0) ) #define FT_PEEK_USHORT( p ) FT_UINT16( FT_BYTE_U16( p, 0, 8 ) | \ FT_BYTE_U16( p, 1, 0 ) ) #define FT_PEEK_LONG( p ) FT_INT32( FT_BYTE_U32( p, 0, 24 ) | \ FT_BYTE_U32( p, 1, 16 ) | \ FT_BYTE_U32( p, 2, 8 ) | \ FT_BYTE_U32( p, 3, 0 ) ) #define FT_PEEK_ULONG( p ) FT_UINT32( FT_BYTE_U32( p, 0, 24 ) | \ FT_BYTE_U32( p, 1, 16 ) | \ FT_BYTE_U32( p, 2, 8 ) | \ FT_BYTE_U32( p, 3, 0 ) ) #define FT_PEEK_OFF3( p ) FT_INT32( FT_BYTE_U32( p, 0, 16 ) | \ FT_BYTE_U32( p, 1, 8 ) | \ FT_BYTE_U32( p, 2, 0 ) ) #define FT_PEEK_UOFF3( p ) FT_UINT32( FT_BYTE_U32( p, 0, 16 ) | \ FT_BYTE_U32( p, 1, 8 ) | \ FT_BYTE_U32( p, 2, 0 ) ) #define FT_PEEK_SHORT_LE( p ) FT_INT16( FT_BYTE_U16( p, 1, 8 ) | \ FT_BYTE_U16( p, 0, 0 ) ) #define FT_PEEK_USHORT_LE( p ) FT_UINT16( FT_BYTE_U16( p, 1, 8 ) | \ FT_BYTE_U16( p, 0, 0 ) ) #define FT_PEEK_LONG_LE( p ) FT_INT32( FT_BYTE_U32( p, 3, 24 ) | \ FT_BYTE_U32( p, 2, 16 ) | \ FT_BYTE_U32( p, 1, 8 ) | \ FT_BYTE_U32( p, 0, 0 ) ) #define FT_PEEK_ULONG_LE( p ) FT_UINT32( FT_BYTE_U32( p, 3, 24 ) | \ FT_BYTE_U32( p, 2, 16 ) | \ FT_BYTE_U32( p, 1, 8 ) | \ FT_BYTE_U32( p, 0, 0 ) ) #define FT_PEEK_OFF3_LE( p ) FT_INT32( FT_BYTE_U32( p, 2, 16 ) | \ FT_BYTE_U32( p, 1, 8 ) | \ FT_BYTE_U32( p, 0, 0 ) ) #define FT_PEEK_UOFF3_LE( p ) FT_UINT32( FT_BYTE_U32( p, 2, 16 ) | \ FT_BYTE_U32( p, 1, 8 ) | \ FT_BYTE_U32( p, 0, 0 ) ) #define FT_NEXT_CHAR( buffer ) \ ( (signed char)*buffer++ ) #define FT_NEXT_BYTE( buffer ) \ ( (unsigned char)*buffer++ ) #define FT_NEXT_SHORT( buffer ) \ ( (short)( buffer += 2, FT_PEEK_SHORT( buffer - 2 ) ) ) #define FT_NEXT_USHORT( buffer ) \ ( (unsigned short)( buffer += 2, FT_PEEK_USHORT( buffer - 2 ) ) ) #define FT_NEXT_OFF3( buffer ) \ ( (long)( buffer += 3, FT_PEEK_OFF3( buffer - 3 ) ) ) #define FT_NEXT_UOFF3( buffer ) \ ( (unsigned long)( buffer += 3, FT_PEEK_UOFF3( buffer - 3 ) ) ) #define FT_NEXT_LONG( buffer ) \ ( (long)( buffer += 4, FT_PEEK_LONG( buffer - 4 ) ) ) #define FT_NEXT_ULONG( buffer ) \ ( (unsigned long)( buffer += 4, FT_PEEK_ULONG( buffer - 4 ) ) ) #define FT_NEXT_SHORT_LE( buffer ) \ ( (short)( buffer += 2, FT_PEEK_SHORT_LE( buffer - 2 ) ) ) #define FT_NEXT_USHORT_LE( buffer ) \ ( (unsigned short)( buffer += 2, FT_PEEK_USHORT_LE( buffer - 2 ) ) ) #define FT_NEXT_OFF3_LE( buffer ) \ ( (long)( buffer += 3, FT_PEEK_OFF3_LE( buffer - 3 ) ) ) #define FT_NEXT_UOFF3_LE( buffer ) \ ( (unsigned long)( buffer += 3, FT_PEEK_UOFF3_LE( buffer - 3 ) ) ) #define FT_NEXT_LONG_LE( buffer ) \ ( (long)( buffer += 4, FT_PEEK_LONG_LE( buffer - 4 ) ) ) #define FT_NEXT_ULONG_LE( buffer ) \ ( (unsigned long)( buffer += 4, FT_PEEK_ULONG_LE( buffer - 4 ) ) ) #define FT_SET_ERROR( expression ) \ ( ( error = (expression) ) != 0 ) #define FT_STREAM_POS() \ FT_Stream_Pos( stream ) #define FT_STREAM_SEEK( position ) \ FT_SET_ERROR( FT_Stream_Seek( stream, \ (FT_ULong)(position) ) ) #define FT_STREAM_SKIP( distance ) \ FT_SET_ERROR( FT_Stream_Skip( stream, \ (FT_Long)(distance) ) ) #define FT_STREAM_READ( buffer, count ) \ FT_SET_ERROR( FT_Stream_Read( stream, \ (FT_Byte*)(buffer), \ (FT_ULong)(count) ) ) #define FT_STREAM_READ_AT( position, buffer, count ) \ FT_SET_ERROR( FT_Stream_ReadAt( stream, \ (FT_ULong)(position), \ (FT_Byte*)buffer, \ (FT_ULong)(count) ) ) #define FT_STREAM_READ_FIELDS( fields, object ) \ FT_SET_ERROR( FT_Stream_ReadFields( stream, fields, object ) ) #define FT_FRAME_ENTER( size ) \ FT_SET_ERROR( \ FT_DEBUG_INNER( FT_Stream_EnterFrame( stream, \ (FT_ULong)(size) ) ) ) #define FT_FRAME_EXIT() \ FT_DEBUG_INNER( FT_Stream_ExitFrame( stream ) ) #define FT_FRAME_EXTRACT( size, bytes ) \ FT_SET_ERROR( \ FT_DEBUG_INNER( FT_Stream_ExtractFrame( stream, \ (FT_ULong)(size), \ (FT_Byte**)&(bytes) ) ) ) #define FT_FRAME_RELEASE( bytes ) \ FT_DEBUG_INNER( FT_Stream_ReleaseFrame( stream, \ (FT_Byte**)&(bytes) ) ) #define FT_FIELD_SIZE( f ) \ (FT_Byte)sizeof ( ((FT_STRUCTURE*)0)->f ) #define FT_FIELD_SIZE_DELTA( f ) \ (FT_Byte)sizeof ( ((FT_STRUCTURE*)0)->f[0] ) #define FT_FIELD_OFFSET( f ) \ (FT_UShort)( offsetof( FT_STRUCTURE, f ) ) #define FT_MAKE_EMPTY_FIELD( frame_op ) { frame_op, 0, 0 } #define FT_FRAME_FIELD( frame_op, field ) \ { \ frame_op, \ FT_FIELD_SIZE( field ), \ FT_FIELD_OFFSET( field ) \ } #define FT_FRAME_START( size ) { ft_frame_start, 0, size } #define FT_FRAME_END { ft_frame_end, 0, 0 } #define FT_FRAME_LONG( f ) FT_FRAME_FIELD( ft_frame_long_be, f ) #define FT_FRAME_ULONG( f ) FT_FRAME_FIELD( ft_frame_ulong_be, f ) #define FT_FRAME_SHORT( f ) FT_FRAME_FIELD( ft_frame_short_be, f ) #define FT_FRAME_USHORT( f ) FT_FRAME_FIELD( ft_frame_ushort_be, f ) #define FT_FRAME_OFF3( f ) FT_FRAME_FIELD( ft_frame_off3_be, f ) #define FT_FRAME_UOFF3( f ) FT_FRAME_FIELD( ft_frame_uoff3_be, f ) #define FT_FRAME_BYTE( f ) FT_FRAME_FIELD( ft_frame_byte, f ) #define FT_FRAME_CHAR( f ) FT_FRAME_FIELD( ft_frame_schar, f ) #define FT_FRAME_LONG_LE( f ) FT_FRAME_FIELD( ft_frame_long_le, f ) #define FT_FRAME_ULONG_LE( f ) FT_FRAME_FIELD( ft_frame_ulong_le, f ) #define FT_FRAME_SHORT_LE( f ) FT_FRAME_FIELD( ft_frame_short_le, f ) #define FT_FRAME_USHORT_LE( f ) FT_FRAME_FIELD( ft_frame_ushort_le, f ) #define FT_FRAME_OFF3_LE( f ) FT_FRAME_FIELD( ft_frame_off3_le, f ) #define FT_FRAME_UOFF3_LE( f ) FT_FRAME_FIELD( ft_frame_uoff3_le, f ) #define FT_FRAME_SKIP_LONG { ft_frame_long_be, 0, 0 } #define FT_FRAME_SKIP_SHORT { ft_frame_short_be, 0, 0 } #define FT_FRAME_SKIP_BYTE { ft_frame_byte, 0, 0 } #define FT_FRAME_BYTES( field, count ) \ { \ ft_frame_bytes, \ count, \ FT_FIELD_OFFSET( field ) \ } #define FT_FRAME_SKIP_BYTES( count ) { ft_frame_skip, count, 0 } #define FT_FRAME_OP_SHIFT 2 #define FT_FRAME_OP_SIGNED 1 #define FT_FRAME_OP_LITTLE 2 #define FT_FRAME_OP_COMMAND( x ) ( x >> FT_FRAME_OP_SHIFT ) #define FT_MAKE_FRAME_OP( command, little, sign ) \ ( ( command << FT_FRAME_OP_SHIFT ) | ( little << 1 ) | sign ) #define FT_FRAME_OP_END 0 #define FT_FRAME_OP_START 1 /* start a new frame */ #define FT_FRAME_OP_BYTE 2 /* read 1-byte value */ #define FT_FRAME_OP_SHORT 3 /* read 2-byte value */ #define FT_FRAME_OP_LONG 4 /* read 4-byte value */ #define FT_FRAME_OP_OFF3 5 /* read 3-byte value */ #define FT_FRAME_OP_BYTES 6 /* read a bytes sequence */ #define FT_DRIVER( x ) ((FT_Driver)(x)) #define FT_DRIVER_CLASS( x ) FT_DRIVER( x )->clazz #define FT_MODULE_FONT_DRIVER 1 /* this module is a font driver */ #define FT_MODULE_RENDERER 2 /* this module is a renderer */ #define FT_MODULE_HINTER 4 /* this module is a glyph hinter */ #define FT_MODULE_STYLER 8 /* this module is a styler */ #define FT_MODULE_DRIVER_SCALABLE 0x100 /* the driver supports */ /* scalable fonts */ #define FT_MODULE_DRIVER_NO_OUTLINES 0x200 /* the driver does not */ /* support vector outlines */ #define FT_MODULE_DRIVER_HAS_HINTER 0x400 /* the driver provides its */ /* own hinter */ #define FT_MODULE( x ) ((FT_Module)( x )) #define FT_MODULE_CLASS( x ) FT_MODULE( x )->clazz #define FT_MODULE_LIBRARY( x ) FT_MODULE( x )->library #define FT_MODULE_MEMORY( x ) FT_MODULE( x )->memory #define FT_MODULE_IS_DRIVER( x ) ( FT_MODULE_CLASS( x )->module_flags & FT_MODULE_FONT_DRIVER ) #define FT_MODULE_IS_RENDERER( x ) ( FT_MODULE_CLASS( x )->module_flags & FT_MODULE_RENDERER ) #define FT_MODULE_IS_HINTER( x ) ( FT_MODULE_CLASS( x )->module_flags & FT_MODULE_HINTER ) #define FT_MODULE_IS_STYLER( x ) ( FT_MODULE_CLASS( x )->module_flags & FT_MODULE_STYLER ) #define FT_DRIVER_IS_SCALABLE( x ) ( FT_MODULE_CLASS( x )->module_flags & FT_MODULE_DRIVER_SCALABLE ) #define FT_DRIVER_USES_OUTLINES( x ) !( FT_MODULE_CLASS( x )->module_flags & FT_MODULE_DRIVER_NO_OUTLINES ) #define FT_DRIVER_HAS_HINTER( x ) ( FT_MODULE_CLASS( x )->module_flags & FT_MODULE_DRIVER_HAS_HINTER ) #define TT_PLATFORM_APPLE_UNICODE 0 #define TT_PLATFORM_MACINTOSH 1 #define TT_PLATFORM_ISO 2 /* deprecated */ #define TT_PLATFORM_MICROSOFT 3 #define TT_PLATFORM_CUSTOM 4 #define TT_PLATFORM_ADOBE 7 /* artificial */ #define TT_MS_ID_SYMBOL_CS 0 #define TT_MS_ID_UNICODE_CS 1 #define TT_MS_ID_SJIS 2 #define TT_MS_ID_GB2312 3 #define TT_MS_ID_BIG_5 4 #define TT_MS_ID_WANSUNG 5 #define TT_MS_ID_JOHAB 6 #define TT_MS_ID_UCS_4 10 #define TT_APPLE_ID_DEFAULT 0 /* Unicode 1.0 */ #define TT_APPLE_ID_UNICODE_1_1 1 /* specify Hangul at U+34xx */ #define TT_APPLE_ID_ISO_10646 2 /* deprecated */ #define TT_APPLE_ID_UNICODE_2_0 3 /* or later */ #define TT_APPLE_ID_UNICODE_32 4 /* 2.0 or later, full repertoire */ #define TT_APPLE_ID_VARIANT_SELECTOR 5 /* variation selector data */ #define FT_CMAP( x ) ((FT_CMap)( x )) #define FT_CMAP_PLATFORM_ID( x ) FT_CMAP( x )->charmap.platform_id #define FT_CMAP_ENCODING_ID( x ) FT_CMAP( x )->charmap.encoding_id #define FT_CMAP_ENCODING( x ) FT_CMAP( x )->charmap.encoding #define FT_CMAP_FACE( x ) FT_CMAP( x )->charmap.face #define FT_OUTLINE_GLYPH_CLASS_GET &ft_outline_glyph_class #define FT_BITMAP_GLYPH_CLASS_GET &ft_bitmap_glyph_class #define FT_DEFAULT_MODULES_GET ft_default_modules #define FT_USE_MODULE( type, x ) (const FT_Module_Class*)&(x), #define FT_RENDERER( x ) ((FT_Renderer)( x )) #define FT_GLYPH( x ) ((FT_Glyph)( x )) #define FT_BITMAP_GLYPH( x ) ((FT_BitmapGlyph)( x )) #define FT_OUTLINE_GLYPH( x ) ((FT_OutlineGlyph)( x )) #define FT_GLYPH_OWN_BITMAP 0x1 #define FT_TRACE( level, varformat ) do { } while ( 0 ) #define FT_TRACE0( varformat ) FT_TRACE( 0, varformat ) #define FT_TRACE1( varformat ) FT_TRACE( 1, varformat ) #define FT_TRACE2( varformat ) FT_TRACE( 2, varformat ) #define FT_TRACE3( varformat ) FT_TRACE( 3, varformat ) #define FT_TRACE4( varformat ) FT_TRACE( 4, varformat ) #define FT_TRACE5( varformat ) FT_TRACE( 5, varformat ) #define FT_TRACE6( varformat ) FT_TRACE( 6, varformat ) #define FT_TRACE7( varformat ) FT_TRACE( 7, varformat ) #define FT_FACE( x ) ((FT_Face)(x)) #define FT_SIZE( x ) ((FT_Size)(x)) #define FT_SLOT( x ) ((FT_GlyphSlot)(x)) #define FT_FACE_DRIVER( x ) FT_FACE( x )->driver #define FT_FACE_LIBRARY( x ) FT_FACE_DRIVER( x )->root.library #define FT_FACE_MEMORY( x ) FT_FACE( x )->memory #define FT_FACE_STREAM( x ) FT_FACE( x )->stream #define FT_SIZE_FACE( x ) FT_SIZE( x )->face #define FT_SLOT_FACE( x ) FT_SLOT( x )->face #define FT_FACE_SLOT( x ) FT_FACE( x )->glyph #define FT_FACE_SIZE( x ) FT_FACE( x )->size #define FT_FACE_FLAG_SCALABLE ( 1L << 0 ) #define FT_FACE_FLAG_FIXED_SIZES ( 1L << 1 ) #define FT_FACE_FLAG_FIXED_WIDTH ( 1L << 2 ) #define FT_FACE_FLAG_SFNT ( 1L << 3 ) #define FT_FACE_FLAG_HORIZONTAL ( 1L << 4 ) #define FT_FACE_FLAG_VERTICAL ( 1L << 5 ) #define FT_FACE_FLAG_KERNING ( 1L << 6 ) #define FT_FACE_FLAG_FAST_GLYPHS ( 1L << 7 ) #define FT_FACE_FLAG_MULTIPLE_MASTERS ( 1L << 8 ) #define FT_FACE_FLAG_GLYPH_NAMES ( 1L << 9 ) #define FT_FACE_FLAG_EXTERNAL_STREAM ( 1L << 10 ) #define FT_FACE_FLAG_HINTER ( 1L << 11 ) #define FT_FACE_FLAG_CID_KEYED ( 1L << 12 ) #define FT_FACE_FLAG_TRICKY ( 1L << 13 ) #define FT_FACE_FLAG_COLOR ( 1L << 14 ) enum { /* generic errors */ FT_NOERRORDEF_( Ok, 0x00, "no error" ) FT_ERRORDEF_( Cannot_Open_Resource, 0x01, "cannot open resource" ) FT_ERRORDEF_( Unknown_File_Format, 0x02, "unknown file format" ) FT_ERRORDEF_( Invalid_File_Format, 0x03, "broken file" ) FT_ERRORDEF_( Invalid_Version, 0x04, "invalid FreeType version" ) FT_ERRORDEF_( Lower_Module_Version, 0x05, "module version is too low" ) FT_ERRORDEF_( Invalid_Argument, 0x06, "invalid argument" ) FT_ERRORDEF_( Unimplemented_Feature, 0x07, "unimplemented feature" ) FT_ERRORDEF_( Invalid_Table, 0x08, "broken table" ) FT_ERRORDEF_( Invalid_Offset, 0x09, "broken offset within table" ) FT_ERRORDEF_( Array_Too_Large, 0x0A, "array allocation size too large" ) FT_ERRORDEF_( Missing_Module, 0x0B, "missing module" ) FT_ERRORDEF_( Missing_Property, 0x0C, "missing property" ) /* glyph/character errors */ FT_ERRORDEF_( Invalid_Glyph_Index, 0x10, "invalid glyph index" ) FT_ERRORDEF_( Invalid_Character_Code, 0x11, "invalid character code" ) FT_ERRORDEF_( Invalid_Glyph_Format, 0x12, "unsupported glyph image format" ) FT_ERRORDEF_( Cannot_Render_Glyph, 0x13, "cannot render this glyph format" ) FT_ERRORDEF_( Invalid_Outline, 0x14, "invalid outline" ) FT_ERRORDEF_( Invalid_Composite, 0x15, "invalid composite glyph" ) FT_ERRORDEF_( Too_Many_Hints, 0x16, "too many hints" ) FT_ERRORDEF_( Invalid_Pixel_Size, 0x17, "invalid pixel size" ) /* handle errors */ FT_ERRORDEF_( Invalid_Handle, 0x20, "invalid object handle" ) FT_ERRORDEF_( Invalid_Library_Handle, 0x21, "invalid library handle" ) FT_ERRORDEF_( Invalid_Driver_Handle, 0x22, "invalid module handle" ) FT_ERRORDEF_( Invalid_Face_Handle, 0x23, "invalid face handle" ) FT_ERRORDEF_( Invalid_Size_Handle, 0x24, "invalid size handle" ) FT_ERRORDEF_( Invalid_Slot_Handle, 0x25, "invalid glyph slot handle" ) FT_ERRORDEF_( Invalid_CharMap_Handle, 0x26, "invalid charmap handle" ) FT_ERRORDEF_( Invalid_Cache_Handle, 0x27, "invalid cache manager handle" ) FT_ERRORDEF_( Invalid_Stream_Handle, 0x28, "invalid stream handle" ) /* driver errors */ FT_ERRORDEF_( Too_Many_Drivers, 0x30, "too many modules" ) FT_ERRORDEF_( Too_Many_Extensions, 0x31, "too many extensions" ) /* memory errors */ FT_ERRORDEF_( Out_Of_Memory, 0x40, "out of memory" ) FT_ERRORDEF_( Unlisted_Object, 0x41, "unlisted object" ) /* stream errors */ FT_ERRORDEF_( Cannot_Open_Stream, 0x51, "cannot open stream" ) FT_ERRORDEF_( Invalid_Stream_Seek, 0x52, "invalid stream seek" ) FT_ERRORDEF_( Invalid_Stream_Skip, 0x53, "invalid stream skip" ) FT_ERRORDEF_( Invalid_Stream_Read, 0x54, "invalid stream read" ) FT_ERRORDEF_( Invalid_Stream_Operation, 0x55, "invalid stream operation" ) FT_ERRORDEF_( Invalid_Frame_Operation, 0x56, "invalid frame operation" ) FT_ERRORDEF_( Nested_Frame_Access, 0x57, "nested frame access" ) FT_ERRORDEF_( Invalid_Frame_Read, 0x58, "invalid frame read" ) /* raster errors */ FT_ERRORDEF_( Raster_Uninitialized, 0x60, "raster uninitialized" ) FT_ERRORDEF_( Raster_Corrupted, 0x61, "raster corrupted" ) FT_ERRORDEF_( Raster_Overflow, 0x62, "raster overflow" ) FT_ERRORDEF_( Raster_Negative_Height, 0x63, "negative height while rastering" ) /* cache errors */ FT_ERRORDEF_( Too_Many_Caches, 0x70, "too many registered caches" ) /* TrueType and SFNT errors */ FT_ERRORDEF_( Invalid_Opcode, 0x80, "invalid opcode" ) FT_ERRORDEF_( Too_Few_Arguments, 0x81, "too few arguments" ) FT_ERRORDEF_( Stack_Overflow, 0x82, "stack overflow" ) FT_ERRORDEF_( Code_Overflow, 0x83, "code overflow" ) FT_ERRORDEF_( Bad_Argument, 0x84, "bad argument" ) FT_ERRORDEF_( Divide_By_Zero, 0x85, "division by zero" ) FT_ERRORDEF_( Invalid_Reference, 0x86, "invalid reference" ) FT_ERRORDEF_( Debug_OpCode, 0x87, "found debug opcode" ) FT_ERRORDEF_( ENDF_In_Exec_Stream, 0x88, "found ENDF opcode in execution stream" ) FT_ERRORDEF_( Nested_DEFS, 0x89, "nested DEFS" ) FT_ERRORDEF_( Invalid_CodeRange, 0x8A, "invalid code range" ) FT_ERRORDEF_( Execution_Too_Long, 0x8B, "execution context too long" ) FT_ERRORDEF_( Too_Many_Function_Defs, 0x8C, "too many function definitions" ) FT_ERRORDEF_( Too_Many_Instruction_Defs, 0x8D, "too many instruction definitions" ) FT_ERRORDEF_( Table_Missing, 0x8E, "SFNT font table missing" ) FT_ERRORDEF_( Horiz_Header_Missing, 0x8F, "horizontal header (hhea) table missing" ) FT_ERRORDEF_( Locations_Missing, 0x90, "locations (loca) table missing" ) FT_ERRORDEF_( Name_Table_Missing, 0x91, "name table missing" ) FT_ERRORDEF_( CMap_Table_Missing, 0x92, "character map (cmap) table missing" ) FT_ERRORDEF_( Hmtx_Table_Missing, 0x93, "horizontal metrics (hmtx) table missing" ) FT_ERRORDEF_( Post_Table_Missing, 0x94, "PostScript (post) table missing" ) FT_ERRORDEF_( Invalid_Horiz_Metrics, 0x95, "invalid horizontal metrics" ) FT_ERRORDEF_( Invalid_CharMap_Format, 0x96, "invalid character map (cmap) format" ) FT_ERRORDEF_( Invalid_PPem, 0x97, "invalid ppem value" ) FT_ERRORDEF_( Invalid_Vert_Metrics, 0x98, "invalid vertical metrics" ) FT_ERRORDEF_( Could_Not_Find_Context, 0x99, "could not find context" ) FT_ERRORDEF_( Invalid_Post_Table_Format, 0x9A, "invalid PostScript (post) table format" ) FT_ERRORDEF_( Invalid_Post_Table, 0x9B, "invalid PostScript (post) table" ) /* CFF, CID, and Type 1 errors */ FT_ERRORDEF_( Syntax_Error, 0xA0, "opcode syntax error" ) FT_ERRORDEF_( Stack_Underflow, 0xA1, "argument stack underflow" ) FT_ERRORDEF_( Ignore, 0xA2, "ignore" ) FT_ERRORDEF_( No_Unicode_Glyph_Name, 0xA3, "no Unicode glyph name found" ) FT_ERRORDEF_( Glyph_Too_Big, 0xA4, "glyph to big for hinting" ) /* BDF errors */ FT_ERRORDEF_( Missing_Startfont_Field, 0xB0, "`STARTFONT' field missing" ) FT_ERRORDEF_( Missing_Font_Field, 0xB1, "`FONT' field missing" ) FT_ERRORDEF_( Missing_Size_Field, 0xB2, "`SIZE' field missing" ) FT_ERRORDEF_( Missing_Fontboundingbox_Field, 0xB3, "`FONTBOUNDINGBOX' field missing" ) FT_ERRORDEF_( Missing_Chars_Field, 0xB4, "`CHARS' field missing" ) FT_ERRORDEF_( Missing_Startchar_Field, 0xB5, "`STARTCHAR' field missing" ) FT_ERRORDEF_( Missing_Encoding_Field, 0xB6, "`ENCODING' field missing" ) FT_ERRORDEF_( Missing_Bbx_Field, 0xB7, "`BBX' field missing" ) FT_ERRORDEF_( Bbx_Too_Big, 0xB8, "`BBX' too big" ) FT_ERRORDEF_( Corrupted_Font_Header, 0xB9, "Font header corrupted or missing fields" ) FT_ERRORDEF_( Corrupted_Font_Glyphs, 0xBA, "Font glyphs corrupted or missing fields" ) FT_ERR_CAT( FT_ERR_PREFIX, Max ) }; #define TTAG_avar FT_MAKE_TAG( 'a', 'v', 'a', 'r' ) #define TTAG_BASE FT_MAKE_TAG( 'B', 'A', 'S', 'E' ) #define TTAG_bdat FT_MAKE_TAG( 'b', 'd', 'a', 't' ) #define TTAG_BDF FT_MAKE_TAG( 'B', 'D', 'F', ' ' ) #define TTAG_bhed FT_MAKE_TAG( 'b', 'h', 'e', 'd' ) #define TTAG_bloc FT_MAKE_TAG( 'b', 'l', 'o', 'c' ) #define TTAG_bsln FT_MAKE_TAG( 'b', 's', 'l', 'n' ) #define TTAG_CBDT FT_MAKE_TAG( 'C', 'B', 'D', 'T' ) #define TTAG_CBLC FT_MAKE_TAG( 'C', 'B', 'L', 'C' ) #define TTAG_CFF FT_MAKE_TAG( 'C', 'F', 'F', ' ' ) #define TTAG_CID FT_MAKE_TAG( 'C', 'I', 'D', ' ' ) #define TTAG_cmap FT_MAKE_TAG( 'c', 'm', 'a', 'p' ) #define TTAG_cvar FT_MAKE_TAG( 'c', 'v', 'a', 'r' ) #define TTAG_cvt FT_MAKE_TAG( 'c', 'v', 't', ' ' ) #define TTAG_DSIG FT_MAKE_TAG( 'D', 'S', 'I', 'G' ) #define TTAG_EBDT FT_MAKE_TAG( 'E', 'B', 'D', 'T' ) #define TTAG_EBLC FT_MAKE_TAG( 'E', 'B', 'L', 'C' ) #define TTAG_EBSC FT_MAKE_TAG( 'E', 'B', 'S', 'C' ) #define TTAG_feat FT_MAKE_TAG( 'f', 'e', 'a', 't' ) #define TTAG_FOND FT_MAKE_TAG( 'F', 'O', 'N', 'D' ) #define TTAG_fpgm FT_MAKE_TAG( 'f', 'p', 'g', 'm' ) #define TTAG_fvar FT_MAKE_TAG( 'f', 'v', 'a', 'r' ) #define TTAG_gasp FT_MAKE_TAG( 'g', 'a', 's', 'p' ) #define TTAG_GDEF FT_MAKE_TAG( 'G', 'D', 'E', 'F' ) #define TTAG_glyf FT_MAKE_TAG( 'g', 'l', 'y', 'f' ) #define TTAG_GPOS FT_MAKE_TAG( 'G', 'P', 'O', 'S' ) #define TTAG_GSUB FT_MAKE_TAG( 'G', 'S', 'U', 'B' ) #define TTAG_gvar FT_MAKE_TAG( 'g', 'v', 'a', 'r' ) #define TTAG_hdmx FT_MAKE_TAG( 'h', 'd', 'm', 'x' ) #define TTAG_head FT_MAKE_TAG( 'h', 'e', 'a', 'd' ) #define TTAG_hhea FT_MAKE_TAG( 'h', 'h', 'e', 'a' ) #define TTAG_hmtx FT_MAKE_TAG( 'h', 'm', 't', 'x' ) #define TTAG_JSTF FT_MAKE_TAG( 'J', 'S', 'T', 'F' ) #define TTAG_just FT_MAKE_TAG( 'j', 'u', 's', 't' ) #define TTAG_kern FT_MAKE_TAG( 'k', 'e', 'r', 'n' ) #define TTAG_lcar FT_MAKE_TAG( 'l', 'c', 'a', 'r' ) #define TTAG_loca FT_MAKE_TAG( 'l', 'o', 'c', 'a' ) #define TTAG_LTSH FT_MAKE_TAG( 'L', 'T', 'S', 'H' ) #define TTAG_LWFN FT_MAKE_TAG( 'L', 'W', 'F', 'N' ) #define TTAG_MATH FT_MAKE_TAG( 'M', 'A', 'T', 'H' ) #define TTAG_maxp FT_MAKE_TAG( 'm', 'a', 'x', 'p' ) #define TTAG_META FT_MAKE_TAG( 'M', 'E', 'T', 'A' ) #define TTAG_MMFX FT_MAKE_TAG( 'M', 'M', 'F', 'X' ) #define TTAG_MMSD FT_MAKE_TAG( 'M', 'M', 'S', 'D' ) #define TTAG_mort FT_MAKE_TAG( 'm', 'o', 'r', 't' ) #define TTAG_morx FT_MAKE_TAG( 'm', 'o', 'r', 'x' ) #define TTAG_name FT_MAKE_TAG( 'n', 'a', 'm', 'e' ) #define TTAG_opbd FT_MAKE_TAG( 'o', 'p', 'b', 'd' ) #define TTAG_OS2 FT_MAKE_TAG( 'O', 'S', '/', '2' ) #define TTAG_OTTO FT_MAKE_TAG( 'O', 'T', 'T', 'O' ) #define TTAG_PCLT FT_MAKE_TAG( 'P', 'C', 'L', 'T' ) #define TTAG_POST FT_MAKE_TAG( 'P', 'O', 'S', 'T' ) #define TTAG_post FT_MAKE_TAG( 'p', 'o', 's', 't' ) #define TTAG_prep FT_MAKE_TAG( 'p', 'r', 'e', 'p' ) #define TTAG_prop FT_MAKE_TAG( 'p', 'r', 'o', 'p' ) #define TTAG_sbix FT_MAKE_TAG( 's', 'b', 'i', 'x' ) #define TTAG_sfnt FT_MAKE_TAG( 's', 'f', 'n', 't' ) #define TTAG_SING FT_MAKE_TAG( 'S', 'I', 'N', 'G' ) #define TTAG_trak FT_MAKE_TAG( 't', 'r', 'a', 'k' ) #define TTAG_true FT_MAKE_TAG( 't', 'r', 'u', 'e' ) #define TTAG_ttc FT_MAKE_TAG( 't', 't', 'c', ' ' ) #define TTAG_ttcf FT_MAKE_TAG( 't', 't', 'c', 'f' ) #define TTAG_TYP1 FT_MAKE_TAG( 'T', 'Y', 'P', '1' ) #define TTAG_typ1 FT_MAKE_TAG( 't', 'y', 'p', '1' ) #define TTAG_VDMX FT_MAKE_TAG( 'V', 'D', 'M', 'X' ) #define TTAG_vhea FT_MAKE_TAG( 'v', 'h', 'e', 'a' ) #define TTAG_vmtx FT_MAKE_TAG( 'v', 'm', 't', 'x' ) #define TTAG_wOFF FT_MAKE_TAG( 'w', 'O', 'F', 'F' ) #if FT_UINT_MAX == 0xFFFFUL #define FT_SIZEOF_INT (16 / FT_CHAR_BIT) #elif FT_UINT_MAX == 0xFFFFFFFFUL #define FT_SIZEOF_INT (32 / FT_CHAR_BIT) #elif FT_UINT_MAX > 0xFFFFFFFFUL && FT_UINT_MAX == 0xFFFFFFFFFFFFFFFFUL #define FT_SIZEOF_INT (64 / FT_CHAR_BIT) #else #error "Unsupported size of int type!" #endif #if FT_ULONG_MAX == 0xFFFFFFFFUL #define FT_SIZEOF_LONG (32 / FT_CHAR_BIT) #elif FT_ULONG_MAX > 0xFFFFFFFFUL && FT_ULONG_MAX == 0xFFFFFFFFFFUL #define FT_SIZEOF_LONG (32 / FT_CHAR_BIT) #elif FT_ULONG_MAX > 0xFFFFFFFFUL && FT_ULONG_MAX == 0xFFFFFFFFFFFFFFFFUL #define FT_SIZEOF_LONG (64 / FT_CHAR_BIT) #else #error "Unsupported size of long type!" #endif #define FT_Stream_FTell( stream ) \ (FT_ULong)( (stream)->cursor - (stream)->base ) #define FT_Stream_SeekSet( stream, off ) \ ( (stream)->cursor = (stream)->base + (off) ) #define ALL_POINTS (FT_UShort*)~(FT_PtrDist)0 #define GX_PT_POINTS_ARE_WORDS 0x80 #define GX_PT_POINT_RUN_COUNT_MASK 0x7F #ifndef FT_UNUSED #define FT_UNUSED(arg) ( (arg) = (arg) ) #endif #if defined( __APPLE__ ) || ( defined( __MWERKS__ ) && defined( macintosh ) ) #include #ifdef ECANCELED #include "AvailabilityMacros.h" #endif #if defined( __LP64__ ) && ( MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4 ) #undef FT_MACINTOSH #endif #elif defined( __SC__ ) || defined( __MRC__ ) #include "ConditionalMacros.h" #if TARGET_OS_MAC #define FT_MACINTOSH 1 #endif #endif typedef signed short FT_Int16; typedef unsigned short FT_UInt16; #if FT_SIZEOF_INT == (32 / FT_CHAR_BIT) typedef signed int FT_Int32; typedef unsigned int FT_UInt32; #elif FT_SIZEOF_LONG == (32 / FT_CHAR_BIT) typedef signed long FT_Int32; typedef unsigned long FT_UInt32; #else #error "no 32bit type found -- please check your configuration files" #endif #if FT_SIZEOF_INT >= (32 / FT_CHAR_BIT) typedef int FT_Fast; typedef unsigned int FT_UFast; #elif FT_SIZEOF_LONG >= (32 / FT_CHAR_BIT) typedef long FT_Fast; typedef unsigned long FT_UFast; #endif #if FT_SIZEOF_LONG == (64 / FT_CHAR_BIT) #define FT_LONG64 #define FT_INT64 long #define FT_UINT64 unsigned long #elif defined( _MSC_VER ) && _MSC_VER >= 900 #define FT_LONG64 #define FT_INT64 __int64 #define FT_UINT64 unsigned __int64 #elif defined( __BORLANDC__ ) #define FT_LONG64 #define FT_INT64 __int64 #define FT_UINT64 unsigned __int64 #elif defined( __WATCOMC__ ) #elif defined( __MWERKS__ ) #define FT_LONG64 #define FT_INT64 long long int #define FT_UINT64 unsigned long long int #elif defined( __GNUC__ ) #define FT_LONG64 #define FT_INT64 long long int #define FT_UINT64 unsigned long long int #endif #if defined( FT_LONG64 ) && !defined( FT_CONFIG_OPTION_FORCE_INT64 ) #ifdef __STDC__ #undef FT_LONG64 #undef FT_INT64 #endif #endif #ifdef FT_LONG64 typedef FT_INT64 FT_Int64; typedef FT_UINT64 FT_UInt64; #endif typedef unsigned char FT_Bool; typedef signed short FT_FWord; typedef unsigned short FT_UFWord; typedef signed char FT_Char; typedef unsigned char FT_Byte; typedef const FT_Byte* FT_Bytes; typedef FT_UInt32 FT_Tag; typedef char FT_String; typedef signed short FT_Short; typedef unsigned short FT_UShort; typedef signed int FT_Int; typedef unsigned int FT_UInt; typedef signed long FT_Long; typedef unsigned long FT_ULong; typedef signed short FT_F2Dot14; typedef signed long FT_F26Dot6; typedef signed long FT_Fixed; typedef int FT_Error; typedef void* FT_Pointer; typedef size_t FT_Offset; typedef ft_ptrdiff_t FT_PtrDist; typedef signed long FT_Pos; typedef FT_Pointer FT_Module_Interface; typedef struct FT_MemoryRec_* FT_Memory; typedef struct FT_LibraryRec_* FT_Library; typedef struct FT_StreamRec_* FT_Stream; typedef struct FT_ModuleRec_* FT_Module; typedef struct FT_DriverRec_* FT_Driver; typedef struct FT_RendererRec_* FT_Renderer; typedef struct FT_FaceRec_* FT_Face; typedef struct FT_SizeRec_* FT_Size; typedef struct FT_GlyphSlotRec_* FT_GlyphSlot; typedef struct FT_CharMapRec_* FT_CharMap; typedef struct FT_ListNodeRec_* FT_ListNode; typedef struct FT_ListRec_* FT_List; typedef struct FT_Size_RequestRec_* FT_Size_Request; typedef struct FT_GlyphRec_* FT_Glyph; typedef struct FT_BitmapGlyphRec_* FT_BitmapGlyph; typedef struct FT_OutlineGlyphRec_* FT_OutlineGlyph; typedef struct FT_RasterRec_* FT_Raster; typedef struct FT_Raster_Params_ FT_Raster_Params; typedef struct FT_BBox_ FT_BBox; typedef struct FT_Span_ FT_Span; typedef struct FT_GlyphLoaderRec_* FT_GlyphLoader; typedef struct FT_SubGlyphRec_* FT_SubGlyph; typedef struct FT_Face_InternalRec_* FT_Face_Internal; typedef struct FT_Size_InternalRec_* FT_Size_Internal; typedef struct FT_Slot_InternalRec_* FT_Slot_Internal; typedef struct FT_CMapRec_* FT_CMap; typedef const struct FT_CMap_ClassRec_* FT_CMap_Class; typedef struct TT_FaceRec_* TT_Face; typedef const struct FT_ServiceDescRec_* FT_ServiceDesc; typedef struct FT_ValidatorRec_ volatile* FT_Validator; typedef struct SFNT_Interface_* SFNT_Service; typedef const struct TT_CMap_ClassRec_* TT_CMap_Class; typedef struct FT_Data_ { const FT_Byte* pointer; FT_Int length; } FT_Data; typedef struct FT_Parameter_ { FT_ULong tag; FT_Pointer data; } FT_Parameter; typedef struct FT_Vector_ { FT_Pos x; FT_Pos y; } FT_Vector; typedef struct FT_Matrix_ { FT_Fixed xx, xy; FT_Fixed yx, yy; } FT_Matrix; typedef struct TT_CMapInfo_ { FT_ULong language; FT_Long format; } TT_CMapInfo; typedef FT_Error (*FT_CMap_InitFunc)(FT_CMap cmap, FT_Pointer init_data); typedef void (*FT_CMap_DoneFunc)(FT_CMap cmap ); typedef FT_UInt (*FT_CMap_CharIndexFunc)(FT_CMap cmap, FT_UInt32 char_code ); typedef FT_UInt (*FT_CMap_CharNextFunc)(FT_CMap cmap, FT_UInt32 *achar_code ); typedef FT_UInt (*FT_CMap_CharVarIndexFunc)(FT_CMap cmap, FT_CMap unicode_cmap, FT_UInt32 char_code, FT_UInt32 variant_selector ); typedef FT_Bool (*FT_CMap_CharVarIsDefaultFunc)( FT_CMap cmap, FT_UInt32 char_code, FT_UInt32 variant_selector ); typedef FT_UInt32 * (*FT_CMap_VariantListFunc)( FT_CMap cmap, FT_Memory mem ); typedef FT_UInt32 * (*FT_CMap_CharVariantListFunc)( FT_CMap cmap, FT_Memory mem, FT_UInt32 char_code ); typedef FT_UInt32 * (*FT_CMap_VariantCharListFunc)( FT_CMap cmap, FT_Memory mem, FT_UInt32 variant_selector ); typedef struct FT_CMap_ClassRec_ { FT_ULong size; FT_CMap_InitFunc init; FT_CMap_DoneFunc done; FT_CMap_CharIndexFunc char_index; FT_CMap_CharNextFunc char_next; /* Subsequent entries are special ones for format 14 -- the variant */ /* selector subtable which behaves like no other */ FT_CMap_CharVarIndexFunc char_var_index; FT_CMap_CharVarIsDefaultFunc char_var_default; FT_CMap_VariantListFunc variant_list; FT_CMap_CharVariantListFunc charvariant_list; FT_CMap_VariantCharListFunc variantchar_list; } FT_CMap_ClassRec; typedef FT_Error (*TT_CMap_ValidateFunc)( FT_Byte* data, FT_Validator valid ); typedef FT_Error (*TT_CMap_Info_GetFunc)( FT_CharMap charmap, TT_CMapInfo *cmap_info ); typedef struct TT_CMap_ClassRec_ { FT_CMap_ClassRec clazz; FT_UInt format; TT_CMap_ValidateFunc validate; TT_CMap_Info_GetFunc get_cmap_info; } TT_CMap_ClassRec; typedef void (*FT_DebugHook_Func)(void* arg); typedef void (*FT_Generic_Finalizer)(void* object); typedef void* (*FT_Alloc_Func)(FT_Memory memory, long size); typedef void (*FT_Free_Func)(FT_Memory memory, void* block); typedef void* (*FT_Realloc_Func)(FT_Memory memory, long cur_size, long new_size, void* block); typedef unsigned long (*FT_Stream_IoFunc)(FT_Stream stream, unsigned long offset, unsigned char* buffer, unsigned long count); typedef void (*FT_Stream_CloseFunc)(FT_Stream stream); typedef FT_Error (*FT_Module_Constructor)( FT_Module module ); typedef void (*FT_Module_Destructor)( FT_Module module ); typedef FT_Module_Interface (*FT_Module_Requester)( FT_Module module, const char* name ); typedef FT_Error (*FT_Glyph_InitFunc)(FT_Glyph glyph, FT_GlyphSlot slot); typedef void (*FT_Glyph_DoneFunc)(FT_Glyph glyph); typedef FT_Error (*FT_Glyph_CopyFunc)(FT_Glyph source, FT_Glyph target); typedef void (*FT_Glyph_TransformFunc)(FT_Glyph glyph, const FT_Matrix* matrix, const FT_Vector* delta ); typedef void (*FT_Glyph_GetBBoxFunc)(FT_Glyph glyph, FT_BBox* abbox ); typedef FT_Error (*FT_Glyph_PrepareFunc)(FT_Glyph glyph, FT_GlyphSlot slot); typedef FT_Error (*FT_Face_InitFunc)(FT_Stream stream, FT_Face face, FT_Int typeface_index, FT_Int num_params, FT_Parameter* parameters); typedef void (*FT_Face_DoneFunc)(FT_Face face); typedef FT_Error (*FT_Size_InitFunc)(FT_Size size); typedef void (*FT_Size_DoneFunc)(FT_Size size); typedef FT_Error (*FT_Slot_InitFunc)(FT_GlyphSlot slot); typedef void (*FT_Slot_DoneFunc)(FT_GlyphSlot slot); typedef FT_Error (*FT_Size_RequestFunc)(FT_Size size, FT_Size_Request req); typedef FT_Error (*FT_Size_SelectFunc)(FT_Size size, FT_ULong size_index); typedef FT_Error (*FT_Slot_LoadFunc)(FT_GlyphSlot slot, FT_Size size, FT_UInt glyph_index, FT_Int32 load_flags); typedef FT_UInt (*FT_CharMap_CharIndexFunc)(FT_CharMap charmap, FT_Long charcode); typedef FT_Long (*FT_CharMap_CharNextFunc)(FT_CharMap charmap, FT_Long charcode); typedef FT_Error (*FT_Face_GetKerningFunc)(FT_Face face, FT_UInt left_glyph, FT_UInt right_glyph, FT_Vector* kerning); typedef FT_Error (*FT_Face_AttachFunc)(FT_Face face, FT_Stream stream); typedef FT_Error (*FT_Face_GetAdvancesFunc)(FT_Face face, FT_UInt first, FT_UInt count, FT_Int32 flags, FT_Fixed* advances); typedef FT_Error (*FT_Renderer_RenderFunc)(FT_Renderer renderer, FT_GlyphSlot slot, FT_UInt mode, const FT_Vector* origin); typedef FT_Error (*FT_Renderer_TransformFunc)(FT_Renderer renderer, FT_GlyphSlot slot, const FT_Matrix* matrix, const FT_Vector* delta); typedef void (*FT_Renderer_GetCBoxFunc)(FT_Renderer renderer, FT_GlyphSlot slot, FT_BBox* cbox); typedef FT_Error (*FT_Renderer_SetModeFunc)(FT_Renderer renderer, FT_ULong mode_tag, FT_Pointer mode_ptr); typedef int (*FT_Raster_NewFunc)(void* memory, FT_Raster* raster); typedef void (*FT_Raster_DoneFunc)(FT_Raster raster); typedef void (*FT_Raster_ResetFunc)(FT_Raster raster, unsigned char* pool_base, unsigned long pool_size); typedef int (*FT_Raster_SetModeFunc)(FT_Raster raster, unsigned long mode, void* args); typedef int (*FT_Raster_RenderFunc)(FT_Raster raster, const FT_Raster_Params* params); typedef void (*FT_SpanFunc)(int y, int count, const FT_Span* spans, void* user); typedef int (*FT_Raster_BitTest_Func)(int y, int x, void* user); typedef void (*FT_Raster_BitSet_Func)(int y, int x, void* user); typedef void (*FT_List_Destructor)(FT_Memory memory, void* data, void* user); #define TT_CMAP_FLAG_UNSORTED 1 #define TT_CMAP_FLAG_OVERLAPPING 2 struct FT_BBox_ { FT_Pos xMin, yMin; FT_Pos xMax, yMax; }; struct FT_Span_ { short x; unsigned short len; unsigned char coverage; }; typedef struct FT_Slot_InternalRec_ { FT_GlyphLoader loader; FT_UInt flags; FT_Bool glyph_transformed; FT_Matrix glyph_matrix; FT_Vector glyph_delta; void* glyph_hints; } FT_GlyphSlot_InternalRec; typedef enum FT_Glyph_Format_ { FT_IMAGE_TAG(FT_GLYPH_FORMAT_NONE, 0, 0, 0, 0), FT_IMAGE_TAG(FT_GLYPH_FORMAT_COMPOSITE, 'c', 'o', 'm', 'p'), FT_IMAGE_TAG(FT_GLYPH_FORMAT_BITMAP, 'b', 'i', 't', 's'), FT_IMAGE_TAG(FT_GLYPH_FORMAT_OUTLINE, 'o', 'u', 't', 'l'), FT_IMAGE_TAG(FT_GLYPH_FORMAT_PLOTTER, 'p', 'l', 'o', 't') } FT_Glyph_Format; typedef struct FT_Raster_Funcs_ { FT_Glyph_Format glyph_format; FT_Raster_NewFunc raster_new; FT_Raster_ResetFunc raster_reset; FT_Raster_SetModeFunc raster_set_mode; FT_Raster_RenderFunc raster_render; FT_Raster_DoneFunc raster_done; } FT_Raster_Funcs; typedef struct FT_Bitmap_ { int rows; int width; int pitch; unsigned char* buffer; short num_grays; char pixel_mode; char palette_mode; void* palette; } FT_Bitmap; struct FT_Raster_Params_ { const FT_Bitmap* target; const void* source; int flags; FT_SpanFunc gray_spans; FT_SpanFunc black_spans; /* doesn't work! */ FT_Raster_BitTest_Func bit_test; /* doesn't work! */ FT_Raster_BitSet_Func bit_set; /* doesn't work! */ void* user; FT_BBox clip_box; }; typedef struct FT_Module_Class_ { FT_ULong module_flags; FT_Long module_size; const FT_String* module_name; FT_Fixed module_version; FT_Fixed module_requires; const void* module_interface; FT_Module_Constructor module_init; FT_Module_Destructor module_done; FT_Module_Requester get_interface; } FT_Module_Class; typedef struct FT_Driver_ClassRec_ { FT_Module_Class root; FT_Long face_object_size; FT_Long size_object_size; FT_Long slot_object_size; FT_Face_InitFunc init_face; FT_Face_DoneFunc done_face; FT_Size_InitFunc init_size; FT_Size_DoneFunc done_size; FT_Slot_InitFunc init_slot; FT_Slot_DoneFunc done_slot; FT_Slot_LoadFunc load_glyph; FT_Face_GetKerningFunc get_kerning; FT_Face_AttachFunc attach_file; FT_Face_GetAdvancesFunc get_advances; /* since version 2.2 */ FT_Size_RequestFunc request_size; FT_Size_SelectFunc select_size; } FT_Driver_ClassRec, *FT_Driver_Class; typedef struct FT_Renderer_Class_ { FT_Module_Class root; FT_Glyph_Format glyph_format; FT_Renderer_RenderFunc render_glyph; FT_Renderer_TransformFunc transform_glyph; FT_Renderer_GetCBoxFunc get_glyph_cbox; FT_Renderer_SetModeFunc set_mode; FT_Raster_Funcs* raster_class; } FT_Renderer_Class; typedef struct FT_Glyph_Class_ { FT_Long glyph_size; FT_Glyph_Format glyph_format; FT_Glyph_InitFunc glyph_init; FT_Glyph_DoneFunc glyph_done; FT_Glyph_CopyFunc glyph_copy; FT_Glyph_TransformFunc glyph_transform; FT_Glyph_GetBBoxFunc glyph_bbox; FT_Glyph_PrepareFunc glyph_prepare; } FT_Glyph_Class; extern const FT_Glyph_Class ft_outline_glyph_class; typedef struct FT_GlyphRec_ { FT_Library library; const FT_Glyph_Class* clazz; FT_Glyph_Format format; FT_Vector advance; } FT_GlyphRec; typedef struct FT_Outline_ { short n_contours; /* number of contours in glyph */ short n_points; /* number of points in the glyph */ FT_Vector* points; /* the outline's points */ char* tags; /* the points flags */ short* contours; /* the contour end points */ int flags; /* outline masks */ } FT_Outline; typedef struct FT_BitmapGlyphRec_ { FT_GlyphRec root; FT_Int left; FT_Int top; FT_Bitmap bitmap; } FT_BitmapGlyphRec; typedef struct FT_OutlineGlyphRec_ { FT_GlyphRec root; FT_Outline outline; } FT_OutlineGlyphRec; typedef struct FT_SubGlyphRec_ { FT_Int index; FT_UShort flags; FT_Int arg1; FT_Int arg2; FT_Matrix transform; } FT_SubGlyphRec; typedef struct FT_MemoryRec_ { void* user; FT_Alloc_Func alloc; FT_Free_Func free; FT_Realloc_Func realloc; } FT_MemoryRec; typedef struct FT_ListNodeRec_ { FT_ListNode prev; FT_ListNode next; void* data; } FT_ListNodeRec; typedef struct FT_ListRec_ { FT_ListNode head; FT_ListNode tail; } FT_ListRec; #define FT_MAX_MODULES 32 typedef struct FT_LibraryRec_ { FT_Memory memory; FT_Int version_major; FT_Int version_minor; FT_Int version_patch; FT_UInt num_modules; FT_Module modules[FT_MAX_MODULES]; FT_ListRec renderers; FT_Renderer cur_renderer; FT_Module auto_hinter; FT_Byte* raster_pool; FT_ULong raster_pool_size; FT_DebugHook_Func debug_hooks[4]; #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING FT_LcdFilter lcd_filter; FT_Int lcd_extra; /* number of extra pixels */ FT_Byte lcd_weights[7]; /* filter weights, if any */ FT_Bitmap_LcdFilterFunc lcd_filter_func; /* filtering callback */ #endif #ifdef FT_CONFIG_OPTION_PIC FT_PIC_Container pic_container; #endif FT_Int refcount; } FT_LibraryRec; typedef union FT_StreamDesc_ { long value; void* pointer; } FT_StreamDesc; typedef struct FT_StreamRec_ { unsigned char* base; unsigned long size; unsigned long pos; FT_StreamDesc descriptor; FT_StreamDesc pathname; FT_Stream_IoFunc read; FT_Stream_CloseFunc close; FT_Memory memory; unsigned char* cursor; unsigned char* limit; } FT_StreamRec; typedef struct FT_ModuleRec_ { FT_Module_Class* clazz; FT_Library library; FT_Memory memory; } FT_ModuleRec; typedef struct FT_DriverRec_ { FT_ModuleRec root; FT_Driver_Class clazz; FT_ListRec faces_list; FT_GlyphLoader glyph_loader; } FT_DriverRec; typedef struct FT_GlyphLoadRec_ { FT_Outline outline; /* outline */ FT_Vector* extra_points; /* extra points table */ FT_Vector* extra_points2; /* second extra points table */ FT_UInt num_subglyphs; /* number of subglyphs */ FT_SubGlyph subglyphs; /* subglyphs */ } FT_GlyphLoadRec, *FT_GlyphLoad; typedef struct FT_GlyphLoaderRec_ { FT_Memory memory; FT_UInt max_points; FT_UInt max_contours; FT_UInt max_subglyphs; FT_Bool use_extra; FT_GlyphLoadRec base; FT_GlyphLoadRec current; void* other; /* for possible future extension? */ } FT_GlyphLoaderRec; typedef struct FT_RendererRec_ { FT_ModuleRec root; FT_Renderer_Class* clazz; FT_Glyph_Format glyph_format; FT_Glyph_Class glyph_class; FT_Raster raster; FT_Raster_RenderFunc raster_render; FT_Renderer_RenderFunc render; } FT_RendererRec; typedef struct FT_Bitmap_Size_ { FT_Short height; FT_Short width; FT_Pos size; FT_Pos x_ppem; FT_Pos y_ppem; } FT_Bitmap_Size; typedef struct FT_ServiceCacheRec_ { FT_Pointer service_POSTSCRIPT_FONT_NAME; FT_Pointer service_MULTI_MASTERS; FT_Pointer service_GLYPH_DICT; FT_Pointer service_PFR_METRICS; FT_Pointer service_WINFNT; } FT_ServiceCacheRec, *FT_ServiceCache; typedef struct FT_Incremental_MetricsRec_ { FT_Long bearing_x; FT_Long bearing_y; FT_Long advance; FT_Long advance_v; /* since 2.3.12 */ } FT_Incremental_MetricsRec; typedef struct FT_IncrementalRec_* FT_Incremental; typedef FT_Error (*FT_Incremental_GetGlyphDataFunc)( FT_Incremental incremental, FT_UInt glyph_index, FT_Data* adata ); typedef void (*FT_Incremental_FreeGlyphDataFunc)( FT_Incremental incremental, FT_Data* data ); typedef FT_Error (*FT_Incremental_GetGlyphMetricsFunc) ( FT_Incremental incremental, FT_UInt glyph_index, FT_Bool vertical, FT_Incremental_MetricsRec *ametrics ); typedef struct FT_Incremental_FuncsRec_ { FT_Incremental_GetGlyphDataFunc get_glyph_data; FT_Incremental_FreeGlyphDataFunc free_glyph_data; FT_Incremental_GetGlyphMetricsFunc get_glyph_metrics; } FT_Incremental_FuncsRec; typedef struct FT_Incremental_InterfaceRec_ { const FT_Incremental_FuncsRec* funcs; FT_Incremental object; } FT_Incremental_InterfaceRec; typedef FT_Incremental_InterfaceRec* FT_Incremental_Interface; typedef struct FT_Face_InternalRec_ { FT_Matrix transform_matrix; FT_Vector transform_delta; FT_Int transform_flags; FT_ServiceCacheRec services; #ifdef FT_CONFIG_OPTION_INCREMENTAL FT_Incremental_InterfaceRec* incremental_interface; #endif FT_Bool ignore_unpatented_hinter; FT_Int refcount; } FT_Face_InternalRec; typedef struct FT_Generic_ { void* data; FT_Generic_Finalizer finalizer; } FT_Generic; typedef struct FT_FaceRec_ { FT_Long num_faces; FT_Long face_index; FT_Long face_flags; FT_Long style_flags; FT_Long num_glyphs; FT_String* family_name; FT_String* style_name; FT_Int num_fixed_sizes; FT_Bitmap_Size* available_sizes; FT_Int num_charmaps; FT_CharMap* charmaps; FT_Generic generic; /*# The following member variables (down to `underline_thickness') */ /*# are only relevant to scalable outlines; cf. @FT_Bitmap_Size */ /*# for bitmap fonts. */ FT_BBox bbox; FT_UShort units_per_EM; FT_Short ascender; FT_Short descender; FT_Short height; FT_Short max_advance_width; FT_Short max_advance_height; FT_Short underline_position; FT_Short underline_thickness; FT_GlyphSlot glyph; FT_Size size; FT_CharMap charmap; /*@private begin */ FT_Driver driver; FT_Memory memory; FT_Stream stream; FT_ListRec sizes_list; FT_Generic autohint; /* face-specific auto-hinter data */ void* extensions; /* unused */ FT_Face_Internal internal; /*@private end */ } FT_FaceRec; typedef struct FT_Size_Metrics_ { FT_UShort x_ppem; /* horizontal pixels per EM */ FT_UShort y_ppem; /* vertical pixels per EM */ FT_Fixed x_scale; /* scaling values used to convert font */ FT_Fixed y_scale; /* units to 26.6 fractional pixels */ FT_Pos ascender; /* ascender in 26.6 frac. pixels */ FT_Pos descender; /* descender in 26.6 frac. pixels */ FT_Pos height; /* text height in 26.6 frac. pixels */ FT_Pos max_advance; /* max horizontal advance, in 26.6 pixels */ } FT_Size_Metrics; typedef struct FT_Size_InternalRec_ { /* empty */ } FT_Size_InternalRec; typedef struct FT_SizeRec_ { FT_Face face; /* parent face object */ FT_Generic generic; /* generic pointer for client uses */ FT_Size_Metrics metrics; /* size metrics */ FT_Size_Internal internal; } FT_SizeRec; typedef enum FT_Encoding_ { FT_ENC_TAG(FT_ENCODING_NONE, 0, 0, 0, 0), FT_ENC_TAG(FT_ENCODING_MS_SYMBOL, 's', 'y', 'm', 'b'), FT_ENC_TAG(FT_ENCODING_UNICODE, 'u', 'n', 'i', 'c'), FT_ENC_TAG(FT_ENCODING_SJIS, 's', 'j', 'i', 's'), FT_ENC_TAG(FT_ENCODING_GB2312, 'g', 'b', ' ', ' '), FT_ENC_TAG(FT_ENCODING_BIG5, 'b', 'i', 'g', '5'), FT_ENC_TAG(FT_ENCODING_WANSUNG, 'w', 'a', 'n', 's'), FT_ENC_TAG(FT_ENCODING_JOHAB, 'j', 'o', 'h', 'a'), FT_ENCODING_MS_SJIS = FT_ENCODING_SJIS, FT_ENCODING_MS_GB2312 = FT_ENCODING_GB2312, FT_ENCODING_MS_BIG5 = FT_ENCODING_BIG5, FT_ENCODING_MS_WANSUNG = FT_ENCODING_WANSUNG, FT_ENCODING_MS_JOHAB = FT_ENCODING_JOHAB, FT_ENC_TAG(FT_ENCODING_ADOBE_STANDARD, 'A', 'D', 'O', 'B'), FT_ENC_TAG(FT_ENCODING_ADOBE_EXPERT, 'A', 'D', 'B', 'E'), FT_ENC_TAG(FT_ENCODING_ADOBE_CUSTOM, 'A', 'D', 'B', 'C'), FT_ENC_TAG(FT_ENCODING_ADOBE_LATIN_1, 'l', 'a', 't', '1'), FT_ENC_TAG(FT_ENCODING_OLD_LATIN_2, 'l', 'a', 't', '2'), FT_ENC_TAG(FT_ENCODING_APPLE_ROMAN, 'a', 'r', 'm', 'n') } FT_Encoding; typedef struct FT_CharMapRec_ { FT_Face face; FT_Encoding encoding; FT_UShort platform_id; FT_UShort encoding_id; } FT_CharMapRec; typedef struct FT_UnitVector_ { FT_F2Dot14 x; FT_F2Dot14 y; } FT_UnitVector; typedef struct FT_Open_Args_ { FT_UInt flags; const FT_Byte* memory_base; FT_Long memory_size; FT_String* pathname; FT_Stream stream; FT_Module driver; FT_Int num_params; FT_Parameter* params; } FT_Open_Args; typedef enum FT_Size_Request_Type_ { FT_SIZE_REQUEST_TYPE_NOMINAL, FT_SIZE_REQUEST_TYPE_REAL_DIM, FT_SIZE_REQUEST_TYPE_BBOX, FT_SIZE_REQUEST_TYPE_CELL, FT_SIZE_REQUEST_TYPE_SCALES, FT_SIZE_REQUEST_TYPE_MAX } FT_Size_Request_Type; typedef struct FT_Size_RequestRec_ { FT_Size_Request_Type type; FT_Long width; FT_Long height; FT_UInt horiResolution; FT_UInt vertResolution; } FT_Size_RequestRec; typedef struct FT_CMapRec_ { FT_CharMapRec charmap; FT_CMap_Class clazz; } FT_CMapRec; typedef enum FT_Render_Mode_ { FT_RENDER_MODE_NORMAL = 0, FT_RENDER_MODE_LIGHT, FT_RENDER_MODE_MONO, FT_RENDER_MODE_LCD, FT_RENDER_MODE_LCD_V, FT_RENDER_MODE_MAX } FT_Render_Mode; typedef enum FT_Kerning_Mode_ { FT_KERNING_DEFAULT = 0, FT_KERNING_UNFITTED, FT_KERNING_UNSCALED } FT_Kerning_Mode; typedef struct TTC_HeaderRec_ { FT_ULong tag; FT_Fixed version; FT_Long count; FT_ULong* offsets; } TTC_HeaderRec; typedef struct TT_TableRec_ { FT_ULong Tag; /* table type */ FT_ULong CheckSum; /* table checksum */ FT_ULong Offset; /* table file offset */ FT_ULong Length; /* table length */ } TT_TableRec, *TT_Table; typedef struct TT_Header_ { FT_Fixed Table_Version; FT_Fixed Font_Revision; FT_Long CheckSum_Adjust; FT_Long Magic_Number; FT_UShort Flags; FT_UShort Units_Per_EM; FT_Long Created [2]; FT_Long Modified[2]; FT_Short xMin; FT_Short yMin; FT_Short xMax; FT_Short yMax; FT_UShort Mac_Style; FT_UShort Lowest_Rec_PPEM; FT_Short Font_Direction; FT_Short Index_To_Loc_Format; FT_Short Glyph_Data_Format; } TT_Header; typedef struct TT_HoriHeader_ { FT_Fixed Version; FT_Short Ascender; FT_Short Descender; FT_Short Line_Gap; FT_UShort advance_Width_Max; /* advance width maximum */ FT_Short min_Left_Side_Bearing; /* minimum left-sb */ FT_Short min_Right_Side_Bearing; /* minimum right-sb */ FT_Short xMax_Extent; /* xmax extents */ FT_Short caret_Slope_Rise; FT_Short caret_Slope_Run; FT_Short caret_Offset; FT_Short Reserved[4]; FT_Short metric_Data_Format; FT_UShort number_Of_HMetrics; /* The following fields are not defined by the TrueType specification */ /* but they are used to connect the metrics header to the relevant */ /* `HMTX' table. */ void* long_metrics; void* short_metrics; } TT_HoriHeader; typedef struct TT_MaxProfile_ { FT_Fixed version; FT_UShort numGlyphs; FT_UShort maxPoints; FT_UShort maxContours; FT_UShort maxCompositePoints; FT_UShort maxCompositeContours; FT_UShort maxZones; FT_UShort maxTwilightPoints; FT_UShort maxStorage; FT_UShort maxFunctionDefs; FT_UShort maxInstructionDefs; FT_UShort maxStackElements; FT_UShort maxSizeOfInstructions; FT_UShort maxComponentElements; FT_UShort maxComponentDepth; } TT_MaxProfile; typedef struct TT_VertHeader_ { FT_Fixed Version; FT_Short Ascender; FT_Short Descender; FT_Short Line_Gap; FT_UShort advance_Height_Max; /* advance height maximum */ FT_Short min_Top_Side_Bearing; /* minimum left-sb or top-sb */ FT_Short min_Bottom_Side_Bearing; /* minimum right-sb or bottom-sb */ FT_Short yMax_Extent; /* xmax or ymax extents */ FT_Short caret_Slope_Rise; FT_Short caret_Slope_Run; FT_Short caret_Offset; FT_Short Reserved[4]; FT_Short metric_Data_Format; FT_UShort number_Of_VMetrics; /* The following fields are not defined by the TrueType specification */ /* but they're used to connect the metrics header to the relevant */ /* `HMTX' or `VMTX' table. */ void* long_metrics; void* short_metrics; } TT_VertHeader; typedef struct TT_NameEntryRec_ { FT_UShort platformID; FT_UShort encodingID; FT_UShort languageID; FT_UShort nameID; FT_UShort stringLength; FT_ULong stringOffset; /* this last field is not defined in the spec */ /* but used by the FreeType engine */ FT_Byte* string; } TT_NameEntryRec, *TT_NameEntry; typedef struct TT_NameTableRec_ { FT_UShort format; FT_UInt numNameRecords; FT_UInt storageOffset; TT_NameEntryRec* names; FT_Stream stream; } TT_NameTableRec, *TT_NameTable; typedef struct TT_OS2_ { FT_UShort version; /* 0x0001 - more or 0xFFFF */ FT_Short xAvgCharWidth; FT_UShort usWeightClass; FT_UShort usWidthClass; FT_Short fsType; FT_Short ySubscriptXSize; FT_Short ySubscriptYSize; FT_Short ySubscriptXOffset; FT_Short ySubscriptYOffset; FT_Short ySuperscriptXSize; FT_Short ySuperscriptYSize; FT_Short ySuperscriptXOffset; FT_Short ySuperscriptYOffset; FT_Short yStrikeoutSize; FT_Short yStrikeoutPosition; FT_Short sFamilyClass; FT_Byte panose[10]; FT_ULong ulUnicodeRange1; /* Bits 0-31 */ FT_ULong ulUnicodeRange2; /* Bits 32-63 */ FT_ULong ulUnicodeRange3; /* Bits 64-95 */ FT_ULong ulUnicodeRange4; /* Bits 96-127 */ FT_Char achVendID[4]; FT_UShort fsSelection; FT_UShort usFirstCharIndex; FT_UShort usLastCharIndex; FT_Short sTypoAscender; FT_Short sTypoDescender; FT_Short sTypoLineGap; FT_UShort usWinAscent; FT_UShort usWinDescent; /* only version 1 and higher: */ FT_ULong ulCodePageRange1; /* Bits 0-31 */ FT_ULong ulCodePageRange2; /* Bits 32-63 */ /* only version 2 and higher: */ FT_Short sxHeight; FT_Short sCapHeight; FT_UShort usDefaultChar; FT_UShort usBreakChar; FT_UShort usMaxContext; /* only version 5 and higher: */ FT_UShort usLowerOpticalPointSize; /* in twips (1/20th points) */ FT_UShort usUpperOpticalPointSize; /* in twips (1/20th points) */ } TT_OS2; typedef struct TT_Postscript_ { FT_Fixed FormatType; FT_Fixed italicAngle; FT_Short underlinePosition; FT_Short underlineThickness; FT_ULong isFixedPitch; FT_ULong minMemType42; FT_ULong maxMemType42; FT_ULong minMemType1; FT_ULong maxMemType1; /* Glyph names follow in the file, but we don't */ /* load them by default. See the ttpost.c file. */ } TT_Postscript; typedef struct TT_GlyphZoneRec_ { FT_Memory memory; FT_UShort max_points; FT_UShort max_contours; FT_UShort n_points; /* number of points in zone */ FT_Short n_contours; /* number of contours */ FT_Vector* org; /* original point coordinates */ FT_Vector* cur; /* current point coordinates */ FT_Vector* orus; /* original (unscaled) point coordinates */ FT_Byte* tags; /* current touch flags */ FT_UShort* contours; /* contour end points */ FT_UShort first_point; /* offset of first (#0) point */ } TT_GlyphZoneRec, *TT_GlyphZone; typedef struct TT_Size_Metrics_ { /* for non-square pixels */ FT_Long x_ratio; FT_Long y_ratio; FT_UShort ppem; /* maximum ppem size */ FT_Long ratio; /* current ratio */ FT_Fixed scale; FT_F26Dot6 compensations[4]; /* device-specific compensations */ FT_Bool valid; FT_Bool rotated; /* `is the glyph rotated?'-flag */ FT_Bool stretched; /* `is the glyph stretched?'-flag */ } TT_Size_Metrics; typedef struct TT_SizeRec_ { FT_SizeRec root; /* we have our own copy of metrics so that we can modify */ /* it without affecting auto-hinting (when used) */ FT_Size_Metrics metrics; TT_Size_Metrics ttmetrics; FT_ULong strike_index; /* 0xFFFFFFFF to indicate invalid */ #ifdef TT_USE_BYTECODE_INTERPRETER FT_UInt num_function_defs; /* number of function definitions */ FT_UInt max_function_defs; TT_DefArray function_defs; /* table of function definitions */ FT_UInt num_instruction_defs; /* number of ins. definitions */ FT_UInt max_instruction_defs; TT_DefArray instruction_defs; /* table of ins. definitions */ FT_UInt max_func; FT_UInt max_ins; TT_CodeRangeTable codeRangeTable; TT_GraphicsState GS; FT_ULong cvt_size; /* the scaled control value table */ FT_Long* cvt; FT_UShort storage_size; /* The storage area is now part of */ FT_Long* storage; /* the instance */ TT_GlyphZoneRec twilight; /* The instance's twilight zone */ /* debugging variables */ /* When using the debugger, we must keep the */ /* execution context tied to the instance */ /* object rather than asking it on demand. */ FT_Bool debug; TT_ExecContext context; FT_Bool bytecode_ready; FT_Bool cvt_ready; #endif /* TT_USE_BYTECODE_INTERPRETER */ } TT_SizeRec; typedef struct TT_SizeRec_* TT_Size; typedef struct TT_GraphicsState_ { FT_UShort rp0; FT_UShort rp1; FT_UShort rp2; FT_UnitVector dualVector; FT_UnitVector projVector; FT_UnitVector freeVector; #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING FT_Bool both_x_axis; #endif FT_Long loop; FT_F26Dot6 minimum_distance; FT_Int round_state; FT_Bool auto_flip; FT_F26Dot6 control_value_cutin; FT_F26Dot6 single_width_cutin; FT_F26Dot6 single_width_value; FT_Short delta_base; FT_Short delta_shift; FT_Byte instruct_control; /* According to Greg Hitchcock from Microsoft, the `scan_control' */ /* variable as documented in the TrueType specification is a 32-bit */ /* integer; the high-word part holds the SCANTYPE value, the low-word */ /* part the SCANCTRL value. We separate it into two fields. */ FT_Bool scan_control; FT_Int scan_type; FT_UShort gep0; FT_UShort gep1; FT_UShort gep2; } TT_GraphicsState; typedef struct TT_DefRecord_ { FT_Int range; /* in which code range is it located? */ FT_Long start; /* where does it start? */ FT_Long end; /* where does it end? */ FT_UInt opc; /* function #, or instruction code */ FT_Bool active; /* is it active? */ FT_Bool inline_delta; /* is function that defines inline delta? */ FT_ULong sph_fdef_flags; /* flags to identify special functions */ } TT_DefRecord, *TT_DefArray; typedef struct TT_CallRec_ { FT_Int Caller_Range; FT_Long Caller_IP; FT_Long Cur_Count; TT_DefRecord *Def; /* either FDEF or IDEF */ } TT_CallRec, *TT_CallStack; typedef struct TT_CodeRange_ { FT_Byte* base; FT_ULong size; } TT_CodeRange; typedef struct FT_ServiceDescRec_ { const char* serv_id; /* service name */ const void* serv_data; /* service pointer/data */ } FT_ServiceDescRec; #define TT_MAX_CODE_RANGES 3 typedef TT_CodeRange TT_CodeRangeTable[TT_MAX_CODE_RANGES]; #ifndef TT_CONFIG_OPTION_STATIC_INTERPRETER /* indirect implementation */ #define EXEC_OP_ TT_ExecContext exc, #define EXEC_OP TT_ExecContext exc #define EXEC_ARG_ exc, #define EXEC_ARG exc #else /* static implementation */ #define EXEC_OP_ /* void */ #define EXEC_OP /* void */ #define EXEC_ARG_ /* void */ #define EXEC_ARG /* void */ #endif /* TT_CONFIG_OPTION_STATIC_INTERPRETER */ typedef struct TT_ExecContextRec_* TT_ExecContext; typedef FT_F26Dot6 (*TT_Round_Func)( EXEC_OP_ FT_F26Dot6 distance, FT_F26Dot6 compensation ); /* Point displacement along the freedom vector routine */ typedef void (*TT_Move_Func)( EXEC_OP_ TT_GlyphZone zone, FT_UShort point, FT_F26Dot6 distance ); /* Distance projection along one of the projection vectors */ typedef FT_F26Dot6 (*TT_Project_Func)( EXEC_OP_ FT_Pos dx, FT_Pos dy ); /* reading a cvt value. Take care of non-square pixels if necessary */ typedef FT_F26Dot6 (*TT_Get_CVT_Func)( EXEC_OP_ FT_ULong idx ); /* setting or moving a cvt value. Take care of non-square pixels */ /* if necessary */ typedef void (*TT_Set_CVT_Func)( EXEC_OP_ FT_ULong idx, FT_F26Dot6 value ); typedef struct TT_ExecContextRec_ { TT_Face face; TT_Size size; FT_Memory memory; /* instructions state */ FT_Error error; /* last execution error */ FT_Long top; /* top of exec. stack */ FT_UInt stackSize; /* size of exec. stack */ FT_Long* stack; /* current exec. stack */ FT_Long args; FT_UInt new_top; /* new top after exec. */ TT_GlyphZoneRec zp0, /* zone records */ zp1, zp2, pts, twilight; FT_Size_Metrics metrics; TT_Size_Metrics tt_metrics; /* size metrics */ TT_GraphicsState GS; /* current graphics state */ FT_Int curRange; /* current code range number */ FT_Byte* code; /* current code range */ FT_Long IP; /* current instruction pointer */ FT_Long codeSize; /* size of current range */ FT_Byte opcode; /* current opcode */ FT_Int length; /* length of current opcode */ FT_Bool step_ins; /* true if the interpreter must */ /* increment IP after ins. exec */ FT_ULong cvtSize; FT_Long* cvt; FT_UInt glyphSize; /* glyph instructions buffer size */ FT_Byte* glyphIns; /* glyph instructions buffer */ FT_UInt numFDefs; /* number of function defs */ FT_UInt maxFDefs; /* maximum number of function defs */ TT_DefArray FDefs; /* table of FDefs entries */ FT_UInt numIDefs; /* number of instruction defs */ FT_UInt maxIDefs; /* maximum number of ins defs */ TT_DefArray IDefs; /* table of IDefs entries */ FT_UInt maxFunc; /* maximum function index */ FT_UInt maxIns; /* maximum instruction index */ FT_Int callTop, /* top of call stack during execution */ callSize; /* size of call stack */ TT_CallStack callStack; /* call stack */ FT_UShort maxPoints; /* capacity of this context's `pts' */ FT_Short maxContours; /* record, expressed in points and */ /* contours. */ TT_CodeRangeTable codeRangeTable; /* table of valid code ranges */ /* useful for the debugger */ FT_UShort storeSize; /* size of current storage */ FT_Long* storage; /* storage area */ FT_F26Dot6 period; /* values used for the */ FT_F26Dot6 phase; /* `SuperRounding' */ FT_F26Dot6 threshold; #if 0 /* this seems to be unused */ FT_Int cur_ppem; /* ppem along the current proj vector */ #endif FT_Bool instruction_trap; /* If `True', the interpreter will */ /* exit after each instruction */ TT_GraphicsState default_GS; /* graphics state resulting from */ /* the prep program */ FT_Bool is_composite; /* true if the glyph is composite */ FT_Bool pedantic_hinting; /* true if pedantic interpretation */ /* latest interpreter additions */ FT_Long F_dot_P; /* dot product of freedom and projection */ /* vectors */ TT_Round_Func func_round; /* current rounding function */ TT_Project_Func func_project, /* current projection function */ func_dualproj, /* current dual proj. function */ func_freeProj; /* current freedom proj. func */ TT_Move_Func func_move; /* current point move function */ TT_Move_Func func_move_orig; /* move original position function */ TT_Get_CVT_Func func_read_cvt; /* read a cvt entry */ TT_Set_CVT_Func func_write_cvt; /* write a cvt entry (in pixels) */ TT_Set_CVT_Func func_move_cvt; /* incr a cvt entry (in pixels) */ FT_Bool grayscale; /* are we hinting for grayscale? */ #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING TT_Round_Func func_round_sphn; /* subpixel rounding function */ FT_Bool subpixel; /* Using subpixel hinting? */ FT_Bool ignore_x_mode; /* Standard rendering mode for */ /* subpixel hinting. On if gray */ /* or subpixel hinting is on. */ /* The following 4 aren't fully implemented but here for MS rasterizer */ /* compatibility. */ FT_Bool compatible_widths; /* compatible widths? */ FT_Bool symmetrical_smoothing; /* symmetrical_smoothing? */ FT_Bool bgr; /* bgr instead of rgb? */ FT_Bool subpixel_positioned; /* subpixel positioned */ /* (DirectWrite ClearType)? */ FT_Int rasterizer_version; /* MS rasterizer version */ FT_Bool iup_called; /* IUP called for glyph? */ FT_ULong sph_tweak_flags; /* flags to control */ /* hint tweaks */ FT_ULong sph_in_func_flags; /* flags to indicate if in */ /* special functions */ #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ } TT_ExecContextRec; typedef struct TT_LoaderRec_ { FT_Face face; FT_Size size; FT_GlyphSlot glyph; FT_GlyphLoader gloader; FT_ULong load_flags; FT_UInt glyph_index; FT_Stream stream; FT_Int byte_len; FT_Short n_contours; FT_BBox bbox; FT_Int left_bearing; FT_Int advance; FT_Int linear; FT_Bool linear_def; FT_Vector pp1; FT_Vector pp2; FT_ULong glyf_offset; /* the zone where we load our glyphs */ TT_GlyphZoneRec base; TT_GlyphZoneRec zone; TT_ExecContext exec; FT_Byte* instructions; FT_ULong ins_pos; /* for possible extensibility in other formats */ void* other; /* since version 2.1.8 */ FT_Int top_bearing; FT_Int vadvance; FT_Vector pp3; FT_Vector pp4; /* since version 2.2.1 */ FT_Byte* cursor; FT_Byte* limit; } TT_LoaderRec; typedef struct TT_LoaderRec_* TT_Loader; typedef FT_Error (*TT_Loader_GotoTableFunc)( TT_Face face, FT_ULong tag, FT_Stream stream, FT_ULong* length ); typedef FT_Error (*TT_Loader_StartGlyphFunc)( TT_Loader loader, FT_UInt glyph_index, FT_ULong offset, FT_UInt byte_count ); typedef FT_Error (*TT_Loader_ReadGlyphFunc)( TT_Loader loader ); typedef void (*TT_Loader_EndGlyphFunc)( TT_Loader loader ); typedef struct TT_GaspRangeRec_ { FT_UShort maxPPEM; FT_UShort gaspFlag; } TT_GaspRangeRec, *TT_GaspRange; typedef struct TT_Gasp_ { FT_UShort version; FT_UShort numRanges; TT_GaspRange gaspRanges; } TT_GaspRec; typedef struct TT_PCLT_ { FT_Fixed Version; FT_ULong FontNumber; FT_UShort Pitch; FT_UShort xHeight; FT_UShort Style; FT_UShort TypeFamily; FT_UShort CapHeight; FT_UShort SymbolSet; FT_Char TypeFace[16]; FT_Char CharacterComplement[8]; FT_Char FileName[6]; FT_Char StrokeWeight; FT_Char WidthType; FT_Byte SerifStyle; FT_Byte Reserved; } TT_PCLT; typedef struct TT_SBit_LineMetricsRec_ { FT_Char ascender; FT_Char descender; FT_Byte max_width; FT_Char caret_slope_numerator; FT_Char caret_slope_denominator; FT_Char caret_offset; FT_Char min_origin_SB; FT_Char min_advance_SB; FT_Char max_before_BL; FT_Char min_after_BL; FT_Char pads[2]; } TT_SBit_LineMetricsRec, *TT_SBit_LineMetrics; typedef struct TT_SBit_ScaleRec_ { TT_SBit_LineMetricsRec hori; TT_SBit_LineMetricsRec vert; FT_Byte x_ppem; FT_Byte y_ppem; FT_Byte x_ppem_substitute; FT_Byte y_ppem_substitute; } TT_SBit_ScaleRec, *TT_SBit_Scale; typedef struct TT_Post_20Rec_ { FT_UShort num_glyphs; FT_UShort num_names; FT_UShort* glyph_indices; FT_Char** glyph_names; } TT_Post_20Rec, *TT_Post_20; typedef struct TT_Post_25_ { FT_UShort num_glyphs; FT_Char* offsets; } TT_Post_25Rec, *TT_Post_25; typedef struct TT_Post_NamesRec_ { FT_Bool loaded; union { TT_Post_20Rec format_20; TT_Post_25Rec format_25; } names; } TT_Post_NamesRec, *TT_Post_Names; typedef FT_Error (*TT_Interpreter)( void* exec_context ); typedef enum TT_SbitTableType_ { TT_SBIT_TABLE_TYPE_NONE = 0, TT_SBIT_TABLE_TYPE_EBLC, /* `EBLC' (Microsoft), */ /* `bloc' (Apple) */ TT_SBIT_TABLE_TYPE_CBLC, /* `CBLC' (Google) */ TT_SBIT_TABLE_TYPE_SBIX, /* `sbix' (Apple) */ /* do not remove */ TT_SBIT_TABLE_TYPE_MAX } TT_SbitTableType; typedef struct GX_AVarCorrespondenceRec_ { FT_Fixed fromCoord; FT_Fixed toCoord; } GX_AVarCorrespondenceRec_, *GX_AVarCorrespondence; typedef struct GX_AVarSegmentRec_ { FT_UShort pairCount; GX_AVarCorrespondence correspondence; /* array with pairCount entries */ } GX_AVarSegmentRec, *GX_AVarSegment; typedef struct FT_Var_Axis_ { FT_String* name; FT_Fixed minimum; FT_Fixed def; FT_Fixed maximum; FT_ULong tag; FT_UInt strid; } FT_Var_Axis; typedef struct FT_Var_Named_Style_ { FT_Fixed* coords; FT_UInt strid; } FT_Var_Named_Style; typedef struct FT_MM_Var_ { FT_UInt num_axis; FT_UInt num_designs; FT_UInt num_namedstyles; FT_Var_Axis* axis; FT_Var_Named_Style* namedstyle; } FT_MM_Var; #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT typedef struct GX_BlendRec_ *GX_Blend; #endif typedef struct GX_BlendRec_ { FT_UInt num_axis; FT_Fixed* normalizedcoords; FT_MM_Var* mmvar; FT_Offset mmvar_len; FT_Bool avar_checked; GX_AVarSegment avar_segment; FT_UInt tuplecount; /* shared tuples in `gvar' */ FT_Fixed* tuplecoords; /* tuplecoords[tuplecount][num_axis] */ FT_UInt gv_glyphcnt; FT_ULong* glyphoffsets; } GX_BlendRec; typedef struct TT_FaceRec_ { FT_FaceRec root; TTC_HeaderRec ttc_header; FT_ULong format_tag; FT_UShort num_tables; TT_Table dir_tables; TT_Header header; /* TrueType header table */ TT_HoriHeader horizontal; /* TrueType horizontal header */ TT_MaxProfile max_profile; FT_Bool vertical_info; TT_VertHeader vertical; /* TT Vertical header, if present */ FT_UShort num_names; /* number of name records */ TT_NameTableRec name_table; /* name table */ TT_OS2 os2; /* TrueType OS/2 table */ TT_Postscript postscript; /* TrueType Postscript table */ FT_Byte* cmap_table; /* extracted `cmap' table */ FT_ULong cmap_size; TT_Loader_GotoTableFunc goto_table; TT_Loader_StartGlyphFunc access_glyph_frame; TT_Loader_EndGlyphFunc forget_glyph_frame; TT_Loader_ReadGlyphFunc read_glyph_header; TT_Loader_ReadGlyphFunc read_simple_glyph; TT_Loader_ReadGlyphFunc read_composite_glyph; /* a typeless pointer to the SFNT_Interface table used to load */ /* the basic TrueType tables in the face object */ void* sfnt; /* a typeless pointer to the FT_Service_PsCMapsRec table used to */ /* handle glyph names <-> unicode & Mac values */ void* psnames; /***********************************************************************/ /* */ /* Optional TrueType/OpenType tables */ /* */ /***********************************************************************/ /* grid-fitting and scaling table */ TT_GaspRec gasp; /* the `gasp' table */ /* PCL 5 table */ TT_PCLT pclt; /* embedded bitmaps support */ FT_ULong num_sbit_scales; TT_SBit_Scale sbit_scales; /* postscript names table */ TT_Post_NamesRec postscript_names; /***********************************************************************/ /* */ /* TrueType-specific fields (ignored by the OTF-Type2 driver) */ /* */ /***********************************************************************/ /* the font program, if any */ FT_ULong font_program_size; FT_Byte* font_program; /* the cvt program, if any */ FT_ULong cvt_program_size; FT_Byte* cvt_program; /* the original, unscaled, control value table */ FT_ULong cvt_size; FT_Short* cvt; /* A pointer to the bytecode interpreter to use. This is also */ /* used to hook the debugger for the `ttdebug' utility. */ TT_Interpreter interpreter; #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING /* Use unpatented hinting only. */ FT_Bool unpatented_hinting; #endif /***********************************************************************/ /* */ /* Other tables or fields. This is used by derivative formats like */ /* OpenType. */ /* */ /***********************************************************************/ FT_Generic extra; const char* postscript_name; FT_ULong glyf_len; #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT FT_Bool doblend; GX_Blend blend; #endif /* since version 2.2 */ FT_Byte* horz_metrics; FT_ULong horz_metrics_size; FT_Byte* vert_metrics; FT_ULong vert_metrics_size; FT_ULong num_locations; /* in broken TTF, gid > 0xFFFF */ FT_Byte* glyph_locations; FT_Byte* hdmx_table; FT_ULong hdmx_table_size; FT_UInt hdmx_record_count; FT_ULong hdmx_record_size; FT_Byte* hdmx_record_sizes; FT_Byte* sbit_table; FT_ULong sbit_table_size; TT_SbitTableType sbit_table_type; FT_UInt sbit_num_strikes; FT_Byte* kern_table; FT_ULong kern_table_size; FT_UInt num_kern_tables; FT_UInt32 kern_avail_bits; FT_UInt32 kern_order_bits; #ifdef TT_CONFIG_OPTION_BDF TT_BDFRec bdf; #endif /* TT_CONFIG_OPTION_BDF */ /* since 2.3.0 */ FT_ULong horz_metrics_offset; FT_ULong vert_metrics_offset; #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING /* since 2.4.12 */ FT_ULong sph_found_func_flags; /* special functions found */ /* for this face */ FT_Bool sph_compatibility_mode; #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ } TT_FaceRec; extern "C" FT_Error FT_Init_FreeType(FT_Library* alibrary); extern "C" FT_Error FT_Done_FreeType(FT_Library library); extern "C" FT_Error FT_New_Memory_Face(FT_Library library, const FT_Byte* file_base, FT_Long file_size, FT_Long face_index, FT_Face* aface); extern "C" FT_Error FT_Open_Face(FT_Library library, const FT_Open_Args* args, FT_Long face_index, FT_Face* aface); extern "C" FT_Error FT_Done_Face(FT_Face face); extern "C" FT_Error FT_Select_Size(FT_Face face, FT_Int strike_index); extern "C" FT_Error FT_Request_Size(FT_Face face, FT_Size_Request req); extern "C" FT_Error FT_Set_Char_Size(FT_Face face, FT_F26Dot6 char_width, FT_F26Dot6 char_height, FT_UInt horz_resolution, FT_UInt vert_resolution); extern "C" FT_Error FT_Set_Pixel_Sizes(FT_Face face, FT_UInt pixel_width, FT_UInt pixel_height); extern "C" FT_Error FT_Load_Glyph(FT_Face face, FT_UInt glyph_index, FT_Int32 load_flags); extern "C" FT_Error FT_Load_Char(FT_Face face, FT_ULong char_code, FT_Int32 load_flags); extern "C" void FT_Set_Transform(FT_Face face, FT_Matrix* matrix, FT_Vector* delta); extern "C" FT_Error FT_Render_Glyph(FT_GlyphSlot slot, FT_Render_Mode render_mode); extern "C" FT_Error FT_Get_Kerning(FT_Face face, FT_UInt left_glyph, FT_UInt right_glyph, FT_UInt kern_mode, FT_Vector* akerning); extern "C" FT_Error FT_Get_Track_Kerning(FT_Face face, FT_Fixed point_size, FT_Int degree, FT_Fixed* akerning); extern "C" FT_Error FT_Get_Glyph_Name(FT_Face face, FT_UInt glyph_index, FT_Pointer buffer, FT_UInt buffer_max); extern "C" const char* FT_Get_Postscript_Name(FT_Face face); extern "C" FT_Error FT_Select_Charmap(FT_Face face, FT_Encoding encoding); extern "C" FT_Error FT_Set_Charmap(FT_Face face, FT_CharMap charmap); extern "C" FT_Int FT_Get_Charmap_Index(FT_CharMap charmap); extern "C" FT_UInt FT_Get_Char_Index(FT_Face face, FT_ULong charcode); extern "C" FT_ULong FT_Get_First_Char(FT_Face face, FT_UInt* agindex); extern "C" FT_ULong FT_Get_Next_Char(FT_Face face, FT_ULong char_code, FT_UInt* agindex); extern "C" FT_UInt FT_Get_Name_Index(FT_Face face, FT_String* glyph_name); extern "C" FT_Error FT_Get_SubGlyph_Info(FT_GlyphSlot glyph, FT_UInt sub_index, FT_Int* p_index, FT_UInt* p_flags, FT_Int* p_arg1, FT_Int* p_arg2, FT_Matrix* p_transform); extern "C" FT_UShort FT_Get_FSType_Flags(FT_Face face); extern "C" FT_UInt FT_Face_GetCharVariantIndex(FT_Face face, FT_ULong charcode, FT_ULong variantSelector); extern "C" FT_Int FT_Face_GetCharVariantIsDefault(FT_Face face, FT_ULong charcode, FT_ULong variantSelector); extern "C" FT_UInt32* FT_Face_GetVariantSelectors(FT_Face face); extern "C" FT_UInt32* FT_Face_GetVariantsOfChar(FT_Face face, FT_ULong charcode); extern "C" FT_UInt32* FT_Face_GetCharsOfVariant(FT_Face face, FT_ULong variantSelector); extern "C" FT_Long FT_MulDiv(FT_Long a, FT_Long b, FT_Long c); extern "C" FT_Long FT_MulFix(FT_Long a, FT_Long b); extern "C" FT_Long FT_DivFix(FT_Long a, FT_Long b); extern "C" FT_Fixed FT_RoundFix(FT_Fixed a); extern "C" FT_Fixed FT_CeilFix(FT_Fixed a); extern "C" FT_Fixed FT_FloorFix(FT_Fixed a); extern "C" void FT_Vector_Transform(FT_Vector* vec, const FT_Matrix* matrix); extern "C" void FT_Library_Version(FT_Library library, FT_Int* amajor, FT_Int* aminor, FT_Int* apatch); extern "C" FT_Bool FT_Face_CheckTrueTypePatents(FT_Face face); extern "C" FT_Bool FT_Face_SetUnpatentedHinting(FT_Face face, FT_Bool value); FT_EXPORT_DEF(FT_Error) FT_Get_Advance(FT_Face face, FT_UInt gindex, FT_Int32 flags, FT_Fixed* padvance); typedef struct FT_Glyph_Metrics_ { FT_Pos width; FT_Pos height; FT_Pos horiBearingX; FT_Pos horiBearingY; FT_Pos horiAdvance; FT_Pos vertBearingX; FT_Pos vertBearingY; FT_Pos vertAdvance; } FT_Glyph_Metrics; typedef struct FT_GlyphSlotRec_ { FT_Library library; FT_Face face; FT_GlyphSlot next; FT_UInt reserved; /* retained for binary compatibility */ FT_Generic generic; FT_Glyph_Metrics metrics; FT_Fixed linearHoriAdvance; FT_Fixed linearVertAdvance; FT_Vector advance; FT_Glyph_Format format; FT_Bitmap bitmap; FT_Int bitmap_left; FT_Int bitmap_top; FT_Outline outline; FT_UInt num_subglyphs; FT_SubGlyph subglyphs; void* control_data; long control_len; FT_Pos lsb_delta; FT_Pos rsb_delta; void* other; FT_Slot_Internal internal; } FT_GlyphSlotRec; // ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ class FaceInfo { public: const byte* TTF; FT_Face Face; int SavedHeight; FaceInfo(const byte* ttf) : TTF(ttf) { Face = nullptr; SavedHeight = 0; } ~FaceInfo() { FT_Done_Face(Face); BxFree(TTF); } }; id_ttf CreateTTF(const byte* ttf, const int length) { global_data FT_Library Library = nullptr; FT_Error ErrorResult = FT_Err_Ok; if(Library == nullptr) { if((ErrorResult = FT_Init_FreeType(&Library)) != FT_Err_Ok) { BxASSERT("BxCore::AddOn", false); return nullptr; } } FaceInfo* Info = BxNew_Param(FaceInfo, ttf); if((ErrorResult = FT_New_Memory_Face(Library, ttf, length, 0, &Info->Face)) != FT_Err_Ok) { BxASSERT("BxCore::AddOn<해당 폰트의 로드에 실패하였습니다>", false); BxDelete(Info); return nullptr; } return (id_ttf) Info; } void ReleaseTTF(id_ttf ttf) { BxDelete_ByType(FaceInfo, ttf); } local_func void CheckHeight(FaceInfo* info, int height) { if(info->SavedHeight != height) { info->SavedHeight = height; if(FT_Set_Pixel_Sizes(info->Face, 0, height) != FT_Err_Ok) { BxASSERT("BxCore::AddOn<해당 폰트의 사이즈설정에 실패하였습니다>", false); return; } } } const byte* TTFToBMP(id_ttf ttf, int height, uint code) { FaceInfo* Info = (FaceInfo*) ttf; if(!Info) { // 비트맵구성 const int Width = height / 2 - 1; const int Height = height; const byte* Bmp = BxCore::AddOn::CreateBMP(Width, Height); bitmappixel* BmpFocus = BxCore::AddOn::GetBMPBits(Bmp); // 프로세싱 for(int y = 0; y < Height; ++y) { bitmappixel* BmpFocusEnd = BmpFocus-- + Width; while(++BmpFocus < BmpFocusEnd) BmpFocus->argb = 0xFF000000; } return Bmp; } CheckHeight(Info, height); if(FT_Load_Char(Info->Face, code, FT_LOAD_RENDER) != FT_Err_Ok) { BxASSERT("BxCore::AddOn<해당 폰트의 로드에 실패하였습니다>", false); return nullptr; } // 비트맵구성 FT_Bitmap& FontBitmap = Info->Face->glyph->bitmap; const int Width = FontBitmap.width; const int Height = FontBitmap.rows; const int Ascent = Info->Face->size->metrics.ascender / 64; const int BearingX = Info->Face->glyph->metrics.horiBearingX / 64; const int BearingY = Info->Face->glyph->metrics.horiBearingY / 64; const byte* Bmp = BxCore::AddOn::CreateBMP(Width, Height, BearingX, Ascent - BearingY); bitmappixel* BmpFocus = BxCore::AddOn::GetBMPBits(Bmp); // 프로세싱 for(int y = Height - 1; 0 <= y; --y) { byte* FontFocus = &FontBitmap.buffer[FontBitmap.pitch * y]; bitmappixel* BmpFocusEnd = BmpFocus-- + Width; while(++BmpFocus < BmpFocusEnd) BmpFocus->argb = ((uint) (*(FontFocus++) & 0xFF)) << 24; } return Bmp; } bool TTFToINFO(id_ttf ttf, int height, uint code, int* width, int* ascent) { FaceInfo* Info = (FaceInfo*) ttf; if(!Info) { if(width) *width = height / 2; if(ascent) *ascent = height * 2 / 3; return true; } CheckHeight(Info, height); if(width) { FT_UInt glyph_index = (FT_UInt) code; glyph_index = (FT_UInt) code; if(Info->Face->charmap) glyph_index = FT_Get_Char_Index(Info->Face, code); FT_Fixed advance = 0; FT_Get_Advance(Info->Face, glyph_index, FT_LOAD_NO_HINTING | FT_LOAD_IGNORE_TRANSFORM, &advance); *width = advance / 1024 / 64; } if(ascent) *ascent = Info->Face->size->metrics.ascender / 64; return true; } // ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ #if defined( __CC_ARM ) || defined( __ARMCC__ ) // RVCT #define FT_MulFix_ASSEMBLER(a, b) FT_MulFix_arm(a, b) #define FT_MULFIX_ASSEMBLER_arm #elif defined( __GNUC__ ) #if defined( __arm__ ) && !defined( __CC_ARM ) && !defined( __ARMCC__ ) && (!defined( __thumb__ ) || defined( __thumb2__ )) #define FT_MulFix_ASSEMBLER(a, b) FT_MulFix_gnu_arm(a, b) #define FT_MULFIX_ASSEMBLER_gnu_arm #elif defined( __i386__ ) #define FT_MulFix_ASSEMBLER(a, b) FT_MulFix_gnu_i386(a, b) #define FT_MULFIX_ASSEMBLER_gnu_i386 #endif #elif defined( _MSC_VER ) // Visual C++ #ifdef _M_IX86 #define FT_MulFix_ASSEMBLER(a, b) FT_MulFix_i386(a, b) #define FT_MULFIX_ASSEMBLER_i386 #endif #elif defined( __GNUC__ ) && defined( __x86_64__ ) #define FT_MulFix_ASSEMBLER(a, b) FT_MulFix_x86_64(a, b) #define FT_MULFIX_ASSEMBLER_x86_64 #endif #if defined( FT_MULFIX_ASSEMBLER_arm ) static __inline FT_Int32 FT_MulFix_arm(FT_Int32 a, FT_Int32 b) { register FT_Int32 t, t2; __asm { smull t2, t, b, a /* (lo=t2,hi=t) = a*b */ mov a, t, asr #31 /* a = (hi >> 31) */ add a, a, #0x8000 /* a += 0x8000 */ adds t2, t2, a /* t2 += a */ adc t, t, #0 /* t += carry */ mov a, t2, lsr #16 /* a = t2 >> 16 */ orr a, a, t, lsl #16 /* a |= t << 16 */ } return a; } #elif defined( FT_MULFIX_ASSEMBLER_gnu_arm ) static __inline__ FT_Int32 FT_MulFix_gnu_arm(FT_Int32 a, FT_Int32 b) { register FT_Int32 t, t2; __asm__ __volatile__ ( "smull %1, %2, %4, %3\n\t" /* (lo=%1,hi=%2) = a*b */ "mov %0, %2, asr #31\n\t" /* %0 = (hi >> 31) */ #if defined( __clang__ ) && defined( __thumb2__ ) "add.w %0, %0, #0x8000\n\t" /* %0 += 0x8000 */ #else "add %0, %0, #0x8000\n\t" /* %0 += 0x8000 */ #endif "adds %1, %1, %0\n\t" /* %1 += %0 */ "adc %2, %2, #0\n\t" /* %2 += carry */ "mov %0, %1, lsr #16\n\t" /* %0 = %1 >> 16 */ "orr %0, %0, %2, lsl #16\n\t" /* %0 |= %2 << 16 */ : "=r"(a), "=&r"(t2), "=&r"(t) : "r"(a), "r"(b) : "cc" ); return a; } #elif defined( FT_MULFIX_ASSEMBLER_gnu_i386 ) static __inline__ FT_Int32 FT_MulFix_gnu_i386(FT_Int32 a, FT_Int32 b) { register FT_Int32 result; __asm__ __volatile__ ( "imul %%edx\n" "movl %%edx, %%ecx\n" "sarl $31, %%ecx\n" "addl $0x8000, %%ecx\n" "addl %%ecx, %%eax\n" "adcl $0, %%edx\n" "shrl $16, %%eax\n" "shll $16, %%edx\n" "addl %%edx, %%eax\n" : "=a"(result), "=d"(b) : "a"(a), "d"(b) : "%ecx", "cc" ); return result; } #elif defined( FT_MULFIX_ASSEMBLER_i386 ) static __inline FT_Int32 FT_MulFix_i386(FT_Int32 a, FT_Int32 b) { register FT_Int32 result; __asm { mov eax, a mov edx, b imul edx mov ecx, edx sar ecx, 31 add ecx, 8000h add eax, ecx adc edx, 0 shr eax, 16 shl edx, 16 add eax, edx mov result, eax } return result; } #elif defined( FT_MULFIX_ASSEMBLER_x86_64 ) static __inline__ FT_Int32 FT_MulFix_x86_64(FT_Int32 a, FT_Int32 b) { #if ( __GNUC__ > 4 ) || ( ( __GNUC__ == 4 ) && ( __GNUC_MINOR__ >= 6 ) ) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wlong-long" #endif long long ret, tmp; ret = (long long) a * b; tmp = ret >> 63; ret += 0x8000 + tmp; return (FT_Int32) (ret >> 16); #if ( __GNUC__ > 4 ) || ( ( __GNUC__ == 4 ) && ( __GNUC_MINOR__ >= 6 ) ) #pragma GCC diagnostic pop #endif } #endif FT_BASE_DEF( int ) FT_Throw( FT_Error error, int line, const char* file ) { FT_UNUSED( error ); FT_UNUSED( line ); FT_UNUSED( file ); return 0; } FT_BASE_DEF( FT_Renderer ) FT_Lookup_Renderer( FT_Library library, FT_Glyph_Format format, FT_ListNode* node ) { FT_ListNode cur; FT_Renderer result = 0; if ( !library ) goto Exit; cur = library->renderers.head; if ( node ) { if ( *node ) cur = (*node)->next; *node = 0; } while ( cur ) { FT_Renderer renderer = FT_RENDERER( cur->data ); if ( renderer->glyph_format == format ) { if ( node ) *node = cur; result = renderer; break; } cur = cur->next; } Exit: return result; } static void ft_set_current_renderer( FT_Library library ) { FT_Renderer renderer; renderer = FT_Lookup_Renderer( library, FT_GLYPH_FORMAT_OUTLINE, 0 ); library->cur_renderer = renderer; } FT_EXPORT_DEF( FT_ListNode ) FT_List_Find( FT_List list, void* data ) { FT_ListNode cur; cur = list->head; while ( cur ) { if ( cur->data == data ) return cur; cur = cur->next; } return (FT_ListNode)0; } FT_EXPORT_DEF( void ) FT_List_Up( FT_List list, FT_ListNode node ) { FT_ListNode before, after; before = node->prev; after = node->next; /* check whether we are already on top of the list */ if ( !before ) return; before->next = after; if ( after ) after->prev = before; else list->tail = before; node->prev = 0; node->next = list->head; list->head->prev = node; list->head = node; } FT_EXPORT_DEF( void ) FT_List_Remove( FT_List list, FT_ListNode node ) { FT_ListNode before, after; before = node->prev; after = node->next; if ( before ) before->next = after; else list->head = after; if ( after ) after->prev = before; else list->tail = before; } FT_CALLBACK_DEF( void* ) ft_alloc( FT_Memory memory, long size ) { FT_UNUSED( memory ); return ft_smalloc( size ); } FT_CALLBACK_DEF( void* ) ft_realloc( FT_Memory memory, long cur_size, long new_size, void* block ) { FT_UNUSED( memory ); FT_UNUSED( cur_size ); return ft_srealloc( block, new_size ); } FT_BASE_DEF( FT_Pointer ) ft_mem_qalloc( FT_Memory memory, FT_Long size, FT_Error *p_error ) { FT_Error error = FT_Err_Ok; FT_Pointer block = NULL; if ( size > 0 ) { block = memory->alloc( memory, size ); if ( block == NULL ) error = FT_THROW( Out_Of_Memory ); } else if ( size < 0 ) { /* may help catch/prevent security issues */ error = FT_THROW( Invalid_Argument ); } *p_error = error; return block; } FT_BASE_DEF( FT_Pointer ) ft_mem_alloc( FT_Memory memory, FT_Long size, FT_Error *p_error ) { FT_Error error; FT_Pointer block = ft_mem_qalloc( memory, size, &error ); if ( !error && size > 0 ) FT_MEM_ZERO( block, size ); *p_error = error; return block; } FT_BASE_DEF( void ) ft_mem_free( FT_Memory memory, const void *P ) { if ( P ) memory->free( memory, (void*)P ); } FT_CALLBACK_DEF( void ) ft_free( FT_Memory memory, void* block ) { FT_UNUSED( memory ); ft_sfree( block ); } FT_BASE_DEF( FT_Pointer ) ft_mem_qrealloc( FT_Memory memory, FT_Long item_size, FT_Long cur_count, FT_Long new_count, void* block, FT_Error *p_error ) { FT_Error error = FT_Err_Ok; /* Note that we now accept `item_size == 0' as a valid parameter, in * order to cover very weird cases where an ALLOC_MULT macro would be * called. */ if ( cur_count < 0 || new_count < 0 || item_size < 0 ) { /* may help catch/prevent nasty security issues */ error = FT_THROW( Invalid_Argument ); } else if ( new_count == 0 || item_size == 0 ) { ft_mem_free( memory, block ); block = NULL; } else if ( new_count > FT_INT_MAX/item_size ) { error = FT_THROW( Array_Too_Large ); } else if ( cur_count == 0 ) { FT_ASSERT( block == NULL ); block = ft_mem_alloc( memory, new_count*item_size, &error ); } else { FT_Pointer block2; FT_Long cur_size = cur_count*item_size; FT_Long new_size = new_count*item_size; block2 = memory->realloc( memory, cur_size, new_size, block ); if ( block2 == NULL ) error = FT_THROW( Out_Of_Memory ); else block = block2; } *p_error = error; return block; } FT_BASE_DEF( FT_Pointer ) ft_mem_realloc( FT_Memory memory, FT_Long item_size, FT_Long cur_count, FT_Long new_count, void* block, FT_Error *p_error ) { FT_Error error = FT_Err_Ok; block = ft_mem_qrealloc( memory, item_size, cur_count, new_count, block, &error ); if ( !error && new_count > cur_count ) FT_MEM_ZERO( (char*)block + cur_count * item_size, ( new_count - cur_count ) * item_size ); *p_error = error; return block; } static void ft_remove_renderer( FT_Module module ) { FT_Library library; FT_Memory memory; FT_ListNode node; library = module->library; if ( !library ) return; memory = library->memory; node = FT_List_Find( &library->renderers, module ); if ( node ) { FT_Renderer render = FT_RENDERER( module ); /* release raster object, if any */ if ( render->clazz->glyph_format == FT_GLYPH_FORMAT_OUTLINE && render->raster ) render->clazz->raster_class->raster_done( render->raster ); /* remove from list */ FT_List_Remove( &library->renderers, node ); FT_FREE( node ); ft_set_current_renderer( library ); } } FT_EXPORT_DEF( void ) FT_List_Finalize( FT_List list, FT_List_Destructor destroy, FT_Memory memory, void* user ) { FT_ListNode cur; cur = list->head; while ( cur ) { FT_ListNode next = cur->next; void* data = cur->data; if ( destroy ) destroy( memory, data, user ); FT_FREE( cur ); cur = next; } list->head = 0; list->tail = 0; } FT_BASE_DEF( FT_Error ) FT_GlyphLoader_New( FT_Memory memory, FT_GlyphLoader *aloader ) { FT_GlyphLoader loader = NULL; FT_Error error; if ( !FT_NEW( loader ) ) { loader->memory = memory; *aloader = loader; } return error; } FT_BASE_DEF( void ) FT_GlyphLoader_Rewind( FT_GlyphLoader loader ) { FT_GlyphLoad base = &loader->base; FT_GlyphLoad current = &loader->current; base->outline.n_points = 0; base->outline.n_contours = 0; base->num_subglyphs = 0; *current = *base; } FT_BASE_DEF( void ) FT_GlyphLoader_Reset( FT_GlyphLoader loader ) { FT_Memory memory = loader->memory; FT_FREE( loader->base.outline.points ); FT_FREE( loader->base.outline.tags ); FT_FREE( loader->base.outline.contours ); FT_FREE( loader->base.extra_points ); FT_FREE( loader->base.subglyphs ); loader->base.extra_points2 = NULL; loader->max_points = 0; loader->max_contours = 0; loader->max_subglyphs = 0; FT_GlyphLoader_Rewind( loader ); } FT_BASE_DEF( void ) FT_GlyphLoader_Done( FT_GlyphLoader loader ) { if ( loader ) { FT_Memory memory = loader->memory; FT_GlyphLoader_Reset( loader ); FT_FREE( loader ); } } FT_BASE_DEF( void ) ft_glyphslot_free_bitmap( FT_GlyphSlot slot ) { if ( slot->internal && ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) ) { FT_Memory memory = FT_FACE_MEMORY( slot->face ); FT_FREE( slot->bitmap.buffer ); slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; } else { /* assume that the bitmap buffer was stolen or not */ /* allocated from the heap */ slot->bitmap.buffer = NULL; } } static void ft_glyphslot_done( FT_GlyphSlot slot ) { FT_Driver driver = slot->face->driver; FT_Driver_Class clazz = driver->clazz; FT_Memory memory = driver->root.memory; if ( clazz->done_slot ) clazz->done_slot( slot ); /* free bitmap buffer if needed */ ft_glyphslot_free_bitmap( slot ); /* slot->internal might be NULL in out-of-memory situations */ if ( slot->internal ) { /* free glyph loader */ if ( FT_DRIVER_USES_OUTLINES( driver ) ) { FT_GlyphLoader_Done( slot->internal->loader ); slot->internal->loader = 0; } FT_FREE( slot->internal ); } } 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 = NULL; slot->library = driver->root.library; if ( FT_NEW( internal ) ) goto Exit; slot->internal = internal; if ( FT_DRIVER_USES_OUTLINES( driver ) ) error = FT_GlyphLoader_New( memory, &internal->loader ); if ( !error && clazz->init_slot ) error = clazz->init_slot( slot ); Exit: return error; } static void destroy_size( FT_Memory memory, FT_Size size, FT_Driver driver ) { /* finalize client-specific data */ if ( size->generic.finalizer ) size->generic.finalizer( size ); /* finalize format-specific stuff */ if ( driver->clazz->done_size ) driver->clazz->done_size( size ); FT_FREE( size->internal ); FT_FREE( size ); } static void ft_cmap_done_internal( FT_CMap cmap ) { FT_CMap_Class clazz = cmap->clazz; FT_Face face = cmap->charmap.face; FT_Memory memory = FT_FACE_MEMORY( face ); if ( clazz->done ) clazz->done( cmap ); FT_FREE( cmap ); } static void destroy_charmaps( FT_Face face, FT_Memory memory ) { FT_Int n; if ( !face ) return; for ( n = 0; n < face->num_charmaps; n++ ) { FT_CMap cmap = FT_CMAP( face->charmaps[n] ); ft_cmap_done_internal( cmap ); face->charmaps[n] = NULL; } FT_FREE( face->charmaps ); face->num_charmaps = 0; } typedef struct FT_Frame_Field_ { FT_Byte value; FT_Byte size; FT_UShort offset; } FT_Frame_Field; FT_BASE_DEF( void ) FT_Stream_OpenMemory( FT_Stream stream, const FT_Byte* base, FT_ULong size ) { stream->base = (FT_Byte*) base; stream->size = size; stream->pos = 0; stream->cursor = 0; stream->read = 0; stream->close = 0; } FT_BASE_DEF( void ) FT_Stream_Close( FT_Stream stream ) { if ( stream && stream->close ) stream->close( stream ); } FT_BASE_DEF( FT_Error ) FT_Stream_New( FT_Library library, const FT_Open_Args* args, FT_Stream *astream ) { FT_Error error; FT_Memory memory; FT_Stream stream = NULL; *astream = 0; if ( !library ) return FT_THROW( Invalid_Library_Handle ); if ( !args ) return FT_THROW( Invalid_Argument ); memory = library->memory; if ( FT_NEW( stream ) ) goto Exit; stream->memory = memory; if ( args->flags & FT_OPEN_MEMORY ) { /* create a memory-based stream */ FT_Stream_OpenMemory( stream, (const FT_Byte*)args->memory_base, args->memory_size ); } #ifndef FT_CONFIG_OPTION_DISABLE_STREAM_SUPPORT else if ( args->flags & FT_OPEN_PATHNAME ) { /* create a normal system stream */ error = FT_Stream_Open( stream, args->pathname ); stream->pathname.pointer = args->pathname; } else if ( ( args->flags & FT_OPEN_STREAM ) && args->stream ) { /* use an existing, user-provided stream */ /* in this case, we do not need to allocate a new stream object */ /* since the caller is responsible for closing it himself */ FT_FREE( stream ); stream = args->stream; } #endif else error = FT_THROW( Invalid_Argument ); if ( error ) FT_FREE( stream ); else stream->memory = memory; /* just to be certain */ *astream = stream; Exit: return error; } FT_BASE_DEF( void ) FT_Stream_Free( FT_Stream stream, FT_Int external ) { if ( stream ) { FT_Memory memory = stream->memory; FT_Stream_Close( stream ); if ( !external ) FT_FREE( stream ); } } FT_BASE_DEF( void ) FT_Stream_ExitFrame( FT_Stream stream ) { /* IMPORTANT: The assertion stream->cursor != 0 was removed, given */ /* that it is possible to access a frame of length 0 in */ /* some weird fonts (usually, when accessing an array of */ /* 0 records, like in some strange kern tables). */ /* */ /* In this case, the loader code handles the 0-length table */ /* gracefully; however, stream.cursor is really set to 0 by the */ /* FT_Stream_EnterFrame() call, and this is not an error. */ /* */ FT_ASSERT( stream ); if ( stream->read ) { FT_Memory memory = stream->memory; #ifdef FT_DEBUG_MEMORY ft_mem_free( memory, stream->base ); stream->base = NULL; #else FT_FREE( stream->base ); #endif } stream->cursor = 0; stream->limit = 0; } FT_BASE_DEF( FT_Error ) FT_Stream_Seek( FT_Stream stream, FT_ULong pos ) { FT_Error error = FT_Err_Ok; if ( stream->read ) { if ( stream->read( stream, pos, 0, 0 ) ) { FT_ERROR(( "FT_Stream_Seek:" " invalid i/o; pos = 0x%lx, size = 0x%lx\n", pos, stream->size )); error = FT_THROW( Invalid_Stream_Operation ); } } /* note that seeking to the first position after the file is valid */ else if ( pos > stream->size ) { FT_ERROR(( "FT_Stream_Seek:" " invalid i/o; pos = 0x%lx, size = 0x%lx\n", pos, stream->size )); error = FT_THROW( Invalid_Stream_Operation ); } if ( !error ) stream->pos = pos; return error; } FT_BASE_DEF( FT_Error ) FT_Stream_Skip( FT_Stream stream, FT_Long distance ) { if ( distance < 0 ) return FT_THROW( Invalid_Stream_Operation ); return FT_Stream_Seek( stream, (FT_ULong)( stream->pos + distance ) ); } FT_BASE_DEF( FT_Long ) FT_Stream_Pos( FT_Stream stream ) { return stream->pos; } FT_BASE_DEF( FT_Error ) FT_Stream_ReadAt( FT_Stream stream, FT_ULong pos, FT_Byte* buffer, FT_ULong count ) { FT_Error error = FT_Err_Ok; FT_ULong read_bytes; if ( pos >= stream->size ) { FT_ERROR(( "FT_Stream_ReadAt:" " invalid i/o; pos = 0x%lx, size = 0x%lx\n", pos, stream->size )); return FT_THROW( Invalid_Stream_Operation ); } if ( stream->read ) read_bytes = stream->read( stream, pos, buffer, count ); else { read_bytes = stream->size - pos; if ( read_bytes > count ) read_bytes = count; FT_MEM_COPY( buffer, stream->base + pos, read_bytes ); } stream->pos = pos + read_bytes; if ( read_bytes < count ) { FT_ERROR(( "FT_Stream_ReadAt:" " invalid read; expected %lu bytes, got %lu\n", count, read_bytes )); error = FT_THROW( Invalid_Stream_Operation ); } return error; } FT_BASE_DEF( FT_Error ) FT_Stream_Read( FT_Stream stream, FT_Byte* buffer, FT_ULong count ) { return FT_Stream_ReadAt( stream, stream->pos, buffer, count ); } FT_BASE_DEF( FT_ULong ) FT_Stream_TryRead( FT_Stream stream, FT_Byte* buffer, FT_ULong count ) { FT_ULong read_bytes = 0; if ( stream->pos >= stream->size ) goto Exit; if ( stream->read ) read_bytes = stream->read( stream, stream->pos, buffer, count ); else { read_bytes = stream->size - stream->pos; if ( read_bytes > count ) read_bytes = count; FT_MEM_COPY( buffer, stream->base + stream->pos, read_bytes ); } stream->pos += read_bytes; Exit: return read_bytes; } FT_BASE_DEF( FT_Error ) FT_Stream_EnterFrame( FT_Stream stream, FT_ULong count ) { FT_Error error = FT_Err_Ok; FT_ULong read_bytes; /* check for nested frame access */ FT_ASSERT( stream && stream->cursor == 0 ); if ( stream->read ) { /* allocate the frame in memory */ FT_Memory memory = stream->memory; /* simple sanity check */ if ( count > stream->size ) { FT_ERROR(( "FT_Stream_EnterFrame:" " frame size (%lu) larger than stream size (%lu)\n", count, stream->size )); error = FT_THROW( Invalid_Stream_Operation ); goto Exit; } #ifdef FT_DEBUG_MEMORY /* assume _ft_debug_file and _ft_debug_lineno are already set */ stream->base = (unsigned char*)ft_mem_qalloc( memory, count, &error ); if ( error ) goto Exit; #else if ( FT_QALLOC( stream->base, count ) ) goto Exit; #endif /* read it */ read_bytes = stream->read( stream, stream->pos, stream->base, count ); if ( read_bytes < count ) { FT_ERROR(( "FT_Stream_EnterFrame:" " invalid read; expected %lu bytes, got %lu\n", count, read_bytes )); FT_FREE( stream->base ); error = FT_THROW( Invalid_Stream_Operation ); } stream->cursor = stream->base; stream->limit = stream->cursor + count; stream->pos += read_bytes; } else { /* check current and new position */ if ( stream->pos >= stream->size || stream->size - stream->pos < count ) { FT_ERROR(( "FT_Stream_EnterFrame:" " invalid i/o; pos = 0x%lx, count = %lu, size = 0x%lx\n", stream->pos, count, stream->size )); error = FT_THROW( Invalid_Stream_Operation ); goto Exit; } /* set cursor */ stream->cursor = stream->base + stream->pos; stream->limit = stream->cursor + count; stream->pos += count; } Exit: return error; } FT_BASE_DEF( FT_Error ) FT_Stream_ExtractFrame( FT_Stream stream, FT_ULong count, FT_Byte** pbytes ) { FT_Error error; error = FT_Stream_EnterFrame( stream, count ); if ( !error ) { *pbytes = (FT_Byte*)stream->cursor; /* equivalent to FT_Stream_ExitFrame(), with no memory block release */ stream->cursor = 0; stream->limit = 0; } return error; } FT_BASE_DEF( void ) FT_Stream_ReleaseFrame( FT_Stream stream, FT_Byte** pbytes ) { if ( stream && stream->read ) { FT_Memory memory = stream->memory; #ifdef FT_DEBUG_MEMORY ft_mem_free( memory, *pbytes ); *pbytes = NULL; #else FT_FREE( *pbytes ); #endif } *pbytes = 0; } #define FT_GET_MACRO( func, type ) ( (type)func( stream ) ) #define FT_GET_CHAR() FT_GET_MACRO( FT_Stream_GetChar, FT_Char ) #define FT_GET_BYTE() FT_GET_MACRO( FT_Stream_GetChar, FT_Byte ) #define FT_GET_SHORT() FT_GET_MACRO( FT_Stream_GetUShort, FT_Short ) #define FT_GET_USHORT() FT_GET_MACRO( FT_Stream_GetUShort, FT_UShort ) #define FT_GET_OFF3() FT_GET_MACRO( FT_Stream_GetUOffset, FT_Long ) #define FT_GET_UOFF3() FT_GET_MACRO( FT_Stream_GetUOffset, FT_ULong ) #define FT_GET_LONG() FT_GET_MACRO( FT_Stream_GetULong, FT_Long ) #define FT_GET_ULONG() FT_GET_MACRO( FT_Stream_GetULong, FT_ULong ) #define FT_GET_TAG4() FT_GET_MACRO( FT_Stream_GetULong, FT_ULong ) #define FT_GET_SHORT_LE() FT_GET_MACRO( FT_Stream_GetUShortLE, FT_Short ) #define FT_GET_USHORT_LE() FT_GET_MACRO( FT_Stream_GetUShortLE, FT_UShort ) #define FT_GET_LONG_LE() FT_GET_MACRO( FT_Stream_GetULongLE, FT_Long ) #define FT_GET_ULONG_LE() FT_GET_MACRO( FT_Stream_GetULongLE, FT_ULong ) typedef enum FT_Frame_Op_ { ft_frame_end = 0, ft_frame_start = FT_MAKE_FRAME_OP( FT_FRAME_OP_START, 0, 0 ), ft_frame_byte = FT_MAKE_FRAME_OP( FT_FRAME_OP_BYTE, 0, 0 ), ft_frame_schar = FT_MAKE_FRAME_OP( FT_FRAME_OP_BYTE, 0, 1 ), ft_frame_ushort_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_SHORT, 0, 0 ), ft_frame_short_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_SHORT, 0, 1 ), ft_frame_ushort_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_SHORT, 1, 0 ), ft_frame_short_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_SHORT, 1, 1 ), ft_frame_ulong_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_LONG, 0, 0 ), ft_frame_long_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_LONG, 0, 1 ), ft_frame_ulong_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_LONG, 1, 0 ), ft_frame_long_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_LONG, 1, 1 ), ft_frame_uoff3_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_OFF3, 0, 0 ), ft_frame_off3_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_OFF3, 0, 1 ), ft_frame_uoff3_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_OFF3, 1, 0 ), ft_frame_off3_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_OFF3, 1, 1 ), ft_frame_bytes = FT_MAKE_FRAME_OP( FT_FRAME_OP_BYTES, 0, 0 ), ft_frame_skip = FT_MAKE_FRAME_OP( FT_FRAME_OP_BYTES, 0, 1 ) } FT_Frame_Op; FT_BASE_DEF( FT_Char ) FT_Stream_GetChar( FT_Stream stream ) { FT_Char result; FT_ASSERT( stream && stream->cursor ); result = 0; if ( stream->cursor < stream->limit ) result = *stream->cursor++; return result; } FT_BASE_DEF( FT_UShort ) FT_Stream_GetUShort( FT_Stream stream ) { FT_Byte* p; FT_Short result; FT_ASSERT( stream && stream->cursor ); result = 0; p = stream->cursor; if ( p + 1 < stream->limit ) result = FT_NEXT_USHORT( p ); stream->cursor = p; return result; } FT_BASE_DEF( FT_UShort ) FT_Stream_GetUShortLE( FT_Stream stream ) { FT_Byte* p; FT_Short result; FT_ASSERT( stream && stream->cursor ); result = 0; p = stream->cursor; if ( p + 1 < stream->limit ) result = FT_NEXT_USHORT_LE( p ); stream->cursor = p; return result; } FT_BASE_DEF( FT_ULong ) FT_Stream_GetUOffset( FT_Stream stream ) { FT_Byte* p; FT_Long result; FT_ASSERT( stream && stream->cursor ); result = 0; p = stream->cursor; if ( p + 2 < stream->limit ) result = FT_NEXT_UOFF3( p ); stream->cursor = p; return result; } FT_BASE_DEF( FT_ULong ) FT_Stream_GetULong( FT_Stream stream ) { FT_Byte* p; FT_Long result; FT_ASSERT( stream && stream->cursor ); result = 0; p = stream->cursor; if ( p + 3 < stream->limit ) result = FT_NEXT_ULONG( p ); stream->cursor = p; return result; } FT_BASE_DEF( FT_ULong ) FT_Stream_GetULongLE( FT_Stream stream ) { FT_Byte* p; FT_Long result; FT_ASSERT( stream && stream->cursor ); result = 0; p = stream->cursor; if ( p + 3 < stream->limit ) result = FT_NEXT_ULONG_LE( p ); stream->cursor = p; return result; } FT_BASE_DEF( FT_Char ) FT_Stream_ReadChar( FT_Stream stream, FT_Error* error ) { FT_Byte result = 0; FT_ASSERT( stream ); *error = FT_Err_Ok; if ( stream->read ) { if ( stream->read( stream, stream->pos, &result, 1L ) != 1L ) goto Fail; } else { if ( stream->pos < stream->size ) result = stream->base[stream->pos]; else goto Fail; } stream->pos++; return result; Fail: *error = FT_THROW( Invalid_Stream_Operation ); FT_ERROR(( "FT_Stream_ReadChar:" " invalid i/o; pos = 0x%lx, size = 0x%lx\n", stream->pos, stream->size )); return 0; } FT_BASE_DEF( FT_UShort ) FT_Stream_ReadUShort( FT_Stream stream, FT_Error* error ) { FT_Byte reads[2]; FT_Byte* p = 0; FT_Short result = 0; FT_ASSERT( stream ); *error = FT_Err_Ok; if ( stream->pos + 1 < stream->size ) { if ( stream->read ) { if ( stream->read( stream, stream->pos, reads, 2L ) != 2L ) goto Fail; p = reads; } else { p = stream->base + stream->pos; } if ( p ) result = FT_NEXT_USHORT( p ); } else goto Fail; stream->pos += 2; return result; Fail: *error = FT_THROW( Invalid_Stream_Operation ); FT_ERROR(( "FT_Stream_ReadUShort:" " invalid i/o; pos = 0x%lx, size = 0x%lx\n", stream->pos, stream->size )); return 0; } FT_BASE_DEF( FT_UShort ) FT_Stream_ReadUShortLE( FT_Stream stream, FT_Error* error ) { FT_Byte reads[2]; FT_Byte* p = 0; FT_Short result = 0; FT_ASSERT( stream ); *error = FT_Err_Ok; if ( stream->pos + 1 < stream->size ) { if ( stream->read ) { if ( stream->read( stream, stream->pos, reads, 2L ) != 2L ) goto Fail; p = reads; } else { p = stream->base + stream->pos; } if ( p ) result = FT_NEXT_USHORT_LE( p ); } else goto Fail; stream->pos += 2; return result; Fail: *error = FT_THROW( Invalid_Stream_Operation ); FT_ERROR(( "FT_Stream_ReadUShortLE:" " invalid i/o; pos = 0x%lx, size = 0x%lx\n", stream->pos, stream->size )); return 0; } FT_BASE_DEF( FT_ULong ) FT_Stream_ReadUOffset( FT_Stream stream, FT_Error* error ) { FT_Byte reads[3]; FT_Byte* p = 0; FT_Long result = 0; FT_ASSERT( stream ); *error = FT_Err_Ok; if ( stream->pos + 2 < stream->size ) { if ( stream->read ) { if (stream->read( stream, stream->pos, reads, 3L ) != 3L ) goto Fail; p = reads; } else { p = stream->base + stream->pos; } if ( p ) result = FT_NEXT_UOFF3( p ); } else goto Fail; stream->pos += 3; return result; Fail: *error = FT_THROW( Invalid_Stream_Operation ); FT_ERROR(( "FT_Stream_ReadUOffset:" " invalid i/o; pos = 0x%lx, size = 0x%lx\n", stream->pos, stream->size )); return 0; } FT_BASE_DEF( FT_ULong ) FT_Stream_ReadULong( FT_Stream stream, FT_Error* error ) { FT_Byte reads[4]; FT_Byte* p = 0; FT_Long result = 0; FT_ASSERT( stream ); *error = FT_Err_Ok; if ( stream->pos + 3 < stream->size ) { if ( stream->read ) { if ( stream->read( stream, stream->pos, reads, 4L ) != 4L ) goto Fail; p = reads; } else { p = stream->base + stream->pos; } if ( p ) result = FT_NEXT_ULONG( p ); } else goto Fail; stream->pos += 4; return result; Fail: *error = FT_THROW( Invalid_Stream_Operation ); FT_ERROR(( "FT_Stream_ReadULong:" " invalid i/o; pos = 0x%lx, size = 0x%lx\n", stream->pos, stream->size )); return 0; } FT_BASE_DEF( FT_ULong ) FT_Stream_ReadULongLE( FT_Stream stream, FT_Error* error ) { FT_Byte reads[4]; FT_Byte* p = 0; FT_Long result = 0; FT_ASSERT( stream ); *error = FT_Err_Ok; if ( stream->pos + 3 < stream->size ) { if ( stream->read ) { if ( stream->read( stream, stream->pos, reads, 4L ) != 4L ) goto Fail; p = reads; } else { p = stream->base + stream->pos; } if ( p ) result = FT_NEXT_ULONG_LE( p ); } else goto Fail; stream->pos += 4; return result; Fail: *error = FT_THROW( Invalid_Stream_Operation ); FT_ERROR(( "FT_Stream_ReadULongLE:" " invalid i/o; pos = 0x%lx, size = 0x%lx\n", stream->pos, stream->size )); return 0; } FT_BASE_DEF( FT_Error ) FT_Stream_ReadFields( FT_Stream stream, const FT_Frame_Field* fields, void* structure ) { FT_Error error; FT_Bool frame_accessed = 0; FT_Byte* cursor; if ( !fields || !stream ) return FT_THROW( Invalid_Argument ); cursor = stream->cursor; error = FT_Err_Ok; do { FT_ULong value; FT_Int sign_shift; FT_Byte* p; switch ( fields->value ) { case ft_frame_start: /* access a new frame */ error = FT_Stream_EnterFrame( stream, fields->offset ); if ( error ) goto Exit; frame_accessed = 1; cursor = stream->cursor; fields++; continue; /* loop! */ case ft_frame_bytes: /* read a byte sequence */ case ft_frame_skip: /* skip some bytes */ { FT_UInt len = fields->size; if ( cursor + len > stream->limit ) { error = FT_THROW( Invalid_Stream_Operation ); goto Exit; } if ( fields->value == ft_frame_bytes ) { p = (FT_Byte*)structure + fields->offset; FT_MEM_COPY( p, cursor, len ); } cursor += len; fields++; continue; } case ft_frame_byte: case ft_frame_schar: /* read a single byte */ value = FT_NEXT_BYTE( cursor ); sign_shift = 24; break; case ft_frame_short_be: case ft_frame_ushort_be: /* read a 2-byte big-endian short */ value = FT_NEXT_USHORT( cursor) ; sign_shift = 16; break; case ft_frame_short_le: case ft_frame_ushort_le: /* read a 2-byte little-endian short */ value = FT_NEXT_USHORT_LE( cursor ); sign_shift = 16; break; case ft_frame_long_be: case ft_frame_ulong_be: /* read a 4-byte big-endian long */ value = FT_NEXT_ULONG( cursor ); sign_shift = 0; break; case ft_frame_long_le: case ft_frame_ulong_le: /* read a 4-byte little-endian long */ value = FT_NEXT_ULONG_LE( cursor ); sign_shift = 0; break; case ft_frame_off3_be: case ft_frame_uoff3_be: /* read a 3-byte big-endian long */ value = FT_NEXT_UOFF3( cursor ); sign_shift = 8; break; case ft_frame_off3_le: case ft_frame_uoff3_le: /* read a 3-byte little-endian long */ value = FT_NEXT_UOFF3_LE( cursor ); sign_shift = 8; break; default: /* otherwise, exit the loop */ stream->cursor = cursor; goto Exit; } /* now, compute the signed value is necessary */ if ( fields->value & FT_FRAME_OP_SIGNED ) value = (FT_ULong)( (FT_Int32)( value << sign_shift ) >> sign_shift ); /* finally, store the value in the object */ p = (FT_Byte*)structure + fields->offset; switch ( fields->size ) { case ( 8 / FT_CHAR_BIT ): *(FT_Byte*)p = (FT_Byte)value; break; case ( 16 / FT_CHAR_BIT ): *(FT_UShort*)p = (FT_UShort)value; break; case ( 32 / FT_CHAR_BIT ): *(FT_UInt32*)p = (FT_UInt32)value; break; default: /* for 64-bit systems */ *(FT_ULong*)p = (FT_ULong)value; } /* go to next field */ fields++; } while ( 1 ); Exit: /* close the frame if it was opened by this read */ if ( frame_accessed ) FT_Stream_ExitFrame( stream ); return error; } FT_BASE_DEF( FT_Error ) FT_New_GlyphSlot( FT_Face face, FT_GlyphSlot *aslot ) { FT_Error error; FT_Driver driver; FT_Driver_Class clazz; FT_Memory memory; FT_GlyphSlot slot = NULL; if ( !face || !face->driver ) return FT_THROW( Invalid_Argument ); driver = face->driver; clazz = driver->clazz; memory = driver->root.memory; FT_TRACE4(( "FT_New_GlyphSlot: Creating new slot object\n" )); if ( !FT_ALLOC( slot, clazz->slot_object_size ) ) { slot->face = face; error = ft_glyphslot_init( slot ); if ( error ) { ft_glyphslot_done( slot ); FT_FREE( slot ); goto Exit; } slot->next = face->glyph; face->glyph = slot; if ( aslot ) *aslot = slot; } else if ( aslot ) *aslot = 0; Exit: FT_TRACE4(( "FT_New_GlyphSlot: Return %d\n", error )); return error; } /* documentation is in ftobjs.h */ FT_BASE_DEF( void ) FT_Done_GlyphSlot( FT_GlyphSlot slot ) { if ( slot ) { FT_Driver driver = slot->face->driver; FT_Memory memory = driver->root.memory; FT_GlyphSlot prev; FT_GlyphSlot cur; /* Remove slot from its parent face's list */ prev = NULL; cur = slot->face->glyph; while ( cur ) { if ( cur == slot ) { if ( !prev ) slot->face->glyph = cur->next; else prev->next = cur->next; /* finalize client-specific data */ if ( slot->generic.finalizer ) slot->generic.finalizer( slot ); ft_glyphslot_done( slot ); FT_FREE( slot ); break; } prev = cur; cur = cur->next; } } } static void destroy_face( FT_Memory memory, FT_Face face, FT_Driver driver ) { FT_Driver_Class clazz = driver->clazz; /* discard auto-hinting data */ if ( face->autohint.finalizer ) face->autohint.finalizer( face->autohint.data ); /* Discard glyph slots for this face. */ /* Beware! FT_Done_GlyphSlot() changes the field `face->glyph' */ while ( face->glyph ) FT_Done_GlyphSlot( face->glyph ); /* discard all sizes for this face */ FT_List_Finalize( &face->sizes_list, (FT_List_Destructor)destroy_size, memory, driver ); face->size = 0; /* now discard client data */ if ( face->generic.finalizer ) face->generic.finalizer( face ); /* discard charmaps */ destroy_charmaps( face, memory ); /* finalize format-specific stuff */ if ( clazz->done_face ) clazz->done_face( face ); /* close the stream for this face if needed */ FT_Stream_Free( face->stream, ( face->face_flags & FT_FACE_FLAG_EXTERNAL_STREAM ) != 0 ); face->stream = 0; /* get rid of it */ if ( face->internal ) { FT_FREE( face->internal ); } FT_FREE( face ); } static void Destroy_Driver( FT_Driver driver ) { FT_List_Finalize( &driver->faces_list, (FT_List_Destructor)destroy_face, driver->root.memory, driver ); /* check whether we need to drop the driver's glyph loader */ if ( FT_DRIVER_USES_OUTLINES( driver ) ) FT_GlyphLoader_Done( driver->glyph_loader ); } static void Destroy_Module( FT_Module module ) { FT_Memory memory = module->memory; FT_Module_Class* clazz = module->clazz; FT_Library library = module->library; if ( library && library->auto_hinter == module ) library->auto_hinter = 0; /* if the module is a renderer */ if ( FT_MODULE_IS_RENDERER( module ) ) ft_remove_renderer( module ); /* if the module is a font driver, add some steps */ if ( FT_MODULE_IS_DRIVER( module ) ) Destroy_Driver( FT_DRIVER( module ) ); /* finalize the module object */ if ( clazz->module_done ) clazz->module_done( module ); /* discard it */ FT_FREE( module ); } FT_EXPORT_DEF( FT_Error ) FT_Remove_Module( FT_Library library, FT_Module module ) { /* try to find the module from the table, then remove it from there */ if ( !library ) return FT_THROW( Invalid_Library_Handle ); if ( module ) { FT_Module* cur = library->modules; FT_Module* limit = cur + library->num_modules; for ( ; cur < limit; cur++ ) { if ( cur[0] == module ) { /* remove it from the table */ library->num_modules--; limit--; while ( cur < limit ) { cur[0] = cur[1]; cur++; } limit[0] = 0; /* destroy the module */ Destroy_Module( module ); return FT_Err_Ok; } } } return FT_THROW( Invalid_Driver_Handle ); } FT_EXPORT_DEF( void ) FT_List_Add( FT_List list, FT_ListNode node ) { FT_ListNode before = list->tail; node->next = 0; node->prev = before; if ( before ) before->next = node; else list->head = node; list->tail = node; } static FT_Error ft_add_renderer( FT_Module module ) { FT_Library library = module->library; FT_Memory memory = library->memory; FT_Error error; FT_ListNode node = NULL; if ( FT_NEW( node ) ) goto Exit; { FT_Renderer render = FT_RENDERER( module ); FT_Renderer_Class* clazz = (FT_Renderer_Class*)module->clazz; render->clazz = clazz; render->glyph_format = clazz->glyph_format; /* allocate raster object if needed */ if ( clazz->glyph_format == FT_GLYPH_FORMAT_OUTLINE && clazz->raster_class->raster_new ) { error = clazz->raster_class->raster_new( memory, &render->raster ); if ( error ) goto Fail; render->raster_render = clazz->raster_class->raster_render; render->render = clazz->render_glyph; } /* add to list */ node->data = module; FT_List_Add( &library->renderers, node ); ft_set_current_renderer( library ); } Fail: if ( error ) FT_FREE( node ); Exit: return error; } FT_EXPORT_DEF( FT_Error ) FT_Add_Module( FT_Library library, const FT_Module_Class* clazz ) { FT_Error error; FT_Memory memory; FT_Module module; FT_UInt nn; #define FREETYPE_VER_FIXED ( ( (FT_Long)FREETYPE_MAJOR << 16 ) | \ FREETYPE_MINOR ) if ( !library ) return FT_THROW( Invalid_Library_Handle ); if ( !clazz ) return FT_THROW( Invalid_Argument ); /* check freetype version */ if ( clazz->module_requires > FREETYPE_VER_FIXED ) return FT_THROW( Invalid_Version ); /* look for a module with the same name in the library's table */ for ( nn = 0; nn < library->num_modules; nn++ ) { module = library->modules[nn]; if ( ft_strcmp( module->clazz->module_name, clazz->module_name ) == 0 ) { /* this installed module has the same name, compare their versions */ if ( clazz->module_version <= module->clazz->module_version ) return FT_THROW( Lower_Module_Version ); /* remove the module from our list, then exit the loop to replace */ /* it by our new version.. */ FT_Remove_Module( library, module ); break; } } memory = library->memory; error = FT_Err_Ok; if ( library->num_modules >= FT_MAX_MODULES ) { error = FT_THROW( Too_Many_Drivers ); goto Exit; } /* allocate module object */ if ( FT_ALLOC( module, clazz->module_size ) ) goto Exit; /* base initialization */ module->library = library; module->memory = memory; module->clazz = (FT_Module_Class*)clazz; /* check whether the module is a renderer - this must be performed */ /* before the normal module initialization */ if ( FT_MODULE_IS_RENDERER( module ) ) { /* add to the renderers list */ error = ft_add_renderer( module ); if ( error ) goto Fail; } /* is the module a auto-hinter? */ if ( FT_MODULE_IS_HINTER( module ) ) library->auto_hinter = module; /* if the module is a font driver */ if ( FT_MODULE_IS_DRIVER( module ) ) { /* allocate glyph loader if needed */ FT_Driver driver = FT_DRIVER( module ); driver->clazz = (FT_Driver_Class)module->clazz; if ( FT_DRIVER_USES_OUTLINES( driver ) ) { error = FT_GlyphLoader_New( memory, &driver->glyph_loader ); if ( error ) goto Fail; } } if ( clazz->module_init ) { error = clazz->module_init( module ); if ( error ) goto Fail; } /* add module to the library's table */ library->modules[library->num_modules++] = module; Exit: return error; Fail: if ( FT_MODULE_IS_DRIVER( module ) ) { FT_Driver driver = FT_DRIVER( module ); if ( FT_DRIVER_USES_OUTLINES( driver ) ) FT_GlyphLoader_Done( driver->glyph_loader ); } if ( FT_MODULE_IS_RENDERER( module ) ) { FT_Renderer renderer = FT_RENDERER( module ); if ( renderer->clazz && renderer->clazz->glyph_format == FT_GLYPH_FORMAT_OUTLINE && renderer->raster ) renderer->clazz->raster_class->raster_done( renderer->raster ); } FT_FREE( module ); goto Exit; } FT_BASE_DEF( FT_Memory ) FT_New_Memory( void ) { FT_Memory memory; memory = (FT_Memory)ft_smalloc( sizeof ( *memory ) ); if ( memory ) { memory->user = 0; memory->alloc = ft_alloc; memory->realloc = ft_realloc; memory->free = ft_free; #ifdef FT_DEBUG_MEMORY ft_mem_debug_init( memory ); #endif } return memory; } FT_EXPORT_DEF( FT_Error ) FT_New_Size( FT_Face face, FT_Size *asize ) { FT_Error error; FT_Memory memory; FT_Driver driver; FT_Driver_Class clazz; FT_Size size = 0; FT_ListNode node = 0; if ( !face ) return FT_THROW( Invalid_Face_Handle ); if ( !asize ) return FT_THROW( Invalid_Size_Handle ); if ( !face->driver ) return FT_THROW( Invalid_Driver_Handle ); *asize = 0; driver = face->driver; clazz = driver->clazz; memory = face->memory; /* Allocate new size object and perform basic initialisation */ if ( FT_ALLOC( size, clazz->size_object_size ) || FT_NEW( node ) ) goto Exit; size->face = face; /* for now, do not use any internal fields in size objects */ size->internal = 0; if ( clazz->init_size ) error = clazz->init_size( size ); /* in case of success, add to the face's list */ if ( !error ) { *asize = size; node->data = size; FT_List_Add( &face->sizes_list, node ); } Exit: if ( error ) { FT_FREE( node ); FT_FREE( size ); } return error; } FT_EXPORT_DEF( FT_Error ) FT_Done_Library( FT_Library library ) { FT_Memory memory; if ( !library ) return FT_THROW( Invalid_Library_Handle ); library->refcount--; if ( library->refcount > 0 ) goto Exit; memory = library->memory; /* * 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 m, n; const char* driver_name[] = { "type42", NULL }; for ( m = 0; m < sizeof ( driver_name ) / sizeof ( driver_name[0] ); m++ ) { 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 ( driver_name[m] && ft_strcmp( module_name, driver_name[m] ) != 0 ) continue; 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" )); } } } } /* Close all other modules in the library */ #if 1 /* XXX Modules are removed in the reversed order so that */ /* type42 module is removed before truetype module. This */ /* avoids double free in some occasions. It is a hack. */ while ( library->num_modules > 0 ) FT_Remove_Module( library, library->modules[library->num_modules - 1] ); #else { FT_UInt n; for ( n = 0; n < library->num_modules; n++ ) { FT_Module module = library->modules[n]; if ( module ) { Destroy_Module( module ); library->modules[n] = 0; } } } #endif /* Destroy raster objects */ 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; } FT_BASE_DEF( void ) FT_Done_Memory( FT_Memory memory ) { #ifdef FT_DEBUG_MEMORY ft_mem_debug_done( memory ); #endif ft_sfree( memory ); } extern const FT_Module_Class* const ft_default_modules[]; FT_EXPORT_DEF( void ) FT_Add_Default_Modules( FT_Library library ) { FT_Error error; const FT_Module_Class* const* cur; /* FT_DEFAULT_MODULES_GET dereferences `library' in PIC mode */ #ifdef FT_CONFIG_OPTION_PIC if ( !library ) return; #endif /* GCC 4.6 warns the type difference: * FT_Module_Class** != const FT_Module_Class* const* */ cur = (const FT_Module_Class* const*) FT_DEFAULT_MODULES_GET; /* test for valid `library' delayed to FT_Add_Module() */ while ( *cur ) { error = FT_Add_Module( library, *cur ); /* notify errors, but don't stop */ if ( error ) FT_TRACE0(( "FT_Add_Default_Module:" " Cannot install `%s', error = 0x%x\n", (*cur)->module_name, error )); cur++; } } FT_EXPORT_DEF( FT_Error ) FT_New_Library( FT_Memory memory, FT_Library *alibrary ) { FT_Library library = NULL; FT_Error error; if ( !memory ) return FT_THROW( Invalid_Argument ); #ifdef FT_DEBUG_LEVEL_ERROR /* init debugging support */ ft_debug_init(); #endif /* first of all, allocate the library object */ if ( FT_NEW( library ) ) return 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; #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; } // ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ #define FT_LOCAL( x ) extern "C" x #define FT_LOCAL_DEF( x ) extern "C" x #define FT_PARAM_TAG_INCREMENTAL FT_MAKE_TAG( 'i', 'n', 'c', 'r' ) extern "C" FT_Error FT_Init_FreeType(FT_Library* alibrary) { FT_Error error; FT_Memory memory; /* First of all, allocate a new system object -- this function is part */ /* of the system-specific component, i.e. `ftsystem.c'. */ memory = FT_New_Memory(); if ( !memory ) { FT_ERROR(( "FT_Init_FreeType: cannot find memory manager\n" )); return FT_THROW( Unimplemented_Feature ); } /* build a library out of it, then fill it with the set of */ /* default drivers. */ error = FT_New_Library( memory, alibrary ); if ( error ) FT_Done_Memory( memory ); else FT_Add_Default_Modules( *alibrary ); return error; } extern "C" FT_Error FT_Done_FreeType(FT_Library library) { if ( library ) { FT_Memory memory = library->memory; /* Discard the library object */ FT_Done_Library( library ); /* discard memory manager */ FT_Done_Memory( memory ); } return FT_Err_Ok; } extern "C" FT_Error FT_New_Memory_Face(FT_Library library, const FT_Byte* file_base, FT_Long file_size, FT_Long face_index, FT_Face* aface) { FT_Open_Args args; /* test for valid `library' and `face' delayed to FT_Open_Face() */ if ( !file_base ) return FT_THROW( Invalid_Argument ); 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 ); } static FT_Error find_unicode_charmap( FT_Face face ) { FT_CharMap* first; FT_CharMap* cur; /* caller should have already checked that `face' is valid */ FT_ASSERT( face ); first = face->charmaps; if ( !first ) return FT_THROW( Invalid_CharMap_Handle ); /* * The original TrueType specification(s) only specified charmap * formats that are capable of mapping 8 or 16 bit character codes to * glyph indices. * * However, recent updates to the Apple and OpenType specifications * introduced new formats that are capable of mapping 32-bit character * codes as well. And these are already used on some fonts, mainly to * map non-BMP Asian ideographs as defined in Unicode. * * For compatibility purposes, these fonts generally come with * *several* Unicode charmaps: * * - One of them in the "old" 16-bit format, that cannot access * all glyphs in the font. * * - Another one in the "new" 32-bit format, that can access all * the glyphs. * * This function has been written to always favor a 32-bit charmap * when found. Otherwise, a 16-bit one is returned when found. */ /* Since the `interesting' table, with IDs (3,10), is normally the */ /* last one, we loop backwards. This loses with type1 fonts with */ /* non-BMP characters (<.0001%), this wins with .ttf with non-BMP */ /* chars (.01% ?), and this is the same about 99.99% of the time! */ cur = first + face->num_charmaps; /* points after the last one */ for ( ; --cur >= first; ) { if ( cur[0]->encoding == FT_ENCODING_UNICODE ) { /* 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]->platform_id == TT_PLATFORM_APPLE_UNICODE && 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 FT_Err_Ok; } } } /* 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; ) { 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; } } return FT_THROW( Invalid_CharMap_Handle ); } 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_THROW( 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_THROW( Table_Missing ); } static void ft_recompute_scaled_metrics( FT_Face face, FT_Size_Metrics* metrics ) { /* Compute root ascender, descender, test height, and max_advance */ #ifdef GRID_FIT_METRICS metrics->ascender = FT_PIX_CEIL( FT_MulFix( face->ascender, metrics->y_scale ) ); metrics->descender = FT_PIX_FLOOR( FT_MulFix( face->descender, metrics->y_scale ) ); metrics->height = FT_PIX_ROUND( FT_MulFix( face->height, metrics->y_scale ) ); metrics->max_advance = FT_PIX_ROUND( FT_MulFix( face->max_advance_width, metrics->x_scale ) ); #else /* !GRID_FIT_METRICS */ metrics->ascender = FT_MulFix( face->ascender, metrics->y_scale ); metrics->descender = FT_MulFix( face->descender, metrics->y_scale ); metrics->height = FT_MulFix( face->height, metrics->y_scale ); metrics->max_advance = FT_MulFix( face->max_advance_width, metrics->x_scale ); #endif /* !GRID_FIT_METRICS */ } FT_BASE_DEF( void ) FT_Select_Metrics( FT_Face face, FT_ULong strike_index ) { FT_Size_Metrics* metrics; FT_Bitmap_Size* bsize; metrics = &face->size->metrics; bsize = face->available_sizes + strike_index; metrics->x_ppem = (FT_UShort)( ( bsize->x_ppem + 32 ) >> 6 ); metrics->y_ppem = (FT_UShort)( ( bsize->y_ppem + 32 ) >> 6 ); if ( FT_IS_SCALABLE( face ) ) { metrics->x_scale = FT_DivFix( bsize->x_ppem, face->units_per_EM ); metrics->y_scale = FT_DivFix( bsize->y_ppem, face->units_per_EM ); ft_recompute_scaled_metrics( face, metrics ); } else { metrics->x_scale = 1L << 16; metrics->y_scale = 1L << 16; metrics->ascender = bsize->y_ppem; metrics->descender = 0; metrics->height = bsize->height << 6; metrics->max_advance = bsize->x_ppem; } FT_TRACE5(( "FT_Select_Metrics:\n" )); FT_TRACE5(( " x scale: %d (%f)\n", metrics->x_scale, metrics->x_scale / 65536.0 )); FT_TRACE5(( " y scale: %d (%f)\n", metrics->y_scale, metrics->y_scale / 65536.0 )); FT_TRACE5(( " ascender: %f\n", metrics->ascender / 64.0 )); FT_TRACE5(( " descender: %f\n", metrics->descender / 64.0 )); FT_TRACE5(( " height: %f\n", metrics->height / 64.0 )); FT_TRACE5(( " max advance: %f\n", metrics->max_advance / 64.0 )); FT_TRACE5(( " x ppem: %d\n", metrics->x_ppem )); FT_TRACE5(( " y ppem: %d\n", metrics->y_ppem )); } typedef struct TT_SBit_MetricsRec_ { FT_UShort height; FT_UShort width; FT_Short horiBearingX; FT_Short horiBearingY; FT_UShort horiAdvance; FT_Short vertBearingX; FT_Short vertBearingY; FT_UShort vertAdvance; } TT_SBit_MetricsRec, *TT_SBit_Metrics; typedef struct TT_SBit_RangeRec_ { FT_UShort first_glyph; FT_UShort last_glyph; FT_UShort index_format; FT_UShort image_format; FT_ULong image_offset; FT_ULong image_size; TT_SBit_MetricsRec metrics; FT_ULong num_glyphs; FT_ULong* glyph_offsets; FT_UShort* glyph_codes; FT_ULong table_offset; } TT_SBit_RangeRec, *TT_SBit_Range; typedef struct TT_SBit_StrikeRec_ { FT_Int num_ranges; TT_SBit_Range sbit_ranges; FT_ULong ranges_offset; FT_ULong color_ref; TT_SBit_LineMetricsRec hori; TT_SBit_LineMetricsRec vert; FT_UShort start_glyph; FT_UShort end_glyph; FT_Byte x_ppem; FT_Byte y_ppem; FT_Byte bit_depth; FT_Char flags; } TT_SBit_StrikeRec, *TT_SBit_Strike; typedef FT_Error (*TT_Init_Face_Func)( FT_Stream stream, TT_Face face, FT_Int face_index, FT_Int num_params, FT_Parameter* params ); typedef FT_Error (*TT_Load_Face_Func)( FT_Stream stream, TT_Face face, FT_Int face_index, FT_Int num_params, FT_Parameter* params ); typedef void (*TT_Done_Face_Func)( TT_Face face ); typedef FT_Error (*TT_Load_Any_Func)( TT_Face face, FT_ULong tag, FT_Long offset, FT_Byte *buffer, FT_ULong* length ); typedef FT_Error (*TT_Find_SBit_Image_Func)( TT_Face face, FT_UInt glyph_index, FT_ULong strike_index, TT_SBit_Range *arange, TT_SBit_Strike *astrike, FT_ULong *aglyph_offset ); typedef FT_Error (*TT_Load_SBit_Metrics_Func)( FT_Stream stream, TT_SBit_Range range, TT_SBit_Metrics metrics ); typedef FT_Error (*TT_Load_SBit_Image_Func)( TT_Face face, FT_ULong strike_index, FT_UInt glyph_index, FT_UInt load_flags, FT_Stream stream, FT_Bitmap *amap, TT_SBit_MetricsRec *ametrics ); typedef FT_Error (*TT_Set_SBit_Strike_Func)( TT_Face face, FT_Size_Request req, FT_ULong* astrike_index ); typedef FT_Error (*TT_Load_Strike_Metrics_Func)( TT_Face face, FT_ULong strike_index, FT_Size_Metrics* metrics ); typedef FT_Error (*TT_Get_PS_Name_Func)( TT_Face face, FT_UInt idx, FT_String** PSname ); typedef FT_Error (*TT_Load_Metrics_Func)( TT_Face face, FT_Stream stream, FT_Bool vertical ); typedef FT_Error (*TT_Get_Metrics_Func)( TT_Face face, FT_Bool vertical, FT_UInt gindex, FT_Short* abearing, FT_UShort* aadvance ); typedef FT_Error (*TT_Load_Table_Func)( TT_Face face, FT_Stream stream ); typedef void (*TT_Free_Table_Func)( TT_Face face ); typedef FT_Int (*TT_Face_GetKerningFunc)( TT_Face face, FT_UInt left_glyph, FT_UInt right_glyph ); typedef struct SFNT_Interface_ { TT_Loader_GotoTableFunc goto_table; TT_Init_Face_Func init_face; TT_Load_Face_Func load_face; TT_Done_Face_Func done_face; FT_Module_Requester get_interface; TT_Load_Any_Func load_any; /* these functions are called by `load_face' but they can also */ /* be called from external modules, if there is a need to do so */ TT_Load_Table_Func load_head; TT_Load_Metrics_Func load_hhea; TT_Load_Table_Func load_cmap; TT_Load_Table_Func load_maxp; TT_Load_Table_Func load_os2; TT_Load_Table_Func load_post; TT_Load_Table_Func load_name; TT_Free_Table_Func free_name; /* this field was called `load_kerning' up to version 2.1.10 */ TT_Load_Table_Func load_kern; TT_Load_Table_Func load_gasp; TT_Load_Table_Func load_pclt; /* see `ttload.h'; this field was called `load_bitmap_header' up to */ /* version 2.1.10 */ TT_Load_Table_Func load_bhed; TT_Load_SBit_Image_Func load_sbit_image; /* see `ttpost.h' */ TT_Get_PS_Name_Func get_psname; TT_Free_Table_Func free_psnames; /* starting here, the structure differs from version 2.1.7 */ /* this field was introduced in version 2.1.8, named `get_psname' */ TT_Face_GetKerningFunc get_kerning; /* new elements introduced after version 2.1.10 */ /* load the font directory, i.e., the offset table and */ /* the table directory */ TT_Load_Table_Func load_font_dir; TT_Load_Metrics_Func load_hmtx; TT_Load_Table_Func load_eblc; TT_Free_Table_Func free_eblc; TT_Set_SBit_Strike_Func set_sbit_strike; TT_Load_Strike_Metrics_Func load_strike_metrics; TT_Get_Metrics_Func get_metrics; } SFNT_Interface; FT_LOCAL_DEF( FT_Error ) tt_size_reset( TT_Size size ); #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS static FT_Error tt_size_select( FT_Size size, FT_ULong strike_index ) { TT_Face ttface = (TT_Face)size->face; TT_Size ttsize = (TT_Size)size; FT_Error error = FT_Err_Ok; ttsize->strike_index = strike_index; if ( FT_IS_SCALABLE( size->face ) ) { /* use the scaled metrics, even when tt_size_reset fails */ FT_Select_Metrics( size->face, strike_index ); tt_size_reset( ttsize ); } else { SFNT_Service sfnt = (SFNT_Service) ttface->sfnt; FT_Size_Metrics* metrics = &size->metrics; error = sfnt->load_strike_metrics( ttface, strike_index, metrics ); if ( error ) ttsize->strike_index = 0xFFFFFFFFUL; } return error; } #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ #ifdef FT_CONFIG_OPTION_INCREMENTAL static void tt_get_metrics_incr_overrides( TT_Loader loader, FT_UInt glyph_index ) { TT_Face face = (TT_Face)loader->face; FT_Short left_bearing = 0, top_bearing = 0; FT_UShort advance_width = 0, advance_height = 0; /* If this is an incrementally loaded font check whether there are */ /* overriding metrics for this glyph. */ if ( face->root.internal->incremental_interface && face->root.internal->incremental_interface->funcs->get_glyph_metrics ) { FT_Incremental_MetricsRec metrics; FT_Error error; metrics.bearing_x = loader->left_bearing; metrics.bearing_y = 0; metrics.advance = loader->advance; metrics.advance_v = 0; error = face->root.internal->incremental_interface->funcs->get_glyph_metrics( face->root.internal->incremental_interface->object, glyph_index, FALSE, &metrics ); if ( error ) goto Exit; left_bearing = (FT_Short)metrics.bearing_x; advance_width = (FT_UShort)metrics.advance; #if 0 /* GWW: Do I do the same for vertical metrics? */ metrics.bearing_x = 0; metrics.bearing_y = loader->top_bearing; metrics.advance = loader->vadvance; error = face->root.internal->incremental_interface->funcs->get_glyph_metrics( face->root.internal->incremental_interface->object, glyph_index, TRUE, &metrics ); if ( error ) goto Exit; top_bearing = (FT_Short)metrics.bearing_y; advance_height = (FT_UShort)metrics.advance; #endif /* 0 */ loader->left_bearing = left_bearing; loader->advance = advance_width; loader->top_bearing = top_bearing; loader->vadvance = advance_height; if ( !loader->linear_def ) { loader->linear_def = 1; loader->linear = advance_width; } } Exit: return; } #endif /* FT_CONFIG_OPTION_INCREMENTAL */ FT_LOCAL( FT_Error ) tt_get_cmap_info( FT_CharMap charmap, TT_CMapInfo *cmap_info ) { FT_CMap cmap = (FT_CMap)charmap; TT_CMap_Class clazz = (TT_CMap_Class)cmap->clazz; return clazz->get_cmap_info( charmap, cmap_info ); } static FT_String* tt_name_entry_ascii_from_utf16( TT_NameEntry entry, FT_Memory memory ) { FT_String* string = NULL; FT_UInt len, code, n; FT_Byte* read = (FT_Byte*)entry->string; FT_Error error; len = (FT_UInt)entry->stringLength / 2; if ( FT_NEW_ARRAY( string, len + 1 ) ) return NULL; for ( n = 0; n < len; n++ ) { code = FT_NEXT_USHORT( read ); if ( code == 0 ) break; if ( code < 32 || code > 127 ) code = '?'; string[n] = (char)code; } string[n] = 0; return string; } static FT_String* tt_name_entry_ascii_from_other( TT_NameEntry entry, FT_Memory memory ) { FT_String* string = NULL; FT_UInt len, code, n; FT_Byte* read = (FT_Byte*)entry->string; FT_Error error; len = (FT_UInt)entry->stringLength; if ( FT_NEW_ARRAY( string, len + 1 ) ) return NULL; for ( n = 0; n < len; n++ ) { code = *read++; if ( code == 0 ) break; if ( code < 32 || code > 127 ) code = '?'; string[n] = (char)code; } string[n] = 0; return string; } #ifndef FT_CONFIG_OPTION_PIC #define FT_DEFINE_SERVICE_TTCMAPSREC( class_, get_cmap_info_ ) \ static const FT_Service_TTCMapsRec class_ = \ { \ get_cmap_info_ \ }; #else /* FT_CONFIG_OPTION_PIC */ #define FT_DEFINE_SERVICE_TTCMAPSREC( class_, get_cmap_info_ ) \ void \ FT_Init_Class_ ## class_( FT_Library library, \ FT_Service_TTCMapsRec* clazz ) \ { \ FT_UNUSED( library ); \ \ clazz->get_cmap_info = get_cmap_info_; \ } #endif /* FT_CONFIG_OPTION_PIC */ #define FT_SERVICE_ID_TT_CMAP "tt-cmaps" #define FT_SERVICE_ID_GLYPH_DICT "glyph-dict" #define FT_SERVICE_ID_POSTSCRIPT_FONT_NAME "postscript-font-name" #define FT_SERVICE_ID_SFNT_TABLE "sfnt-table" FT_DEFINE_SERVICE( TTCMaps ) { TT_CMap_Info_GetFunc get_cmap_info; }; FT_DEFINE_SERVICE_TTCMAPSREC( tt_service_get_cmap_info, (TT_CMap_Info_GetFunc)tt_get_cmap_info ) static FT_Error tt_face_load_generic_header( TT_Face face, FT_Stream stream, FT_ULong tag ); #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS FT_LOCAL_DEF( FT_Error ) tt_face_load_bhed( TT_Face face, FT_Stream stream ) { return tt_face_load_generic_header( face, stream, TTAG_bhed ); } #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ FT_LOCAL_DEF( FT_Error ) tt_face_load_sbit( TT_Face face, FT_Stream stream ) { FT_Error error; FT_ULong table_size; face->sbit_table = NULL; face->sbit_table_size = 0; face->sbit_table_type = TT_SBIT_TABLE_TYPE_NONE; face->sbit_num_strikes = 0; error = face->goto_table( face, TTAG_CBLC, stream, &table_size ); if ( !error ) face->sbit_table_type = TT_SBIT_TABLE_TYPE_CBLC; else { error = face->goto_table( face, TTAG_EBLC, stream, &table_size ); if ( error ) error = face->goto_table( face, TTAG_bloc, stream, &table_size ); if ( !error ) face->sbit_table_type = TT_SBIT_TABLE_TYPE_EBLC; } if ( error ) { error = face->goto_table( face, TTAG_sbix, stream, &table_size ); if ( !error ) face->sbit_table_type = TT_SBIT_TABLE_TYPE_SBIX; } if ( error ) goto Exit; if ( table_size < 8 ) { FT_ERROR(( "tt_face_load_sbit_strikes: table too short\n" )); error = FT_THROW( Invalid_File_Format ); goto Exit; } switch ( (FT_UInt)face->sbit_table_type ) { case TT_SBIT_TABLE_TYPE_EBLC: case TT_SBIT_TABLE_TYPE_CBLC: { FT_Byte* p; FT_Fixed version; FT_ULong num_strikes; FT_UInt count; if ( FT_FRAME_EXTRACT( table_size, face->sbit_table ) ) goto Exit; face->sbit_table_size = table_size; p = face->sbit_table; version = FT_NEXT_ULONG( p ); num_strikes = FT_NEXT_ULONG( p ); if ( ( version & 0xFFFF0000UL ) != 0x00020000UL ) { error = FT_THROW( Unknown_File_Format ); goto Exit; } if ( num_strikes >= 0x10000UL ) { error = FT_THROW( Invalid_File_Format ); goto Exit; } /* * Count the number of strikes available in the table. We are a bit * paranoid there and don't trust the data. */ count = (FT_UInt)num_strikes; if ( 8 + 48UL * count > table_size ) count = (FT_UInt)( ( table_size - 8 ) / 48 ); face->sbit_num_strikes = count; } break; case TT_SBIT_TABLE_TYPE_SBIX: { FT_UShort version; FT_UShort flags; FT_ULong num_strikes; FT_UInt count; if ( FT_FRAME_ENTER( 8 ) ) goto Exit; version = FT_GET_USHORT(); flags = FT_GET_USHORT(); num_strikes = FT_GET_ULONG(); FT_FRAME_EXIT(); if ( version < 1 ) { error = FT_THROW( Unknown_File_Format ); goto Exit; } if ( flags != 0x0001 || num_strikes >= 0x10000UL ) { error = FT_THROW( Invalid_File_Format ); goto Exit; } /* * Count the number of strikes available in the table. We are a bit * paranoid there and don't trust the data. */ count = (FT_UInt)num_strikes; if ( 8 + 4UL * count > table_size ) count = (FT_UInt)( ( table_size - 8 ) / 4 ); if ( FT_STREAM_SEEK( FT_STREAM_POS() - 8 ) ) goto Exit; face->sbit_table_size = 8 + count * 4; if ( FT_FRAME_EXTRACT( face->sbit_table_size, face->sbit_table ) ) goto Exit; face->sbit_num_strikes = count; } break; default: error = FT_THROW( Unknown_File_Format ); break; } if ( !error ) FT_TRACE3(( "sbit_num_strikes: %u\n", face->sbit_num_strikes )); return FT_Err_Ok; Exit: if ( error ) { if ( face->sbit_table ) FT_FRAME_RELEASE( face->sbit_table ); face->sbit_table_size = 0; face->sbit_table_type = TT_SBIT_TABLE_TYPE_NONE; } return error; } FT_LOCAL_DEF( void ) tt_face_free_sbit( TT_Face face ) { FT_Stream stream = face->root.stream; FT_FRAME_RELEASE( face->sbit_table ); face->sbit_table_size = 0; face->sbit_table_type = TT_SBIT_TABLE_TYPE_NONE; face->sbit_num_strikes = 0; } typedef struct TT_SBitDecoderRec_ { TT_Face face; FT_Stream stream; FT_Bitmap* bitmap; TT_SBit_Metrics metrics; FT_Bool metrics_loaded; FT_Bool bitmap_allocated; FT_Byte bit_depth; FT_ULong ebdt_start; FT_ULong ebdt_size; FT_ULong strike_index_array; FT_ULong strike_index_count; FT_Byte* eblc_base; FT_Byte* eblc_limit; } TT_SBitDecoderRec, *TT_SBitDecoder; typedef enum FT_Pixel_Mode_ { FT_PIXEL_MODE_NONE = 0, FT_PIXEL_MODE_MONO, FT_PIXEL_MODE_GRAY, FT_PIXEL_MODE_GRAY2, FT_PIXEL_MODE_GRAY4, FT_PIXEL_MODE_LCD, FT_PIXEL_MODE_LCD_V, FT_PIXEL_MODE_BGRA, FT_PIXEL_MODE_MAX /* do not remove */ } FT_Pixel_Mode; static const FT_Bitmap null_bitmap = { 0, 0, 0, 0, 0, 0, 0, 0 }; FT_EXPORT_DEF( void ) FT_Bitmap_New( FT_Bitmap *abitmap ) { *abitmap = null_bitmap; } FT_EXPORT_DEF( FT_Error ) FT_Bitmap_Done( FT_Library library, FT_Bitmap *bitmap ) { FT_Memory memory; if ( !library ) return FT_THROW( Invalid_Library_Handle ); if ( !bitmap ) return FT_THROW( Invalid_Argument ); memory = library->memory; FT_FREE( bitmap->buffer ); *bitmap = null_bitmap; return FT_Err_Ok; } static FT_Byte ft_gray_for_premultiplied_srgb_bgra( const FT_Byte* bgra ) { FT_Long a = bgra[3]; FT_Long b = bgra[0]; FT_Long g = bgra[1]; FT_Long r = bgra[2]; FT_Long l; /* Short-circuit transparent color to avoid div-by-zero. */ if ( !a ) return 0; /* * Luminosity for sRGB is defined using ~0.2126,0.7152,0.0722 * coefficients for RGB channels *on the linear colors*. * A gamma of 2.2 is fair to assume. And then, we need to * undo the premultiplication too. * * http://accessibility.kde.org/hsl-adjusted.php * * We do the computation with integers only. */ /* Undo premultification, get the number in a 16.16 form. */ b = FT_MulDiv( b, 65536, a ); g = FT_MulDiv( g, 65536, a ); r = FT_MulDiv( r, 65536, a ); a = a * 256; /* Apply gamma of 2.0 instead of 2.2. */ b = FT_MulFix( b, b ); g = FT_MulFix( g, g ); r = FT_MulFix( r, r ); /* Apply coefficients. */ b = FT_MulFix( b, 4731 /* 0.0722 * 65536 */ ); g = FT_MulFix( g, 46871 /* 0.7152 * 65536 */ ); r = FT_MulFix( r, 13933 /* 0.2126 * 65536 */ ); l = r + g + b; /* * Final transparency can be determined this way: * * - If alpha is zero, we want 0. * - If alpha is zero and luminosity is zero, we want 255. * - If alpha is zero and luminosity is one, we want 0. * * So the formula is a * (1 - l). */ return (FT_Byte)( FT_MulFix( 65535 - l, a ) >> 8 ); } FT_EXPORT_DEF( FT_Error ) FT_Bitmap_Convert( FT_Library library, const FT_Bitmap *source, FT_Bitmap *target, FT_Int alignment ) { FT_Error error = FT_Err_Ok; FT_Memory memory; if ( !library ) return FT_THROW( Invalid_Library_Handle ); memory = library->memory; switch ( source->pixel_mode ) { case FT_PIXEL_MODE_MONO: case FT_PIXEL_MODE_GRAY: case FT_PIXEL_MODE_GRAY2: case FT_PIXEL_MODE_GRAY4: case FT_PIXEL_MODE_LCD: case FT_PIXEL_MODE_LCD_V: case FT_PIXEL_MODE_BGRA: { FT_Int pad; FT_Long old_size; old_size = target->rows * target->pitch; if ( old_size < 0 ) old_size = -old_size; target->pixel_mode = FT_PIXEL_MODE_GRAY; target->rows = source->rows; target->width = source->width; pad = 0; if ( alignment > 0 ) { pad = source->width % alignment; if ( pad != 0 ) pad = alignment - pad; } target->pitch = source->width + pad; if ( target->pitch > 0 && (FT_ULong)target->rows > FT_ULONG_MAX / target->pitch ) return FT_THROW( Invalid_Argument ); if ( target->rows * target->pitch > old_size && FT_QREALLOC( target->buffer, old_size, target->rows * target->pitch ) ) return error; } break; default: error = FT_THROW( Invalid_Argument ); } switch ( source->pixel_mode ) { case FT_PIXEL_MODE_MONO: { FT_Byte* s = source->buffer; FT_Byte* t = target->buffer; FT_Int i; target->num_grays = 2; for ( i = source->rows; i > 0; i-- ) { FT_Byte* ss = s; FT_Byte* tt = t; FT_Int j; /* get the full bytes */ for ( j = source->width >> 3; j > 0; j-- ) { FT_Int val = ss[0]; /* avoid a byte->int cast on each line */ tt[0] = (FT_Byte)( ( val & 0x80 ) >> 7 ); tt[1] = (FT_Byte)( ( val & 0x40 ) >> 6 ); tt[2] = (FT_Byte)( ( val & 0x20 ) >> 5 ); tt[3] = (FT_Byte)( ( val & 0x10 ) >> 4 ); tt[4] = (FT_Byte)( ( val & 0x08 ) >> 3 ); tt[5] = (FT_Byte)( ( val & 0x04 ) >> 2 ); tt[6] = (FT_Byte)( ( val & 0x02 ) >> 1 ); tt[7] = (FT_Byte)( val & 0x01 ); tt += 8; ss += 1; } /* get remaining pixels (if any) */ j = source->width & 7; if ( j > 0 ) { FT_Int val = *ss; for ( ; j > 0; j-- ) { tt[0] = (FT_Byte)( ( val & 0x80 ) >> 7); val <<= 1; tt += 1; } } s += source->pitch; t += target->pitch; } } break; case FT_PIXEL_MODE_GRAY: case FT_PIXEL_MODE_LCD: case FT_PIXEL_MODE_LCD_V: { FT_Int width = source->width; FT_Byte* s = source->buffer; FT_Byte* t = target->buffer; FT_Int s_pitch = source->pitch; FT_Int t_pitch = target->pitch; FT_Int i; target->num_grays = 256; for ( i = source->rows; i > 0; i-- ) { FT_ARRAY_COPY( t, s, width ); s += s_pitch; t += t_pitch; } } break; case FT_PIXEL_MODE_GRAY2: { FT_Byte* s = source->buffer; FT_Byte* t = target->buffer; FT_Int i; target->num_grays = 4; for ( i = source->rows; i > 0; i-- ) { FT_Byte* ss = s; FT_Byte* tt = t; FT_Int j; /* get the full bytes */ for ( j = source->width >> 2; j > 0; j-- ) { FT_Int val = ss[0]; tt[0] = (FT_Byte)( ( val & 0xC0 ) >> 6 ); tt[1] = (FT_Byte)( ( val & 0x30 ) >> 4 ); tt[2] = (FT_Byte)( ( val & 0x0C ) >> 2 ); tt[3] = (FT_Byte)( ( val & 0x03 ) ); ss += 1; tt += 4; } j = source->width & 3; if ( j > 0 ) { FT_Int val = ss[0]; for ( ; j > 0; j-- ) { tt[0] = (FT_Byte)( ( val & 0xC0 ) >> 6 ); val <<= 2; tt += 1; } } s += source->pitch; t += target->pitch; } } break; case FT_PIXEL_MODE_GRAY4: { FT_Byte* s = source->buffer; FT_Byte* t = target->buffer; FT_Int i; target->num_grays = 16; for ( i = source->rows; i > 0; i-- ) { FT_Byte* ss = s; FT_Byte* tt = t; FT_Int j; /* get the full bytes */ for ( j = source->width >> 1; j > 0; j-- ) { FT_Int val = ss[0]; tt[0] = (FT_Byte)( ( val & 0xF0 ) >> 4 ); tt[1] = (FT_Byte)( ( val & 0x0F ) ); ss += 1; tt += 2; } if ( source->width & 1 ) tt[0] = (FT_Byte)( ( ss[0] & 0xF0 ) >> 4 ); s += source->pitch; t += target->pitch; } } break; case FT_PIXEL_MODE_BGRA: { FT_Byte* s = source->buffer; FT_Byte* t = target->buffer; FT_Int s_pitch = source->pitch; FT_Int t_pitch = target->pitch; FT_Int i; target->num_grays = 256; for ( i = source->rows; i > 0; i-- ) { FT_Byte* ss = s; FT_Byte* tt = t; FT_Int j; for ( j = source->width; j > 0; j-- ) { tt[0] = ft_gray_for_premultiplied_srgb_bgra( ss ); ss += 4; tt += 1; } s += s_pitch; t += t_pitch; } } break; default: ; } return error; } static FT_Error tt_sbit_decoder_init( TT_SBitDecoder decoder, TT_Face face, FT_ULong strike_index, TT_SBit_MetricsRec* metrics ) { FT_Error error; FT_Stream stream = face->root.stream; FT_ULong ebdt_size; error = face->goto_table( face, TTAG_CBDT, stream, &ebdt_size ); if ( error ) error = face->goto_table( face, TTAG_EBDT, stream, &ebdt_size ); if ( error ) error = face->goto_table( face, TTAG_bdat, stream, &ebdt_size ); if ( error ) goto Exit; decoder->face = face; decoder->stream = stream; decoder->bitmap = &face->root.glyph->bitmap; decoder->metrics = metrics; decoder->metrics_loaded = 0; decoder->bitmap_allocated = 0; decoder->ebdt_start = FT_STREAM_POS(); decoder->ebdt_size = ebdt_size; decoder->eblc_base = face->sbit_table; decoder->eblc_limit = face->sbit_table + face->sbit_table_size; /* now find the strike corresponding to the index */ { FT_Byte* p; if ( 8 + 48 * strike_index + 3 * 4 + 34 + 1 > face->sbit_table_size ) { error = FT_THROW( Invalid_File_Format ); goto Exit; } p = decoder->eblc_base + 8 + 48 * strike_index; decoder->strike_index_array = FT_NEXT_ULONG( p ); p += 4; decoder->strike_index_count = FT_NEXT_ULONG( p ); p += 34; decoder->bit_depth = *p; if ( decoder->strike_index_array > face->sbit_table_size || decoder->strike_index_array + 8 * decoder->strike_index_count > face->sbit_table_size ) error = FT_THROW( Invalid_File_Format ); } Exit: return error; } static void tt_sbit_decoder_done( TT_SBitDecoder decoder ) { FT_UNUSED( decoder ); } static FT_Error tt_sbit_decoder_load_metrics( TT_SBitDecoder decoder, FT_Byte* *pp, FT_Byte* limit, FT_Bool big ) { FT_Byte* p = *pp; TT_SBit_Metrics metrics = decoder->metrics; if ( p + 5 > limit ) goto Fail; metrics->height = p[0]; metrics->width = p[1]; metrics->horiBearingX = (FT_Char)p[2]; metrics->horiBearingY = (FT_Char)p[3]; metrics->horiAdvance = p[4]; p += 5; if ( big ) { if ( p + 3 > limit ) goto Fail; metrics->vertBearingX = (FT_Char)p[0]; metrics->vertBearingY = (FT_Char)p[1]; metrics->vertAdvance = p[2]; p += 3; } decoder->metrics_loaded = 1; *pp = p; return FT_Err_Ok; Fail: FT_TRACE1(( "tt_sbit_decoder_load_metrics: broken table" )); return FT_THROW( Invalid_Argument ); } static FT_Error tt_sbit_decoder_load_byte_aligned( TT_SBitDecoder decoder, FT_Byte* p, FT_Byte* limit, FT_Int x_pos, FT_Int y_pos ) { FT_Error error = FT_Err_Ok; FT_Byte* line; FT_Int bit_height, bit_width, pitch, width, height, line_bits, h; FT_Bitmap* bitmap; /* check that we can write the glyph into the bitmap */ bitmap = decoder->bitmap; bit_width = bitmap->width; bit_height = bitmap->rows; pitch = bitmap->pitch; line = bitmap->buffer; width = decoder->metrics->width; height = decoder->metrics->height; line_bits = width * decoder->bit_depth; if ( x_pos < 0 || x_pos + width > bit_width || y_pos < 0 || y_pos + height > bit_height ) { FT_TRACE1(( "tt_sbit_decoder_load_byte_aligned:" " invalid bitmap dimensions\n" )); error = FT_THROW( Invalid_File_Format ); goto Exit; } if ( p + ( ( line_bits + 7 ) >> 3 ) * height > limit ) { FT_TRACE1(( "tt_sbit_decoder_load_byte_aligned: broken bitmap\n" )); error = FT_THROW( Invalid_File_Format ); goto Exit; } /* now do the blit */ line += y_pos * pitch + ( x_pos >> 3 ); x_pos &= 7; if ( x_pos == 0 ) /* the easy one */ { for ( h = height; h > 0; h--, line += pitch ) { FT_Byte* pwrite = line; FT_Int w; for ( w = line_bits; w >= 8; w -= 8 ) { pwrite[0] = (FT_Byte)( pwrite[0] | *p++ ); pwrite += 1; } if ( w > 0 ) pwrite[0] = (FT_Byte)( pwrite[0] | ( *p++ & ( 0xFF00U >> w ) ) ); } } else /* x_pos > 0 */ { for ( h = height; h > 0; h--, line += pitch ) { FT_Byte* pwrite = line; FT_Int w; FT_UInt wval = 0; for ( w = line_bits; w >= 8; w -= 8 ) { wval = (FT_UInt)( wval | *p++ ); pwrite[0] = (FT_Byte)( pwrite[0] | ( wval >> x_pos ) ); pwrite += 1; wval <<= 8; } if ( w > 0 ) wval = (FT_UInt)( wval | ( *p++ & ( 0xFF00U >> w ) ) ); /* all bits read and there are `x_pos + w' bits to be written */ pwrite[0] = (FT_Byte)( pwrite[0] | ( wval >> x_pos ) ); if ( x_pos + w > 8 ) { pwrite++; wval <<= 8; pwrite[0] = (FT_Byte)( pwrite[0] | ( wval >> x_pos ) ); } } } Exit: if ( !error ) FT_TRACE3(( "tt_sbit_decoder_load_byte_aligned: loaded\n" )); return error; } static FT_Error tt_sbit_decoder_load_bit_aligned( TT_SBitDecoder decoder, FT_Byte* p, FT_Byte* limit, FT_Int x_pos, FT_Int y_pos ) { FT_Error error = FT_Err_Ok; FT_Byte* line; FT_Int bit_height, bit_width, pitch, width, height, line_bits, h, nbits; FT_Bitmap* bitmap; FT_UShort rval; /* check that we can write the glyph into the bitmap */ bitmap = decoder->bitmap; bit_width = bitmap->width; bit_height = bitmap->rows; pitch = bitmap->pitch; line = bitmap->buffer; width = decoder->metrics->width; height = decoder->metrics->height; line_bits = width * decoder->bit_depth; if ( x_pos < 0 || x_pos + width > bit_width || y_pos < 0 || y_pos + height > bit_height ) { FT_TRACE1(( "tt_sbit_decoder_load_bit_aligned:" " invalid bitmap dimensions\n" )); error = FT_THROW( Invalid_File_Format ); goto Exit; } if ( p + ( ( line_bits * height + 7 ) >> 3 ) > limit ) { FT_TRACE1(( "tt_sbit_decoder_load_bit_aligned: broken bitmap\n" )); error = FT_THROW( Invalid_File_Format ); goto Exit; } /* now do the blit */ /* adjust `line' to point to the first byte of the bitmap */ line += y_pos * pitch + ( x_pos >> 3 ); x_pos &= 7; /* the higher byte of `rval' is used as a buffer */ rval = 0; nbits = 0; for ( h = height; h > 0; h--, line += pitch ) { FT_Byte* pwrite = line; FT_Int w = line_bits; /* handle initial byte (in target bitmap) specially if necessary */ if ( x_pos ) { w = ( line_bits < 8 - x_pos ) ? line_bits : 8 - x_pos; if ( h == height ) { rval = *p++; nbits = x_pos; } else if ( nbits < w ) { if ( p < limit ) rval |= *p++; nbits += 8 - w; } else { rval >>= 8; nbits -= w; } *pwrite++ |= ( ( rval >> nbits ) & 0xFF ) & ( ~( 0xFF << w ) << ( 8 - w - x_pos ) ); rval <<= 8; w = line_bits - w; } /* handle medial bytes */ for ( ; w >= 8; w -= 8 ) { rval |= *p++; *pwrite++ |= ( rval >> nbits ) & 0xFF; rval <<= 8; } /* handle final byte if necessary */ if ( w > 0 ) { if ( nbits < w ) { if ( p < limit ) rval |= *p++; *pwrite |= ( ( rval >> nbits ) & 0xFF ) & ( 0xFF00U >> w ); nbits += 8 - w; rval <<= 8; } else { *pwrite |= ( ( rval >> nbits ) & 0xFF ) & ( 0xFF00U >> w ); nbits -= w; } } } Exit: if ( !error ) FT_TRACE3(( "tt_sbit_decoder_load_bit_aligned: loaded\n" )); return error; } static FT_Error tt_sbit_decoder_load_image( TT_SBitDecoder decoder, FT_UInt glyph_index, FT_Int x_pos, FT_Int y_pos ); static FT_Error tt_sbit_decoder_load_compound( TT_SBitDecoder decoder, FT_Byte* p, FT_Byte* limit, FT_Int x_pos, FT_Int y_pos ) { FT_Error error = FT_Err_Ok; FT_UInt num_components, nn; FT_Char horiBearingX = decoder->metrics->horiBearingX; FT_Char horiBearingY = decoder->metrics->horiBearingY; FT_Byte horiAdvance = decoder->metrics->horiAdvance; FT_Char vertBearingX = decoder->metrics->vertBearingX; FT_Char vertBearingY = decoder->metrics->vertBearingY; FT_Byte vertAdvance = decoder->metrics->vertAdvance; if ( p + 2 > limit ) goto Fail; num_components = FT_NEXT_USHORT( p ); if ( p + 4 * num_components > limit ) { FT_TRACE1(( "tt_sbit_decoder_load_compound: broken table\n" )); goto Fail; } FT_TRACE3(( "tt_sbit_decoder_load_compound: loading %d components\n", num_components )); for ( nn = 0; nn < num_components; nn++ ) { FT_UInt gindex = FT_NEXT_USHORT( p ); FT_Byte dx = FT_NEXT_BYTE( p ); FT_Byte dy = FT_NEXT_BYTE( p ); /* NB: a recursive call */ error = tt_sbit_decoder_load_image( decoder, gindex, x_pos + dx, y_pos + dy ); if ( error ) break; } FT_TRACE3(( "tt_sbit_decoder_load_compound: done\n" )); decoder->metrics->horiBearingX = horiBearingX; decoder->metrics->horiBearingY = horiBearingY; decoder->metrics->horiAdvance = horiAdvance; decoder->metrics->vertBearingX = vertBearingX; decoder->metrics->vertBearingY = vertBearingY; decoder->metrics->vertAdvance = vertAdvance; decoder->metrics->width = (FT_Byte)decoder->bitmap->width; decoder->metrics->height = (FT_Byte)decoder->bitmap->rows; Exit: return error; Fail: error = FT_THROW( Invalid_File_Format ); goto Exit; } FT_BASE_DEF( FT_Error ) ft_glyphslot_alloc_bitmap( FT_GlyphSlot slot, FT_ULong size ) { FT_Memory memory = FT_FACE_MEMORY( slot->face ); FT_Error error; if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) FT_FREE( slot->bitmap.buffer ); else slot->internal->flags |= FT_GLYPH_OWN_BITMAP; (void)FT_ALLOC( slot->bitmap.buffer, size ); return error; } static FT_Error tt_sbit_decoder_alloc_bitmap( TT_SBitDecoder decoder ) { FT_Error error = FT_Err_Ok; FT_UInt width, height; FT_Bitmap* map = decoder->bitmap; FT_Long size; if ( !decoder->metrics_loaded ) { error = FT_THROW( Invalid_Argument ); goto Exit; } width = decoder->metrics->width; height = decoder->metrics->height; map->width = (int)width; map->rows = (int)height; switch ( decoder->bit_depth ) { case 1: map->pixel_mode = FT_PIXEL_MODE_MONO; map->pitch = ( map->width + 7 ) >> 3; map->num_grays = 2; break; case 2: map->pixel_mode = FT_PIXEL_MODE_GRAY2; map->pitch = ( map->width + 3 ) >> 2; map->num_grays = 4; break; case 4: map->pixel_mode = FT_PIXEL_MODE_GRAY4; map->pitch = ( map->width + 1 ) >> 1; map->num_grays = 16; break; case 8: map->pixel_mode = FT_PIXEL_MODE_GRAY; map->pitch = map->width; map->num_grays = 256; break; case 32: map->pixel_mode = FT_PIXEL_MODE_BGRA; map->pitch = map->width * 4; map->num_grays = 256; break; default: error = FT_THROW( Invalid_File_Format ); goto Exit; } size = map->rows * map->pitch; /* check that there is no empty image */ if ( size == 0 ) goto Exit; /* exit successfully! */ error = ft_glyphslot_alloc_bitmap( decoder->face->root.glyph, size ); if ( error ) goto Exit; decoder->bitmap_allocated = 1; Exit: return error; } typedef FT_Error (*TT_SBitDecoder_LoadFunc)( TT_SBitDecoder decoder, FT_Byte* p, FT_Byte* plimit, FT_Int x_pos, FT_Int y_pos ); static FT_Error tt_sbit_decoder_load_bitmap( TT_SBitDecoder decoder, FT_UInt glyph_format, FT_ULong glyph_start, FT_ULong glyph_size, FT_Int x_pos, FT_Int y_pos ) { FT_Error error; FT_Stream stream = decoder->stream; FT_Byte* p; FT_Byte* p_limit; FT_Byte* data; /* seek into the EBDT table now */ if ( glyph_start + glyph_size > decoder->ebdt_size ) { error = FT_THROW( Invalid_Argument ); goto Exit; } if ( FT_STREAM_SEEK( decoder->ebdt_start + glyph_start ) || FT_FRAME_EXTRACT( glyph_size, data ) ) goto Exit; p = data; p_limit = p + glyph_size; /* read the data, depending on the glyph format */ switch ( glyph_format ) { case 1: case 2: case 8: case 17: error = tt_sbit_decoder_load_metrics( decoder, &p, p_limit, 0 ); break; case 6: case 7: case 9: case 18: error = tt_sbit_decoder_load_metrics( decoder, &p, p_limit, 1 ); break; default: error = FT_Err_Ok; } if ( error ) goto Fail; { TT_SBitDecoder_LoadFunc loader; switch ( glyph_format ) { case 1: case 6: loader = tt_sbit_decoder_load_byte_aligned; break; case 2: case 7: { /* Don't trust `glyph_format'. For example, Apple's main Korean */ /* system font, `AppleMyungJo.ttf' (version 7.0d2e6), uses glyph */ /* format 7, but the data is format 6. We check whether we have */ /* an excessive number of bytes in the image: If it is equal to */ /* the value for a byte-aligned glyph, use the other loading */ /* routine. */ /* */ /* Note that for some (width,height) combinations, where the */ /* width is not a multiple of 8, the sizes for bit- and */ /* byte-aligned data are equal, for example (7,7) or (15,6). We */ /* then prefer what `glyph_format' specifies. */ FT_UInt width = decoder->metrics->width; FT_UInt height = decoder->metrics->height; FT_UInt bit_size = ( width * height + 7 ) >> 3; FT_UInt byte_size = height * ( ( width + 7 ) >> 3 ); if ( bit_size < byte_size && byte_size == (FT_UInt)( p_limit - p ) ) loader = tt_sbit_decoder_load_byte_aligned; else loader = tt_sbit_decoder_load_bit_aligned; } break; case 5: loader = tt_sbit_decoder_load_bit_aligned; break; case 8: if ( p + 1 > p_limit ) goto Fail; p += 1; /* skip padding */ /* fall-through */ case 9: loader = tt_sbit_decoder_load_compound; break; case 17: /* small metrics, PNG image data */ case 18: /* big metrics, PNG image data */ case 19: /* metrics in EBLC, PNG image data */ #ifdef FT_CONFIG_OPTION_USE_PNG loader = tt_sbit_decoder_load_png; break; #else error = FT_THROW( Unimplemented_Feature ); goto Fail; #endif /* FT_CONFIG_OPTION_USE_PNG */ default: error = FT_THROW( Invalid_Table ); goto Fail; } if ( !decoder->bitmap_allocated ) { error = tt_sbit_decoder_alloc_bitmap( decoder ); if ( error ) goto Fail; } error = loader( decoder, p, p_limit, x_pos, y_pos ); } Fail: FT_FRAME_RELEASE( data ); Exit: return error; } static FT_Error tt_sbit_decoder_load_image( TT_SBitDecoder decoder, FT_UInt glyph_index, FT_Int x_pos, FT_Int y_pos ) { /* * First, we find the correct strike range that applies to this * glyph index. */ FT_Byte* p = decoder->eblc_base + decoder->strike_index_array; FT_Byte* p_limit = decoder->eblc_limit; FT_ULong num_ranges = decoder->strike_index_count; FT_UInt start, end, index_format, image_format; FT_ULong image_start = 0, image_end = 0, image_offset; for ( ; num_ranges > 0; num_ranges-- ) { start = FT_NEXT_USHORT( p ); end = FT_NEXT_USHORT( p ); if ( glyph_index >= start && glyph_index <= end ) goto FoundRange; p += 4; /* ignore index offset */ } goto NoBitmap; FoundRange: image_offset = FT_NEXT_ULONG( p ); /* overflow check */ p = decoder->eblc_base + decoder->strike_index_array; if ( image_offset > (FT_ULong)( p_limit - p ) ) goto Failure; p += image_offset; if ( p + 8 > p_limit ) goto NoBitmap; /* now find the glyph's location and extend within the ebdt table */ index_format = FT_NEXT_USHORT( p ); image_format = FT_NEXT_USHORT( p ); image_offset = FT_NEXT_ULONG ( p ); switch ( index_format ) { case 1: /* 4-byte offsets relative to `image_offset' */ p += 4 * ( glyph_index - start ); if ( p + 8 > p_limit ) goto NoBitmap; image_start = FT_NEXT_ULONG( p ); image_end = FT_NEXT_ULONG( p ); if ( image_start == image_end ) /* missing glyph */ goto NoBitmap; break; case 2: /* big metrics, constant image size */ { FT_ULong image_size; if ( p + 12 > p_limit ) goto NoBitmap; image_size = FT_NEXT_ULONG( p ); if ( tt_sbit_decoder_load_metrics( decoder, &p, p_limit, 1 ) ) goto NoBitmap; image_start = image_size * ( glyph_index - start ); image_end = image_start + image_size; } break; case 3: /* 2-byte offsets relative to 'image_offset' */ p += 2 * ( glyph_index - start ); if ( p + 4 > p_limit ) goto NoBitmap; image_start = FT_NEXT_USHORT( p ); image_end = FT_NEXT_USHORT( p ); if ( image_start == image_end ) /* missing glyph */ goto NoBitmap; break; case 4: /* sparse glyph array with (glyph,offset) pairs */ { FT_ULong mm, num_glyphs; if ( p + 4 > p_limit ) goto NoBitmap; num_glyphs = FT_NEXT_ULONG( p ); /* overflow check for p + ( num_glyphs + 1 ) * 4 */ if ( num_glyphs > (FT_ULong)( ( ( p_limit - p ) >> 2 ) - 1 ) ) goto NoBitmap; for ( mm = 0; mm < num_glyphs; mm++ ) { FT_UInt gindex = FT_NEXT_USHORT( p ); if ( gindex == glyph_index ) { image_start = FT_NEXT_USHORT( p ); p += 2; image_end = FT_PEEK_USHORT( p ); break; } p += 2; } if ( mm >= num_glyphs ) goto NoBitmap; } break; case 5: /* constant metrics with sparse glyph codes */ case 19: { FT_ULong image_size, mm, num_glyphs; if ( p + 16 > p_limit ) goto NoBitmap; image_size = FT_NEXT_ULONG( p ); if ( tt_sbit_decoder_load_metrics( decoder, &p, p_limit, 1 ) ) goto NoBitmap; num_glyphs = FT_NEXT_ULONG( p ); /* overflow check for p + 2 * num_glyphs */ if ( num_glyphs > (FT_ULong)( ( p_limit - p ) >> 1 ) ) goto NoBitmap; for ( mm = 0; mm < num_glyphs; mm++ ) { FT_UInt gindex = FT_NEXT_USHORT( p ); if ( gindex == glyph_index ) break; } if ( mm >= num_glyphs ) goto NoBitmap; image_start = image_size * mm; image_end = image_start + image_size; } break; default: goto NoBitmap; } if ( image_start > image_end ) goto NoBitmap; image_end -= image_start; image_start = image_offset + image_start; FT_TRACE3(( "tt_sbit_decoder_load_image:" " found sbit (format %d) for glyph index %d\n", image_format, glyph_index )); return tt_sbit_decoder_load_bitmap( decoder, image_format, image_start, image_end, x_pos, y_pos ); Failure: return FT_THROW( Invalid_Table ); NoBitmap: FT_TRACE4(( "tt_sbit_decoder_load_image:" " no sbit found for glyph index %d\n", glyph_index )); return FT_THROW( Invalid_Argument ); } FT_LOCAL_DEF( FT_Error ) tt_face_get_metrics( TT_Face face, FT_Bool vertical, FT_UInt gindex, FT_Short *abearing, FT_UShort *aadvance ); static FT_Error tt_face_load_sbix_image( TT_Face face, FT_ULong strike_index, FT_UInt glyph_index, FT_Stream stream, FT_Bitmap *map, TT_SBit_MetricsRec *metrics ) { FT_UInt sbix_pos, strike_offset, glyph_start, glyph_end; FT_ULong table_size; FT_Int originOffsetX, originOffsetY; FT_Tag graphicType; FT_Int recurse_depth = 0; FT_Error error; FT_Byte* p; FT_UNUSED( map ); metrics->width = 0; metrics->height = 0; p = face->sbit_table + 8 + 4 * strike_index; strike_offset = FT_NEXT_ULONG( p ); error = face->goto_table( face, TTAG_sbix, stream, &table_size ); if ( error ) return error; sbix_pos = FT_STREAM_POS(); retry: if ( glyph_index > (FT_UInt)face->root.num_glyphs ) return FT_THROW( Invalid_Argument ); if ( strike_offset >= table_size || table_size - strike_offset < 4 + glyph_index * 4 + 8 ) return FT_THROW( Invalid_File_Format ); if ( FT_STREAM_SEEK( sbix_pos + strike_offset + 4 + glyph_index * 4 ) || FT_FRAME_ENTER( 8 ) ) return error; glyph_start = FT_GET_ULONG(); glyph_end = FT_GET_ULONG(); FT_FRAME_EXIT(); if ( glyph_start == glyph_end ) return FT_THROW( Invalid_Argument ); if ( glyph_start > glyph_end || glyph_end - glyph_start < 8 || table_size - strike_offset < glyph_end ) return FT_THROW( Invalid_File_Format ); if ( FT_STREAM_SEEK( sbix_pos + strike_offset + glyph_start ) || FT_FRAME_ENTER( glyph_end - glyph_start ) ) return error; originOffsetX = FT_GET_SHORT(); originOffsetY = FT_GET_SHORT(); graphicType = FT_GET_TAG4(); switch ( graphicType ) { case FT_MAKE_TAG( 'd', 'u', 'p', 'e' ): if ( recurse_depth < 4 ) { glyph_index = FT_GET_USHORT(); FT_FRAME_EXIT(); recurse_depth++; goto retry; } error = FT_THROW( Invalid_File_Format ); break; case FT_MAKE_TAG( 'p', 'n', 'g', ' ' ): #ifdef FT_CONFIG_OPTION_USE_PNG error = Load_SBit_Png( face->root.glyph, 0, 0, 32, metrics, stream->memory, stream->cursor, glyph_end - glyph_start - 8, TRUE ); #else error = FT_THROW( Unimplemented_Feature ); #endif break; case FT_MAKE_TAG( 'j', 'p', 'g', ' ' ): case FT_MAKE_TAG( 't', 'i', 'f', 'f' ): error = FT_THROW( Unknown_File_Format ); break; default: error = FT_THROW( Unimplemented_Feature ); break; } FT_FRAME_EXIT(); if ( !error ) { FT_Short abearing; FT_UShort aadvance; tt_face_get_metrics( face, FALSE, glyph_index, &abearing, &aadvance ); metrics->horiBearingX = originOffsetX; metrics->horiBearingY = -originOffsetY + metrics->height; metrics->horiAdvance = aadvance * face->root.size->metrics.x_ppem / face->header.Units_Per_EM; } return error; } FT_BASE_DEF( void ) ft_glyphslot_set_bitmap( FT_GlyphSlot slot, FT_Byte* buffer ) { ft_glyphslot_free_bitmap( slot ); slot->bitmap.buffer = buffer; FT_ASSERT( (slot->internal->flags & FT_GLYPH_OWN_BITMAP) == 0 ); } FT_LOCAL( FT_Error ) tt_face_load_sbit_image( TT_Face face, FT_ULong strike_index, FT_UInt glyph_index, FT_UInt load_flags, FT_Stream stream, FT_Bitmap *map, TT_SBit_MetricsRec *metrics ) { FT_Error error = FT_Err_Ok; switch ( (FT_UInt)face->sbit_table_type ) { case TT_SBIT_TABLE_TYPE_EBLC: case TT_SBIT_TABLE_TYPE_CBLC: { TT_SBitDecoderRec decoder[1]; error = tt_sbit_decoder_init( decoder, face, strike_index, metrics ); if ( !error ) { error = tt_sbit_decoder_load_image( decoder, glyph_index, 0, 0 ); tt_sbit_decoder_done( decoder ); } } break; case TT_SBIT_TABLE_TYPE_SBIX: error = tt_face_load_sbix_image( face, strike_index, glyph_index, stream, map, metrics ); break; default: error = FT_THROW( Unknown_File_Format ); break; } /* Flatten color bitmaps if color was not requested. */ if ( !error && !( load_flags & FT_LOAD_COLOR ) && map->pixel_mode == FT_PIXEL_MODE_BGRA ) { FT_Bitmap new_map; FT_Library library = face->root.glyph->library; FT_Bitmap_New( &new_map ); /* Convert to 8bit grayscale. */ error = FT_Bitmap_Convert( library, map, &new_map, 1 ); if ( error ) FT_Bitmap_Done( library, &new_map ); else { map->pixel_mode = new_map.pixel_mode; map->pitch = new_map.pitch; map->num_grays = new_map.num_grays; ft_glyphslot_set_bitmap( face->root.glyph, new_map.buffer ); face->root.glyph->internal->flags |= FT_GLYPH_OWN_BITMAP; } } return error; } typedef FT_UInt32 (*PS_Unicode_ValueFunc)( const char* glyph_name ); /* * Macintosh name id to glyph name. NULL if invalid index. */ typedef const char* (*PS_Macintosh_NameFunc)( FT_UInt name_index ); /* * Adobe standard string ID to glyph name. NULL if invalid index. */ typedef const char* (*PS_Adobe_Std_StringsFunc)( FT_UInt string_index ); /* * Simple unicode -> glyph index charmap built from font glyph names * table. */ typedef struct PS_UniMap_ { FT_UInt32 unicode; /* bit 31 set: is glyph variant */ FT_UInt glyph_index; } PS_UniMap; typedef struct PS_UnicodesRec_* PS_Unicodes; typedef struct PS_UnicodesRec_ { FT_CMapRec cmap; FT_UInt num_maps; PS_UniMap* maps; } PS_UnicodesRec; /* * A function which returns a glyph name for a given index. Returns * NULL if invalid index. */ typedef const char* (*PS_GetGlyphNameFunc)( FT_Pointer data, FT_UInt string_index ); /* * A function used to release the glyph name returned by * PS_GetGlyphNameFunc, when needed */ typedef void (*PS_FreeGlyphNameFunc)( FT_Pointer data, const char* name ); typedef FT_Error (*PS_Unicodes_InitFunc)( FT_Memory memory, PS_Unicodes unicodes, FT_UInt num_glyphs, PS_GetGlyphNameFunc get_glyph_name, PS_FreeGlyphNameFunc free_glyph_name, FT_Pointer glyph_data ); typedef FT_UInt (*PS_Unicodes_CharIndexFunc)( PS_Unicodes unicodes, FT_UInt32 unicode ); typedef FT_UInt32 (*PS_Unicodes_CharNextFunc)( PS_Unicodes unicodes, FT_UInt32 *unicode ); FT_DEFINE_SERVICE( PsCMaps ) { PS_Unicode_ValueFunc unicode_value; PS_Unicodes_InitFunc unicodes_init; PS_Unicodes_CharIndexFunc unicodes_char_index; PS_Unicodes_CharNextFunc unicodes_char_next; PS_Macintosh_NameFunc macintosh_name; PS_Adobe_Std_StringsFunc adobe_std_strings; const unsigned short* adobe_std_encoding; const unsigned short* adobe_expert_encoding; }; #ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES #define MAC_NAME( x ) ( (FT_String*)psnames->macintosh_name( x ) ) #else /* FT_CONFIG_OPTION_POSTSCRIPT_NAMES */ /* Otherwise, we ignore the `PSNames' module, and provide our own */ /* table of Mac names. Thus, it is possible to build a version of */ /* FreeType without the Type 1 driver & PSNames module. */ #define MAC_NAME( x ) ( (FT_String*)tt_post_default_names[x] ) /* the 258 default Mac PS glyph names */ static const FT_String* const tt_post_default_names[258] = { /* 0 */ ".notdef", ".null", "CR", "space", "exclam", "quotedbl", "numbersign", "dollar", "percent", "ampersand", /* 10 */ "quotesingle", "parenleft", "parenright", "asterisk", "plus", "comma", "hyphen", "period", "slash", "zero", /* 20 */ "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "colon", /* 30 */ "semicolon", "less", "equal", "greater", "question", "at", "A", "B", "C", "D", /* 40 */ "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", /* 50 */ "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", /* 60 */ "Y", "Z", "bracketleft", "backslash", "bracketright", "asciicircum", "underscore", "grave", "a", "b", /* 70 */ "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", /* 80 */ "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", /* 90 */ "w", "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde", "Adieresis", "Aring", /* 100 */ "Ccedilla", "Eacute", "Ntilde", "Odieresis", "Udieresis", "aacute", "agrave", "acircumflex", "adieresis", "atilde", /* 110 */ "aring", "ccedilla", "eacute", "egrave", "ecircumflex", "edieresis", "iacute", "igrave", "icircumflex", "idieresis", /* 120 */ "ntilde", "oacute", "ograve", "ocircumflex", "odieresis", "otilde", "uacute", "ugrave", "ucircumflex", "udieresis", /* 130 */ "dagger", "degree", "cent", "sterling", "section", "bullet", "paragraph", "germandbls", "registered", "copyright", /* 140 */ "trademark", "acute", "dieresis", "notequal", "AE", "Oslash", "infinity", "plusminus", "lessequal", "greaterequal", /* 150 */ "yen", "mu", "partialdiff", "summation", "product", "pi", "integral", "ordfeminine", "ordmasculine", "Omega", /* 160 */ "ae", "oslash", "questiondown", "exclamdown", "logicalnot", "radical", "florin", "approxequal", "Delta", "guillemotleft", /* 170 */ "guillemotright", "ellipsis", "nbspace", "Agrave", "Atilde", "Otilde", "OE", "oe", "endash", "emdash", /* 180 */ "quotedblleft", "quotedblright", "quoteleft", "quoteright", "divide", "lozenge", "ydieresis", "Ydieresis", "fraction", "currency", /* 190 */ "guilsinglleft", "guilsinglright", "fi", "fl", "daggerdbl", "periodcentered", "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex", /* 200 */ "Ecircumflex", "Aacute", "Edieresis", "Egrave", "Iacute", "Icircumflex", "Idieresis", "Igrave", "Oacute", "Ocircumflex", /* 210 */ "apple", "Ograve", "Uacute", "Ucircumflex", "Ugrave", "dotlessi", "circumflex", "tilde", "macron", "breve", /* 220 */ "dotaccent", "ring", "cedilla", "hungarumlaut", "ogonek", "caron", "Lslash", "lslash", "Scaron", "scaron", /* 230 */ "Zcaron", "zcaron", "brokenbar", "Eth", "eth", "Yacute", "yacute", "Thorn", "thorn", "minus", /* 240 */ "multiply", "onesuperior", "twosuperior", "threesuperior", "onehalf", "onequarter", "threequarters", "franc", "Gbreve", "gbreve", /* 250 */ "Idot", "Scedilla", "scedilla", "Cacute", "cacute", "Ccaron", "ccaron", "dmacron", }; #endif /* FT_CONFIG_OPTION_POSTSCRIPT_NAMES */ static FT_Error load_format_20( TT_Face face, FT_Stream stream, FT_Long post_limit ) { FT_Memory memory = stream->memory; FT_Error error; FT_Int num_glyphs; FT_UShort num_names; FT_UShort* glyph_indices = 0; FT_Char** name_strings = 0; if ( FT_READ_USHORT( num_glyphs ) ) goto Exit; /* UNDOCUMENTED! The number of glyphs in this table can be smaller */ /* than the value in the maxp table (cf. cyberbit.ttf). */ /* There already exist fonts which have more than 32768 glyph names */ /* in this table, so the test for this threshold has been dropped. */ if ( num_glyphs > face->max_profile.numGlyphs ) { error = FT_THROW( Invalid_File_Format ); goto Exit; } /* load the indices */ { FT_Int n; if ( FT_NEW_ARRAY ( glyph_indices, num_glyphs ) || FT_FRAME_ENTER( num_glyphs * 2L ) ) goto Fail; for ( n = 0; n < num_glyphs; n++ ) glyph_indices[n] = FT_GET_USHORT(); FT_FRAME_EXIT(); } /* compute number of names stored in table */ { FT_Int n; num_names = 0; for ( n = 0; n < num_glyphs; n++ ) { FT_Int idx; idx = glyph_indices[n]; if ( idx >= 258 ) { idx -= 257; if ( idx > num_names ) num_names = (FT_UShort)idx; } } } /* now load the name strings */ { FT_UShort n; if ( FT_NEW_ARRAY( name_strings, num_names ) ) goto Fail; for ( n = 0; n < num_names; n++ ) { FT_UInt len; if ( FT_STREAM_POS() >= post_limit ) break; else { FT_TRACE6(( "load_format_20: %d byte left in post table\n", post_limit - FT_STREAM_POS() )); if ( FT_READ_BYTE( len ) ) goto Fail1; } if ( (FT_Int)len > post_limit || FT_STREAM_POS() > post_limit - (FT_Int)len ) { FT_ERROR(( "load_format_20:" " exceeding string length (%d)," " truncating at end of post table (%d byte left)\n", len, post_limit - FT_STREAM_POS() )); len = FT_MAX( 0, post_limit - FT_STREAM_POS() ); } if ( FT_NEW_ARRAY( name_strings[n], len + 1 ) || FT_STREAM_READ( name_strings[n], len ) ) goto Fail1; name_strings[n][len] = '\0'; } if ( n < num_names ) { FT_ERROR(( "load_format_20:" " all entries in post table are already parsed," " using NULL names for gid %d - %d\n", n, num_names - 1 )); for ( ; n < num_names; n++ ) if ( FT_NEW_ARRAY( name_strings[n], 1 ) ) goto Fail1; else name_strings[n][0] = '\0'; } } /* all right, set table fields and exit successfully */ { TT_Post_20 table = &face->postscript_names.names.format_20; table->num_glyphs = (FT_UShort)num_glyphs; table->num_names = (FT_UShort)num_names; table->glyph_indices = glyph_indices; table->glyph_names = name_strings; } return FT_Err_Ok; Fail1: { FT_UShort n; for ( n = 0; n < num_names; n++ ) FT_FREE( name_strings[n] ); } Fail: FT_FREE( name_strings ); FT_FREE( glyph_indices ); Exit: return error; } static FT_Error load_format_25( TT_Face face, FT_Stream stream, FT_Long post_limit ) { FT_Memory memory = stream->memory; FT_Error error; FT_Int num_glyphs; FT_Char* offset_table = 0; FT_UNUSED( post_limit ); /* UNDOCUMENTED! This value appears only in the Apple TT specs. */ if ( FT_READ_USHORT( num_glyphs ) ) goto Exit; /* check the number of glyphs */ if ( num_glyphs > face->max_profile.numGlyphs || num_glyphs > 258 ) { error = FT_THROW( Invalid_File_Format ); goto Exit; } if ( FT_NEW_ARRAY( offset_table, num_glyphs ) || FT_STREAM_READ( offset_table, num_glyphs ) ) goto Fail; /* now check the offset table */ { FT_Int n; for ( n = 0; n < num_glyphs; n++ ) { FT_Long idx = (FT_Long)n + offset_table[n]; if ( idx < 0 || idx > num_glyphs ) { error = FT_THROW( Invalid_File_Format ); goto Fail; } } } /* OK, set table fields and exit successfully */ { TT_Post_25 table = &face->postscript_names.names.format_25; table->num_glyphs = (FT_UShort)num_glyphs; table->offsets = offset_table; } return FT_Err_Ok; Fail: FT_FREE( offset_table ); Exit: return error; } static FT_Error load_post_names( TT_Face face ) { FT_Stream stream; FT_Error error; FT_Fixed format; FT_ULong post_len; FT_Long post_limit; /* get a stream for the face's resource */ stream = face->root.stream; /* seek to the beginning of the PS names table */ error = face->goto_table( face, TTAG_post, stream, &post_len ); if ( error ) goto Exit; post_limit = FT_STREAM_POS() + post_len; format = face->postscript.FormatType; /* go to beginning of subtable */ if ( FT_STREAM_SKIP( 32 ) ) goto Exit; /* now read postscript table */ if ( format == 0x00020000L ) error = load_format_20( face, stream, post_limit ); else if ( format == 0x00028000L ) error = load_format_25( face, stream, post_limit ); else error = FT_THROW( Invalid_File_Format ); face->postscript_names.loaded = 1; Exit: return error; } FT_LOCAL_DEF( FT_Error ) tt_face_get_ps_name( TT_Face face, FT_UInt idx, FT_String** PSname ) { FT_Error error; TT_Post_Names names; FT_Fixed format; #ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES FT_Service_PsCMaps psnames; #endif if ( !face ) return FT_THROW( Invalid_Face_Handle ); if ( idx >= (FT_UInt)face->max_profile.numGlyphs ) return FT_THROW( Invalid_Glyph_Index ); #ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES psnames = (FT_Service_PsCMaps)face->psnames; if ( !psnames ) return FT_THROW( Unimplemented_Feature ); #endif names = &face->postscript_names; /* `.notdef' by default */ *PSname = MAC_NAME( 0 ); format = face->postscript.FormatType; if ( format == 0x00010000L ) { if ( idx < 258 ) /* paranoid checking */ *PSname = MAC_NAME( idx ); } else if ( format == 0x00020000L ) { TT_Post_20 table = &names->names.format_20; if ( !names->loaded ) { error = load_post_names( face ); if ( error ) goto End; } if ( idx < (FT_UInt)table->num_glyphs ) { FT_UShort name_index = table->glyph_indices[idx]; if ( name_index < 258 ) *PSname = MAC_NAME( name_index ); else *PSname = (FT_String*)table->glyph_names[name_index - 258]; } } else if ( format == 0x00028000L ) { TT_Post_25 table = &names->names.format_25; if ( !names->loaded ) { error = load_post_names( face ); if ( error ) goto End; } if ( idx < (FT_UInt)table->num_glyphs ) /* paranoid checking */ { idx += table->offsets[idx]; *PSname = MAC_NAME( idx ); } } /* nothing to do for format == 0x00030000L */ End: return FT_Err_Ok; } FT_LOCAL_DEF( void ) tt_face_free_ps_names( TT_Face face ) { FT_Memory memory = face->root.memory; TT_Post_Names names = &face->postscript_names; FT_Fixed format; if ( names->loaded ) { format = face->postscript.FormatType; if ( format == 0x00020000L ) { TT_Post_20 table = &names->names.format_20; FT_UShort n; FT_FREE( table->glyph_indices ); table->num_glyphs = 0; for ( n = 0; n < table->num_names; n++ ) FT_FREE( table->glyph_names[n] ); FT_FREE( table->glyph_names ); table->num_names = 0; } else if ( format == 0x00028000L ) { TT_Post_25 table = &names->names.format_25; FT_FREE( table->offsets ); table->num_glyphs = 0; } } names->loaded = 0; } #define FT_REQUEST_WIDTH( req ) \ ( (req)->horiResolution \ ? (FT_Pos)( (req)->width * (req)->horiResolution + 36 ) / 72 \ : (req)->width ) #define FT_REQUEST_HEIGHT( req ) \ ( (req)->vertResolution \ ? (FT_Pos)( (req)->height * (req)->vertResolution + 36 ) / 72 \ : (req)->height ) FT_BASE_DEF( FT_Error ) FT_Match_Size( FT_Face face, FT_Size_Request req, FT_Bool ignore_width, FT_ULong* size_index ) { FT_Int i; FT_Long w, h; if ( !FT_HAS_FIXED_SIZES( face ) ) return FT_THROW( Invalid_Face_Handle ); /* FT_Bitmap_Size doesn't provide enough info... */ if ( req->type != FT_SIZE_REQUEST_TYPE_NOMINAL ) return FT_THROW( Unimplemented_Feature ); w = FT_REQUEST_WIDTH ( req ); h = FT_REQUEST_HEIGHT( req ); if ( req->width && !req->height ) h = w; else if ( !req->width && req->height ) w = h; w = FT_PIX_ROUND( w ); h = FT_PIX_ROUND( h ); for ( i = 0; i < face->num_fixed_sizes; i++ ) { FT_Bitmap_Size* bsize = face->available_sizes + i; if ( h != FT_PIX_ROUND( bsize->y_ppem ) ) continue; if ( w == FT_PIX_ROUND( bsize->x_ppem ) || ignore_width ) { FT_TRACE3(( "FT_Match_Size: bitmap strike %d matches\n", i )); if ( size_index ) *size_index = (FT_ULong)i; return FT_Err_Ok; } } return FT_THROW( Invalid_Pixel_Size ); } FT_LOCAL_DEF( FT_Error ) tt_face_set_sbit_strike( TT_Face face, FT_Size_Request req, FT_ULong* astrike_index ) { return FT_Match_Size( (FT_Face)face, req, 0, astrike_index ); } FT_LOCAL_DEF( FT_Error ) tt_face_load_strike_metrics( TT_Face face, FT_ULong strike_index, FT_Size_Metrics* metrics ) { if ( strike_index >= (FT_ULong)face->sbit_num_strikes ) return FT_THROW( Invalid_Argument ); switch ( (FT_UInt)face->sbit_table_type ) { case TT_SBIT_TABLE_TYPE_EBLC: case TT_SBIT_TABLE_TYPE_CBLC: { FT_Byte* strike; strike = face->sbit_table + 8 + strike_index * 48; metrics->x_ppem = (FT_UShort)strike[44]; metrics->y_ppem = (FT_UShort)strike[45]; metrics->ascender = (FT_Char)strike[16] << 6; /* hori.ascender */ metrics->descender = (FT_Char)strike[17] << 6; /* hori.descender */ metrics->height = metrics->ascender - metrics->descender; /* Is this correct? */ metrics->max_advance = ( (FT_Char)strike[22] + /* min_origin_SB */ strike[18] + /* max_width */ (FT_Char)strike[23] /* min_advance_SB */ ) << 6; return FT_Err_Ok; } case TT_SBIT_TABLE_TYPE_SBIX: { FT_Stream stream = face->root.stream; FT_UInt offset, ppem, resolution, upem; TT_HoriHeader *hori; FT_ULong table_size; FT_Error error; FT_Byte* p; p = face->sbit_table + 8 + 4 * strike_index; offset = FT_NEXT_ULONG( p ); error = face->goto_table( face, TTAG_sbix, stream, &table_size ); if ( error ) return error; if ( offset + 4 > table_size ) return FT_THROW( Invalid_File_Format ); if ( FT_STREAM_SEEK( FT_STREAM_POS() + offset ) || FT_FRAME_ENTER( 4 ) ) return error; ppem = FT_GET_USHORT(); resolution = FT_GET_USHORT(); FT_UNUSED( resolution ); /* What to do with this? */ FT_FRAME_EXIT(); upem = face->header.Units_Per_EM; hori = &face->horizontal; metrics->x_ppem = ppem; metrics->y_ppem = ppem; metrics->ascender = ppem * hori->Ascender * 64 / upem; metrics->descender = ppem * hori->Descender * 64 / upem; metrics->height = ppem * ( hori->Ascender - hori->Descender + hori->Line_Gap ) * 64 / upem; metrics->max_advance = ppem * hori->advance_Width_Max * 64 / upem; return error; } default: return FT_THROW( Unknown_File_Format ); } } typedef enum FT_Sfnt_Tag_ { ft_sfnt_head = 0, /* TT_Header */ ft_sfnt_maxp = 1, /* TT_MaxProfile */ ft_sfnt_os2 = 2, /* TT_OS2 */ ft_sfnt_hhea = 3, /* TT_HoriHeader */ ft_sfnt_vhea = 4, /* TT_VertHeader */ ft_sfnt_post = 5, /* TT_Postscript */ ft_sfnt_pclt = 6, /* TT_PCLT */ sfnt_max /* internal end mark */ } FT_Sfnt_Tag; /* * Used to implement FT_Load_Sfnt_Table(). */ typedef FT_Error (*FT_SFNT_TableLoadFunc)( FT_Face face, FT_ULong tag, FT_Long offset, FT_Byte* buffer, FT_ULong* length ); /* * Used to implement FT_Get_Sfnt_Table(). */ typedef void* (*FT_SFNT_TableGetFunc)( FT_Face face, FT_Sfnt_Tag tag ); /* * Used to implement FT_Sfnt_Table_Info(). */ typedef FT_Error (*FT_SFNT_TableInfoFunc)( FT_Face face, FT_UInt idx, FT_ULong *tag, FT_ULong *offset, FT_ULong *length ); FT_DEFINE_SERVICE( SFNT_Table ) { FT_SFNT_TableLoadFunc load_table; FT_SFNT_TableGetFunc get_table; FT_SFNT_TableInfoFunc table_info; }; #ifndef FT_CONFIG_OPTION_PIC #define FT_DEFINE_SERVICE_SFNT_TABLEREC( class_, load_, get_, info_ ) \ static const FT_Service_SFNT_TableRec class_ = \ { \ load_, get_, info_ \ }; #else /* FT_CONFIG_OPTION_PIC */ #define FT_DEFINE_SERVICE_SFNT_TABLEREC( class_, load_, get_, info_ ) \ void \ FT_Init_Class_ ## class_( FT_Service_SFNT_TableRec* clazz ) \ { \ clazz->load_table = load_; \ clazz->get_table = get_; \ clazz->table_info = info_; \ } #endif /* FT_CONFIG_OPTION_PIC */ #ifndef FT_CONFIG_OPTION_PIC #define FT_DEFINE_SERVICE_PSFONTNAMEREC( class_, get_ps_font_name_ ) \ static const FT_Service_PsFontNameRec class_ = \ { \ get_ps_font_name_ \ }; #else /* FT_CONFIG_OPTION_PIC */ #define FT_DEFINE_SERVICE_PSFONTNAMEREC( class_, get_ps_font_name_ ) \ void \ FT_Init_Class_ ## class_( FT_Library library, \ FT_Service_PsFontNameRec* clazz ) \ { \ FT_UNUSED( library ); \ \ clazz->get_ps_font_name = get_ps_font_name_; \ } #endif /* FT_CONFIG_OPTION_PIC */ #ifndef FT_CONFIG_OPTION_PIC #define FT_DEFINE_SERVICE_GLYPHDICTREC( class_, \ get_name_, \ name_index_) \ static const FT_Service_GlyphDictRec class_ = \ { \ get_name_, name_index_ \ }; #else /* FT_CONFIG_OPTION_PIC */ #define FT_DEFINE_SERVICE_GLYPHDICTREC( class_, \ get_name_, \ name_index_) \ void \ FT_Init_Class_ ## class_( FT_Library library, \ FT_Service_GlyphDictRec* clazz ) \ { \ FT_UNUSED( library ); \ \ clazz->get_name = get_name_; \ clazz->name_index = name_index_; \ } #endif /* FT_CONFIG_OPTION_PIC */ static void* get_sfnt_table( TT_Face face, FT_Sfnt_Tag tag ) { void* table; switch ( tag ) { case ft_sfnt_head: table = &face->header; break; case ft_sfnt_hhea: table = &face->horizontal; break; case ft_sfnt_vhea: table = face->vertical_info ? &face->vertical : 0; break; case ft_sfnt_os2: table = face->os2.version == 0xFFFFU ? 0 : &face->os2; break; case ft_sfnt_post: table = &face->postscript; break; case ft_sfnt_maxp: table = &face->max_profile; break; case ft_sfnt_pclt: table = face->pclt.Version ? &face->pclt : 0; break; default: table = 0; } return table; } typedef FT_Error (*FT_SFNT_TableLoadFunc)( FT_Face face, FT_ULong tag, FT_Long offset, FT_Byte* buffer, FT_ULong* length ); /* * Used to implement FT_Get_Sfnt_Table(). */ typedef void* (*FT_SFNT_TableGetFunc)( FT_Face face, FT_Sfnt_Tag tag ); /* * Used to implement FT_Sfnt_Table_Info(). */ typedef FT_Error (*FT_SFNT_TableInfoFunc)( FT_Face face, FT_UInt idx, FT_ULong *tag, FT_ULong *offset, FT_ULong *length ); static FT_Error sfnt_table_info( TT_Face face, FT_UInt idx, FT_ULong *tag, FT_ULong *offset, FT_ULong *length ) { if ( !offset || !length ) return FT_THROW( Invalid_Argument ); if ( !tag ) *length = face->num_tables; else { if ( idx >= face->num_tables ) return FT_THROW( Table_Missing ); *tag = face->dir_tables[idx].Tag; *offset = face->dir_tables[idx].Offset; *length = face->dir_tables[idx].Length; } return FT_Err_Ok; } static const char* sfnt_get_ps_name( TT_Face face ) { FT_Int n, found_win, found_apple; const char* result = NULL; /* shouldn't happen, but just in case to avoid memory leaks */ if ( face->postscript_name ) return face->postscript_name; /* scan the name table to see whether we have a Postscript name here, */ /* either in Macintosh or Windows platform encodings */ found_win = -1; found_apple = -1; for ( n = 0; n < face->num_names; n++ ) { TT_NameEntryRec* name = face->name_table.names + n; if ( name->nameID == 6 && name->stringLength > 0 ) { if ( name->platformID == 3 && name->encodingID == 1 && name->languageID == 0x409 ) found_win = n; if ( name->platformID == 1 && name->encodingID == 0 && name->languageID == 0 ) found_apple = n; } } if ( found_win != -1 ) { FT_Memory memory = face->root.memory; TT_NameEntryRec* name = face->name_table.names + found_win; FT_UInt len = name->stringLength / 2; FT_Error error = FT_Err_Ok; FT_UNUSED( error ); if ( !FT_ALLOC( result, name->stringLength + 1 ) ) { FT_Stream stream = face->name_table.stream; FT_String* r = (FT_String*)result; FT_Byte* p; if ( FT_STREAM_SEEK( name->stringOffset ) || FT_FRAME_ENTER( name->stringLength ) ) { FT_FREE( result ); name->stringLength = 0; name->stringOffset = 0; FT_FREE( name->string ); goto Exit; } p = (FT_Byte*)stream->cursor; for ( ; len > 0; len--, p += 2 ) { if ( p[0] == 0 && p[1] >= 32 && p[1] < 128 ) *r++ = p[1]; } *r = '\0'; FT_FRAME_EXIT(); } goto Exit; } if ( found_apple != -1 ) { FT_Memory memory = face->root.memory; TT_NameEntryRec* name = face->name_table.names + found_apple; FT_UInt len = name->stringLength; FT_Error error = FT_Err_Ok; FT_UNUSED( error ); if ( !FT_ALLOC( result, len + 1 ) ) { FT_Stream stream = face->name_table.stream; if ( FT_STREAM_SEEK( name->stringOffset ) || FT_STREAM_READ( result, len ) ) { name->stringOffset = 0; name->stringLength = 0; FT_FREE( name->string ); FT_FREE( result ); goto Exit; } ((char*)result)[len] = '\0'; } } Exit: face->postscript_name = result; return result; } FT_LOCAL_DEF( FT_Error ) tt_face_load_any( TT_Face face, FT_ULong tag, FT_Long offset, FT_Byte* buffer, FT_ULong* length ); FT_DEFINE_SERVICE_SFNT_TABLEREC( sfnt_service_sfnt_table, (FT_SFNT_TableLoadFunc)tt_face_load_any, (FT_SFNT_TableGetFunc) get_sfnt_table, (FT_SFNT_TableInfoFunc)sfnt_table_info ) typedef FT_Error (*FT_Kerning_TrackGetFunc)( FT_Face face, FT_Fixed point_size, FT_Int degree, FT_Fixed* akerning ); #define FT_SERVICE_ID_KERNING "kerning" FT_DEFINE_SERVICE( Kerning ) { FT_Kerning_TrackGetFunc get_track; }; typedef const char* (*FT_PsName_GetFunc)( FT_Face face ); typedef const char* (*FT_PsName_GetFunc)( FT_Face face ); FT_DEFINE_SERVICE( PsFontName ) { FT_PsName_GetFunc get_ps_font_name; }; FT_DEFINE_SERVICE_PSFONTNAMEREC( sfnt_service_ps_name, (FT_PsName_GetFunc)sfnt_get_ps_name ) FT_BASE_DEF( FT_Int ) ft_mem_strcpyn( char* dst, const char* src, FT_ULong size ) { while ( size > 1 && *src != 0 ) { *dst++ = *src++; size--; } *dst = 0; /* always zero-terminate */ return *src != 0; } #define FT_STRCPYN( dst, src, size ) \ ft_mem_strcpyn( (char*)dst, (const char*)(src), (FT_ULong)(size) ) #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES /* * GLYPH DICT SERVICE * */ static FT_Error sfnt_get_glyph_name( TT_Face face, FT_UInt glyph_index, FT_Pointer buffer, FT_UInt buffer_max ) { FT_String* gname; FT_Error error; error = tt_face_get_ps_name( face, glyph_index, &gname ); if ( !error ) FT_STRCPYN( buffer, gname, buffer_max ); return error; } static FT_UInt sfnt_get_name_index( TT_Face face, FT_String* glyph_name ) { FT_Face root = &face->root; FT_UInt i, max_gid = FT_UINT_MAX; if ( root->num_glyphs < 0 ) return 0; else if ( (FT_ULong)root->num_glyphs < FT_UINT_MAX ) max_gid = (FT_UInt)root->num_glyphs; else FT_TRACE0(( "Ignore glyph names for invalid GID 0x%08x - 0x%08x\n", FT_UINT_MAX, root->num_glyphs )); for ( i = 0; i < max_gid; i++ ) { FT_String* gname; FT_Error error = tt_face_get_ps_name( face, i, &gname ); if ( error ) continue; if ( !ft_strcmp( glyph_name, gname ) ) return i; } return 0; } typedef FT_Error (*FT_GlyphDict_GetNameFunc)( FT_Face face, FT_UInt glyph_index, FT_Pointer buffer, FT_UInt buffer_max ); typedef FT_UInt (*FT_GlyphDict_NameIndexFunc)( FT_Face face, FT_String* glyph_name ); FT_DEFINE_SERVICE( GlyphDict ) { FT_GlyphDict_GetNameFunc get_name; FT_GlyphDict_NameIndexFunc name_index; /* optional */ }; FT_DEFINE_SERVICE_GLYPHDICTREC( sfnt_service_glyph_dict, (FT_GlyphDict_GetNameFunc) sfnt_get_glyph_name, (FT_GlyphDict_NameIndexFunc)sfnt_get_name_index ) #endif /* TT_CONFIG_OPTION_POSTSCRIPT_NAMES */ typedef struct SFNT_HeaderRec_ { FT_ULong format_tag; FT_UShort num_tables; FT_UShort search_range; FT_UShort entry_selector; FT_UShort range_shift; FT_ULong offset; /* not in file */ } SFNT_HeaderRec, *SFNT_Header; static FT_Error check_table_dir( SFNT_Header sfnt, FT_Stream stream ) { FT_Error error; FT_UShort nn, valid_entries = 0; FT_UInt has_head = 0, has_sing = 0, has_meta = 0; FT_ULong offset = sfnt->offset + 12; static const FT_Frame_Field table_dir_entry_fields[] = { #undef FT_STRUCTURE #define FT_STRUCTURE TT_TableRec FT_FRAME_START( 16 ), FT_FRAME_ULONG( Tag ), FT_FRAME_ULONG( CheckSum ), FT_FRAME_ULONG( Offset ), FT_FRAME_ULONG( Length ), FT_FRAME_END }; if ( FT_STREAM_SEEK( offset ) ) goto Exit; for ( nn = 0; nn < sfnt->num_tables; nn++ ) { TT_TableRec table; if ( FT_STREAM_READ_FIELDS( table_dir_entry_fields, &table ) ) { nn--; FT_TRACE2(( "check_table_dir:" " can read only %d table%s in font (instead of %d)\n", nn, nn == 1 ? "" : "s", sfnt->num_tables )); sfnt->num_tables = nn; break; } /* we ignore invalid tables */ if ( table.Offset + table.Length > stream->size ) { FT_TRACE2(( "check_table_dir: table entry %d invalid\n", nn )); continue; } else valid_entries++; if ( table.Tag == TTAG_head || table.Tag == TTAG_bhed ) { FT_UInt32 magic; #ifndef TT_CONFIG_OPTION_EMBEDDED_BITMAPS if ( table.Tag == TTAG_head ) #endif has_head = 1; /* * The table length should be 0x36, but certain font tools make it * 0x38, so we will just check that it is greater. * * Note that according to the specification, the table must be * padded to 32-bit lengths, but this doesn't apply to the value of * its `Length' field! * */ if ( table.Length < 0x36 ) { FT_TRACE2(( "check_table_dir:" " `head' or `bhed' table too small\n" )); error = FT_THROW( Table_Missing ); goto Exit; } if ( FT_STREAM_SEEK( table.Offset + 12 ) || FT_READ_ULONG( magic ) ) goto Exit; if ( magic != 0x5F0F3CF5UL ) FT_TRACE2(( "check_table_dir:" " invalid magic number in `head' or `bhed' table\n")); if ( FT_STREAM_SEEK( offset + ( nn + 1 ) * 16 ) ) goto Exit; } else if ( table.Tag == TTAG_SING ) has_sing = 1; else if ( table.Tag == TTAG_META ) has_meta = 1; } sfnt->num_tables = valid_entries; if ( sfnt->num_tables == 0 ) { FT_TRACE2(( "check_table_dir: no tables found\n" )); error = FT_THROW( Unknown_File_Format ); goto Exit; } /* if `sing' and `meta' tables are present, there is no `head' table */ if ( has_head || ( has_sing && has_meta ) ) { error = FT_Err_Ok; goto Exit; } else { FT_TRACE2(( "check_table_dir:" )); #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS FT_TRACE2(( " neither `head', `bhed', nor `sing' table found\n" )); #else FT_TRACE2(( " neither `head' nor `sing' table found\n" )); #endif error = FT_THROW( Table_Missing ); } Exit: return error; } static FT_Error new_memory_stream( FT_Library library, FT_Byte* base, FT_ULong size, FT_Stream_CloseFunc close, FT_Stream *astream ) { FT_Error error; FT_Memory memory; FT_Stream stream = NULL; if ( !library ) return FT_THROW( Invalid_Library_Handle ); if ( !base ) return FT_THROW( Invalid_Argument ); *astream = 0; memory = library->memory; if ( FT_NEW( stream ) ) goto Exit; FT_Stream_OpenMemory( stream, base, size ); stream->close = close; *astream = stream; Exit: return error; } static void memory_stream_close( FT_Stream stream ) { FT_Memory memory = stream->memory; FT_FREE( stream->base ); stream->size = 0; stream->base = 0; stream->close = 0; } FT_EXPORT_DEF( FT_Module ) FT_Get_Module( FT_Library library, const char* module_name ) { FT_Module result = 0; FT_Module* cur; FT_Module* limit; if ( !library || !module_name ) return result; cur = library->modules; limit = cur + library->num_modules; for ( ; cur < limit; cur++ ) if ( ft_strcmp( cur[0]->clazz->module_name, module_name ) == 0 ) { result = cur[0]; break; } return result; } FT_BASE_DEF( const void* ) FT_Get_Module_Interface( FT_Library library, const char* mod_name ) { FT_Module module; /* test for valid `library' delayed to FT_Get_Module() */ module = FT_Get_Module( library, mod_name ); return module ? module->clazz->module_interface : 0; } FT_LOCAL_DEF( FT_Error ) open_face_from_buffer( FT_Library library, FT_Byte* base, FT_ULong size, FT_Long face_index, const char* driver_name, FT_Face *aface ) { FT_Open_Args args; FT_Error error; FT_Stream stream = NULL; FT_Memory memory = library->memory; error = new_memory_stream( library, base, size, memory_stream_close, &stream ); if ( error ) { FT_FREE( base ); return error; } args.flags = FT_OPEN_STREAM; args.stream = stream; if ( driver_name ) { args.flags = args.flags | FT_OPEN_DRIVER; 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; } FT_BASE_DEF( FT_Error ) FT_Raccess_Get_HeaderInfo( FT_Library library, FT_Stream stream, FT_Long rfork_offset, FT_Long *map_offset, FT_Long *rdata_pos ) { FT_Error error; unsigned char head[16], head2[16]; FT_Long map_pos, rdata_len; int allzeros, allmatch, i; FT_Long type_list; FT_UNUSED( library ); error = FT_Stream_Seek( stream, rfork_offset ); if ( error ) return error; error = FT_Stream_Read( stream, (FT_Byte *)head, 16 ); if ( error ) return error; *rdata_pos = rfork_offset + ( ( head[0] << 24 ) | ( head[1] << 16 ) | ( head[2] << 8 ) | head[3] ); map_pos = rfork_offset + ( ( head[4] << 24 ) | ( head[5] << 16 ) | ( head[6] << 8 ) | head[7] ); rdata_len = ( head[ 8] << 24 ) | ( head[ 9] << 16 ) | ( head[10] << 8 ) | head[11]; /* map_len = head[12] .. head[15] */ if ( *rdata_pos + rdata_len != map_pos || map_pos == rfork_offset ) return FT_THROW( Unknown_File_Format ); error = FT_Stream_Seek( stream, map_pos ); if ( error ) return error; head2[15] = (FT_Byte)( head[15] + 1 ); /* make it be different */ error = FT_Stream_Read( stream, (FT_Byte*)head2, 16 ); if ( error ) return error; allzeros = 1; allmatch = 1; for ( i = 0; i < 16; ++i ) { if ( head2[i] != 0 ) allzeros = 0; if ( head2[i] != head[i] ) allmatch = 0; } if ( !allzeros && !allmatch ) return FT_THROW( Unknown_File_Format ); /* If we have reached this point then it is probably a mac resource */ /* file. Now, does it contain any interesting resources? */ /* Skip handle to next resource map, the file resource number, and */ /* attributes. */ (void)FT_STREAM_SKIP( 4 /* skip handle to next resource map */ + 2 /* skip file resource number */ + 2 ); /* skip attributes */ if ( FT_READ_USHORT( type_list ) ) return error; if ( type_list == -1 ) return FT_THROW( Unknown_File_Format ); error = FT_Stream_Seek( stream, map_pos + type_list ); if ( error ) return error; *map_offset = map_pos + type_list; return FT_Err_Ok; } #define FT_RACCESS_N_RULES 9 typedef struct FT_RFork_Ref_ { FT_UShort res_id; FT_ULong offset; } FT_RFork_Ref; static int ft_raccess_sort_ref_by_id( FT_RFork_Ref* a, FT_RFork_Ref* b ) { if ( a->res_id < b->res_id ) return -1; else if ( a->res_id > b->res_id ) return 1; else return 0; } FT_BASE_DEF( FT_Error ) FT_Raccess_Get_DataOffsets( FT_Library library, FT_Stream stream, FT_Long map_offset, FT_Long rdata_pos, FT_Long tag, FT_Bool sort_by_res_id, FT_Long **offsets, FT_Long *count ) { FT_Error error; int i, j, cnt, subcnt; FT_Long tag_internal, rpos; FT_Memory memory = library->memory; FT_Long temp; FT_Long *offsets_internal = NULL; FT_RFork_Ref *ref = NULL; FT_TRACE3(( "\n" )); error = FT_Stream_Seek( stream, map_offset ); if ( error ) return error; if ( FT_READ_USHORT( cnt ) ) return error; cnt++; for ( i = 0; i < cnt; ++i ) { if ( FT_READ_LONG( tag_internal ) || FT_READ_USHORT( subcnt ) || FT_READ_USHORT( rpos ) ) return error; FT_TRACE2(( "Resource tags: %c%c%c%c\n", (char)( 0xff & ( tag_internal >> 24 ) ), (char)( 0xff & ( tag_internal >> 16 ) ), (char)( 0xff & ( tag_internal >> 8 ) ), (char)( 0xff & ( tag_internal >> 0 ) ) )); FT_TRACE3(( " : subcount=%d, suboffset=0x%04x\n", subcnt, rpos )); if ( tag_internal == tag ) { *count = subcnt + 1; rpos += map_offset; error = FT_Stream_Seek( stream, rpos ); if ( error ) return error; if ( FT_NEW_ARRAY( ref, *count ) ) return error; for ( j = 0; j < *count; ++j ) { if ( FT_READ_USHORT( ref[j].res_id ) ) goto Exit; if ( FT_STREAM_SKIP( 2 ) ) /* resource name */ goto Exit; if ( FT_READ_LONG( temp ) ) goto Exit; if ( FT_STREAM_SKIP( 4 ) ) /* mbz */ goto Exit; ref[j].offset = temp & 0xFFFFFFL; FT_TRACE3(( " [%d]:" " resource_id=0x%04x, offset=0x%08x\n", j, ref[j].res_id, ref[j].offset )); } if (sort_by_res_id) { ft_qsort( ref, *count, sizeof ( FT_RFork_Ref ), ( int(*)(const void*, const void*) ) ft_raccess_sort_ref_by_id ); FT_TRACE3(( " -- sort resources by their ids --\n" )); for ( j = 0; j < *count; ++ j ) { FT_TRACE3(( " [%d]:" " resource_id=0x%04x, offset=0x%08x\n", j, ref[j].res_id, ref[j].offset )); } } if ( FT_NEW_ARRAY( offsets_internal, *count ) ) goto Exit; /* XXX: duplicated reference ID, * gap between reference IDs are acceptable? * further investigation on Apple implementation is needed. */ for ( j = 0; j < *count; ++j ) offsets_internal[j] = rdata_pos + ref[j].offset; *offsets = offsets_internal; error = FT_Err_Ok; Exit: FT_FREE( ref ); return error; } } return FT_THROW( Cannot_Open_Resource ); } 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 = NULL; 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, FT_MIN( face_index, 0 ), is_sfnt_cid ? "cid" : "type1", aface ); Exit: { FT_Error error1; if ( FT_ERR_EQ( error, Unknown_File_Format ) ) { error1 = FT_Stream_Seek( stream, pos ); if ( error1 ) return error1; } return error; } } static FT_Error Mac_Read_sfnt_Resource( FT_Library library, FT_Stream stream, FT_Long *offsets, FT_Long resource_cnt, FT_Long face_index, FT_Face *aface ) { FT_Memory memory = library->memory; FT_Byte* sfnt_data = NULL; FT_Error error; FT_Long flag_offset; FT_Long rlen; int is_cff; FT_Long face_index_in_resource = 0; if ( face_index == -1 ) face_index = 0; if ( face_index >= resource_cnt ) return FT_THROW( Cannot_Open_Resource ); flag_offset = offsets[face_index]; error = FT_Stream_Seek( stream, flag_offset ); if ( error ) goto Exit; if ( FT_READ_LONG( rlen ) ) goto Exit; if ( rlen == -1 ) return FT_THROW( 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 && !ft_memcmp( sfnt_data, "OTTO", 4 ); error = open_face_from_buffer( library, sfnt_data, rlen, face_index_in_resource, is_cff ? "cff" : "truetype", aface ); Exit: return error; } static FT_Error Mac_Read_POST_Resource( FT_Library library, FT_Stream stream, FT_Long *offsets, FT_Long resource_cnt, FT_Long face_index, FT_Face *aface ) { FT_Error error = FT_ERR( Cannot_Open_Resource ); FT_Memory memory = library->memory; FT_Byte* pfb_data = NULL; int i, type, flags; FT_Long len; FT_Long pfb_len, pfb_pos, pfb_lenpos; FT_Long rlen, temp; if ( face_index == -1 ) face_index = 0; if ( face_index != 0 ) return error; /* Find the length of all the POST resources, concatenated. Assume */ /* worst case (each resource in its own section). */ pfb_len = 0; for ( i = 0; i < resource_cnt; ++i ) { error = FT_Stream_Seek( stream, offsets[i] ); if ( error ) goto Exit; if ( FT_READ_LONG( temp ) ) goto Exit; pfb_len += temp + 6; } if ( FT_ALLOC( pfb_data, (FT_Long)pfb_len + 2 ) ) goto Exit; pfb_data[0] = 0x80; pfb_data[1] = 1; /* Ascii section */ pfb_data[2] = 0; /* 4-byte length, fill in later */ pfb_data[3] = 0; pfb_data[4] = 0; pfb_data[5] = 0; pfb_pos = 6; pfb_lenpos = 2; len = 0; type = 1; for ( i = 0; i < resource_cnt; ++i ) { error = FT_Stream_Seek( stream, offsets[i] ); if ( error ) goto Exit2; if ( FT_READ_LONG( rlen ) ) goto Exit; if ( FT_READ_USHORT( flags ) ) goto Exit; 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 ); pfb_data[pfb_lenpos + 3] = (FT_Byte)( len >> 24 ); 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; len = rlen; pfb_data[pfb_pos++] = (FT_Byte)type; pfb_lenpos = pfb_pos; pfb_data[pfb_pos++] = 0; /* 4-byte length, fill in later */ pfb_data[pfb_pos++] = 0; pfb_data[pfb_pos++] = 0; 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 ); pfb_data[pfb_lenpos + 3] = (FT_Byte)( len >> 24 ); return open_face_from_buffer( library, pfb_data, pfb_pos, face_index, "type1", aface ); Exit2: FT_FREE( pfb_data ); Exit: return error; } static FT_Error IsMacResource( FT_Library library, FT_Stream stream, FT_Long resource_offset, FT_Long face_index, FT_Face *aface ) { FT_Memory memory = library->memory; FT_Error error; FT_Long map_offset, rdara_pos; FT_Long *data_offsets; FT_Long count; error = FT_Raccess_Get_HeaderInfo( library, stream, resource_offset, &map_offset, &rdara_pos ); if ( error ) return error; /* POST resources must be sorted to concatenate properly */ error = FT_Raccess_Get_DataOffsets( library, stream, map_offset, rdara_pos, TTAG_POST, TRUE, &data_offsets, &count ); if ( !error ) { error = Mac_Read_POST_Resource( library, stream, data_offsets, count, face_index, aface ); FT_FREE( data_offsets ); /* POST exists in an LWFN providing a single face */ if ( !error ) (*aface)->num_faces = 1; return error; } /* sfnt resources should not be sorted to preserve the face order by QuickDraw API */ error = FT_Raccess_Get_DataOffsets( library, stream, map_offset, rdara_pos, TTAG_sfnt, FALSE, &data_offsets, &count ); if ( !error ) { FT_Long face_index_internal = face_index % count; error = Mac_Read_sfnt_Resource( library, stream, data_offsets, count, face_index_internal, aface ); FT_FREE( data_offsets ); if ( !error ) (*aface)->num_faces = count; } return error; } static FT_Error IsMacBinary( FT_Library library, FT_Stream stream, FT_Long face_index, FT_Face *aface ) { unsigned char header[128]; FT_Error error; FT_Long dlen, offset; if ( NULL == stream ) return FT_THROW( Invalid_Stream_Operation ); error = FT_Stream_Seek( stream, 0 ); if ( error ) goto Exit; error = FT_Stream_Read( stream, (FT_Byte*)header, 128 ); if ( error ) goto Exit; if ( header[ 0] != 0 || header[74] != 0 || header[82] != 0 || header[ 1] == 0 || header[ 1] > 33 || header[63] != 0 || header[2 + header[1]] != 0 ) return FT_THROW( Unknown_File_Format ); dlen = ( header[0x53] << 24 ) | ( header[0x54] << 16 ) | ( header[0x55] << 8 ) | header[0x56]; #if 0 rlen = ( header[0x57] << 24 ) | ( header[0x58] << 16 ) | ( header[0x59] << 8 ) | header[0x5a]; #endif /* 0 */ offset = 128 + ( ( dlen + 127 ) & ~127 ); return IsMacResource( library, stream, offset, face_index, aface ); Exit: return error; } #ifndef FT_CONFIG_OPTION_PIC #define FT_OUTLINE_GLYPH_CLASS_GET &ft_outline_glyph_class #define FT_BITMAP_GLYPH_CLASS_GET &ft_bitmap_glyph_class #define FT_DEFAULT_MODULES_GET ft_default_modules #ifdef FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK #define FT_RACCESS_GUESS_TABLE_GET ft_raccess_guess_table #endif #endif #ifndef FT_CONFIG_OPTION_PIC /* this array is a storage in non-PIC mode, so ; is needed in END */ #define CONST_FT_RFORK_RULE_ARRAY_BEGIN( name, type ) \ const type name[] = { #define CONST_FT_RFORK_RULE_ARRAY_ENTRY( func_suffix, type_suffix ) \ { raccess_guess_ ## func_suffix, \ FT_RFork_Rule_ ## type_suffix }, #define CONST_FT_RFORK_RULE_ARRAY_END }; #else /* FT_CONFIG_OPTION_PIC */ /* this array is a function in PIC mode, so no ; is needed in END */ #define CONST_FT_RFORK_RULE_ARRAY_BEGIN( name, type ) \ void \ FT_Init_Table_ ## name( type* storage ) \ { \ type* local = storage; \ \ \ int i = 0; #define CONST_FT_RFORK_RULE_ARRAY_ENTRY( func_suffix, type_suffix ) \ local[i].func = raccess_guess_ ## func_suffix; \ local[i].type = FT_RFork_Rule_ ## type_suffix; \ i++; #define CONST_FT_RFORK_RULE_ARRAY_END } #endif /* FT_CONFIG_OPTION_PIC */ typedef FT_Error (*ft_raccess_guess_func)( FT_Library library, FT_Stream stream, char *base_file_name, char **result_file_name, FT_Long *result_offset ); typedef enum FT_RFork_Rule_ { FT_RFork_Rule_invalid = -2, FT_RFork_Rule_uknown, /* -1 */ FT_RFork_Rule_apple_double, FT_RFork_Rule_apple_single, FT_RFork_Rule_darwin_ufs_export, FT_RFork_Rule_darwin_newvfs, FT_RFork_Rule_darwin_hfsplus, FT_RFork_Rule_vfat, FT_RFork_Rule_linux_cap, FT_RFork_Rule_linux_double, FT_RFork_Rule_linux_netatalk } FT_RFork_Rule; /* For fast translation between rule index and rule type, * the macros FT_RFORK_xxx should be kept consistent with * the raccess_guess_funcs table */ typedef struct ft_raccess_guess_rec_ { ft_raccess_guess_func func; FT_RFork_Rule type; } ft_raccess_guess_rec; static FT_Error raccess_guess_apple_generic( FT_Library library, FT_Stream stream, char *base_file_name, FT_Int32 magic, FT_Long *result_offset ) { FT_Int32 magic_from_stream; FT_Error error; FT_Int32 version_number = 0; FT_UShort n_of_entries; int i; FT_UInt32 entry_id, entry_offset, entry_length = 0; const FT_UInt32 resource_fork_entry_id = 0x2; FT_UNUSED( library ); FT_UNUSED( base_file_name ); FT_UNUSED( version_number ); FT_UNUSED( entry_length ); if ( FT_READ_LONG( magic_from_stream ) ) return error; if ( magic_from_stream != magic ) return FT_THROW( Unknown_File_Format ); if ( FT_READ_LONG( version_number ) ) return error; /* filler */ error = FT_Stream_Skip( stream, 16 ); if ( error ) return error; if ( FT_READ_USHORT( n_of_entries ) ) return error; if ( n_of_entries == 0 ) return FT_THROW( Unknown_File_Format ); for ( i = 0; i < n_of_entries; i++ ) { if ( FT_READ_LONG( entry_id ) ) return error; if ( entry_id == resource_fork_entry_id ) { if ( FT_READ_LONG( entry_offset ) || FT_READ_LONG( entry_length ) ) continue; *result_offset = entry_offset; return FT_Err_Ok; } else { error = FT_Stream_Skip( stream, 4 + 4 ); /* offset + length */ if ( error ) return error; } } return FT_THROW( Unknown_File_Format ); } static FT_Error raccess_guess_apple_double( FT_Library library, FT_Stream stream, char *base_file_name, char **result_file_name, FT_Long *result_offset ); static FT_Error raccess_guess_linux_double_from_file_name( FT_Library library, char *file_name, FT_Long *result_offset ) { FT_Open_Args args2; FT_Stream stream2; char * nouse = NULL; FT_Error error; args2.flags = FT_OPEN_PATHNAME; args2.pathname = file_name; error = FT_Stream_New( library, &args2, &stream2 ); if ( error ) return error; error = raccess_guess_apple_double( library, stream2, file_name, &nouse, result_offset ); FT_Stream_Free( stream2, 0 ); return error; } static char* raccess_make_file_name( FT_Memory memory, const char *original_name, const char *insertion ) { char* new_name = NULL; const char* tmp; const char* slash; size_t new_length; FT_Error error = FT_Err_Ok; FT_UNUSED( error ); new_length = ft_strlen( original_name ) + ft_strlen( insertion ); if ( FT_ALLOC( new_name, new_length + 1 ) ) return NULL; tmp = ft_strrchr( original_name, '/' ); if ( tmp ) { ft_strncpy( new_name, original_name, tmp - original_name + 1 ); new_name[tmp - original_name + 1] = '\0'; slash = tmp + 1; } else { slash = original_name; new_name[0] = '\0'; } ft_strcat( new_name, insertion ); ft_strcat( new_name, slash ); return new_name; } static FT_Error raccess_guess_apple_double( FT_Library library, FT_Stream stream, char *base_file_name, char **result_file_name, FT_Long *result_offset ) { FT_Int32 magic = ( 0x00 << 24 ) | ( 0x05 << 16 ) | ( 0x16 << 8 ) | 0x07; *result_file_name = NULL; if ( NULL == stream ) return FT_THROW( Cannot_Open_Stream ); return raccess_guess_apple_generic( library, stream, base_file_name, magic, result_offset ); } static FT_Error raccess_guess_apple_single( FT_Library library, FT_Stream stream, char *base_file_name, char **result_file_name, FT_Long *result_offset ) { FT_Int32 magic = ( 0x00 << 24 ) | ( 0x05 << 16 ) | ( 0x16 << 8 ) | 0x00; *result_file_name = NULL; if ( NULL == stream ) return FT_THROW( Cannot_Open_Stream ); return raccess_guess_apple_generic( library, stream, base_file_name, magic, result_offset ); } static FT_Error raccess_guess_darwin_ufs_export( FT_Library library, FT_Stream stream, char *base_file_name, char **result_file_name, FT_Long *result_offset ) { char* newpath; FT_Error error; FT_Memory memory; FT_UNUSED( stream ); memory = library->memory; newpath = raccess_make_file_name( memory, base_file_name, "._" ); if ( !newpath ) return FT_THROW( Out_Of_Memory ); error = raccess_guess_linux_double_from_file_name( library, newpath, result_offset ); if ( !error ) *result_file_name = newpath; else FT_FREE( newpath ); return error; } static FT_Error raccess_guess_darwin_hfsplus( FT_Library library, FT_Stream stream, char *base_file_name, char **result_file_name, FT_Long *result_offset ) { /* Only meaningful on systems with hfs+ drivers (or Macs). */ FT_Error error; char* newpath = NULL; FT_Memory memory; FT_Long base_file_len = (FT_Long)ft_strlen( base_file_name ); FT_UNUSED( stream ); memory = library->memory; if ( base_file_len + 6 > FT_INT_MAX ) return FT_THROW( Array_Too_Large ); if ( FT_ALLOC( newpath, base_file_len + 6 ) ) return error; FT_MEM_COPY( newpath, base_file_name, base_file_len ); FT_MEM_COPY( newpath + base_file_len, "/rsrc", 6 ); *result_file_name = newpath; *result_offset = 0; return FT_Err_Ok; } static FT_Error raccess_guess_darwin_newvfs( FT_Library library, FT_Stream stream, char *base_file_name, char **result_file_name, FT_Long *result_offset ) { /* Only meaningful on systems with Mac OS X (> 10.1). */ FT_Error error; char* newpath = NULL; FT_Memory memory; FT_Long base_file_len = (FT_Long)ft_strlen( base_file_name ); FT_UNUSED( stream ); memory = library->memory; if ( base_file_len + 18 > FT_INT_MAX ) return FT_THROW( Array_Too_Large ); if ( FT_ALLOC( newpath, base_file_len + 18 ) ) return error; FT_MEM_COPY( newpath, base_file_name, base_file_len ); FT_MEM_COPY( newpath + base_file_len, "/..namedfork/rsrc", 18 ); *result_file_name = newpath; *result_offset = 0; return FT_Err_Ok; } static FT_Error raccess_guess_vfat( FT_Library library, FT_Stream stream, char *base_file_name, char **result_file_name, FT_Long *result_offset ) { char* newpath; FT_Memory memory; FT_UNUSED( stream ); memory = library->memory; newpath = raccess_make_file_name( memory, base_file_name, "resource.frk/" ); if ( !newpath ) return FT_THROW( Out_Of_Memory ); *result_file_name = newpath; *result_offset = 0; return FT_Err_Ok; } static FT_Error raccess_guess_linux_cap( FT_Library library, FT_Stream stream, char *base_file_name, char **result_file_name, FT_Long *result_offset ) { char* newpath; FT_Memory memory; FT_UNUSED( stream ); memory = library->memory; newpath = raccess_make_file_name( memory, base_file_name, ".resource/" ); if ( !newpath ) return FT_THROW( Out_Of_Memory ); *result_file_name = newpath; *result_offset = 0; return FT_Err_Ok; } static FT_Error raccess_guess_linux_double( FT_Library library, FT_Stream stream, char *base_file_name, char **result_file_name, FT_Long *result_offset ) { char* newpath; FT_Error error; FT_Memory memory; FT_UNUSED( stream ); memory = library->memory; newpath = raccess_make_file_name( memory, base_file_name, "%" ); if ( !newpath ) return FT_THROW( Out_Of_Memory ); error = raccess_guess_linux_double_from_file_name( library, newpath, result_offset ); if ( !error ) *result_file_name = newpath; else FT_FREE( newpath ); return error; } static FT_Error raccess_guess_linux_netatalk( FT_Library library, FT_Stream stream, char *base_file_name, char **result_file_name, FT_Long *result_offset ) { char* newpath; FT_Error error; FT_Memory memory; FT_UNUSED( stream ); memory = library->memory; newpath = raccess_make_file_name( memory, base_file_name, ".AppleDouble/" ); if ( !newpath ) return FT_THROW( Out_Of_Memory ); error = raccess_guess_linux_double_from_file_name( library, newpath, result_offset ); if ( !error ) *result_file_name = newpath; else FT_FREE( newpath ); return error; } CONST_FT_RFORK_RULE_ARRAY_BEGIN(ft_raccess_guess_table, ft_raccess_guess_rec) CONST_FT_RFORK_RULE_ARRAY_ENTRY(apple_double, apple_double) CONST_FT_RFORK_RULE_ARRAY_ENTRY(apple_single, apple_single) CONST_FT_RFORK_RULE_ARRAY_ENTRY(darwin_ufs_export, darwin_ufs_export) CONST_FT_RFORK_RULE_ARRAY_ENTRY(darwin_newvfs, darwin_newvfs) CONST_FT_RFORK_RULE_ARRAY_ENTRY(darwin_hfsplus, darwin_hfsplus) CONST_FT_RFORK_RULE_ARRAY_ENTRY(vfat, vfat) CONST_FT_RFORK_RULE_ARRAY_ENTRY(linux_cap, linux_cap) CONST_FT_RFORK_RULE_ARRAY_ENTRY(linux_double, linux_double) CONST_FT_RFORK_RULE_ARRAY_ENTRY(linux_netatalk, linux_netatalk) CONST_FT_RFORK_RULE_ARRAY_END FT_BASE_DEF( void ) FT_Raccess_Guess( FT_Library library, FT_Stream stream, char* base_name, char **new_names, FT_Long *offsets, FT_Error *errors ) { FT_Int i; for ( i = 0; i < FT_RACCESS_N_RULES; i++ ) { new_names[i] = NULL; if ( NULL != stream ) errors[i] = FT_Stream_Seek( stream, 0 ); else errors[i] = FT_Err_Ok; if ( errors[i] ) continue ; errors[i] = (FT_RACCESS_GUESS_TABLE_GET[i].func)( library, stream, base_name, &(new_names[i]), &(offsets[i]) ); } return; } #ifndef FT_MACINTOSH static FT_RFork_Rule raccess_get_rule_type_from_rule_index( FT_Library library, FT_UInt rule_index ) { FT_UNUSED( library ); if ( rule_index >= FT_RACCESS_N_RULES ) return FT_RFork_Rule_invalid; return FT_RACCESS_GUESS_TABLE_GET[rule_index].type; } /* * For this function, refer ftbase.h. */ FT_LOCAL_DEF( FT_Bool ) ft_raccess_rule_by_darwin_vfs( FT_Library library, FT_UInt rule_index ) { switch( raccess_get_rule_type_from_rule_index( library, rule_index ) ) { case FT_RFork_Rule_darwin_newvfs: case FT_RFork_Rule_darwin_hfsplus: return TRUE; default: return FALSE; } } #endif static FT_Error load_face_in_embedded_rfork( FT_Library library, FT_Stream stream, FT_Long face_index, FT_Face *aface, const FT_Open_Args *args ) { #undef FT_COMPONENT #define FT_COMPONENT trace_raccess FT_Memory memory = library->memory; FT_Error error = FT_ERR( Unknown_File_Format ); int i; 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 = 0; FT_Raccess_Guess( library, stream, args->pathname, file_names, offsets, errors ); for ( i = 0; i < FT_RACCESS_N_RULES; i++ ) { is_darwin_vfs = ft_raccess_rule_by_darwin_vfs( library, 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 )); continue; } args2.flags = FT_OPEN_PATHNAME; args2.pathname = file_names[i] ? file_names[i] : args->pathname; FT_TRACE3(( "Try rule %d: %s (offset=%d) ...", i, args2.pathname, offsets[i] )); error = FT_Stream_New( library, &args2, &stream2 ); if ( is_darwin_vfs && FT_ERR_EQ( error, Cannot_Open_Stream ) ) vfs_rfork_has_no_font = TRUE; if ( error ) { FT_TRACE3(( "failed\n" )); continue; } error = IsMacResource( library, stream2, offsets[i], face_index, aface ); FT_Stream_Free( stream2, 0 ); FT_TRACE3(( "%s\n", error ? "failed": "successful" )); if ( !error ) break; else if ( is_darwin_vfs ) vfs_rfork_has_no_font = TRUE; } for (i = 0; i < FT_RACCESS_N_RULES; i++) { if ( file_names[i] ) FT_FREE( file_names[i] ); } /* Caller (load_mac_face) requires FT_Err_Unknown_File_Format. */ if ( error ) error = FT_ERR( Unknown_File_Format ); return error; #undef FT_COMPONENT #define FT_COMPONENT trace_objs } static FT_Error load_mac_face( FT_Library library, FT_Stream stream, FT_Long face_index, FT_Face *aface, const FT_Open_Args *args ) { FT_Error error; FT_UNUSED( args ); error = IsMacBinary( library, stream, face_index, aface ); if ( FT_ERR_EQ( error, Unknown_File_Format ) ) { #undef FT_COMPONENT #define FT_COMPONENT trace_raccess FT_TRACE3(( "Try as dfont: %s ...", args->pathname )); error = IsMacResource( library, stream, 0, face_index, aface ); FT_TRACE3(( "%s\n", error ? "failed" : "successful" )); #undef FT_COMPONENT #define FT_COMPONENT trace_objs } if ( ( FT_ERR_EQ( error, Unknown_File_Format ) || FT_ERR_EQ( error, Invalid_Stream_Operation ) ) && ( args->flags & FT_OPEN_PATHNAME ) ) error = load_face_in_embedded_rfork( library, stream, face_index, aface, args ); return error; } typedef FT_GlyphSlot TT_GlyphSlot; #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS static FT_Error load_sbit_image( TT_Size size, TT_GlyphSlot glyph, FT_UInt glyph_index, FT_Int32 load_flags ) { TT_Face face; SFNT_Service sfnt; FT_Stream stream; FT_Error error; TT_SBit_MetricsRec metrics; face = (TT_Face)glyph->face; sfnt = (SFNT_Service)face->sfnt; stream = face->root.stream; error = sfnt->load_sbit_image( face, size->strike_index, glyph_index, (FT_Int)load_flags, stream, &glyph->bitmap, &metrics ); if ( !error ) { glyph->outline.n_points = 0; glyph->outline.n_contours = 0; glyph->metrics.width = (FT_Pos)metrics.width << 6; glyph->metrics.height = (FT_Pos)metrics.height << 6; glyph->metrics.horiBearingX = (FT_Pos)metrics.horiBearingX << 6; glyph->metrics.horiBearingY = (FT_Pos)metrics.horiBearingY << 6; glyph->metrics.horiAdvance = (FT_Pos)metrics.horiAdvance << 6; glyph->metrics.vertBearingX = (FT_Pos)metrics.vertBearingX << 6; glyph->metrics.vertBearingY = (FT_Pos)metrics.vertBearingY << 6; glyph->metrics.vertAdvance = (FT_Pos)metrics.vertAdvance << 6; glyph->format = FT_GLYPH_FORMAT_BITMAP; if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) { glyph->bitmap_left = metrics.vertBearingX; glyph->bitmap_top = metrics.vertBearingY; } else { glyph->bitmap_left = metrics.horiBearingX; glyph->bitmap_top = metrics.horiBearingY; } } return error; } #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ static FT_Error open_face( FT_Driver driver, FT_Stream *astream, FT_Bool external_stream, FT_Long face_index, FT_Int num_params, FT_Parameter* params, FT_Face *aface ) { FT_Memory memory; FT_Driver_Class clazz; FT_Face face = NULL; FT_Face_Internal internal = NULL; FT_Error error, error2; clazz = driver->clazz; memory = driver->root.memory; /* allocate the face object and perform basic initialization */ if ( FT_ALLOC( face, clazz->face_object_size ) ) goto Fail; face->driver = driver; face->memory = memory; face->stream = *astream; /* set the FT_FACE_FLAG_EXTERNAL_STREAM bit for FT_Done_Face */ if ( external_stream ) face->face_flags |= FT_FACE_FLAG_EXTERNAL_STREAM; if ( FT_NEW( internal ) ) goto Fail; face->internal = internal; #ifdef FT_CONFIG_OPTION_INCREMENTAL { int i; face->internal->incremental_interface = 0; for ( i = 0; i < num_params && !face->internal->incremental_interface; i++ ) if ( params[i].tag == FT_PARAM_TAG_INCREMENTAL ) face->internal->incremental_interface = (FT_Incremental_Interface)params[i].data; } #endif if ( clazz->init_face ) error = clazz->init_face( *astream, face, (FT_Int)face_index, num_params, params ); *astream = face->stream; /* Stream may have been changed. */ if ( error ) goto Fail; /* select Unicode charmap by default */ error2 = find_unicode_charmap( face ); /* if no Unicode charmap can be found, FT_Err_Invalid_CharMap_Handle */ /* is returned. */ /* no error should happen, but we want to play safe */ if ( error2 && FT_ERR_NEQ( error2, Invalid_CharMap_Handle ) ) { error = error2; goto Fail; } *aface = face; Fail: if ( error ) { destroy_charmaps( face, memory ); if ( clazz->done_face ) clazz->done_face( face ); FT_FREE( internal ); FT_FREE( face ); *aface = 0; } return error; } extern "C" FT_Error FT_Open_Face(FT_Library library, const FT_Open_Args* args, FT_Long face_index, FT_Face* aface) { FT_Error error; FT_Driver driver = NULL; FT_Memory memory = NULL; 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 */ /* FT_Stream_New() */ if ( ( !aface && face_index >= 0 ) || !args ) return FT_THROW( Invalid_Argument ); external_stream = FT_BOOL( ( args->flags & FT_OPEN_STREAM ) && args->stream ); /* create input stream */ error = FT_Stream_New( library, args, &stream ); if ( error ) goto Fail3; memory = library->memory; /* If the font driver is specified in the `args' structure, use */ /* it. Otherwise, we scan the list of registered drivers. */ if ( ( args->flags & FT_OPEN_DRIVER ) && args->driver ) { driver = FT_DRIVER( args->driver ); /* not all modules are drivers, so check... */ if ( FT_MODULE_IS_DRIVER( driver ) ) { FT_Int num_params = 0; FT_Parameter* params = 0; if ( args->flags & FT_OPEN_PARAMS ) { num_params = args->num_params; params = args->params; } error = open_face( driver, &stream, external_stream, face_index, num_params, params, &face ); if ( !error ) goto Success; } else error = FT_THROW( Invalid_Handle ); FT_Stream_Free( stream, external_stream ); goto Fail; } else { error = FT_ERR( Missing_Module ); /* check each font driver for an appropriate format */ cur = library->modules; limit = cur + library->num_modules; for ( ; cur < limit; cur++ ) { /* not all modules are font drivers, so check... */ if ( FT_MODULE_IS_DRIVER( cur[0] ) ) { FT_Int num_params = 0; FT_Parameter* params = 0; driver = FT_DRIVER( cur[0] ); if ( args->flags & FT_OPEN_PARAMS ) { num_params = args->num_params; params = args->params; } error = open_face( driver, &stream, external_stream, face_index, num_params, params, &face ); if ( !error ) goto Success; #ifdef FT_CONFIG_OPTION_MAC_FONTS if ( ft_strcmp( cur[0]->clazz->module_name, "truetype" ) == 0 && FT_ERR_EQ( error, 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_ERR_NEQ( error, Unknown_File_Format ) ) goto Fail3; } } 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_ERR_NEQ( error, Cannot_Open_Stream ) && FT_ERR_NEQ( error, Unknown_File_Format ) && FT_ERR_NEQ( error, Invalid_Stream_Operation ) ) goto Fail2; #if !defined( FT_MACINTOSH ) && defined( FT_CONFIG_OPTION_MAC_FONTS ) error = load_mac_face( library, stream, face_index, aface, args ); if ( !error ) { /* We don't want to go to Success here. We've already done that. */ /* On the other hand, if we succeeded we still need to close this */ /* stream (we opened a different stream which extracted the */ /* interesting information out of this stream here. That stream */ /* will still be open and the face will point to it). */ FT_Stream_Free( stream, external_stream ); return error; } if ( FT_ERR_NEQ( error, Unknown_File_Format ) ) goto Fail2; #endif /* !FT_MACINTOSH && FT_CONFIG_OPTION_MAC_FONTS */ /* no driver is able to handle this format */ error = FT_THROW( Unknown_File_Format ); Fail2: FT_Stream_Free( stream, external_stream ); goto Fail; } Success: FT_TRACE4(( "FT_Open_Face: New face object, adding to list\n" )); /* add the face object to its driver's list */ if ( FT_NEW( node ) ) goto Fail; node->data = face; /* don't assume driver is the same as face->driver, so use */ /* face->driver instead. */ FT_List_Add( &face->driver->faces_list, node ); /* now allocate a glyph slot object for the face */ FT_TRACE4(( "FT_Open_Face: Creating glyph slot\n" )); if ( face_index >= 0 ) { error = FT_New_GlyphSlot( face, NULL ); if ( error ) goto Fail; /* finally, allocate a size object for the face */ { FT_Size size; FT_TRACE4(( "FT_Open_Face: Creating size object\n" )); error = FT_New_Size( face, &size ); if ( error ) goto Fail; face->size = size; } } /* some checks */ if ( FT_IS_SCALABLE( face ) ) { if ( face->height < 0 ) face->height = (FT_Short)-face->height; if ( !FT_HAS_VERTICAL( face ) ) face->max_advance_height = (FT_Short)face->height; } if ( FT_HAS_FIXED_SIZES( face ) ) { FT_Int i; for ( i = 0; i < face->num_fixed_sizes; i++ ) { FT_Bitmap_Size* bsize = face->available_sizes + i; if ( bsize->height < 0 ) bsize->height = (FT_Short)-bsize->height; if ( bsize->x_ppem < 0 ) bsize->x_ppem = (FT_Short)-bsize->x_ppem; if ( bsize->y_ppem < 0 ) bsize->y_ppem = -bsize->y_ppem; } } /* initialize internal face data */ { FT_Face_Internal internal = face->internal; internal->transform_matrix.xx = 0x10000L; internal->transform_matrix.xy = 0; internal->transform_matrix.yx = 0; internal->transform_matrix.yy = 0x10000L; internal->transform_delta.x = 0; internal->transform_delta.y = 0; internal->refcount = 1; } if ( aface ) *aface = face; else FT_Done_Face( face ); goto Exit; Fail: if ( node ) FT_Done_Face( face ); /* face must be in the driver's list */ else if ( face ) destroy_face( memory, face, driver ); Exit: FT_TRACE4(( "FT_Open_Face: Return %d\n", error )); return error; } extern "C" FT_Error FT_Done_Face(FT_Face face) { FT_Error error; FT_Driver driver; FT_Memory memory; FT_ListNode node; error = FT_ERR( Invalid_Face_Handle ); if ( face && face->driver ) { face->internal->refcount--; if ( face->internal->refcount > 0 ) error = FT_Err_Ok; else { driver = face->driver; memory = driver->root.memory; /* 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; } extern "C" FT_Error FT_Select_Size(FT_Face face, FT_Int strike_index) { FT_Driver_Class clazz; if ( !face || !FT_HAS_FIXED_SIZES( face ) ) return FT_THROW( Invalid_Face_Handle ); if ( strike_index < 0 || strike_index >= face->num_fixed_sizes ) return FT_THROW( Invalid_Argument ); clazz = face->driver->clazz; if ( clazz->select_size ) { FT_Error error; error = clazz->select_size( face->size, (FT_ULong)strike_index ); #ifdef FT_DEBUG_LEVEL_TRACE { FT_Size_Metrics* metrics = &face->size->metrics; FT_TRACE5(( "FT_Select_Size (font driver's `select_size'):\n" )); FT_TRACE5(( " x scale: %d (%f)\n", metrics->x_scale, metrics->x_scale / 65536.0 )); FT_TRACE5(( " y scale: %d (%f)\n", metrics->y_scale, metrics->y_scale / 65536.0 )); FT_TRACE5(( " ascender: %f\n", metrics->ascender / 64.0 )); FT_TRACE5(( " descender: %f\n", metrics->descender / 64.0 )); FT_TRACE5(( " height: %f\n", metrics->height / 64.0 )); FT_TRACE5(( " max advance: %f\n", metrics->max_advance / 64.0 )); FT_TRACE5(( " x ppem: %d\n", metrics->x_ppem )); FT_TRACE5(( " y ppem: %d\n", metrics->y_ppem )); } #endif return error; } FT_Select_Metrics( face, (FT_ULong)strike_index ); return FT_Err_Ok; } FT_BASE_DEF( void ) FT_Request_Metrics( FT_Face face, FT_Size_Request req ) { FT_Size_Metrics* metrics; metrics = &face->size->metrics; if ( FT_IS_SCALABLE( face ) ) { FT_Long w = 0, h = 0, scaled_w = 0, scaled_h = 0; switch ( req->type ) { case FT_SIZE_REQUEST_TYPE_NOMINAL: w = h = face->units_per_EM; break; case FT_SIZE_REQUEST_TYPE_REAL_DIM: w = h = face->ascender - face->descender; break; case FT_SIZE_REQUEST_TYPE_BBOX: w = face->bbox.xMax - face->bbox.xMin; h = face->bbox.yMax - face->bbox.yMin; break; case FT_SIZE_REQUEST_TYPE_CELL: w = face->max_advance_width; h = face->ascender - face->descender; break; case FT_SIZE_REQUEST_TYPE_SCALES: metrics->x_scale = (FT_Fixed)req->width; metrics->y_scale = (FT_Fixed)req->height; if ( !metrics->x_scale ) metrics->x_scale = metrics->y_scale; else if ( !metrics->y_scale ) metrics->y_scale = metrics->x_scale; goto Calculate_Ppem; case FT_SIZE_REQUEST_TYPE_MAX: break; } /* to be on the safe side */ if ( w < 0 ) w = -w; if ( h < 0 ) h = -h; scaled_w = FT_REQUEST_WIDTH ( req ); scaled_h = FT_REQUEST_HEIGHT( req ); /* determine scales */ if ( req->width ) { metrics->x_scale = FT_DivFix( scaled_w, w ); if ( req->height ) { metrics->y_scale = FT_DivFix( scaled_h, h ); if ( req->type == FT_SIZE_REQUEST_TYPE_CELL ) { if ( metrics->y_scale > metrics->x_scale ) metrics->y_scale = metrics->x_scale; else metrics->x_scale = metrics->y_scale; } } else { metrics->y_scale = metrics->x_scale; scaled_h = FT_MulDiv( scaled_w, h, w ); } } else { metrics->x_scale = metrics->y_scale = FT_DivFix( scaled_h, h ); scaled_w = FT_MulDiv( scaled_h, w, h ); } Calculate_Ppem: /* calculate the ppems */ if ( req->type != FT_SIZE_REQUEST_TYPE_NOMINAL ) { scaled_w = FT_MulFix( face->units_per_EM, metrics->x_scale ); scaled_h = FT_MulFix( face->units_per_EM, metrics->y_scale ); } metrics->x_ppem = (FT_UShort)( ( scaled_w + 32 ) >> 6 ); metrics->y_ppem = (FT_UShort)( ( scaled_h + 32 ) >> 6 ); ft_recompute_scaled_metrics( face, metrics ); } else { FT_ZERO( metrics ); metrics->x_scale = 1L << 16; metrics->y_scale = 1L << 16; } FT_TRACE5(( "FT_Request_Metrics:\n" )); FT_TRACE5(( " x scale: %d (%f)\n", metrics->x_scale, metrics->x_scale / 65536.0 )); FT_TRACE5(( " y scale: %d (%f)\n", metrics->y_scale, metrics->y_scale / 65536.0 )); FT_TRACE5(( " ascender: %f\n", metrics->ascender / 64.0 )); FT_TRACE5(( " descender: %f\n", metrics->descender / 64.0 )); FT_TRACE5(( " height: %f\n", metrics->height / 64.0 )); FT_TRACE5(( " max advance: %f\n", metrics->max_advance / 64.0 )); FT_TRACE5(( " x ppem: %d\n", metrics->x_ppem )); FT_TRACE5(( " y ppem: %d\n", metrics->y_ppem )); } extern "C" FT_Error FT_Request_Size(FT_Face face, FT_Size_Request req) { FT_Driver_Class clazz; FT_ULong strike_index; if ( !face ) return FT_THROW( Invalid_Face_Handle ); if ( !req || req->width < 0 || req->height < 0 || req->type >= FT_SIZE_REQUEST_TYPE_MAX ) return FT_THROW( Invalid_Argument ); clazz = face->driver->clazz; if ( clazz->request_size ) { FT_Error error; error = clazz->request_size( face->size, req ); #ifdef FT_DEBUG_LEVEL_TRACE { FT_Size_Metrics* metrics = &face->size->metrics; FT_TRACE5(( "FT_Request_Size (font driver's `request_size'):\n" )); FT_TRACE5(( " x scale: %d (%f)\n", metrics->x_scale, metrics->x_scale / 65536.0 )); FT_TRACE5(( " y scale: %d (%f)\n", metrics->y_scale, metrics->y_scale / 65536.0 )); FT_TRACE5(( " ascender: %f\n", metrics->ascender / 64.0 )); FT_TRACE5(( " descender: %f\n", metrics->descender / 64.0 )); FT_TRACE5(( " height: %f\n", metrics->height / 64.0 )); FT_TRACE5(( " max advance: %f\n", metrics->max_advance / 64.0 )); FT_TRACE5(( " x ppem: %d\n", metrics->x_ppem )); FT_TRACE5(( " y ppem: %d\n", metrics->y_ppem )); } #endif return error; } /* * The reason that a driver doesn't have `request_size' defined is * either that the scaling here suffices or that the supported formats * are bitmap-only and size matching is not implemented. * * In the latter case, a simple size matching is done. */ if ( !FT_IS_SCALABLE( face ) && FT_HAS_FIXED_SIZES( face ) ) { FT_Error error; error = FT_Match_Size( face, req, 0, &strike_index ); if ( error ) return error; return FT_Select_Size( face, (FT_Int)strike_index ); } FT_Request_Metrics( face, req ); return FT_Err_Ok; } extern "C" FT_Error FT_Set_Char_Size(FT_Face face, FT_F26Dot6 char_width, FT_F26Dot6 char_height, FT_UInt horz_resolution, FT_UInt vert_resolution) { FT_Size_RequestRec req; if ( !char_width ) char_width = char_height; else if ( !char_height ) char_height = char_width; if ( !horz_resolution ) horz_resolution = vert_resolution; else if ( !vert_resolution ) vert_resolution = horz_resolution; if ( char_width < 1 * 64 ) char_width = 1 * 64; if ( char_height < 1 * 64 ) char_height = 1 * 64; if ( !horz_resolution ) horz_resolution = vert_resolution = 72; req.type = FT_SIZE_REQUEST_TYPE_NOMINAL; req.width = char_width; req.height = char_height; req.horiResolution = horz_resolution; req.vertResolution = vert_resolution; return FT_Request_Size( face, &req ); } extern "C" FT_Error FT_Set_Pixel_Sizes(FT_Face face, FT_UInt pixel_width, FT_UInt pixel_height) { FT_Size_RequestRec req; if ( pixel_width == 0 ) pixel_width = pixel_height; else if ( pixel_height == 0 ) pixel_height = pixel_width; if ( pixel_width < 1 ) pixel_width = 1; if ( pixel_height < 1 ) pixel_height = 1; /* use `>=' to avoid potential compiler warning on 16bit platforms */ if ( pixel_width >= 0xFFFFU ) pixel_width = 0xFFFFU; if ( pixel_height >= 0xFFFFU ) pixel_height = 0xFFFFU; req.type = FT_SIZE_REQUEST_TYPE_NOMINAL; req.width = pixel_width << 6; req.height = pixel_height << 6; req.horiResolution = 0; req.vertResolution = 0; return FT_Request_Size( face, &req ); } static void ft_glyphslot_clear( FT_GlyphSlot slot ) { /* free bitmap if needed */ ft_glyphslot_free_bitmap( slot ); /* clear all public fields in the glyph slot */ FT_ZERO( &slot->metrics ); FT_ZERO( &slot->outline ); slot->bitmap.width = 0; slot->bitmap.rows = 0; slot->bitmap.pitch = 0; slot->bitmap.pixel_mode = 0; /* `slot->bitmap.buffer' has been handled by ft_glyphslot_free_bitmap */ slot->bitmap_left = 0; slot->bitmap_top = 0; slot->num_subglyphs = 0; slot->subglyphs = 0; slot->control_data = 0; slot->control_len = 0; slot->other = 0; slot->format = FT_GLYPH_FORMAT_NONE; slot->linearHoriAdvance = 0; slot->linearVertAdvance = 0; slot->lsb_delta = 0; slot->rsb_delta = 0; } typedef struct FT_AutoHinterRec_ *FT_AutoHinter; typedef void (*FT_AutoHinter_GlobalGetFunc)( FT_AutoHinter hinter, FT_Face face, void** global_hints, long* global_len ); typedef void (*FT_AutoHinter_GlobalDoneFunc)( FT_AutoHinter hinter, void* global ); typedef void (*FT_AutoHinter_GlobalResetFunc)( FT_AutoHinter hinter, FT_Face face ); typedef FT_Error (*FT_AutoHinter_GlyphLoadFunc)( FT_AutoHinter hinter, FT_GlyphSlot slot, FT_Size size, FT_UInt glyph_index, FT_Int32 load_flags ); typedef struct FT_AutoHinter_InterfaceRec_ { FT_AutoHinter_GlobalResetFunc reset_face; FT_AutoHinter_GlobalGetFunc get_global_hints; FT_AutoHinter_GlobalDoneFunc done_global_hints; FT_AutoHinter_GlyphLoadFunc load_glyph; } FT_AutoHinter_InterfaceRec, *FT_AutoHinter_Interface; #define FT_IS_TRICKY( face ) ( face->face_flags & FT_FACE_FLAG_TRICKY ) #define FT_IS_SFNT( face ) ( face->face_flags & FT_FACE_FLAG_SFNT ) FT_EXPORT_DEF( FT_Error ) FT_Outline_Check( FT_Outline* outline ) { if ( outline ) { FT_Int n_points = outline->n_points; FT_Int n_contours = outline->n_contours; FT_Int end0, end; FT_Int n; /* empty glyph? */ if ( n_points == 0 && n_contours == 0 ) return 0; /* check point and contour counts */ if ( n_points <= 0 || n_contours <= 0 ) goto Bad; end0 = end = -1; for ( n = 0; n < n_contours; n++ ) { end = outline->contours[n]; /* note that we don't accept empty contours */ if ( end <= end0 || end >= n_points ) goto Bad; end0 = end; } if ( end != n_points - 1 ) goto Bad; /* XXX: check the tags array */ return 0; } Bad: return FT_THROW( Invalid_Argument ); } static FT_Renderer ft_lookup_glyph_renderer( FT_GlyphSlot slot ) { FT_Face face = slot->face; FT_Library library = FT_FACE_LIBRARY( face ); FT_Renderer result = library->cur_renderer; if ( !result || result->glyph_format != slot->format ) result = FT_Lookup_Renderer( library, slot->format, 0 ); return result; } FT_BASE_DEF( FT_Pointer ) ft_service_list_lookup( FT_ServiceDesc service_descriptors, const char* service_id ) { FT_Pointer result = NULL; FT_ServiceDesc desc = service_descriptors; if ( desc && service_id ) { for ( ; desc->serv_id != NULL; desc++ ) { if ( ft_strcmp( desc->serv_id, service_id ) == 0 ) { result = (FT_Pointer)desc->serv_data; break; } } } return result; } FT_EXPORT_DEF( void ) FT_Outline_Transform( const FT_Outline* outline, const FT_Matrix* matrix ) { FT_Vector* vec; FT_Vector* limit; if ( !outline || !matrix ) return; vec = outline->points; limit = vec + outline->n_points; for ( ; vec < limit; vec++ ) FT_Vector_Transform( vec, matrix ); } FT_EXPORT_DEF( void ) FT_Outline_Translate( const FT_Outline* outline, FT_Pos xOffset, FT_Pos yOffset ) { FT_UShort n; FT_Vector* vec; if ( !outline ) return; vec = outline->points; for ( n = 0; n < outline->n_points; n++ ) { vec->x += xOffset; vec->y += yOffset; vec++; } } extern "C" FT_Error FT_Load_Glyph(FT_Face face, FT_UInt glyph_index, FT_Int32 load_flags) { FT_Error error; FT_Driver driver; FT_GlyphSlot slot; FT_Library library; FT_Bool autohint = FALSE; FT_Module hinter; TT_Face ttface = (TT_Face)face; if ( !face || !face->size || !face->glyph ) return FT_THROW( Invalid_Face_Handle ); /* The validity test for `glyph_index' is performed by the */ /* font drivers. */ slot = face->glyph; ft_glyphslot_clear( slot ); driver = face->driver; library = driver->root.library; hinter = library->auto_hinter; /* resolve load flags dependencies */ if ( load_flags & FT_LOAD_NO_RECURSE ) load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_TRANSFORM; if ( load_flags & FT_LOAD_NO_SCALE ) { load_flags |= FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP; load_flags &= ~FT_LOAD_RENDER; } /* * 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 and/or rotations by integer multiples of 90 degrees. * * - 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 or if there isn't * any hinting bytecode in the TrueType/OpenType font. * * - Exception: The font is `tricky' and requires the native hinter to * load properly. */ 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 ) && ( ( load_flags & FT_LOAD_IGNORE_TRANSFORM ) || ( 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 ); /* the check for `num_locations' assures that we actually */ /* test for instructions in a TTF and not in a CFF-based OTF */ /* */ /* since `maxSizeOfInstructions' might be unreliable, we */ /* check the size of the `fpgm' and `prep' tables, too -- */ /* the assumption is that there don't exist real TTFs where */ /* both `fpgm' and `prep' tables are missing */ if ( mode == FT_RENDER_MODE_LIGHT || face->internal->ignore_unpatented_hinter || ( FT_IS_SFNT( face ) && ttface->num_locations && ttface->max_profile.maxSizeOfInstructions == 0 && ttface->font_program_size == 0 && ttface->cvt_program_size == 0 ) ) autohint = TRUE; } } if ( autohint ) { FT_AutoHinter_Interface hinting; /* try to load embedded bitmaps first if available */ /* */ /* XXX: This is really a temporary hack that should disappear */ /* promptly with FreeType 2.1! */ /* */ if ( FT_HAS_FIXED_SIZES( face ) && ( load_flags & FT_LOAD_NO_BITMAP ) == 0 ) { error = driver->clazz->load_glyph( slot, face->size, glyph_index, load_flags | FT_LOAD_SBITS_ONLY ); if ( !error && slot->format == FT_GLYPH_FORMAT_BITMAP ) goto Load_Ok; } { 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_Interface)hinter->clazz->module_interface; error = hinting->load_glyph( (FT_AutoHinter)hinter, slot, face->size, glyph_index, load_flags ); internal->transform_flags = transform_flags; } } else { error = driver->clazz->load_glyph( slot, face->size, glyph_index, load_flags ); if ( error ) goto Exit; if ( slot->format == FT_GLYPH_FORMAT_OUTLINE ) { /* check that the loaded outline is correct */ error = FT_Outline_Check( &slot->outline ); if ( error ) goto Exit; #ifdef GRID_FIT_METRICS if ( !( load_flags & FT_LOAD_NO_HINTING ) ) ft_glyphslot_grid_fit_metrics( slot, FT_BOOL( load_flags & FT_LOAD_VERTICAL_LAYOUT ) ); #endif } } Load_Ok: /* compute the advance */ if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) { slot->advance.x = 0; slot->advance.y = slot->metrics.vertAdvance; } else { slot->advance.x = slot->metrics.horiAdvance; slot->advance.y = 0; } /* compute the linear advance in 16.16 pixels */ if ( ( load_flags & FT_LOAD_LINEAR_DESIGN ) == 0 && ( FT_IS_SCALABLE( face ) ) ) { FT_Size_Metrics* metrics = &face->size->metrics; /* it's tricky! */ slot->linearHoriAdvance = FT_MulDiv( slot->linearHoriAdvance, metrics->x_scale, 64 ); slot->linearVertAdvance = FT_MulDiv( slot->linearVertAdvance, metrics->y_scale, 64 ); } if ( ( load_flags & FT_LOAD_IGNORE_TRANSFORM ) == 0 ) { FT_Face_Internal internal = face->internal; /* now, transform the glyph image if needed */ if ( internal->transform_flags ) { /* get renderer */ FT_Renderer renderer = ft_lookup_glyph_renderer( slot ); if ( renderer ) error = renderer->clazz->transform_glyph( 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_flags & 1 ) FT_Outline_Transform( &slot->outline, &internal->transform_matrix ); if ( internal->transform_flags & 2 ) 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 && slot->format != FT_GLYPH_FORMAT_COMPOSITE && load_flags & FT_LOAD_RENDER ) { FT_Render_Mode mode = FT_LOAD_TARGET_MODE( load_flags ); if ( mode == FT_RENDER_MODE_NORMAL && (load_flags & FT_LOAD_MONOCHROME ) ) mode = FT_RENDER_MODE_MONO; error = FT_Render_Glyph( slot, mode ); } Exit: return error; } extern "C" FT_Error FT_Load_Char(FT_Face face, FT_ULong char_code, FT_Int32 load_flags) { FT_UInt glyph_index; if ( !face ) return FT_THROW( Invalid_Face_Handle ); glyph_index = (FT_UInt)char_code; if ( face->charmap ) glyph_index = FT_Get_Char_Index( face, char_code ); return FT_Load_Glyph( face, glyph_index, load_flags ); } extern "C" void FT_Set_Transform(FT_Face face, FT_Matrix* matrix, FT_Vector* delta) { FT_Face_Internal internal; if ( !face ) return; internal = face->internal; internal->transform_flags = 0; if ( !matrix ) { internal->transform_matrix.xx = 0x10000L; internal->transform_matrix.xy = 0; internal->transform_matrix.yx = 0; internal->transform_matrix.yy = 0x10000L; matrix = &internal->transform_matrix; } else internal->transform_matrix = *matrix; /* set transform_flags bit flag 0 if `matrix' isn't the identity */ if ( ( matrix->xy | matrix->yx ) || matrix->xx != 0x10000L || matrix->yy != 0x10000L ) internal->transform_flags |= 1; if ( !delta ) { internal->transform_delta.x = 0; internal->transform_delta.y = 0; delta = &internal->transform_delta; } else internal->transform_delta = *delta; /* set transform_flags bit flag 1 if `delta' isn't the null vector */ if ( delta->x | delta->y ) internal->transform_flags |= 2; } FT_EXPORT_DEF( FT_Error ) FT_Set_Renderer( FT_Library library, FT_Renderer renderer, FT_UInt num_params, FT_Parameter* parameters ) { FT_ListNode node; FT_Error error = FT_Err_Ok; if ( !library ) return FT_THROW( Invalid_Library_Handle ); if ( !renderer ) return FT_THROW( Invalid_Argument ); node = FT_List_Find( &library->renderers, renderer ); if ( !node ) { error = FT_THROW( Invalid_Argument ); goto Exit; } FT_List_Up( &library->renderers, node ); if ( renderer->glyph_format == FT_GLYPH_FORMAT_OUTLINE ) library->cur_renderer = renderer; if ( num_params > 0 ) { FT_Renderer_SetModeFunc set_mode = renderer->clazz->set_mode; for ( ; num_params > 0; num_params-- ) { error = set_mode( renderer, parameters->tag, parameters->data ); if ( error ) break; parameters++; } } Exit: return error; } FT_BASE_DEF( FT_Error ) FT_Render_Glyph_Internal( FT_Library library, FT_GlyphSlot slot, FT_Render_Mode render_mode ) { FT_Error error = FT_Err_Ok; FT_Renderer renderer; /* if it is already a bitmap, no need to do anything */ switch ( slot->format ) { case FT_GLYPH_FORMAT_BITMAP: /* already a bitmap, don't do anything */ break; default: { FT_ListNode node = 0; FT_Bool update = 0; /* small shortcut for the very common case */ if ( slot->format == FT_GLYPH_FORMAT_OUTLINE ) { renderer = library->cur_renderer; node = library->renderers.head; } else renderer = FT_Lookup_Renderer( library, slot->format, &node ); error = FT_ERR( Unimplemented_Feature ); while ( renderer ) { error = renderer->render( renderer, slot, render_mode, NULL ); if ( !error || FT_ERR_NEQ( error, Cannot_Render_Glyph ) ) break; /* FT_Err_Cannot_Render_Glyph is returned if the render mode */ /* is unsupported by the current renderer for this glyph image */ /* format. */ /* now, look for another renderer that supports the same */ /* format. */ renderer = FT_Lookup_Renderer( library, slot->format, &node ); update = 1; } /* if we changed the current renderer for the glyph image format */ /* we need to select it as the next current one */ if ( !error && update && renderer ) FT_Set_Renderer( library, renderer, 0, 0 ); } } #ifdef FT_DEBUG_LEVEL_TRACE #undef FT_COMPONENT #define FT_COMPONENT trace_bitmap /* we convert to a single bitmap format for computing the checksum */ { FT_Bitmap bitmap; FT_Error err; FT_Bitmap_New( &bitmap ); err = FT_Bitmap_Convert( library, &slot->bitmap, &bitmap, 1 ); if ( !err ) { MD5_CTX ctx; unsigned char md5[16]; int i; MD5_Init( &ctx); MD5_Update( &ctx, bitmap.buffer, bitmap.rows * bitmap.pitch ); MD5_Final( md5, &ctx ); FT_TRACE3(( "MD5 checksum for %dx%d bitmap:\n" " ", bitmap.rows, bitmap.pitch )); for ( i = 0; i < 16; i++ ) FT_TRACE3(( "%02X", md5[i] )); FT_TRACE3(( "\n" )); } FT_Bitmap_Done( library, &bitmap ); } #undef FT_COMPONENT #define FT_COMPONENT trace_objs #endif /* FT_DEBUG_LEVEL_TRACE */ return error; } extern "C" FT_Error FT_Render_Glyph(FT_GlyphSlot slot, FT_Render_Mode render_mode) { FT_Library library; if ( !slot || !slot->face ) return FT_THROW( Invalid_Argument ); library = FT_FACE_LIBRARY( slot->face ); return FT_Render_Glyph_Internal( library, slot, render_mode ); } extern "C" FT_Error FT_Get_Kerning(FT_Face face, FT_UInt left_glyph, FT_UInt right_glyph, FT_UInt kern_mode, FT_Vector* akerning) { FT_Error error = FT_Err_Ok; FT_Driver driver; if ( !face ) return FT_THROW( Invalid_Face_Handle ); if ( !akerning ) return FT_THROW( Invalid_Argument ); driver = face->driver; akerning->x = 0; akerning->y = 0; if ( driver->clazz->get_kerning ) { error = driver->clazz->get_kerning( face, left_glyph, right_glyph, akerning ); if ( !error ) { if ( kern_mode != FT_KERNING_UNSCALED ) { akerning->x = FT_MulFix( akerning->x, face->size->metrics.x_scale ); akerning->y = FT_MulFix( akerning->y, face->size->metrics.y_scale ); if ( kern_mode != FT_KERNING_UNFITTED ) { /* we scale down kerning values for small ppem values */ /* to avoid that rounding makes them too big. */ /* `25' has been determined heuristically. */ if ( face->size->metrics.x_ppem < 25 ) akerning->x = FT_MulDiv( akerning->x, face->size->metrics.x_ppem, 25 ); if ( face->size->metrics.y_ppem < 25 ) akerning->y = FT_MulDiv( akerning->y, face->size->metrics.y_ppem, 25 ); akerning->x = FT_PIX_ROUND( akerning->x ); akerning->y = FT_PIX_ROUND( akerning->y ); } } } } return error; } extern "C" FT_Error FT_Get_Track_Kerning(FT_Face face, FT_Fixed point_size, FT_Int degree, FT_Fixed* akerning) { FT_Service_Kerning service; FT_Error error = FT_Err_Ok; if ( !face ) return FT_THROW( Invalid_Face_Handle ); if ( !akerning ) return FT_THROW( Invalid_Argument ); FT_FACE_FIND_SERVICE( face, service, KERNING ); if ( !service ) return FT_THROW( Unimplemented_Feature ); error = service->get_track( face, point_size, degree, akerning ); return error; } extern "C" FT_Error FT_Get_Glyph_Name(FT_Face face, FT_UInt glyph_index, FT_Pointer buffer, FT_UInt buffer_max) { FT_Error error = FT_ERR( Invalid_Argument ); /* clean up buffer */ if ( buffer && buffer_max > 0 ) ((FT_Byte*)buffer)[0] = 0; if ( face && (FT_Long)glyph_index <= face->num_glyphs && FT_HAS_GLYPH_NAMES( face ) ) { FT_Service_GlyphDict service; FT_FACE_LOOKUP_SERVICE( face, service, GLYPH_DICT ); if ( service && service->get_name ) error = service->get_name( face, glyph_index, buffer, buffer_max ); } return error; } extern "C" const char* FT_Get_Postscript_Name(FT_Face face) { const char* result = NULL; if ( !face ) goto Exit; if ( !result ) { FT_Service_PsFontName service; FT_FACE_LOOKUP_SERVICE( face, service, POSTSCRIPT_FONT_NAME ); if ( service && service->get_ps_font_name ) result = service->get_ps_font_name( face ); } Exit: return result; } extern "C" FT_Error FT_Select_Charmap(FT_Face face, FT_Encoding encoding) { FT_CharMap* cur; FT_CharMap* limit; if ( !face ) return FT_THROW( Invalid_Face_Handle ); if ( encoding == FT_ENCODING_NONE ) return FT_THROW( Invalid_Argument ); /* FT_ENCODING_UNICODE is special. We try to find the `best' Unicode */ /* charmap available, i.e., one with UCS-4 characters, if possible. */ /* */ /* This is done by find_unicode_charmap() above, to share code. */ if ( encoding == FT_ENCODING_UNICODE ) return find_unicode_charmap( face ); cur = face->charmaps; if ( !cur ) return FT_THROW( Invalid_CharMap_Handle ); limit = cur + face->num_charmaps; for ( ; cur < limit; cur++ ) { 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; } } return FT_THROW( Invalid_Argument ); } FT_EXPORT_DEF( FT_Long ) FT_Get_CMap_Format( FT_CharMap charmap ) { FT_Service_TTCMaps service; FT_Face face; TT_CMapInfo cmap_info; if ( !charmap || !charmap->face ) return -1; face = charmap->face; FT_FACE_FIND_SERVICE( face, service, TT_CMAP ); if ( service == NULL ) return -1; if ( service->get_cmap_info( charmap, &cmap_info )) return -1; return cmap_info.format; } extern "C" FT_Error FT_Set_Charmap(FT_Face face, FT_CharMap charmap) { FT_CharMap* cur; FT_CharMap* limit; if ( !face ) return FT_THROW( Invalid_Face_Handle ); cur = face->charmaps; if ( !cur ) return FT_THROW( Invalid_CharMap_Handle ); if ( FT_Get_CMap_Format( charmap ) == 14 ) return FT_THROW( Invalid_Argument ); limit = cur + face->num_charmaps; for ( ; cur < limit; cur++ ) { 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; } } return FT_THROW( Invalid_Argument ); } extern "C" FT_Int FT_Get_Charmap_Index(FT_CharMap charmap) { 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; } extern "C" FT_UInt FT_Get_Char_Index(FT_Face face, FT_ULong charcode) { FT_UInt result = 0; if ( face && face->charmap ) { FT_CMap cmap = FT_CMAP( face->charmap ); 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; } extern "C" FT_ULong FT_Get_First_Char(FT_Face face, FT_UInt* agindex) { FT_ULong result = 0; FT_UInt gindex = 0; /* only do something if we have a charmap, and we have glyphs at all */ if ( face && face->charmap && face->num_glyphs ) { gindex = FT_Get_Char_Index( face, 0 ); if ( gindex == 0 || gindex >= (FT_UInt)face->num_glyphs ) result = FT_Get_Next_Char( face, 0, &gindex ); } if ( agindex ) *agindex = gindex; return result; } extern "C" FT_ULong FT_Get_Next_Char(FT_Face face, FT_ULong charcode, FT_UInt* agindex) { FT_ULong result = 0; FT_UInt gindex = 0; if ( face && face->charmap && face->num_glyphs ) { FT_UInt32 code = (FT_UInt32)charcode; FT_CMap cmap = FT_CMAP( face->charmap ); do { gindex = cmap->clazz->char_next( cmap, &code ); } while ( gindex >= (FT_UInt)face->num_glyphs ); result = ( gindex == 0 ) ? 0 : code; } if ( agindex ) *agindex = gindex; return result; } extern "C" FT_UInt FT_Get_Name_Index(FT_Face face, FT_String* glyph_name) { FT_UInt result = 0; if ( face && FT_HAS_GLYPH_NAMES( face ) ) { FT_Service_GlyphDict service; FT_FACE_LOOKUP_SERVICE( face, service, GLYPH_DICT ); if ( service && service->name_index ) result = service->name_index( face, glyph_name ); } return result; } extern "C" FT_Error FT_Get_SubGlyph_Info(FT_GlyphSlot glyph, FT_UInt sub_index, FT_Int* p_index, FT_UInt* p_flags, FT_Int* p_arg1, FT_Int* p_arg2, FT_Matrix* p_transform) { FT_Error error = FT_ERR( Invalid_Argument ); if ( glyph && glyph->subglyphs && glyph->format == FT_GLYPH_FORMAT_COMPOSITE && sub_index < glyph->num_subglyphs ) { FT_SubGlyph subg = glyph->subglyphs + sub_index; *p_index = subg->index; *p_flags = subg->flags; *p_arg1 = subg->arg1; *p_arg2 = subg->arg2; *p_transform = subg->transform; } return error; } typedef struct PS_FontInfoRec_* PS_FontInfo; typedef struct PS_FontInfoRec_ { FT_String* version; FT_String* notice; FT_String* full_name; FT_String* family_name; FT_String* weight; FT_Long italic_angle; FT_Bool is_fixed_pitch; FT_Short underline_position; FT_UShort underline_thickness; } PS_FontInfoRec; typedef struct PS_FontExtraRec_ { FT_UShort fs_type; } PS_FontExtraRec; typedef struct PS_PrivateRec_* PS_Private; typedef struct PS_PrivateRec_ { FT_Int unique_id; FT_Int lenIV; FT_Byte num_blue_values; FT_Byte num_other_blues; FT_Byte num_family_blues; FT_Byte num_family_other_blues; FT_Short blue_values[14]; FT_Short other_blues[10]; FT_Short family_blues [14]; FT_Short family_other_blues[10]; FT_Fixed blue_scale; FT_Int blue_shift; FT_Int blue_fuzz; FT_UShort standard_width[1]; FT_UShort standard_height[1]; FT_Byte num_snap_widths; FT_Byte num_snap_heights; FT_Bool force_bold; FT_Bool round_stem_up; FT_Short snap_widths [13]; /* including std width */ FT_Short snap_heights[13]; /* including std height */ FT_Fixed expansion_factor; FT_Long language_group; FT_Long password; FT_Short min_feature[2]; } PS_PrivateRec; typedef enum PS_Dict_Keys_ { /* conventionally in the font dictionary */ PS_DICT_FONT_TYPE, /* FT_Byte */ PS_DICT_FONT_MATRIX, /* FT_Fixed */ PS_DICT_FONT_BBOX, /* FT_Fixed */ PS_DICT_PAINT_TYPE, /* FT_Byte */ PS_DICT_FONT_NAME, /* FT_String* */ PS_DICT_UNIQUE_ID, /* FT_Int */ PS_DICT_NUM_CHAR_STRINGS, /* FT_Int */ PS_DICT_CHAR_STRING_KEY, /* FT_String* */ PS_DICT_CHAR_STRING, /* FT_String* */ PS_DICT_ENCODING_TYPE, /* T1_EncodingType */ PS_DICT_ENCODING_ENTRY, /* FT_String* */ /* conventionally in the font Private dictionary */ PS_DICT_NUM_SUBRS, /* FT_Int */ PS_DICT_SUBR, /* FT_String* */ PS_DICT_STD_HW, /* FT_UShort */ PS_DICT_STD_VW, /* FT_UShort */ PS_DICT_NUM_BLUE_VALUES, /* FT_Byte */ PS_DICT_BLUE_VALUE, /* FT_Short */ PS_DICT_BLUE_FUZZ, /* FT_Int */ PS_DICT_NUM_OTHER_BLUES, /* FT_Byte */ PS_DICT_OTHER_BLUE, /* FT_Short */ PS_DICT_NUM_FAMILY_BLUES, /* FT_Byte */ PS_DICT_FAMILY_BLUE, /* FT_Short */ PS_DICT_NUM_FAMILY_OTHER_BLUES, /* FT_Byte */ PS_DICT_FAMILY_OTHER_BLUE, /* FT_Short */ PS_DICT_BLUE_SCALE, /* FT_Fixed */ PS_DICT_BLUE_SHIFT, /* FT_Int */ PS_DICT_NUM_STEM_SNAP_H, /* FT_Byte */ PS_DICT_STEM_SNAP_H, /* FT_Short */ PS_DICT_NUM_STEM_SNAP_V, /* FT_Byte */ PS_DICT_STEM_SNAP_V, /* FT_Short */ PS_DICT_FORCE_BOLD, /* FT_Bool */ PS_DICT_RND_STEM_UP, /* FT_Bool */ PS_DICT_MIN_FEATURE, /* FT_Short */ PS_DICT_LEN_IV, /* FT_Int */ PS_DICT_PASSWORD, /* FT_Long */ PS_DICT_LANGUAGE_GROUP, /* FT_Long */ /* conventionally in the font FontInfo dictionary */ PS_DICT_VERSION, /* FT_String* */ PS_DICT_NOTICE, /* FT_String* */ PS_DICT_FULL_NAME, /* FT_String* */ PS_DICT_FAMILY_NAME, /* FT_String* */ PS_DICT_WEIGHT, /* FT_String* */ PS_DICT_IS_FIXED_PITCH, /* FT_Bool */ PS_DICT_UNDERLINE_POSITION, /* FT_Short */ PS_DICT_UNDERLINE_THICKNESS, /* FT_UShort */ PS_DICT_FS_TYPE, /* FT_UShort */ PS_DICT_ITALIC_ANGLE, /* FT_Long */ PS_DICT_MAX = PS_DICT_ITALIC_ANGLE } PS_Dict_Keys; typedef FT_Error (*PS_GetFontInfoFunc)( FT_Face face, PS_FontInfoRec* afont_info ); typedef FT_Error (*PS_GetFontExtraFunc)( FT_Face face, PS_FontExtraRec* afont_extra ); typedef FT_Int (*PS_HasGlyphNamesFunc)( FT_Face face ); typedef FT_Error (*PS_GetFontPrivateFunc)( FT_Face face, PS_PrivateRec* afont_private ); typedef FT_Long (*PS_GetFontValueFunc)( FT_Face face, PS_Dict_Keys key, FT_UInt idx, void *value, FT_Long value_len ); #define FT_SERVICE_ID_POSTSCRIPT_INFO "postscript-info" FT_DEFINE_SERVICE( PsInfo ) { PS_GetFontInfoFunc ps_get_font_info; PS_GetFontExtraFunc ps_get_font_extra; PS_HasGlyphNamesFunc ps_has_glyph_names; PS_GetFontPrivateFunc ps_get_font_private; PS_GetFontValueFunc ps_get_font_value; }; FT_EXPORT_DEF( void* ) FT_Get_Sfnt_Table( FT_Face face, FT_Sfnt_Tag tag ) { void* table = 0; FT_Service_SFNT_Table service; if ( face && FT_IS_SFNT( face ) ) { FT_FACE_FIND_SERVICE( face, service, SFNT_TABLE ); if ( service != NULL ) table = service->get_table( face, tag ); } return table; } extern "C" FT_UShort FT_Get_FSType_Flags(FT_Face face) { TT_OS2* os2; /* first, try to get the fs_type directly from the font */ if ( face ) { FT_Service_PsInfo service = NULL; FT_FACE_FIND_SERVICE( face, service, POSTSCRIPT_INFO ); if ( service && service->ps_get_font_extra ) { PS_FontExtraRec extra; if ( !service->ps_get_font_extra( face, &extra ) && extra.fs_type != 0 ) return extra.fs_type; } } /* look at FSType before fsType for Type42 */ if ( ( os2 = (TT_OS2*)FT_Get_Sfnt_Table( face, ft_sfnt_os2 ) ) != NULL && os2->version != 0xFFFFU ) return os2->fsType; return 0; } 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; } extern "C" 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; } extern "C" 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; } extern "C" 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; } extern "C" 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; } extern "C" 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; } extern "C" FT_Long FT_MulDiv(FT_Long a, FT_Long b, FT_Long c) { #ifdef FT_LONG64 FT_Int s; FT_Long d; s = 1; if ( a < 0 ) { a = -a; s = -1; } if ( b < 0 ) { b = -b; s = -s; } if ( c < 0 ) { c = -c; s = -s; } d = (FT_Long)( c > 0 ? ( (FT_Int64)a * b + ( c >> 1 ) ) / c : 0x7FFFFFFFL ); return ( s > 0 ) ? d : -d; #else long s; /* XXX: this function does not allow 64-bit arguments */ if ( a == 0 || b == c ) return a; s = a; a = FT_ABS( a ); s ^= b; b = FT_ABS( b ); s ^= c; c = FT_ABS( c ); if ( a <= 46340L && b <= 46340L && c <= 176095L && c > 0 ) a = ( a * b + ( c >> 1 ) ) / c; else if ( (FT_Int32)c > 0 ) { FT_Int64 temp, temp2; ft_multo64( (FT_Int32)a, (FT_Int32)b, &temp ); temp2.hi = 0; temp2.lo = (FT_UInt32)(c >> 1); FT_Add64( &temp, &temp2, &temp ); a = ft_div64by32( temp.hi, temp.lo, (FT_Int32)c ); } else a = 0x7FFFFFFFL; return ( s < 0 ? -a : a ); #endif } FT_BASE_DEF( FT_Long ) FT_MulDiv_No_Round( FT_Long a, FT_Long b, FT_Long c ) { FT_Int s; FT_Long d; s = 1; if ( a < 0 ) { a = -a; s = -1; } if ( b < 0 ) { b = -b; s = -s; } if ( c < 0 ) { c = -c; s = -s; } d = (FT_Long)( c > 0 ? (FT_Int64)a * b / c : 0x7FFFFFFFL ); return ( s > 0 ) ? d : -d; } extern "C" FT_Long FT_MulFix(FT_Long a, FT_Long b) { #ifdef FT_MulFix_ASSEMBLER return FT_MulFix_ASSEMBLER( a, b ); #elif defined( FT_LONG64 ) FT_Int s = 1; FT_Long c; if ( a < 0 ) { a = -a; s = -1; } if ( b < 0 ) { b = -b; s = -s; } c = (FT_Long)( ( (FT_Int64)a * b + 0x8000L ) >> 16 ); return ( s > 0 ) ? c : -c; #else FT_Long s; FT_ULong ua, ub; if ( a == 0 || b == 0x10000L ) return a; s = a; a = FT_ABS( a ); s ^= b; b = FT_ABS( b ); ua = (FT_ULong)a; ub = (FT_ULong)b; if ( ua <= 2048 && ub <= 1048576L ) ua = ( ua * ub + 0x8000UL ) >> 16; else { FT_ULong al = ua & 0xFFFFUL; ua = ( ua >> 16 ) * ub + al * ( ub >> 16 ) + ( ( al * ( ub & 0xFFFFUL ) + 0x8000UL ) >> 16 ); } return ( s < 0 ? -(FT_Long)ua : (FT_Long)ua ); #endif } extern "C" FT_Long FT_DivFix(FT_Long a, FT_Long b) { #ifdef FT_LONG64 FT_Int32 s; FT_UInt32 q; s = 1; if ( a < 0 ) { a = -a; s = -1; } if ( b < 0 ) { b = -b; s = -s; } if ( b == 0 ) /* check for division by 0 */ q = 0x7FFFFFFFL; else /* compute result directly */ q = (FT_UInt32)( ( ( (FT_UInt64)a << 16 ) + ( b >> 1 ) ) / b ); return ( s < 0 ? -(FT_Long)q : (FT_Long)q ); #else FT_Int32 s; FT_UInt32 q; /* XXX: this function does not allow 64-bit arguments */ s = (FT_Int32)a; a = FT_ABS( a ); s ^= (FT_Int32)b; b = FT_ABS( b ); if ( (FT_UInt32)b == 0 ) { /* check for division by 0 */ q = (FT_UInt32)0x7FFFFFFFL; } else if ( ( a >> 16 ) == 0 ) { /* compute result directly */ q = (FT_UInt32)( ( (FT_ULong)a << 16 ) + ( b >> 1 ) ) / (FT_UInt32)b; } else { /* we need more bits; we have to do it by hand */ FT_Int64 temp, temp2; temp.hi = (FT_Int32)( a >> 16 ); temp.lo = (FT_UInt32)a << 16; temp2.hi = 0; temp2.lo = (FT_UInt32)( b >> 1 ); FT_Add64( &temp, &temp2, &temp ); q = ft_div64by32( temp.hi, temp.lo, (FT_Int32)b ); } return ( s < 0 ? -(FT_Int32)q : (FT_Int32)q ); #endif } extern "C" FT_Fixed FT_RoundFix(FT_Fixed a) { return ( a >= 0 ) ? ( a + 0x8000L ) & ~0xFFFFL : -((-a + 0x8000L ) & ~0xFFFFL ); } extern "C" FT_Fixed FT_CeilFix(FT_Fixed a) { return ( a >= 0 ) ? ( a + 0xFFFFL ) & ~0xFFFFL : -((-a + 0xFFFFL ) & ~0xFFFFL ); } extern "C" FT_Fixed FT_FloorFix(FT_Fixed a) { return ( a >= 0 ) ? a & ~0xFFFFL : -((-a) & ~0xFFFFL ); } extern "C" void FT_Vector_Transform(FT_Vector* vector, const FT_Matrix* matrix) { FT_Pos xz, yz; if ( !vector || !matrix ) return; xz = FT_MulFix( vector->x, matrix->xx ) + FT_MulFix( vector->y, matrix->xy ); yz = FT_MulFix( vector->x, matrix->yx ) + FT_MulFix( vector->y, matrix->yy ); vector->x = xz; vector->y = yz; } extern "C" void FT_Library_Version(FT_Library library, FT_Int* amajor, FT_Int* aminor, FT_Int* apatch) { FT_Int major = 0; FT_Int minor = 0; FT_Int patch = 0; if ( library ) { major = library->version_major; minor = library->version_minor; patch = library->version_patch; } if ( amajor ) *amajor = major; if ( aminor ) *aminor = minor; if ( apatch ) *apatch = patch; } static FT_Bool _tt_check_patents_in_range( FT_Stream stream, FT_ULong size ) { FT_Bool result = FALSE; FT_Error error; FT_Bytes p, end; if ( FT_FRAME_ENTER( size ) ) return 0; p = stream->cursor; end = p + size; while ( p < end ) { switch (p[0]) { case 0x06: /* SPvTL // */ case 0x07: /* SPvTL + */ case 0x08: /* SFvTL // */ case 0x09: /* SFvTL + */ case 0x0A: /* SPvFS */ case 0x0B: /* SFvFS */ result = TRUE; goto Exit; case 0x40: if ( p + 1 >= end ) goto Exit; p += p[1] + 2; break; case 0x41: if ( p + 1 >= end ) goto Exit; p += p[1] * 2 + 2; break; case 0x71: /* DELTAP2 */ case 0x72: /* DELTAP3 */ case 0x73: /* DELTAC0 */ case 0x74: /* DELTAC1 */ case 0x75: /* DELTAC2 */ result = TRUE; goto Exit; case 0xB0: case 0xB1: case 0xB2: case 0xB3: case 0xB4: case 0xB5: case 0xB6: case 0xB7: p += ( p[0] - 0xB0 ) + 2; break; case 0xB8: case 0xB9: case 0xBA: case 0xBB: case 0xBC: case 0xBD: case 0xBE: case 0xBF: p += ( p[0] - 0xB8 ) * 2 + 3; break; default: p += 1; break; } } Exit: FT_UNUSED( error ); FT_FRAME_EXIT(); return result; } static FT_Bool _tt_check_patents_in_table( FT_Face face, FT_ULong tag ) { FT_Stream stream = face->stream; FT_Error error = FT_Err_Ok; FT_Service_SFNT_Table service; FT_Bool result = FALSE; FT_FACE_FIND_SERVICE( face, service, SFNT_TABLE ); if ( service ) { FT_UInt i = 0; FT_ULong tag_i = 0, offset_i = 0, length_i = 0; for ( i = 0; !error && tag_i != tag ; i++ ) error = service->table_info( face, i, &tag_i, &offset_i, &length_i ); if ( error || FT_STREAM_SEEK( offset_i ) ) goto Exit; result = _tt_check_patents_in_range( stream, length_i ); } Exit: return result; } typedef FT_ULong (*TT_Glyf_GetLocationFunc)( FT_Face face, FT_UInt gindex, FT_ULong *psize ); #define FT_SERVICE_ID_TT_GLYF "tt-glyf" FT_DEFINE_SERVICE( TTGlyf ) { TT_Glyf_GetLocationFunc get_location; }; static FT_Bool _tt_face_check_patents( FT_Face face ) { FT_Stream stream = face->stream; FT_UInt gindex; FT_Error error; FT_Bool result; FT_Service_TTGlyf service; result = _tt_check_patents_in_table( face, TTAG_fpgm ); if ( result ) goto Exit; result = _tt_check_patents_in_table( face, TTAG_prep ); if ( result ) goto Exit; FT_FACE_FIND_SERVICE( face, service, TT_GLYF ); if ( service == NULL ) goto Exit; for ( gindex = 0; gindex < (FT_UInt)face->num_glyphs; gindex++ ) { FT_ULong offset, num_ins, size; FT_Int num_contours; offset = service->get_location( face, gindex, &size ); if ( size == 0 ) continue; if ( FT_STREAM_SEEK( offset ) || FT_READ_SHORT( num_contours ) ) continue; if ( num_contours >= 0 ) /* simple glyph */ { if ( FT_STREAM_SKIP( 8 + num_contours * 2 ) ) continue; } else /* compound glyph */ { FT_Bool has_instr = 0; if ( FT_STREAM_SKIP( 8 ) ) continue; /* now read each component */ for (;;) { FT_UInt flags, toskip; if( FT_READ_USHORT( flags ) ) break; toskip = 2 + 1 + 1; if ( ( flags & ( 1 << 0 ) ) != 0 ) /* ARGS_ARE_WORDS */ toskip += 2; if ( ( flags & ( 1 << 3 ) ) != 0 ) /* WE_HAVE_A_SCALE */ toskip += 2; else if ( ( flags & ( 1 << 6 ) ) != 0 ) /* WE_HAVE_X_Y_SCALE */ toskip += 4; else if ( ( flags & ( 1 << 7 ) ) != 0 ) /* WE_HAVE_A_2x2 */ toskip += 8; if ( ( flags & ( 1 << 8 ) ) != 0 ) /* WE_HAVE_INSTRUCTIONS */ has_instr = 1; if ( FT_STREAM_SKIP( toskip ) ) goto NextGlyph; if ( ( flags & ( 1 << 5 ) ) == 0 ) /* MORE_COMPONENTS */ break; } if ( !has_instr ) goto NextGlyph; } if ( FT_READ_USHORT( num_ins ) ) continue; result = _tt_check_patents_in_range( stream, num_ins ); if ( result ) goto Exit; NextGlyph: ; } Exit: return result; } extern "C" FT_Bool FT_Face_CheckTrueTypePatents(FT_Face face) { FT_Bool result = FALSE; if ( face && FT_IS_SFNT( face ) ) result = _tt_face_check_patents( face ); return result; } extern "C" FT_Bool FT_Face_SetUnpatentedHinting(FT_Face face, FT_Bool value) { FT_Bool result = FALSE; #if defined( TT_CONFIG_OPTION_UNPATENTED_HINTING ) && \ !defined( TT_CONFIG_OPTION_BYTECODE_INTERPRETER ) if ( face && FT_IS_SFNT( face ) ) { result = !face->internal->ignore_unpatented_hinter; face->internal->ignore_unpatented_hinter = !value; } #else FT_UNUSED( face ); FT_UNUSED( value ); #endif return result; } // ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ #ifdef TT_USE_BYTECODE_INTERPRETER #define TT_HINTER_FLAG FT_MODULE_DRIVER_HAS_HINTER #else #define TT_HINTER_FLAG 0 #endif #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS #define TT_SIZE_SELECT tt_size_select #else #define TT_SIZE_SELECT 0 #endif #ifndef FT_CONFIG_OPTION_PIC #define FT_DECLARE_DRIVER( class_ ) \ FT_CALLBACK_TABLE \ const FT_Driver_ClassRec class_; #define FT_DEFINE_DRIVER( \ class_, \ flags_, \ size_, \ name_, \ version_, \ requires_, \ interface_, \ init_, \ done_, \ get_interface_, \ face_object_size_, \ size_object_size_, \ slot_object_size_, \ init_face_, \ done_face_, \ init_size_, \ done_size_, \ init_slot_, \ done_slot_, \ load_glyph_, \ get_kerning_, \ attach_file_, \ get_advances_, \ request_size_, \ select_size_ ) \ FT_CALLBACK_TABLE_DEF \ const FT_Driver_ClassRec class_ = \ { \ FT_DEFINE_ROOT_MODULE( flags_, \ size_, \ name_, \ version_, \ requires_, \ interface_, \ init_, \ done_, \ get_interface_ ) \ \ face_object_size_, \ size_object_size_, \ slot_object_size_, \ \ init_face_, \ done_face_, \ \ init_size_, \ done_size_, \ \ init_slot_, \ done_slot_, \ \ load_glyph_, \ \ get_kerning_, \ attach_file_, \ get_advances_, \ \ request_size_, \ select_size_ \ }; #else #define FT_DECLARE_DRIVER( class_ ) FT_DECLARE_MODULE( class_ ) #define FT_DEFINE_DRIVER( \ class_, \ flags_, \ size_, \ name_, \ version_, \ requires_, \ interface_, \ init_, \ done_, \ get_interface_, \ face_object_size_, \ size_object_size_, \ slot_object_size_, \ init_face_, \ done_face_, \ init_size_, \ done_size_, \ init_slot_, \ done_slot_, \ load_glyph_, \ get_kerning_, \ attach_file_, \ get_advances_, \ request_size_, \ select_size_ ) \ void \ FT_Destroy_Class_ ## class_( FT_Library library, \ FT_Module_Class* clazz ) \ { \ FT_Memory memory = library->memory; \ FT_Driver_Class dclazz = (FT_Driver_Class)clazz; \ \ \ class_ ## _pic_free( library ); \ if ( dclazz ) \ FT_FREE( dclazz ); \ } \ \ \ FT_Error \ FT_Create_Class_ ## class_( FT_Library library, \ FT_Module_Class** output_class ) \ { \ FT_Driver_Class clazz = NULL; \ FT_Error error; \ FT_Memory memory = library->memory; \ \ \ if ( FT_ALLOC( clazz, sizeof ( *clazz ) ) ) \ return error; \ \ error = class_ ## _pic_init( library ); \ if ( error ) \ { \ FT_FREE( clazz ); \ return error; \ } \ \ FT_DEFINE_ROOT_MODULE( flags_, \ size_, \ name_, \ version_, \ requires_, \ interface_, \ init_, \ done_, \ get_interface_ ) \ \ clazz->face_object_size = face_object_size_; \ clazz->size_object_size = size_object_size_; \ clazz->slot_object_size = slot_object_size_; \ \ clazz->init_face = init_face_; \ clazz->done_face = done_face_; \ \ clazz->init_size = init_size_; \ clazz->done_size = done_size_; \ \ clazz->init_slot = init_slot_; \ clazz->done_slot = done_slot_; \ \ clazz->load_glyph = load_glyph_; \ \ clazz->get_kerning = get_kerning_; \ clazz->attach_file = attach_file_; \ clazz->get_advances = get_advances_; \ \ clazz->request_size = request_size_; \ clazz->select_size = select_size_; \ \ *output_class = (FT_Module_Class*)clazz; \ \ return FT_Err_Ok; \ } #endif #ifndef FT_CONFIG_OPTION_PIC #define FT_DECLARE_MODULE( class_ ) \ FT_CALLBACK_TABLE \ const FT_Module_Class class_; #define FT_DEFINE_ROOT_MODULE( \ flags_, \ size_, \ name_, \ version_, \ requires_, \ interface_, \ init_, \ done_, \ get_interface_ ) \ { \ flags_, \ size_, \ \ name_, \ version_, \ requires_, \ \ interface_, \ \ init_, \ done_, \ get_interface_, \ }, #define FT_DEFINE_MODULE( \ class_, \ flags_, \ size_, \ name_, \ version_, \ requires_, \ interface_, \ init_, \ done_, \ get_interface_ ) \ FT_CALLBACK_TABLE_DEF \ const FT_Module_Class class_ = \ { \ flags_, \ size_, \ \ name_, \ version_, \ requires_, \ \ interface_, \ \ init_, \ done_, \ get_interface_, \ }; #else #define FT_DECLARE_MODULE( class_ ) \ FT_Error \ FT_Create_Class_ ## class_( FT_Library library, \ FT_Module_Class** output_class ); \ void \ FT_Destroy_Class_ ## class_( FT_Library library, \ FT_Module_Class* clazz ); #define FT_DEFINE_ROOT_MODULE( \ flags_, \ size_, \ name_, \ version_, \ requires_, \ interface_, \ init_, \ done_, \ get_interface_ ) \ clazz->root.module_flags = flags_; \ clazz->root.module_size = size_; \ clazz->root.module_name = name_; \ clazz->root.module_version = version_; \ clazz->root.module_requires = requires_; \ \ clazz->root.module_interface = interface_; \ \ clazz->root.module_init = init_; \ clazz->root.module_done = done_; \ clazz->root.get_interface = get_interface_; #define FT_DEFINE_MODULE( \ class_, \ flags_, \ size_, \ name_, \ version_, \ requires_, \ interface_, \ init_, \ done_, \ get_interface_ ) \ void \ FT_Destroy_Class_ ## class_( FT_Library library, \ FT_Module_Class* clazz ) \ { \ FT_Memory memory = library->memory; \ \ \ class_ ## _pic_free( library ); \ if ( clazz ) \ FT_FREE( clazz ); \ } \ \ \ FT_Error \ FT_Create_Class_ ## class_( FT_Library library, \ FT_Module_Class** output_class ) \ { \ FT_Memory memory = library->memory; \ FT_Module_Class* clazz = NULL; \ FT_Error error; \ \ \ if ( FT_ALLOC( clazz, sizeof ( *clazz ) ) ) \ return error; \ error = class_ ## _pic_init( library ); \ if ( error ) \ { \ FT_FREE( clazz ); \ return error; \ } \ \ clazz->module_flags = flags_; \ clazz->module_size = size_; \ clazz->module_name = name_; \ clazz->module_version = version_; \ clazz->module_requires = requires_; \ \ clazz->module_interface = interface_; \ \ clazz->module_init = init_; \ clazz->module_done = done_; \ clazz->get_interface = get_interface_; \ \ *output_class = clazz; \ \ return FT_Err_Ok; \ } #endif #ifndef FT_CONFIG_OPTION_PIC #define FT_DEFINE_AUTOHINTER_INTERFACE( \ class_, \ reset_face_, \ get_global_hints_, \ done_global_hints_, \ load_glyph_ ) \ FT_CALLBACK_TABLE_DEF \ const FT_AutoHinter_InterfaceRec class_ = \ { \ reset_face_, \ get_global_hints_, \ done_global_hints_, \ load_glyph_ \ }; #else /* FT_CONFIG_OPTION_PIC */ #define FT_DEFINE_AUTOHINTER_INTERFACE( \ class_, \ reset_face_, \ get_global_hints_, \ done_global_hints_, \ load_glyph_ ) \ void \ FT_Init_Class_ ## class_( FT_Library library, \ FT_AutoHinter_InterfaceRec* clazz ) \ { \ FT_UNUSED( library ); \ \ clazz->reset_face = reset_face_; \ clazz->get_global_hints = get_global_hints_; \ clazz->done_global_hints = done_global_hints_; \ clazz->load_glyph = load_glyph_; \ } #endif /* FT_CONFIG_OPTION_PIC */ #ifndef FT_CONFIG_OPTION_PIC #define FT_DECLARE_RENDERER( class_ ) \ FT_EXPORT_VAR( const FT_Renderer_Class ) class_; #define FT_DEFINE_RENDERER( \ class_, \ flags_, \ size_, \ name_, \ version_, \ requires_, \ interface_, \ init_, \ done_, \ get_interface_, \ glyph_format_, \ render_glyph_, \ transform_glyph_, \ get_glyph_cbox_, \ set_mode_, \ raster_class_ ) \ FT_CALLBACK_TABLE_DEF \ const FT_Renderer_Class class_ = \ { \ FT_DEFINE_ROOT_MODULE( flags_, \ size_, \ name_, \ version_, \ requires_, \ interface_, \ init_, \ done_, \ get_interface_ ) \ glyph_format_, \ \ render_glyph_, \ transform_glyph_, \ get_glyph_cbox_, \ set_mode_, \ \ raster_class_ \ }; #else #define FT_DECLARE_RENDERER( class_ ) FT_DECLARE_MODULE( class_ ) #define FT_DEFINE_RENDERER( \ class_, \ flags_, \ size_, \ name_, \ version_, \ requires_, \ interface_, \ init_, \ done_, \ get_interface_, \ glyph_format_, \ render_glyph_, \ transform_glyph_, \ get_glyph_cbox_, \ set_mode_, \ raster_class_ ) \ void \ FT_Destroy_Class_ ## class_( FT_Library library, \ FT_Module_Class* clazz ) \ { \ FT_Renderer_Class* rclazz = (FT_Renderer_Class*)clazz; \ FT_Memory memory = library->memory; \ \ \ class_ ## _pic_free( library ); \ if ( rclazz ) \ FT_FREE( rclazz ); \ } \ \ \ FT_Error \ FT_Create_Class_ ## class_( FT_Library library, \ FT_Module_Class** output_class ) \ { \ FT_Renderer_Class* clazz = NULL; \ FT_Error error; \ FT_Memory memory = library->memory; \ \ \ if ( FT_ALLOC( clazz, sizeof ( *clazz ) ) ) \ return error; \ \ error = class_ ## _pic_init( library ); \ if ( error ) \ { \ FT_FREE( clazz ); \ return error; \ } \ \ FT_DEFINE_ROOT_MODULE( flags_, \ size_, \ name_, \ version_, \ requires_, \ interface_, \ init_, \ done_, \ get_interface_ ) \ \ clazz->glyph_format = glyph_format_; \ \ clazz->render_glyph = render_glyph_; \ clazz->transform_glyph = transform_glyph_; \ clazz->get_glyph_cbox = get_glyph_cbox_; \ clazz->set_mode = set_mode_; \ \ clazz->raster_class = raster_class_; \ \ *output_class = (FT_Module_Class*)clazz; \ \ return FT_Err_Ok; \ } #endif #ifdef __cplusplus #define FT_CALLBACK_TABLE extern "C" #define FT_CALLBACK_TABLE_DEF extern "C" #else #define FT_CALLBACK_TABLE extern #define FT_CALLBACK_TABLE_DEF /* nothing */ #endif #ifdef __cplusplus #define FT_EXPORT_VAR( x ) extern "C" x #else #define FT_EXPORT_VAR( x ) extern x #endif FT_DECLARE_DRIVER(tt_driver_class) FT_DECLARE_MODULE(autofit_module_class) FT_DECLARE_MODULE(sfnt_module_class) FT_DECLARE_MODULE(psnames_module_class) FT_DECLARE_RENDERER(ft_raster1_renderer_class) FT_DECLARE_RENDERER(ft_smooth_renderer_class) const FT_Module_Class* const ft_default_modules[] = { FT_USE_MODULE( FT_Driver_ClassRec, tt_driver_class ) FT_USE_MODULE( FT_Module_Class, autofit_module_class ) FT_USE_MODULE( FT_Module_Class, sfnt_module_class ) FT_USE_MODULE( FT_Module_Class, psnames_module_class ) FT_USE_MODULE( FT_Renderer_Class, ft_raster1_renderer_class ) FT_USE_MODULE( FT_Renderer_Class, ft_smooth_renderer_class ) 0 }; // ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ typedef struct TT_DriverRec_* TT_Driver; FT_LOCAL( FT_Error ) tt_driver_init( FT_Module ttdriver ); FT_LOCAL( void ) tt_driver_done( FT_Module ttdriver ); FT_CALLBACK_DEF( FT_Module_Interface ) tt_get_interface( FT_Module driver, const char* tt_interface ); FT_LOCAL_DEF( FT_Error ) tt_face_init( FT_Stream stream, FT_Face ttface, FT_Int face_index, FT_Int num_params, FT_Parameter* params ); FT_LOCAL_DEF( void ) tt_face_done( FT_Face ttface ); FT_LOCAL_DEF( FT_Error ) tt_size_init( FT_Size ttsize ); FT_LOCAL_DEF( void ) tt_size_done( FT_Size ttsize ); FT_LOCAL_DEF( FT_Error ) tt_slot_init( FT_GlyphSlot slot ); static FT_Error tt_glyph_load( FT_GlyphSlot ttslot, FT_Size ttsize, FT_UInt glyph_index, FT_Int32 load_flags ); static FT_Error tt_get_kerning( FT_Face ttface, FT_UInt left_glyph, FT_UInt right_glyph, FT_Vector* kerning ); static FT_Error tt_get_advances( FT_Face ttface, FT_UInt start, FT_UInt count, FT_Int32 flags, FT_Fixed *advances ); static FT_Error tt_size_request( FT_Size size, FT_Size_Request req ); static FT_Error tt_property_set( FT_Module module, const char* property_name, const void* value ); static FT_Error tt_property_get( FT_Module module, const char* property_name, const void* value ); typedef struct TT_DriverRec_ { FT_DriverRec root; TT_ExecContext context; /* execution context */ TT_GlyphZoneRec zone; /* glyph loader points zone */ FT_UInt interpreter_version; } TT_DriverRec; FT_DEFINE_DRIVER( tt_driver_class, FT_MODULE_FONT_DRIVER | FT_MODULE_DRIVER_SCALABLE | TT_HINTER_FLAG, sizeof ( TT_DriverRec ), "truetype", /* driver name */ 0x10000L, /* driver version == 1.0 */ 0x20000L, /* driver requires FreeType 2.0 or above */ (void*)0, /* driver specific interface */ tt_driver_init, tt_driver_done, tt_get_interface, sizeof ( TT_FaceRec ), sizeof ( TT_SizeRec ), sizeof ( FT_GlyphSlotRec ), tt_face_init, tt_face_done, tt_size_init, tt_size_done, tt_slot_init, 0, /* FT_Slot_DoneFunc */ tt_glyph_load, tt_get_kerning, 0, /* FT_Face_AttachFunc */ tt_get_advances, tt_size_request, TT_SIZE_SELECT ) FT_LOCAL_DEF( FT_Error ) tt_driver_init( FT_Module ttdriver ) /* TT_Driver */ { #ifdef TT_USE_BYTECODE_INTERPRETER TT_Driver driver = (TT_Driver)ttdriver; if ( !TT_New_Context( driver ) ) return FT_THROW( Could_Not_Find_Context ); #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING driver->interpreter_version = TT_INTERPRETER_VERSION_38; #else driver->interpreter_version = TT_INTERPRETER_VERSION_35; #endif #else /* !TT_USE_BYTECODE_INTERPRETER */ FT_UNUSED( ttdriver ); #endif /* !TT_USE_BYTECODE_INTERPRETER */ return FT_Err_Ok; } FT_LOCAL_DEF( void ) tt_driver_done( FT_Module ttdriver ) /* TT_Driver */ { #ifdef TT_USE_BYTECODE_INTERPRETER TT_Driver driver = (TT_Driver)ttdriver; /* destroy the execution context */ if ( driver->context ) { TT_Done_Context( driver->context ); driver->context = NULL; } #else FT_UNUSED( ttdriver ); #endif } #ifndef FT_CONFIG_OPTION_PIC #define FT_DEFINE_SERVICE_TTGLYFREC( class_, get_location_ ) \ static const FT_Service_TTGlyfRec class_ = \ { \ get_location_ \ }; #else /* FT_CONFIG_OPTION_PIC */ #define FT_DEFINE_SERVICE_TTGLYFREC( class_, get_location_ ) \ void \ FT_Init_Class_ ## class_( FT_Service_TTGlyfRec* clazz ) \ { \ clazz->get_location = get_location_; \ } #endif /* FT_CONFIG_OPTION_PIC */ #define FT_SERVICE_ID_PROPERTIES "properties" typedef FT_Error (*FT_Properties_SetFunc)( FT_Module module, const char* property_name, const void* value ); typedef FT_Error (*FT_Properties_GetFunc)( FT_Module module, const char* property_name, void* value ); FT_DEFINE_SERVICE( Properties ) { FT_Properties_SetFunc set_property; FT_Properties_GetFunc get_property; }; #ifndef FT_CONFIG_OPTION_PIC #define FT_DEFINE_SERVICE_PROPERTIESREC( class_, \ set_property_, \ get_property_ ) \ static const FT_Service_PropertiesRec class_ = \ { \ set_property_, \ get_property_ \ }; #else /* FT_CONFIG_OPTION_PIC */ #define FT_DEFINE_SERVICE_PROPERTIESREC( class_, \ set_property_, \ get_property_ ) \ void \ FT_Init_Class_ ## class_( FT_Service_PropertiesRec* clazz ) \ { \ clazz->set_property = set_property_; \ clazz->get_property = get_property_; \ } #endif /* FT_CONFIG_OPTION_PIC */ FT_LOCAL_DEF( FT_ULong ) tt_face_get_location( TT_Face face, FT_UInt gindex, FT_UInt *asize ) { FT_ULong pos1, pos2; FT_Byte* p; FT_Byte* p_limit; pos1 = pos2 = 0; if ( gindex < face->num_locations ) { if ( face->header.Index_To_Loc_Format != 0 ) { p = face->glyph_locations + gindex * 4; p_limit = face->glyph_locations + face->num_locations * 4; pos1 = FT_NEXT_ULONG( p ); pos2 = pos1; if ( p + 4 <= p_limit ) pos2 = FT_NEXT_ULONG( p ); } else { p = face->glyph_locations + gindex * 2; p_limit = face->glyph_locations + face->num_locations * 2; pos1 = FT_NEXT_USHORT( p ); pos2 = pos1; if ( p + 2 <= p_limit ) pos2 = FT_NEXT_USHORT( p ); pos1 <<= 1; pos2 <<= 1; } } /* Check broken location data */ if ( pos1 > face->glyf_len ) { FT_TRACE1(( "tt_face_get_location:" " too large offset=0x%08lx found for gid=0x%04lx," " exceeding the end of glyf table (0x%08lx)\n", pos1, gindex, face->glyf_len )); *asize = 0; return 0; } if ( pos2 > face->glyf_len ) { FT_TRACE1(( "tt_face_get_location:" " too large offset=0x%08lx found for gid=0x%04lx," " truncate at the end of glyf table (0x%08lx)\n", pos2, gindex + 1, face->glyf_len )); pos2 = face->glyf_len; } /* The `loca' table must be ordered; it refers to the length of */ /* an entry as the difference between the current and the next */ /* position. However, there do exist (malformed) fonts which */ /* don't obey this rule, so we are only able to provide an */ /* upper bound for the size. */ /* */ /* We get (intentionally) a wrong, non-zero result in case the */ /* `glyf' table is missing. */ if ( pos2 >= pos1 ) *asize = (FT_UInt)( pos2 - pos1 ); else *asize = (FT_UInt)( face->glyf_len - pos1 ); return pos1; } FT_DEFINE_SERVICE_TTGLYFREC( tt_service_truetype_glyf, (TT_Glyf_GetLocationFunc)tt_face_get_location ) FT_DEFINE_SERVICE_PROPERTIESREC( tt_service_properties, (FT_Properties_SetFunc)tt_property_set, (FT_Properties_GetFunc)tt_property_get ) #ifndef FT_CONFIG_OPTION_PIC #define TT_SERVICES_GET tt_services #define TT_SERVICE_GX_MULTI_MASTERS_GET tt_service_gx_multi_masters #define TT_SERVICE_TRUETYPE_GLYF_GET tt_service_truetype_glyf #define TT_SERVICE_PROPERTIES_GET tt_service_properties #else /* FT_CONFIG_OPTION_PIC */ #include FT_MULTIPLE_MASTERS_H #include FT_SERVICE_MULTIPLE_MASTERS_H #include FT_SERVICE_TRUETYPE_GLYF_H #include FT_SERVICE_PROPERTIES_H typedef struct TTModulePIC_ { FT_ServiceDescRec* tt_services; #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT FT_Service_MultiMastersRec tt_service_gx_multi_masters; #endif FT_Service_TTGlyfRec tt_service_truetype_glyf; FT_Service_PropertiesRec tt_service_properties; } TTModulePIC; #define GET_PIC( lib ) \ ( (TTModulePIC*)((lib)->pic_container.truetype) ) #define TT_SERVICES_GET \ ( GET_PIC( library )->tt_services ) #define TT_SERVICE_GX_MULTI_MASTERS_GET \ ( GET_PIC( library )->tt_service_gx_multi_masters ) #define TT_SERVICE_TRUETYPE_GLYF_GET \ ( GET_PIC( library )->tt_service_truetype_glyf ) #define TT_SERVICE_PROPERTIES_GET \ ( GET_PIC( library )->tt_service_properties ) /* see ttpic.c for the implementation */ void tt_driver_class_pic_free( FT_Library library ); FT_Error tt_driver_class_pic_init( FT_Library library ); #endif /* FT_CONFIG_OPTION_PIC */ #ifndef FT_CONFIG_OPTION_PIC #define FT_DEFINE_SERVICEDESCREC1( class_, \ serv_id_1, serv_data_1 ) \ static const FT_ServiceDescRec class_[] = \ { \ { serv_id_1, serv_data_1 }, \ { NULL, NULL } \ }; #define FT_DEFINE_SERVICEDESCREC2( class_, \ serv_id_1, serv_data_1, \ serv_id_2, serv_data_2 ) \ static const FT_ServiceDescRec class_[] = \ { \ { serv_id_1, serv_data_1 }, \ { serv_id_2, serv_data_2 }, \ { NULL, NULL } \ }; #define FT_DEFINE_SERVICEDESCREC3( class_, \ serv_id_1, serv_data_1, \ serv_id_2, serv_data_2, \ serv_id_3, serv_data_3 ) \ static const FT_ServiceDescRec class_[] = \ { \ { serv_id_1, serv_data_1 }, \ { serv_id_2, serv_data_2 }, \ { serv_id_3, serv_data_3 }, \ { NULL, NULL } \ }; #define FT_DEFINE_SERVICEDESCREC4( class_, \ serv_id_1, serv_data_1, \ serv_id_2, serv_data_2, \ serv_id_3, serv_data_3, \ serv_id_4, serv_data_4 ) \ static const FT_ServiceDescRec class_[] = \ { \ { serv_id_1, serv_data_1 }, \ { serv_id_2, serv_data_2 }, \ { serv_id_3, serv_data_3 }, \ { serv_id_4, serv_data_4 }, \ { NULL, NULL } \ }; #define FT_DEFINE_SERVICEDESCREC5( class_, \ serv_id_1, serv_data_1, \ serv_id_2, serv_data_2, \ serv_id_3, serv_data_3, \ serv_id_4, serv_data_4, \ serv_id_5, serv_data_5 ) \ static const FT_ServiceDescRec class_[] = \ { \ { serv_id_1, serv_data_1 }, \ { serv_id_2, serv_data_2 }, \ { serv_id_3, serv_data_3 }, \ { serv_id_4, serv_data_4 }, \ { serv_id_5, serv_data_5 }, \ { NULL, NULL } \ }; #define FT_DEFINE_SERVICEDESCREC6( class_, \ serv_id_1, serv_data_1, \ serv_id_2, serv_data_2, \ serv_id_3, serv_data_3, \ serv_id_4, serv_data_4, \ serv_id_5, serv_data_5, \ serv_id_6, serv_data_6 ) \ static const FT_ServiceDescRec class_[] = \ { \ { serv_id_1, serv_data_1 }, \ { serv_id_2, serv_data_2 }, \ { serv_id_3, serv_data_3 }, \ { serv_id_4, serv_data_4 }, \ { serv_id_5, serv_data_5 }, \ { serv_id_6, serv_data_6 }, \ { NULL, NULL } \ }; #define FT_DEFINE_SERVICEDESCREC7( class_, \ serv_id_1, serv_data_1, \ serv_id_2, serv_data_2, \ serv_id_3, serv_data_3, \ serv_id_4, serv_data_4, \ serv_id_5, serv_data_5, \ serv_id_6, serv_data_6, \ serv_id_7, serv_data_7 ) \ static const FT_ServiceDescRec class_[] = \ { \ { serv_id_1, serv_data_1 }, \ { serv_id_2, serv_data_2 }, \ { serv_id_3, serv_data_3 }, \ { serv_id_4, serv_data_4 }, \ { serv_id_5, serv_data_5 }, \ { serv_id_6, serv_data_6 }, \ { serv_id_7, serv_data_7 }, \ { NULL, NULL } \ }; #else /* FT_CONFIG_OPTION_PIC */ #define FT_DEFINE_SERVICEDESCREC1( class_, \ serv_id_1, serv_data_1 ) \ void \ FT_Destroy_Class_ ## class_( FT_Library library, \ FT_ServiceDescRec* clazz ) \ { \ FT_Memory memory = library->memory; \ \ \ if ( clazz ) \ FT_FREE( clazz ); \ } \ \ FT_Error \ FT_Create_Class_ ## class_( FT_Library library, \ FT_ServiceDescRec** output_class ) \ { \ FT_ServiceDescRec* clazz = NULL; \ FT_Error error; \ FT_Memory memory = library->memory; \ \ \ if ( FT_ALLOC( clazz, sizeof ( *clazz ) * 2 ) ) \ return error; \ \ clazz[0].serv_id = serv_id_1; \ clazz[0].serv_data = serv_data_1; \ clazz[1].serv_id = NULL; \ clazz[1].serv_data = NULL; \ \ *output_class = clazz; \ \ return FT_Err_Ok; \ } #define FT_DEFINE_SERVICEDESCREC2( class_, \ serv_id_1, serv_data_1, \ serv_id_2, serv_data_2 ) \ void \ FT_Destroy_Class_ ## class_( FT_Library library, \ FT_ServiceDescRec* clazz ) \ { \ FT_Memory memory = library->memory; \ \ \ if ( clazz ) \ FT_FREE( clazz ); \ } \ \ FT_Error \ FT_Create_Class_ ## class_( FT_Library library, \ FT_ServiceDescRec** output_class ) \ { \ FT_ServiceDescRec* clazz = NULL; \ FT_Error error; \ FT_Memory memory = library->memory; \ \ \ if ( FT_ALLOC( clazz, sizeof ( *clazz ) * 3 ) ) \ return error; \ \ clazz[0].serv_id = serv_id_1; \ clazz[0].serv_data = serv_data_1; \ clazz[1].serv_id = serv_id_2; \ clazz[1].serv_data = serv_data_2; \ clazz[2].serv_id = NULL; \ clazz[2].serv_data = NULL; \ \ *output_class = clazz; \ \ return FT_Err_Ok; \ } #define FT_DEFINE_SERVICEDESCREC3( class_, \ serv_id_1, serv_data_1, \ serv_id_2, serv_data_2, \ serv_id_3, serv_data_3 ) \ void \ FT_Destroy_Class_ ## class_( FT_Library library, \ FT_ServiceDescRec* clazz ) \ { \ FT_Memory memory = library->memory; \ \ \ if ( clazz ) \ FT_FREE( clazz ); \ } \ \ FT_Error \ FT_Create_Class_ ## class_( FT_Library library, \ FT_ServiceDescRec** output_class ) \ { \ FT_ServiceDescRec* clazz = NULL; \ FT_Error error; \ FT_Memory memory = library->memory; \ \ \ if ( FT_ALLOC( clazz, sizeof ( *clazz ) * 4 ) ) \ return error; \ \ clazz[0].serv_id = serv_id_1; \ clazz[0].serv_data = serv_data_1; \ clazz[1].serv_id = serv_id_2; \ clazz[1].serv_data = serv_data_2; \ clazz[2].serv_id = serv_id_3; \ clazz[2].serv_data = serv_data_3; \ clazz[3].serv_id = NULL; \ clazz[3].serv_data = NULL; \ \ *output_class = clazz; \ \ return FT_Err_Ok; \ } #define FT_DEFINE_SERVICEDESCREC4( class_, \ serv_id_1, serv_data_1, \ serv_id_2, serv_data_2, \ serv_id_3, serv_data_3, \ serv_id_4, serv_data_4 ) \ void \ FT_Destroy_Class_ ## class_( FT_Library library, \ FT_ServiceDescRec* clazz ) \ { \ FT_Memory memory = library->memory; \ \ \ if ( clazz ) \ FT_FREE( clazz ); \ } \ \ FT_Error \ FT_Create_Class_ ## class_( FT_Library library, \ FT_ServiceDescRec** output_class ) \ { \ FT_ServiceDescRec* clazz = NULL; \ FT_Error error; \ FT_Memory memory = library->memory; \ \ \ if ( FT_ALLOC( clazz, sizeof ( *clazz ) * 5 ) ) \ return error; \ \ clazz[0].serv_id = serv_id_1; \ clazz[0].serv_data = serv_data_1; \ clazz[1].serv_id = serv_id_2; \ clazz[1].serv_data = serv_data_2; \ clazz[2].serv_id = serv_id_3; \ clazz[2].serv_data = serv_data_3; \ clazz[3].serv_id = serv_id_4; \ clazz[3].serv_data = serv_data_4; \ clazz[4].serv_id = NULL; \ clazz[4].serv_data = NULL; \ \ *output_class = clazz; \ \ return FT_Err_Ok; \ } #define FT_DEFINE_SERVICEDESCREC5( class_, \ serv_id_1, serv_data_1, \ serv_id_2, serv_data_2, \ serv_id_3, serv_data_3, \ serv_id_4, serv_data_4, \ serv_id_5, serv_data_5 ) \ void \ FT_Destroy_Class_ ## class_( FT_Library library, \ FT_ServiceDescRec* clazz ) \ { \ FT_Memory memory = library->memory; \ \ \ if ( clazz ) \ FT_FREE( clazz ); \ } \ \ FT_Error \ FT_Create_Class_ ## class_( FT_Library library, \ FT_ServiceDescRec** output_class ) \ { \ FT_ServiceDescRec* clazz = NULL; \ FT_Error error; \ FT_Memory memory = library->memory; \ \ \ if ( FT_ALLOC( clazz, sizeof ( *clazz ) * 6 ) ) \ return error; \ \ clazz[0].serv_id = serv_id_1; \ clazz[0].serv_data = serv_data_1; \ clazz[1].serv_id = serv_id_2; \ clazz[1].serv_data = serv_data_2; \ clazz[2].serv_id = serv_id_3; \ clazz[2].serv_data = serv_data_3; \ clazz[3].serv_id = serv_id_4; \ clazz[3].serv_data = serv_data_4; \ clazz[4].serv_id = serv_id_5; \ clazz[4].serv_data = serv_data_5; \ clazz[5].serv_id = NULL; \ clazz[5].serv_data = NULL; \ \ *output_class = clazz; \ \ return FT_Err_Ok; \ } #define FT_DEFINE_SERVICEDESCREC6( class_, \ serv_id_1, serv_data_1, \ serv_id_2, serv_data_2, \ serv_id_3, serv_data_3, \ serv_id_4, serv_data_4, \ serv_id_5, serv_data_5, \ serv_id_6, serv_data_6 ) \ void \ FT_Destroy_Class_ ## class_( FT_Library library, \ FT_ServiceDescRec* clazz ) \ { \ FT_Memory memory = library->memory; \ \ \ if ( clazz ) \ FT_FREE( clazz ); \ } \ \ FT_Error \ FT_Create_Class_ ## class_( FT_Library library, \ FT_ServiceDescRec** output_class) \ { \ FT_ServiceDescRec* clazz = NULL; \ FT_Error error; \ FT_Memory memory = library->memory; \ \ \ if ( FT_ALLOC( clazz, sizeof ( *clazz ) * 7 ) ) \ return error; \ \ clazz[0].serv_id = serv_id_1; \ clazz[0].serv_data = serv_data_1; \ clazz[1].serv_id = serv_id_2; \ clazz[1].serv_data = serv_data_2; \ clazz[2].serv_id = serv_id_3; \ clazz[2].serv_data = serv_data_3; \ clazz[3].serv_id = serv_id_4; \ clazz[3].serv_data = serv_data_4; \ clazz[4].serv_id = serv_id_5; \ clazz[4].serv_data = serv_data_5; \ clazz[5].serv_id = serv_id_6; \ clazz[5].serv_data = serv_data_6; \ clazz[6].serv_id = NULL; \ clazz[6].serv_data = NULL; \ \ *output_class = clazz; \ \ return FT_Err_Ok; \ } #define FT_DEFINE_SERVICEDESCREC7( class_, \ serv_id_1, serv_data_1, \ serv_id_2, serv_data_2, \ serv_id_3, serv_data_3, \ serv_id_4, serv_data_4, \ serv_id_5, serv_data_5, \ serv_id_6, serv_data_6, \ serv_id_7, serv_data_7 ) \ void \ FT_Destroy_Class_ ## class_( FT_Library library, \ FT_ServiceDescRec* clazz ) \ { \ FT_Memory memory = library->memory; \ \ \ if ( clazz ) \ FT_FREE( clazz ); \ } \ \ FT_Error \ FT_Create_Class_ ## class_( FT_Library library, \ FT_ServiceDescRec** output_class) \ { \ FT_ServiceDescRec* clazz = NULL; \ FT_Error error; \ FT_Memory memory = library->memory; \ \ \ if ( FT_ALLOC( clazz, sizeof ( *clazz ) * 8 ) ) \ return error; \ \ clazz[0].serv_id = serv_id_1; \ clazz[0].serv_data = serv_data_1; \ clazz[1].serv_id = serv_id_2; \ clazz[1].serv_data = serv_data_2; \ clazz[2].serv_id = serv_id_3; \ clazz[2].serv_data = serv_data_3; \ clazz[3].serv_id = serv_id_4; \ clazz[3].serv_data = serv_data_4; \ clazz[4].serv_id = serv_id_5; \ clazz[4].serv_data = serv_data_5; \ clazz[5].serv_id = serv_id_6; \ clazz[5].serv_data = serv_data_6; \ clazz[6].serv_id = serv_id_7; \ clazz[6].serv_data = serv_data_7; \ clazz[7].serv_id = NULL; \ clazz[7].serv_data = NULL; \ \ *output_class = clazz; \ \ return FT_Err_Ok; \ } #endif /* FT_CONFIG_OPTION_PIC */ #define FT_SERVICE_ID_XF86_NAME "xf86-driver-name" #define FT_SERVICE_ID_MULTI_MASTERS "multi-masters" #define FT_SERVICE_ID_TRUETYPE_ENGINE "truetype-engine" #define FT_SERVICE_ID_PROPERTIES "properties" #define FT_XF86_FORMAT_TRUETYPE "TrueType" #define FT_XF86_FORMAT_TYPE_1 "Type 1" #define FT_XF86_FORMAT_BDF "BDF" #define FT_XF86_FORMAT_PCF "PCF" #define FT_XF86_FORMAT_TYPE_42 "Type 42" #define FT_XF86_FORMAT_CID "CID Type 1" #define FT_XF86_FORMAT_CFF "CFF" #define FT_XF86_FORMAT_PFR "PFR" #define FT_XF86_FORMAT_WINFNT "Windows FNT" #define T1_MAX_MM_DESIGNS 16 #define T1_MAX_MM_AXIS 4 #define T1_MAX_MM_MAP_POINTS 20 typedef struct FT_MM_Axis_ { FT_String* name; FT_Long minimum; FT_Long maximum; } FT_MM_Axis; typedef struct FT_Multi_Master_ { FT_UInt num_axis; FT_UInt num_designs; FT_MM_Axis axis[T1_MAX_MM_AXIS]; } FT_Multi_Master; typedef FT_Error (*FT_Get_MM_Func)( FT_Face face, FT_Multi_Master* master ); typedef FT_Error (*FT_Get_MM_Var_Func)( FT_Face face, FT_MM_Var* *master ); typedef FT_Error (*FT_Set_MM_Design_Func)( FT_Face face, FT_UInt num_coords, FT_Long* coords ); typedef FT_Error (*FT_Set_Var_Design_Func)( FT_Face face, FT_UInt num_coords, FT_Fixed* coords ); typedef FT_Error (*FT_Set_MM_Blend_Func)( FT_Face face, FT_UInt num_coords, FT_Long* coords ); FT_DEFINE_SERVICE( MultiMasters ) { FT_Get_MM_Func get_mm; FT_Set_MM_Design_Func set_mm_design; FT_Set_MM_Blend_Func set_mm_blend; FT_Get_MM_Var_Func get_mm_var; FT_Set_Var_Design_Func set_var_design; }; typedef enum T1_EncodingType_ { T1_ENCODING_TYPE_NONE = 0, T1_ENCODING_TYPE_ARRAY, T1_ENCODING_TYPE_STANDARD, T1_ENCODING_TYPE_ISOLATIN1, T1_ENCODING_TYPE_EXPERT } T1_EncodingType; typedef struct T1_EncodingRecRec_ { FT_Int num_chars; FT_Int code_first; FT_Int code_last; FT_UShort* char_index; FT_String** char_name; } T1_EncodingRec, *T1_Encoding; typedef struct T1_FontRec_ { PS_FontInfoRec font_info; /* font info dictionary */ PS_FontExtraRec font_extra; /* font info extra fields */ PS_PrivateRec private_dict; /* private dictionary */ FT_String* font_name; /* top-level dictionary */ T1_EncodingType encoding_type; T1_EncodingRec encoding; FT_Byte* subrs_block; FT_Byte* charstrings_block; FT_Byte* glyph_names_block; FT_Int num_subrs; FT_Byte** subrs; FT_PtrDist* subrs_len; FT_Int num_glyphs; FT_String** glyph_names; /* array of glyph names */ FT_Byte** charstrings; /* array of glyph charstrings */ FT_PtrDist* charstrings_len; FT_Byte paint_type; FT_Byte font_type; FT_Matrix font_matrix; FT_Vector font_offset; FT_BBox font_bbox; FT_Long font_id; FT_Fixed stroke_width; } T1_FontRec, *T1_Font; typedef struct PS_DesignMap_ { FT_Byte num_points; FT_Long* design_points; FT_Fixed* blend_points; } PS_DesignMapRec, *PS_DesignMap; typedef struct PS_BlendRec_ { FT_UInt num_designs; FT_UInt num_axis; FT_String* axis_names[T1_MAX_MM_AXIS]; FT_Fixed* design_pos[T1_MAX_MM_DESIGNS]; PS_DesignMapRec design_map[T1_MAX_MM_AXIS]; FT_Fixed* weight_vector; FT_Fixed* default_weight_vector; PS_FontInfo font_infos[T1_MAX_MM_DESIGNS + 1]; PS_Private privates [T1_MAX_MM_DESIGNS + 1]; FT_ULong blend_bitflags; FT_BBox* bboxes [T1_MAX_MM_DESIGNS + 1]; /* since 2.3.0 */ /* undocumented, optional: the default design instance; */ /* corresponds to default_weight_vector -- */ /* num_default_design_vector == 0 means it is not present */ /* in the font and associated metrics files */ FT_UInt default_design_vector[T1_MAX_MM_DESIGNS]; FT_UInt num_default_design_vector; } PS_BlendRec, *PS_Blend; typedef struct T1_FaceRec_* T1_Face; typedef struct T1_FaceRec_ { FT_FaceRec root; T1_FontRec type1; const void* psnames; const void* psaux; const void* afm_data; FT_CharMapRec charmaprecs[2]; FT_CharMap charmaps[2]; /* support for Multiple Masters fonts */ PS_Blend blend; /* undocumented, optional: indices of subroutines that express */ /* the NormalizeDesignVector and the ConvertDesignVector procedure, */ /* respectively, as Type 2 charstrings; -1 if keywords not present */ FT_Int ndv_idx; FT_Int cdv_idx; /* undocumented, optional: has the same meaning as len_buildchar */ /* for Type 2 fonts; manipulated by othersubrs 19, 24, and 25 */ FT_UInt len_buildchar; FT_Long* buildchar; /* since version 2.1 - interface to PostScript hinter */ const void* pshinter; } T1_FaceRec; FT_LOCAL_DEF( FT_Error ) T1_Get_Multi_Master( T1_Face face, FT_Multi_Master* master ); FT_LOCAL_DEF( FT_Error ) T1_Set_MM_Design( T1_Face face, FT_UInt num_coords, FT_Long* coords ); FT_LOCAL_DEF( FT_Error ) T1_Set_MM_Blend( T1_Face face, FT_UInt num_coords,FT_Fixed* coords ); FT_LOCAL_DEF( FT_Error ) T1_Get_MM_Var( T1_Face face, FT_MM_Var* *master ); FT_LOCAL_DEF( FT_Error ) T1_Set_Var_Design( T1_Face face, FT_UInt num_coords, FT_Fixed* coords ); FT_LOCAL_DEF( FT_Error ) TT_Set_MM_Blend( TT_Face face, FT_UInt num_coords, FT_Fixed* coords ); FT_LOCAL_DEF( FT_Error ) TT_Get_MM_Var( TT_Face face, FT_MM_Var* *master ); FT_LOCAL_DEF( FT_Error ) TT_Set_Var_Design( TT_Face face, FT_UInt num_coords, FT_Fixed* coords ); #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT static const FT_Service_MultiMastersRec t1_service_multi_masters = { (FT_Get_MM_Func) T1_Get_Multi_Master, (FT_Set_MM_Design_Func) T1_Set_MM_Design, (FT_Set_MM_Blend_Func) T1_Set_MM_Blend, (FT_Get_MM_Var_Func) T1_Get_MM_Var, (FT_Set_Var_Design_Func)T1_Set_Var_Design }; #endif #ifndef FT_CONFIG_OPTION_PIC #define FT_DEFINE_SERVICE_MULTIMASTERSREC( class_, \ get_mm_, \ set_mm_design_, \ set_mm_blend_, \ get_mm_var_, \ set_var_design_ ) \ static const FT_Service_MultiMastersRec class_ = \ { \ get_mm_, set_mm_design_, set_mm_blend_, get_mm_var_, set_var_design_ \ }; #else /* FT_CONFIG_OPTION_PIC */ #define FT_DEFINE_SERVICE_MULTIMASTERSREC( class_, \ get_mm_, \ set_mm_design_, \ set_mm_blend_, \ get_mm_var_, \ set_var_design_ ) \ void \ FT_Init_Class_ ## class_( FT_Service_MultiMastersRec* clazz ) \ { \ clazz->get_mm = get_mm_; \ clazz->set_mm_design = set_mm_design_; \ clazz->set_mm_blend = set_mm_blend_; \ clazz->get_mm_var = get_mm_var_; \ clazz->set_var_design = set_var_design_; \ } #endif /* FT_CONFIG_OPTION_PIC */ #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT FT_DEFINE_SERVICE_MULTIMASTERSREC( tt_service_gx_multi_masters, (FT_Get_MM_Func) NULL, (FT_Set_MM_Design_Func) NULL, (FT_Set_MM_Blend_Func) TT_Set_MM_Blend, (FT_Get_MM_Var_Func) TT_Get_MM_Var, (FT_Set_Var_Design_Func)TT_Set_Var_Design ) #endif typedef enum FT_TrueTypeEngineType_ { FT_TRUETYPE_ENGINE_TYPE_NONE = 0, FT_TRUETYPE_ENGINE_TYPE_UNPATENTED, FT_TRUETYPE_ENGINE_TYPE_PATENTED } FT_TrueTypeEngineType; #define FT_SERVICE_ID_TRUETYPE_ENGINE "truetype-engine" FT_DEFINE_SERVICE( TrueTypeEngine ) { FT_TrueTypeEngineType engine_type; }; static const FT_Service_TrueTypeEngineRec tt_service_truetype_engine = { #ifdef TT_USE_BYTECODE_INTERPRETER #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING FT_TRUETYPE_ENGINE_TYPE_UNPATENTED #else FT_TRUETYPE_ENGINE_TYPE_PATENTED #endif #else /* !TT_USE_BYTECODE_INTERPRETER */ FT_TRUETYPE_ENGINE_TYPE_NONE #endif /* TT_USE_BYTECODE_INTERPRETER */ }; #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT FT_DEFINE_SERVICEDESCREC5( tt_services, FT_SERVICE_ID_XF86_NAME, FT_XF86_FORMAT_TRUETYPE, FT_SERVICE_ID_MULTI_MASTERS, &TT_SERVICE_GX_MULTI_MASTERS_GET, FT_SERVICE_ID_TRUETYPE_ENGINE, &tt_service_truetype_engine, FT_SERVICE_ID_TT_GLYF, &TT_SERVICE_TRUETYPE_GLYF_GET, FT_SERVICE_ID_PROPERTIES, &TT_SERVICE_PROPERTIES_GET ) #else FT_DEFINE_SERVICEDESCREC4( tt_services, FT_SERVICE_ID_XF86_NAME, FT_XF86_FORMAT_TRUETYPE, FT_SERVICE_ID_TRUETYPE_ENGINE, &tt_service_truetype_engine, FT_SERVICE_ID_TT_GLYF, &TT_SERVICE_TRUETYPE_GLYF_GET, FT_SERVICE_ID_PROPERTIES, &TT_SERVICE_PROPERTIES_GET ) #endif FT_CALLBACK_DEF( FT_Module_Interface ) tt_get_interface( FT_Module driver, /* TT_Driver */ const char* tt_interface ) { FT_Library library; FT_Module_Interface result; FT_Module sfntd; SFNT_Service sfnt; /* TT_SERVICES_GET derefers `library' in PIC mode */ #ifdef FT_CONFIG_OPTION_PIC if ( !driver ) return NULL; library = driver->library; if ( !library ) return NULL; #endif result = ft_service_list_lookup( TT_SERVICES_GET, tt_interface ); if ( result != NULL ) return result; #ifndef FT_CONFIG_OPTION_PIC if ( !driver ) return NULL; library = driver->library; if ( !library ) return NULL; #endif /* only return the default interface from the SFNT module */ sfntd = FT_Get_Module( library, "sfnt" ); if ( sfntd ) { sfnt = (SFNT_Service)( sfntd->clazz->module_interface ); if ( sfnt ) return sfnt->get_interface( driver, tt_interface ); } return 0; } static FT_Bool tt_check_trickyness_family( FT_String* name ) { #define TRICK_NAMES_MAX_CHARACTERS 19 #define TRICK_NAMES_COUNT 9 static const char trick_names[TRICK_NAMES_COUNT] [TRICK_NAMES_MAX_CHARACTERS + 1] = { "DFKaiSho-SB", /* dfkaisb.ttf */ "DFKaiShu", "DFKai-SB", /* kaiu.ttf */ "HuaTianKaiTi?", /* htkt2.ttf */ "HuaTianSongTi?", /* htst3.ttf */ "Ming(for ISO10646)", /* hkscsiic.ttf & iicore.ttf */ "MingLiU", /* mingliu.ttf & mingliu.ttc */ "PMingLiU", /* mingliu.ttc */ "MingLi43", /* mingli.ttf */ }; int nn; for ( nn = 0; nn < TRICK_NAMES_COUNT; nn++ ) if ( ft_strstr( name, trick_names[nn] ) ) return TRUE; return FALSE; } static FT_UInt32 tt_synth_sfnt_checksum( FT_Stream stream, FT_ULong length ) { FT_Error error; FT_UInt32 checksum = 0; int i; if ( FT_FRAME_ENTER( length ) ) return 0; for ( ; length > 3; length -= 4 ) checksum += (FT_UInt32)FT_GET_ULONG(); for ( i = 3; length > 0; length --, i-- ) checksum += (FT_UInt32)( FT_GET_BYTE() << ( i * 8 ) ); FT_FRAME_EXIT(); return checksum; } static FT_ULong tt_get_sfnt_checksum( TT_Face face, FT_UShort i ) { #if 0 /* if we believe the written value, use following part. */ if ( face->dir_tables[i].CheckSum ) return face->dir_tables[i].CheckSum; #endif if ( !face->goto_table ) return 0; if ( face->goto_table( face, face->dir_tables[i].Tag, face->root.stream, NULL ) ) return 0; return (FT_ULong)tt_synth_sfnt_checksum( face->root.stream, face->dir_tables[i].Length ); } typedef struct tt_sfnt_id_rec_ { FT_ULong CheckSum; FT_ULong Length; } tt_sfnt_id_rec; static FT_Bool tt_check_trickyness_sfnt_ids( TT_Face face ) { #define TRICK_SFNT_IDS_PER_FACE 3 #define TRICK_SFNT_IDS_NUM_FACES 17 static const tt_sfnt_id_rec sfnt_id[TRICK_SFNT_IDS_NUM_FACES] [TRICK_SFNT_IDS_PER_FACE] = { #define TRICK_SFNT_ID_cvt 0 #define TRICK_SFNT_ID_fpgm 1 #define TRICK_SFNT_ID_prep 2 { /* MingLiU 1995 */ { 0x05bcf058, 0x000002e4 }, /* cvt */ { 0x28233bf1, 0x000087c4 }, /* fpgm */ { 0xa344a1ea, 0x000001e1 } /* prep */ }, { /* MingLiU 1996- */ { 0x05bcf058, 0x000002e4 }, /* cvt */ { 0x28233bf1, 0x000087c4 }, /* fpgm */ { 0xa344a1eb, 0x000001e1 } /* prep */ }, { /* DFKaiShu */ { 0x11e5ead4, 0x00000350 }, /* cvt */ { 0x5a30ca3b, 0x00009063 }, /* fpgm */ { 0x13a42602, 0x0000007e } /* prep */ }, { /* HuaTianKaiTi */ { 0xfffbfffc, 0x00000008 }, /* cvt */ { 0x9c9e48b8, 0x0000bea2 }, /* fpgm */ { 0x70020112, 0x00000008 } /* prep */ }, { /* HuaTianSongTi */ { 0xfffbfffc, 0x00000008 }, /* cvt */ { 0x0a5a0483, 0x00017c39 }, /* fpgm */ { 0x70020112, 0x00000008 } /* prep */ }, { /* NEC fadpop7.ttf */ { 0x00000000, 0x00000000 }, /* cvt */ { 0x40c92555, 0x000000e5 }, /* fpgm */ { 0xa39b58e3, 0x0000117c } /* prep */ }, { /* NEC fadrei5.ttf */ { 0x00000000, 0x00000000 }, /* cvt */ { 0x33c41652, 0x000000e5 }, /* fpgm */ { 0x26d6c52a, 0x00000f6a } /* prep */ }, { /* NEC fangot7.ttf */ { 0x00000000, 0x00000000 }, /* cvt */ { 0x6db1651d, 0x0000019d }, /* fpgm */ { 0x6c6e4b03, 0x00002492 } /* prep */ }, { /* NEC fangyo5.ttf */ { 0x00000000, 0x00000000 }, /* cvt */ { 0x40c92555, 0x000000e5 }, /* fpgm */ { 0xde51fad0, 0x0000117c } /* prep */ }, { /* NEC fankyo5.ttf */ { 0x00000000, 0x00000000 }, /* cvt */ { 0x85e47664, 0x000000e5 }, /* fpgm */ { 0xa6c62831, 0x00001caa } /* prep */ }, { /* NEC fanrgo5.ttf */ { 0x00000000, 0x00000000 }, /* cvt */ { 0x2d891cfd, 0x0000019d }, /* fpgm */ { 0xa0604633, 0x00001de8 } /* prep */ }, { /* NEC fangot5.ttc */ { 0x00000000, 0x00000000 }, /* cvt */ { 0x40aa774c, 0x000001cb }, /* fpgm */ { 0x9b5caa96, 0x00001f9a } /* prep */ }, { /* NEC fanmin3.ttc */ { 0x00000000, 0x00000000 }, /* cvt */ { 0x0d3de9cb, 0x00000141 }, /* fpgm */ { 0xd4127766, 0x00002280 } /* prep */ }, { /* NEC FA-Gothic, 1996 */ { 0x00000000, 0x00000000 }, /* cvt */ { 0x4a692698, 0x000001f0 }, /* fpgm */ { 0x340d4346, 0x00001fca } /* prep */ }, { /* NEC FA-Minchou, 1996 */ { 0x00000000, 0x00000000 }, /* cvt */ { 0xcd34c604, 0x00000166 }, /* fpgm */ { 0x6cf31046, 0x000022b0 } /* prep */ }, { /* NEC FA-RoundGothicB, 1996 */ { 0x00000000, 0x00000000 }, /* cvt */ { 0x5da75315, 0x0000019d }, /* fpgm */ { 0x40745a5f, 0x000022e0 } /* prep */ }, { /* NEC FA-RoundGothicM, 1996 */ { 0x00000000, 0x00000000 }, /* cvt */ { 0xf055fc48, 0x000001c2 }, /* fpgm */ { 0x3900ded3, 0x00001e18 } /* prep */ } }; FT_ULong checksum; int num_matched_ids[TRICK_SFNT_IDS_NUM_FACES]; FT_Bool has_cvt, has_fpgm, has_prep; FT_UShort i; int j, k; FT_MEM_SET( num_matched_ids, 0, sizeof ( int ) * TRICK_SFNT_IDS_NUM_FACES ); has_cvt = FALSE; has_fpgm = FALSE; has_prep = FALSE; for ( i = 0; i < face->num_tables; i++ ) { checksum = 0; switch( face->dir_tables[i].Tag ) { case TTAG_cvt: k = TRICK_SFNT_ID_cvt; has_cvt = TRUE; break; case TTAG_fpgm: k = TRICK_SFNT_ID_fpgm; has_fpgm = TRUE; break; case TTAG_prep: k = TRICK_SFNT_ID_prep; has_prep = TRUE; break; default: continue; } for ( j = 0; j < TRICK_SFNT_IDS_NUM_FACES; j++ ) if ( face->dir_tables[i].Length == sfnt_id[j][k].Length ) { if ( !checksum ) checksum = tt_get_sfnt_checksum( face, i ); if ( sfnt_id[j][k].CheckSum == checksum ) num_matched_ids[j]++; if ( num_matched_ids[j] == TRICK_SFNT_IDS_PER_FACE ) return TRUE; } } for ( j = 0; j < TRICK_SFNT_IDS_NUM_FACES; j++ ) { if ( !has_cvt && !sfnt_id[j][TRICK_SFNT_ID_cvt].Length ) num_matched_ids[j] ++; if ( !has_fpgm && !sfnt_id[j][TRICK_SFNT_ID_fpgm].Length ) num_matched_ids[j] ++; if ( !has_prep && !sfnt_id[j][TRICK_SFNT_ID_prep].Length ) num_matched_ids[j] ++; if ( num_matched_ids[j] == TRICK_SFNT_IDS_PER_FACE ) return TRUE; } return FALSE; } static FT_Bool tt_check_trickyness( FT_Face face ) { if ( !face ) return FALSE; /* For first, check the face name for quick check. */ if ( face->family_name && tt_check_trickyness_family( face->family_name ) ) return TRUE; /* Type42 fonts may lack `name' tables, we thus try to identify */ /* tricky fonts by checking the checksums of Type42-persistent */ /* sfnt tables (`cvt', `fpgm', and `prep'). */ if ( tt_check_trickyness_sfnt_ids( (TT_Face)face ) ) return TRUE; return FALSE; } FT_LOCAL_DEF( FT_Error ) tt_face_load_hdmx( TT_Face face, FT_Stream stream ) { FT_Error error; FT_Memory memory = stream->memory; FT_UInt version, nn, num_records; FT_ULong table_size, record_size; FT_Byte* p; FT_Byte* limit; /* this table is optional */ error = face->goto_table( face, TTAG_hdmx, stream, &table_size ); if ( error || table_size < 8 ) return FT_Err_Ok; if ( FT_FRAME_EXTRACT( table_size, face->hdmx_table ) ) goto Exit; p = face->hdmx_table; limit = p + table_size; version = FT_NEXT_USHORT( p ); num_records = FT_NEXT_USHORT( p ); record_size = FT_NEXT_ULONG( p ); /* The maximum number of bytes in an hdmx device record is the */ /* maximum number of glyphs + 2; this is 0xFFFF + 2; this is */ /* the reason why `record_size' is a long (which we read as */ /* unsigned long for convenience). In practice, two bytes */ /* sufficient to hold the size value. */ /* */ /* There are at least two fonts, HANNOM-A and HANNOM-B version */ /* 2.0 (2005), which get this wrong: The upper two bytes of */ /* the size value are set to 0xFF instead of 0x00. We catch */ /* and fix this. */ if ( record_size >= 0xFFFF0000UL ) record_size &= 0xFFFFU; /* The limit for `num_records' is a heuristic value. */ if ( version != 0 || num_records > 255 || record_size > 0x10001L ) { error = FT_THROW( Invalid_File_Format ); goto Fail; } if ( FT_NEW_ARRAY( face->hdmx_record_sizes, num_records ) ) goto Fail; for ( nn = 0; nn < num_records; nn++ ) { if ( p + record_size > limit ) break; face->hdmx_record_sizes[nn] = p[0]; p += record_size; } face->hdmx_record_count = nn; face->hdmx_table_size = table_size; face->hdmx_record_size = record_size; Exit: return error; Fail: FT_FRAME_RELEASE( face->hdmx_table ); face->hdmx_table_size = 0; goto Exit; } FT_LOCAL_DEF( FT_Error ) tt_face_load_loca( TT_Face face, FT_Stream stream ) { FT_Error error; FT_ULong table_len; FT_Int shift; /* we need the size of the `glyf' table for malformed `loca' tables */ error = face->goto_table( face, TTAG_glyf, stream, &face->glyf_len ); /* it is possible that a font doesn't have a glyf table at all */ /* or its size is zero */ if ( FT_ERR_EQ( error, Table_Missing ) ) face->glyf_len = 0; else if ( error ) goto Exit; FT_TRACE2(( "Locations " )); error = face->goto_table( face, TTAG_loca, stream, &table_len ); if ( error ) { error = FT_THROW( Locations_Missing ); goto Exit; } if ( face->header.Index_To_Loc_Format != 0 ) { shift = 2; if ( table_len >= 0x40000L ) { FT_TRACE2(( "table too large\n" )); error = FT_THROW( Invalid_Table ); goto Exit; } face->num_locations = table_len >> shift; } else { shift = 1; if ( table_len >= 0x20000L ) { FT_TRACE2(( "table too large\n" )); error = FT_THROW( Invalid_Table ); goto Exit; } face->num_locations = table_len >> shift; } if ( face->num_locations != (FT_ULong)face->root.num_glyphs + 1 ) { FT_TRACE2(( "glyph count mismatch! loca: %d, maxp: %d\n", face->num_locations - 1, face->root.num_glyphs )); /* we only handle the case where `maxp' gives a larger value */ if ( face->num_locations <= (FT_ULong)face->root.num_glyphs ) { FT_Long new_loca_len = ( (FT_Long)( face->root.num_glyphs ) + 1 ) << shift; TT_Table entry = face->dir_tables; TT_Table limit = entry + face->num_tables; FT_Long pos = FT_Stream_Pos( stream ); FT_Long dist = 0x7FFFFFFFL; /* compute the distance to next table in font file */ for ( ; entry < limit; entry++ ) { FT_Long diff = entry->Offset - pos; if ( diff > 0 && diff < dist ) dist = diff; } if ( entry == limit ) { /* `loca' is the last table */ dist = stream->size - pos; } if ( new_loca_len <= dist ) { face->num_locations = face->root.num_glyphs + 1; table_len = new_loca_len; FT_TRACE2(( "adjusting num_locations to %d\n", face->num_locations )); } } } /* * Extract the frame. We don't need to decompress it since * we are able to parse it directly. */ if ( FT_FRAME_EXTRACT( table_len, face->glyph_locations ) ) goto Exit; FT_TRACE2(( "loaded\n" )); Exit: return error; } FT_LOCAL_DEF( FT_Error ) tt_face_load_cvt( TT_Face face, FT_Stream stream ) { #ifdef TT_USE_BYTECODE_INTERPRETER FT_Error error; FT_Memory memory = stream->memory; FT_ULong table_len; FT_TRACE2(( "CVT " )); error = face->goto_table( face, TTAG_cvt, stream, &table_len ); if ( error ) { FT_TRACE2(( "is missing\n" )); face->cvt_size = 0; face->cvt = NULL; error = FT_Err_Ok; goto Exit; } face->cvt_size = table_len / 2; if ( FT_NEW_ARRAY( face->cvt, face->cvt_size ) ) goto Exit; if ( FT_FRAME_ENTER( face->cvt_size * 2L ) ) goto Exit; { FT_Short* cur = face->cvt; FT_Short* limit = cur + face->cvt_size; for ( ; cur < limit; cur++ ) *cur = FT_GET_SHORT(); } FT_FRAME_EXIT(); FT_TRACE2(( "loaded\n" )); #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT if ( face->doblend ) error = tt_face_vary_cvt( face, stream ); #endif Exit: return error; #else /* !TT_USE_BYTECODE_INTERPRETER */ FT_UNUSED( face ); FT_UNUSED( stream ); return FT_Err_Ok; #endif } typedef enum GX_TupleIndexFlags_ { GX_TI_EMBEDDED_TUPLE_COORD = 0x8000, GX_TI_INTERMEDIATE_TUPLE = 0x4000, GX_TI_PRIVATE_POINT_NUMBERS = 0x2000, GX_TI_RESERVED_TUPLE_FLAG = 0x1000, GX_TI_TUPLE_INDEX_MASK = 0x0FFF } GX_TupleIndexFlags; static FT_Fixed ft_var_apply_tuple( GX_Blend blend, FT_UShort tupleIndex, FT_Fixed* tuple_coords, FT_Fixed* im_start_coords, FT_Fixed* im_end_coords ); static FT_UShort* ft_var_readpackedpoints( FT_Stream stream, FT_UInt *point_cnt ); static FT_Short* ft_var_readpackeddeltas( FT_Stream stream, FT_Offset delta_cnt ); FT_LOCAL_DEF( FT_Error ) tt_face_vary_cvt( TT_Face face, FT_Stream stream ) { FT_Error error; FT_Memory memory = stream->memory; FT_ULong table_start; FT_ULong table_len; FT_UInt tupleCount; FT_ULong offsetToData; FT_ULong here; FT_UInt i, j; FT_Fixed* tuple_coords = NULL; FT_Fixed* im_start_coords = NULL; FT_Fixed* im_end_coords = NULL; GX_Blend blend = face->blend; FT_UInt point_count; FT_UShort* localpoints; FT_Short* deltas; FT_TRACE2(( "CVAR " )); if ( blend == NULL ) { FT_TRACE2(( "tt_face_vary_cvt: no blend specified\n" )); error = FT_Err_Ok; goto Exit; } if ( face->cvt == NULL ) { FT_TRACE2(( "tt_face_vary_cvt: no `cvt ' table\n" )); error = FT_Err_Ok; goto Exit; } error = face->goto_table( face, TTAG_cvar, stream, &table_len ); if ( error ) { FT_TRACE2(( "is missing\n" )); error = FT_Err_Ok; goto Exit; } if ( FT_FRAME_ENTER( table_len ) ) { error = FT_Err_Ok; goto Exit; } table_start = FT_Stream_FTell( stream ); if ( FT_GET_LONG() != 0x00010000L ) { FT_TRACE2(( "bad table version\n" )); error = FT_Err_Ok; goto FExit; } if ( FT_NEW_ARRAY( tuple_coords, blend->num_axis ) || FT_NEW_ARRAY( im_start_coords, blend->num_axis ) || FT_NEW_ARRAY( im_end_coords, blend->num_axis ) ) goto FExit; tupleCount = FT_GET_USHORT(); offsetToData = table_start + FT_GET_USHORT(); /* The documentation implies there are flags packed into the */ /* tuplecount, but John Jenkins says that shared points don't apply */ /* to `cvar', and no other flags are defined. */ for ( i = 0; i < ( tupleCount & 0xFFF ); ++i ) { FT_UInt tupleDataSize; FT_UInt tupleIndex; FT_Fixed apply; tupleDataSize = FT_GET_USHORT(); tupleIndex = FT_GET_USHORT(); /* There is no provision here for a global tuple coordinate section, */ /* so John says. There are no tuple indices, just embedded tuples. */ if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD ) { for ( j = 0; j < blend->num_axis; ++j ) tuple_coords[j] = FT_GET_SHORT() << 2; /* convert from */ /* short frac to fixed */ } else { /* skip this tuple; it makes no sense */ if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) for ( j = 0; j < 2 * blend->num_axis; ++j ) (void)FT_GET_SHORT(); offsetToData += tupleDataSize; continue; } if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) { for ( j = 0; j < blend->num_axis; ++j ) im_start_coords[j] = FT_GET_SHORT() << 2; for ( j = 0; j < blend->num_axis; ++j ) im_end_coords[j] = FT_GET_SHORT() << 2; } apply = ft_var_apply_tuple( blend, (FT_UShort)tupleIndex, tuple_coords, im_start_coords, im_end_coords ); if ( /* tuple isn't active for our blend */ apply == 0 || /* global points not allowed, */ /* if they aren't local, makes no sense */ !( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS ) ) { offsetToData += tupleDataSize; continue; } here = FT_Stream_FTell( stream ); FT_Stream_SeekSet( stream, offsetToData ); localpoints = ft_var_readpackedpoints( stream, &point_count ); deltas = ft_var_readpackeddeltas( stream, point_count == 0 ? face->cvt_size : point_count ); if ( localpoints == NULL || deltas == NULL ) /* failure, ignore it */; else if ( localpoints == ALL_POINTS ) { /* this means that there are deltas for every entry in cvt */ for ( j = 0; j < face->cvt_size; ++j ) face->cvt[j] = (FT_Short)( face->cvt[j] + FT_MulFix( deltas[j], apply ) ); } else { for ( j = 0; j < point_count; ++j ) { int pindex = localpoints[j]; face->cvt[pindex] = (FT_Short)( face->cvt[pindex] + FT_MulFix( deltas[j], apply ) ); } } if ( localpoints != ALL_POINTS ) FT_FREE( localpoints ); FT_FREE( deltas ); offsetToData += tupleDataSize; FT_Stream_SeekSet( stream, here ); } FExit: FT_FRAME_EXIT(); Exit: FT_FREE( tuple_coords ); FT_FREE( im_start_coords ); FT_FREE( im_end_coords ); return error; } FT_LOCAL_DEF( FT_Error ) tt_face_load_fpgm( TT_Face face, FT_Stream stream ) { #ifdef TT_USE_BYTECODE_INTERPRETER FT_Error error; FT_ULong table_len; FT_TRACE2(( "Font program " )); /* The font program is optional */ error = face->goto_table( face, TTAG_fpgm, stream, &table_len ); if ( error ) { face->font_program = NULL; face->font_program_size = 0; error = FT_Err_Ok; FT_TRACE2(( "is missing\n" )); } else { face->font_program_size = table_len; if ( FT_FRAME_EXTRACT( table_len, face->font_program ) ) goto Exit; FT_TRACE2(( "loaded, %12d bytes\n", face->font_program_size )); } Exit: return error; #else /* !TT_USE_BYTECODE_INTERPRETER */ FT_UNUSED( face ); FT_UNUSED( stream ); return FT_Err_Ok; #endif } FT_LOCAL_DEF( FT_Error ) tt_face_load_prep( TT_Face face, FT_Stream stream ) { #ifdef TT_USE_BYTECODE_INTERPRETER FT_Error error; FT_ULong table_len; FT_TRACE2(( "Prep program " )); error = face->goto_table( face, TTAG_prep, stream, &table_len ); if ( error ) { face->cvt_program = NULL; face->cvt_program_size = 0; error = FT_Err_Ok; FT_TRACE2(( "is missing\n" )); } else { face->cvt_program_size = table_len; if ( FT_FRAME_EXTRACT( table_len, face->cvt_program ) ) goto Exit; FT_TRACE2(( "loaded, %12d bytes\n", face->cvt_program_size )); } Exit: return error; #else /* !TT_USE_BYTECODE_INTERPRETER */ FT_UNUSED( face ); FT_UNUSED( stream ); return FT_Err_Ok; #endif } static FT_Bool tt_check_single_notdef( FT_Face ttface ) { FT_Bool result = FALSE; TT_Face face = (TT_Face)ttface; FT_UInt asize; FT_ULong i; FT_ULong glyph_index = 0; FT_UInt count = 0; for( i = 0; i < face->num_locations; i++ ) { tt_face_get_location( face, i, &asize ); if ( asize > 0 ) { count += 1; if ( count > 1 ) break; glyph_index = i; } } /* Only have a single outline. */ if ( count == 1 ) { if ( glyph_index == 0 ) result = TRUE; else { /* FIXME: Need to test glyphname == .notdef ? */ FT_Error error; char buf[8]; error = FT_Get_Glyph_Name( ttface, glyph_index, buf, 8 ); if ( !error && buf[0] == '.' && !ft_strncmp( buf, ".notdef", 8 ) ) result = TRUE; } } return result; } FT_CALLBACK_DEF( FT_Error ) TT_Access_Glyph_Frame( TT_Loader loader, FT_UInt glyph_index, FT_ULong offset, FT_UInt byte_count ) { FT_Error error; FT_Stream stream = loader->stream; /* for non-debug mode */ FT_UNUSED( glyph_index ); FT_TRACE4(( "Glyph %ld\n", glyph_index )); /* the following line sets the `error' variable through macros! */ if ( FT_STREAM_SEEK( offset ) || FT_FRAME_ENTER( byte_count ) ) return error; loader->cursor = stream->cursor; loader->limit = stream->limit; return FT_Err_Ok; } FT_CALLBACK_DEF( FT_Error ) TT_Load_Glyph_Header( TT_Loader loader ) { FT_Byte* p = loader->cursor; FT_Byte* limit = loader->limit; if ( p + 10 > limit ) return FT_THROW( Invalid_Outline ); loader->n_contours = FT_NEXT_SHORT( p ); loader->bbox.xMin = FT_NEXT_SHORT( p ); loader->bbox.yMin = FT_NEXT_SHORT( p ); loader->bbox.xMax = FT_NEXT_SHORT( p ); loader->bbox.yMax = FT_NEXT_SHORT( p ); FT_TRACE5(( " # of contours: %d\n", loader->n_contours )); FT_TRACE5(( " xMin: %4d xMax: %4d\n", loader->bbox.xMin, loader->bbox.xMax )); FT_TRACE5(( " yMin: %4d yMax: %4d\n", loader->bbox.yMin, loader->bbox.yMax )); loader->cursor = p; return FT_Err_Ok; } #define FT_OUTLINE_CONTOURS_MAX SHRT_MAX #define FT_OUTLINE_POINTS_MAX SHRT_MAX static void FT_GlyphLoader_Adjust_Points( FT_GlyphLoader loader ) { FT_Outline* base = &loader->base.outline; FT_Outline* current = &loader->current.outline; current->points = base->points + base->n_points; current->tags = base->tags + base->n_points; current->contours = base->contours + base->n_contours; /* handle extra points table - if any */ if ( loader->use_extra ) { loader->current.extra_points = loader->base.extra_points + base->n_points; loader->current.extra_points2 = loader->base.extra_points2 + base->n_points; } } FT_BASE_DEF( FT_Error ) FT_GlyphLoader_CheckPoints( FT_GlyphLoader loader, FT_UInt n_points, FT_UInt n_contours ) { FT_Memory memory = loader->memory; FT_Error error = FT_Err_Ok; FT_Outline* base = &loader->base.outline; FT_Outline* current = &loader->current.outline; FT_Bool adjust = 0; FT_UInt new_max, old_max; /* check points & tags */ new_max = base->n_points + current->n_points + n_points; old_max = loader->max_points; if ( new_max > old_max ) { new_max = FT_PAD_CEIL( new_max, 8 ); if ( new_max > FT_OUTLINE_POINTS_MAX ) return FT_THROW( Array_Too_Large ); if ( FT_RENEW_ARRAY( base->points, old_max, new_max ) || FT_RENEW_ARRAY( base->tags, old_max, new_max ) ) goto Exit; if ( loader->use_extra ) { if ( FT_RENEW_ARRAY( loader->base.extra_points, old_max * 2, new_max * 2 ) ) goto Exit; FT_ARRAY_MOVE( loader->base.extra_points + new_max, loader->base.extra_points + old_max, old_max ); loader->base.extra_points2 = loader->base.extra_points + new_max; } adjust = 1; loader->max_points = new_max; } /* check contours */ old_max = loader->max_contours; new_max = base->n_contours + current->n_contours + n_contours; if ( new_max > old_max ) { new_max = FT_PAD_CEIL( new_max, 4 ); if ( new_max > FT_OUTLINE_CONTOURS_MAX ) return FT_THROW( Array_Too_Large ); if ( FT_RENEW_ARRAY( base->contours, old_max, new_max ) ) goto Exit; adjust = 1; loader->max_contours = new_max; } if ( adjust ) FT_GlyphLoader_Adjust_Points( loader ); Exit: if ( error ) FT_GlyphLoader_Reset( loader ); return error; } #define FT_GLYPHLOADER_CHECK_P( _loader, _count ) \ ( (_count) == 0 || ((_loader)->base.outline.n_points + \ (_loader)->current.outline.n_points + \ (unsigned long)(_count)) <= (_loader)->max_points ) #define FT_GLYPHLOADER_CHECK_C( _loader, _count ) \ ( (_count) == 0 || ((_loader)->base.outline.n_contours + \ (_loader)->current.outline.n_contours + \ (unsigned long)(_count)) <= (_loader)->max_contours ) #define FT_GLYPHLOADER_CHECK_POINTS( _loader, _points,_contours ) \ ( ( FT_GLYPHLOADER_CHECK_P( _loader, _points ) && \ FT_GLYPHLOADER_CHECK_C( _loader, _contours ) ) \ ? 0 \ : FT_GlyphLoader_CheckPoints( (_loader), (_points), (_contours) ) ) #define FT_CURVE_TAG( flag ) ( flag & 3 ) #define FT_CURVE_TAG_ON 1 #define FT_CURVE_TAG_CONIC 0 #define FT_CURVE_TAG_CUBIC 2 #define FT_CURVE_TAG_HAS_SCANMODE 4 #define FT_CURVE_TAG_TOUCH_X 8 /* reserved for the TrueType hinter */ #define FT_CURVE_TAG_TOUCH_Y 16 /* reserved for the TrueType hinter */ #define FT_CURVE_TAG_TOUCH_BOTH ( FT_CURVE_TAG_TOUCH_X | \ FT_CURVE_TAG_TOUCH_Y ) #define FT_Curve_Tag_On FT_CURVE_TAG_ON #define FT_Curve_Tag_Conic FT_CURVE_TAG_CONIC #define FT_Curve_Tag_Cubic FT_CURVE_TAG_CUBIC #define FT_Curve_Tag_Touch_X FT_CURVE_TAG_TOUCH_X #define FT_Curve_Tag_Touch_Y FT_CURVE_TAG_TOUCH_Y #define ARGS_ARE_WORDS 0x0001 #define ARGS_ARE_XY_VALUES 0x0002 #define ROUND_XY_TO_GRID 0x0004 #define WE_HAVE_A_SCALE 0x0008 /* reserved 0x0010 */ #define MORE_COMPONENTS 0x0020 #define WE_HAVE_AN_XY_SCALE 0x0040 #define WE_HAVE_A_2X2 0x0080 #define WE_HAVE_INSTR 0x0100 #define USE_MY_METRICS 0x0200 #define OVERLAP_COMPOUND 0x0400 #define SCALED_COMPONENT_OFFSET 0x0800 #define UNSCALED_COMPONENT_OFFSET 0x1000 static void FT_GlyphLoader_Adjust_Subglyphs( FT_GlyphLoader loader ) { FT_GlyphLoad base = &loader->base; FT_GlyphLoad current = &loader->current; current->subglyphs = base->subglyphs + base->num_subglyphs; } FT_BASE_DEF( FT_Error ) FT_GlyphLoader_CheckSubGlyphs( FT_GlyphLoader loader, FT_UInt n_subs ) { FT_Memory memory = loader->memory; FT_Error error = FT_Err_Ok; FT_UInt new_max, old_max; FT_GlyphLoad base = &loader->base; FT_GlyphLoad current = &loader->current; new_max = base->num_subglyphs + current->num_subglyphs + n_subs; old_max = loader->max_subglyphs; if ( new_max > old_max ) { new_max = FT_PAD_CEIL( new_max, 2 ); if ( FT_RENEW_ARRAY( base->subglyphs, old_max, new_max ) ) goto Exit; loader->max_subglyphs = new_max; FT_GlyphLoader_Adjust_Subglyphs( loader ); } Exit: return error; } FT_CALLBACK_DEF( FT_Error ) TT_Load_Composite_Glyph( TT_Loader loader ) { FT_Error error; FT_Byte* p = loader->cursor; FT_Byte* limit = loader->limit; FT_GlyphLoader gloader = loader->gloader; FT_SubGlyph subglyph; FT_UInt num_subglyphs; num_subglyphs = 0; do { FT_Fixed xx, xy, yy, yx; FT_UInt count; /* check that we can load a new subglyph */ error = FT_GlyphLoader_CheckSubGlyphs( gloader, num_subglyphs + 1 ); if ( error ) goto Fail; /* check space */ if ( p + 4 > limit ) goto Invalid_Composite; subglyph = gloader->current.subglyphs + num_subglyphs; subglyph->arg1 = subglyph->arg2 = 0; subglyph->flags = FT_NEXT_USHORT( p ); subglyph->index = FT_NEXT_USHORT( p ); /* check space */ count = 2; if ( subglyph->flags & ARGS_ARE_WORDS ) count += 2; if ( subglyph->flags & WE_HAVE_A_SCALE ) count += 2; else if ( subglyph->flags & WE_HAVE_AN_XY_SCALE ) count += 4; else if ( subglyph->flags & WE_HAVE_A_2X2 ) count += 8; if ( p + count > limit ) goto Invalid_Composite; /* read arguments */ if ( subglyph->flags & ARGS_ARE_WORDS ) { subglyph->arg1 = FT_NEXT_SHORT( p ); subglyph->arg2 = FT_NEXT_SHORT( p ); } else { subglyph->arg1 = FT_NEXT_CHAR( p ); subglyph->arg2 = FT_NEXT_CHAR( p ); } /* read transform */ xx = yy = 0x10000L; xy = yx = 0; if ( subglyph->flags & WE_HAVE_A_SCALE ) { xx = (FT_Fixed)FT_NEXT_SHORT( p ) << 2; yy = xx; } else if ( subglyph->flags & WE_HAVE_AN_XY_SCALE ) { xx = (FT_Fixed)FT_NEXT_SHORT( p ) << 2; yy = (FT_Fixed)FT_NEXT_SHORT( p ) << 2; } else if ( subglyph->flags & WE_HAVE_A_2X2 ) { xx = (FT_Fixed)FT_NEXT_SHORT( p ) << 2; yx = (FT_Fixed)FT_NEXT_SHORT( p ) << 2; xy = (FT_Fixed)FT_NEXT_SHORT( p ) << 2; yy = (FT_Fixed)FT_NEXT_SHORT( p ) << 2; } subglyph->transform.xx = xx; subglyph->transform.xy = xy; subglyph->transform.yx = yx; subglyph->transform.yy = yy; num_subglyphs++; } while ( subglyph->flags & MORE_COMPONENTS ); gloader->current.num_subglyphs = num_subglyphs; #ifdef TT_USE_BYTECODE_INTERPRETER { FT_Stream stream = loader->stream; /* we must undo the FT_FRAME_ENTER in order to point */ /* to the composite instructions, if we find some. */ /* We will process them later. */ /* */ loader->ins_pos = (FT_ULong)( FT_STREAM_POS() + p - limit ); } #endif loader->cursor = p; Fail: return error; Invalid_Composite: error = FT_THROW( Invalid_Composite ); goto Fail; } FT_CALLBACK_DEF( FT_Error ) TT_Load_Simple_Glyph( TT_Loader load ) { FT_Error error; FT_Byte* p = load->cursor; FT_Byte* limit = load->limit; FT_GlyphLoader gloader = load->gloader; FT_Int n_contours = load->n_contours; FT_Outline* outline; FT_UShort n_ins; FT_Int n_points; FT_ULong tmp; FT_Byte *flag, *flag_limit; FT_Byte c, count; FT_Vector *vec, *vec_limit; FT_Pos x; FT_Short *cont, *cont_limit, prev_cont; FT_Int xy_size = 0; /* check that we can add the contours to the glyph */ error = FT_GLYPHLOADER_CHECK_POINTS( gloader, 0, n_contours ); if ( error ) goto Fail; /* reading the contours' endpoints & number of points */ cont = gloader->current.outline.contours; cont_limit = cont + n_contours; /* check space for contours array + instructions count */ if ( n_contours >= 0xFFF || p + ( n_contours + 1 ) * 2 > limit ) goto Invalid_Outline; prev_cont = FT_NEXT_SHORT( p ); if ( n_contours > 0 ) cont[0] = prev_cont; if ( prev_cont < 0 ) goto Invalid_Outline; for ( cont++; cont < cont_limit; cont++ ) { cont[0] = FT_NEXT_SHORT( p ); if ( cont[0] <= prev_cont ) { /* unordered contours: this is invalid */ goto Invalid_Outline; } prev_cont = cont[0]; } n_points = 0; if ( n_contours > 0 ) { n_points = cont[-1] + 1; if ( n_points < 0 ) goto Invalid_Outline; } /* note that we will add four phantom points later */ error = FT_GLYPHLOADER_CHECK_POINTS( gloader, n_points + 4, 0 ); if ( error ) goto Fail; /* reading the bytecode instructions */ load->glyph->control_len = 0; load->glyph->control_data = 0; if ( p + 2 > limit ) goto Invalid_Outline; n_ins = FT_NEXT_USHORT( p ); FT_TRACE5(( " Instructions size: %u\n", n_ins )); /* check it */ if ( ( limit - p ) < n_ins ) { FT_TRACE0(( "TT_Load_Simple_Glyph: instruction count mismatch\n" )); error = FT_THROW( Too_Many_Hints ); goto Fail; } #ifdef TT_USE_BYTECODE_INTERPRETER if ( IS_HINTED( load->load_flags ) ) { /* we don't trust `maxSizeOfInstructions' in the `maxp' table */ /* and thus update the bytecode array size by ourselves */ tmp = load->exec->glyphSize; error = Update_Max( load->exec->memory, &tmp, sizeof ( FT_Byte ), (void*)&load->exec->glyphIns, n_ins ); load->exec->glyphSize = (FT_UShort)tmp; if ( error ) return error; load->glyph->control_len = n_ins; load->glyph->control_data = load->exec->glyphIns; FT_MEM_COPY( load->exec->glyphIns, p, (FT_Long)n_ins ); } #endif /* TT_USE_BYTECODE_INTERPRETER */ p += n_ins; outline = &gloader->current.outline; /* reading the point tags */ flag = (FT_Byte*)outline->tags; flag_limit = flag + n_points; FT_ASSERT( flag != NULL ); while ( flag < flag_limit ) { if ( p + 1 > limit ) goto Invalid_Outline; *flag++ = c = FT_NEXT_BYTE( p ); if ( c & 8 ) { if ( p + 1 > limit ) goto Invalid_Outline; count = FT_NEXT_BYTE( p ); if ( flag + (FT_Int)count > flag_limit ) goto Invalid_Outline; for ( ; count > 0; count-- ) *flag++ = c; } } /* reading the X coordinates */ vec = outline->points; vec_limit = vec + n_points; flag = (FT_Byte*)outline->tags; x = 0; if ( p + xy_size > limit ) goto Invalid_Outline; for ( ; vec < vec_limit; vec++, flag++ ) { FT_Pos y = 0; FT_Byte f = *flag; if ( f & 2 ) { if ( p + 1 > limit ) goto Invalid_Outline; y = (FT_Pos)FT_NEXT_BYTE( p ); if ( ( f & 16 ) == 0 ) y = -y; } else if ( ( f & 16 ) == 0 ) { if ( p + 2 > limit ) goto Invalid_Outline; y = (FT_Pos)FT_NEXT_SHORT( p ); } x += y; vec->x = x; /* the cast is for stupid compilers */ *flag = (FT_Byte)( f & ~( 2 | 16 ) ); } /* reading the Y coordinates */ vec = gloader->current.outline.points; vec_limit = vec + n_points; flag = (FT_Byte*)outline->tags; x = 0; for ( ; vec < vec_limit; vec++, flag++ ) { FT_Pos y = 0; FT_Byte f = *flag; if ( f & 4 ) { if ( p + 1 > limit ) goto Invalid_Outline; y = (FT_Pos)FT_NEXT_BYTE( p ); if ( ( f & 32 ) == 0 ) y = -y; } else if ( ( f & 32 ) == 0 ) { if ( p + 2 > limit ) goto Invalid_Outline; y = (FT_Pos)FT_NEXT_SHORT( p ); } x += y; vec->y = x; /* the cast is for stupid compilers */ *flag = (FT_Byte)( f & FT_CURVE_TAG_ON ); } outline->n_points = (FT_UShort)n_points; outline->n_contours = (FT_Short) n_contours; load->cursor = p; Fail: return error; Invalid_Outline: error = FT_THROW( Invalid_Outline ); goto Fail; } FT_CALLBACK_DEF( void ) TT_Forget_Glyph_Frame( TT_Loader loader ) { FT_Stream stream = loader->stream; FT_FRAME_EXIT(); } FT_LOCAL_DEF( void ) TT_Init_Glyph_Loading( TT_Face face ) { face->access_glyph_frame = TT_Access_Glyph_Frame; face->read_glyph_header = TT_Load_Glyph_Header; face->read_simple_glyph = TT_Load_Simple_Glyph; face->read_composite_glyph = TT_Load_Composite_Glyph; face->forget_glyph_frame = TT_Forget_Glyph_Frame; } FT_LOCAL_DEF( FT_Error ) tt_face_init( FT_Stream stream, FT_Face ttface, /* TT_Face */ FT_Int face_index, FT_Int num_params, FT_Parameter* params ) { FT_Error error; FT_Library library; SFNT_Service sfnt; TT_Face face = (TT_Face)ttface; FT_TRACE2(( "TTF driver\n" )); library = ttface->driver->root.library; sfnt = (SFNT_Service)FT_Get_Module_Interface( library, "sfnt" ); if ( !sfnt ) { FT_ERROR(( "tt_face_init: cannot access `sfnt' module\n" )); error = FT_THROW( Missing_Module ); goto Exit; } /* create input stream from resource */ if ( FT_STREAM_SEEK( 0 ) ) goto Exit; /* check that we have a valid TrueType file */ error = sfnt->init_face( stream, face, face_index, num_params, params ); /* Stream may have changed. */ stream = face->root.stream; if ( error ) goto Exit; /* We must also be able to accept Mac/GX fonts, as well as OT ones. */ /* The 0x00020000 tag is completely undocumented; some fonts from */ /* Arphic made for Chinese Windows 3.1 have this. */ if ( face->format_tag != 0x00010000L && /* MS fonts */ face->format_tag != 0x00020000L && /* CJK fonts for Win 3.1 */ face->format_tag != TTAG_true ) /* Mac fonts */ { FT_TRACE2(( " not a TTF font\n" )); goto Bad_Format; } #ifdef TT_USE_BYTECODE_INTERPRETER ttface->face_flags |= FT_FACE_FLAG_HINTER; #endif /* If we are performing a simple font format check, exit immediately. */ if ( face_index < 0 ) return FT_Err_Ok; /* Load font directory */ error = sfnt->load_face( stream, face, face_index, num_params, params ); if ( error ) goto Exit; if ( tt_check_trickyness( ttface ) ) ttface->face_flags |= FT_FACE_FLAG_TRICKY; error = tt_face_load_hdmx( face, stream ); if ( error ) goto Exit; if ( FT_IS_SCALABLE( ttface ) ) { #ifdef FT_CONFIG_OPTION_INCREMENTAL if ( !ttface->internal->incremental_interface ) error = tt_face_load_loca( face, stream ); if ( !error ) error = tt_face_load_cvt( face, stream ); if ( !error ) error = tt_face_load_fpgm( face, stream ); if ( !error ) error = tt_face_load_prep( face, stream ); /* Check the scalable flag based on `loca'. */ if ( !ttface->internal->incremental_interface && ttface->num_fixed_sizes && face->glyph_locations && tt_check_single_notdef( ttface ) ) { FT_TRACE5(( "tt_face_init:" " Only the `.notdef' glyph has an outline.\n" " " " Resetting scalable flag to FALSE.\n" )); ttface->face_flags &= ~FT_FACE_FLAG_SCALABLE; } #else if ( !error ) error = tt_face_load_loca( face, stream ); if ( !error ) error = tt_face_load_cvt( face, stream ); if ( !error ) error = tt_face_load_fpgm( face, stream ); if ( !error ) error = tt_face_load_prep( face, stream ); /* Check the scalable flag based on `loca'. */ if ( ttface->num_fixed_sizes && face->glyph_locations && tt_check_single_notdef( ttface ) ) { FT_TRACE5(( "tt_face_init:" " Only the `.notdef' glyph has an outline.\n" " " " Resetting scalable flag to FALSE.\n" )); ttface->face_flags &= ~FT_FACE_FLAG_SCALABLE; } #endif } #if defined( TT_CONFIG_OPTION_UNPATENTED_HINTING ) && \ !defined( TT_CONFIG_OPTION_BYTECODE_INTERPRETER ) { FT_Bool unpatented_hinting; int i; /* Determine whether unpatented hinting is to be used for this face. */ unpatented_hinting = FT_BOOL ( library->debug_hooks[FT_DEBUG_HOOK_UNPATENTED_HINTING] != NULL ); for ( i = 0; i < num_params && !face->unpatented_hinting; i++ ) if ( params[i].tag == FT_PARAM_TAG_UNPATENTED_HINTING ) unpatented_hinting = TRUE; if ( !unpatented_hinting ) ttface->internal->ignore_unpatented_hinter = TRUE; } #endif /* TT_CONFIG_OPTION_UNPATENTED_HINTING && !TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ /* initialize standard glyph loading routines */ TT_Init_Glyph_Loading( face ); Exit: return error; Bad_Format: error = FT_THROW( Unknown_File_Format ); goto Exit; } FT_LOCAL_DEF( void ) tt_face_done_loca( TT_Face face ) { FT_Stream stream = face->root.stream; FT_FRAME_RELEASE( face->glyph_locations ); face->num_locations = 0; } FT_LOCAL_DEF( void ) tt_face_free_hdmx( TT_Face face ) { FT_Stream stream = face->root.stream; FT_Memory memory = stream->memory; FT_FREE( face->hdmx_record_sizes ); FT_FRAME_RELEASE( face->hdmx_table ); } FT_LOCAL_DEF( void ) tt_done_blend( FT_Memory memory, GX_Blend blend ) { if ( blend != NULL ) { FT_UInt i; FT_FREE( blend->normalizedcoords ); FT_FREE( blend->mmvar ); if ( blend->avar_segment != NULL ) { for ( i = 0; i < blend->num_axis; ++i ) FT_FREE( blend->avar_segment[i].correspondence ); FT_FREE( blend->avar_segment ); } FT_FREE( blend->tuplecoords ); FT_FREE( blend->glyphoffsets ); FT_FREE( blend ); } } FT_LOCAL_DEF( void ) tt_face_done( FT_Face ttface ) /* TT_Face */ { TT_Face face = (TT_Face)ttface; FT_Memory memory; FT_Stream stream; SFNT_Service sfnt; if ( !face ) return; memory = ttface->memory; stream = ttface->stream; sfnt = (SFNT_Service)face->sfnt; /* for `extended TrueType formats' (i.e. compressed versions) */ if ( face->extra.finalizer ) face->extra.finalizer( face->extra.data ); if ( sfnt ) sfnt->done_face( face ); /* freeing the locations table */ tt_face_done_loca( face ); tt_face_free_hdmx( face ); /* freeing the CVT */ FT_FREE( face->cvt ); face->cvt_size = 0; /* freeing the programs */ FT_FRAME_RELEASE( face->font_program ); FT_FRAME_RELEASE( face->cvt_program ); face->font_program_size = 0; face->cvt_program_size = 0; #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT tt_done_blend( memory, face->blend ); face->blend = NULL; #endif } FT_LOCAL_DEF( FT_Error ) tt_size_init( FT_Size ttsize ) /* TT_Size */ { TT_Size size = (TT_Size)ttsize; FT_Error error = FT_Err_Ok; #ifdef TT_USE_BYTECODE_INTERPRETER size->bytecode_ready = 0; size->cvt_ready = 0; #endif size->ttmetrics.valid = FALSE; size->strike_index = 0xFFFFFFFFUL; return error; } FT_LOCAL_DEF( void ) tt_size_done( FT_Size ttsize ) /* TT_Size */ { TT_Size size = (TT_Size)ttsize; #ifdef TT_USE_BYTECODE_INTERPRETER if ( size->bytecode_ready ) tt_size_done_bytecode( ttsize ); #endif size->ttmetrics.valid = FALSE; } FT_BASE_DEF( FT_Error ) FT_GlyphLoader_CreateExtra( FT_GlyphLoader loader ) { FT_Error error; FT_Memory memory = loader->memory; if ( !FT_NEW_ARRAY( loader->base.extra_points, 2 * loader->max_points ) ) { loader->use_extra = 1; loader->base.extra_points2 = loader->base.extra_points + loader->max_points; FT_GlyphLoader_Adjust_Points( loader ); } return error; } FT_LOCAL_DEF( FT_Error ) tt_slot_init( FT_GlyphSlot slot ) { return FT_GlyphLoader_CreateExtra( slot->internal->loader ); } static FT_Error tt_loader_init( TT_Loader loader, TT_Size size, TT_GlyphSlot glyph, FT_Int32 load_flags, FT_Bool glyf_table_only ) { TT_Face face; FT_Stream stream; #ifdef TT_USE_BYTECODE_INTERPRETER FT_Bool pedantic = FT_BOOL( load_flags & FT_LOAD_PEDANTIC ); #endif face = (TT_Face)glyph->face; stream = face->root.stream; FT_MEM_ZERO( loader, sizeof ( TT_LoaderRec ) ); #ifdef TT_USE_BYTECODE_INTERPRETER /* load execution context */ if ( IS_HINTED( load_flags ) && !glyf_table_only ) { TT_ExecContext exec; FT_Bool grayscale; #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( face ); FT_Bool subpixel = FALSE; #if 0 /* not used yet */ FT_Bool compatible_widths; FT_Bool symmetrical_smoothing; FT_Bool bgr; FT_Bool subpixel_positioned; #endif #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ FT_Bool reexecute = FALSE; if ( !size->cvt_ready ) { FT_Error error = tt_size_ready_bytecode( size, pedantic ); if ( error ) return error; } /* query new execution context */ exec = size->debug ? size->context : ( (TT_Driver)FT_FACE_DRIVER( face ) )->context; if ( !exec ) return FT_THROW( Could_Not_Find_Context ); #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 ) { subpixel = FT_BOOL( ( FT_LOAD_TARGET_MODE( load_flags ) != FT_RENDER_MODE_MONO ) && SPH_OPTION_SET_SUBPIXEL ); if ( subpixel ) grayscale = FALSE; else if ( SPH_OPTION_SET_GRAYSCALE ) { grayscale = TRUE; subpixel = FALSE; } else grayscale = FALSE; if ( FT_IS_TRICKY( glyph->face ) ) subpixel = FALSE; exec->ignore_x_mode = subpixel || grayscale; exec->rasterizer_version = SPH_OPTION_SET_RASTERIZER_VERSION; if ( exec->sph_tweak_flags & SPH_TWEAK_RASTERIZER_35 ) exec->rasterizer_version = TT_INTERPRETER_VERSION_35; #if 1 exec->compatible_widths = SPH_OPTION_SET_COMPATIBLE_WIDTHS; exec->symmetrical_smoothing = FALSE; exec->bgr = FALSE; exec->subpixel_positioned = TRUE; #else /* 0 */ exec->compatible_widths = FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) != TT_LOAD_COMPATIBLE_WIDTHS ); exec->symmetrical_smoothing = FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) != TT_LOAD_SYMMETRICAL_SMOOTHING ); exec->bgr = FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) != TT_LOAD_BGR ); exec->subpixel_positioned = FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) != TT_LOAD_SUBPIXEL_POSITIONED ); #endif /* 0 */ } else #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ { grayscale = FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) != FT_RENDER_MODE_MONO ); } TT_Load_Context( exec, face, size ); #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 ) { /* a change from mono to subpixel rendering (and vice versa) */ /* requires a re-execution of the CVT program */ if ( subpixel != exec->subpixel ) { FT_TRACE4(( "tt_loader_init: subpixel hinting change," " re-executing `prep' table\n" )); exec->subpixel = subpixel; reexecute = TRUE; } /* a change from mono to grayscale rendering (and vice versa) */ /* requires a re-execution of the CVT program */ if ( grayscale != exec->grayscale ) { FT_TRACE4(( "tt_loader_init: grayscale hinting change," " re-executing `prep' table\n" )); exec->grayscale = grayscale; reexecute = TRUE; } } else #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ { /* a change from mono to grayscale rendering (and vice versa) */ /* requires a re-execution of the CVT program */ if ( grayscale != exec->grayscale ) { FT_TRACE4(( "tt_loader_init: grayscale change," " re-executing `prep' table\n" )); exec->grayscale = grayscale; reexecute = TRUE; } } if ( reexecute ) { FT_UInt i; for ( i = 0; i < size->cvt_size; i++ ) size->cvt[i] = FT_MulFix( face->cvt[i], size->ttmetrics.scale ); tt_size_run_prep( size, pedantic ); } /* see whether the cvt program has disabled hinting */ if ( exec->GS.instruct_control & 1 ) load_flags |= FT_LOAD_NO_HINTING; /* load default graphics state -- if needed */ if ( exec->GS.instruct_control & 2 ) exec->GS = tt_default_graphics_state; exec->pedantic_hinting = FT_BOOL( load_flags & FT_LOAD_PEDANTIC ); loader->exec = exec; loader->instructions = exec->glyphIns; } #endif /* TT_USE_BYTECODE_INTERPRETER */ /* seek to the beginning of the glyph table -- for Type 42 fonts */ /* the table might be accessed from a Postscript stream or something */ /* else... */ #ifdef FT_CONFIG_OPTION_INCREMENTAL if ( face->root.internal->incremental_interface ) loader->glyf_offset = 0; else #endif { FT_Error error = face->goto_table( face, TTAG_glyf, stream, 0 ); if ( FT_ERR_EQ( error, Table_Missing ) ) loader->glyf_offset = 0; else if ( error ) { FT_ERROR(( "tt_loader_init: could not access glyph table\n" )); return error; } else loader->glyf_offset = FT_STREAM_POS(); } /* get face's glyph loader */ if ( !glyf_table_only ) { FT_GlyphLoader gloader = glyph->internal->loader; FT_GlyphLoader_Rewind( gloader ); loader->gloader = gloader; } loader->load_flags = load_flags; loader->face = (FT_Face)face; loader->size = (FT_Size)size; loader->glyph = (FT_GlyphSlot)glyph; loader->stream = stream; return FT_Err_Ok; } FT_LOCAL_DEF( void ) TT_Get_HMetrics( TT_Face face, FT_UInt idx, FT_Short* lsb, FT_UShort* aw ) { ( (SFNT_Service)face->sfnt )->get_metrics( face, 0, idx, lsb, aw ); FT_TRACE5(( " advance width (font units): %d\n", *aw )); FT_TRACE5(( " left side bearing (font units): %d\n", *lsb )); } FT_LOCAL_DEF( void ) TT_Get_VMetrics( TT_Face face, FT_UInt idx, FT_Pos yMax, FT_Short* tsb, FT_UShort* ah ) { if ( face->vertical_info ) ( (SFNT_Service)face->sfnt )->get_metrics( face, 1, idx, tsb, ah ); else if ( face->os2.version != 0xFFFFU ) { *tsb = face->os2.sTypoAscender - yMax; *ah = face->os2.sTypoAscender - face->os2.sTypoDescender; } else { *tsb = face->horizontal.Ascender - yMax; *ah = face->horizontal.Ascender - face->horizontal.Descender; } FT_TRACE5(( " advance height (font units): %d\n", *ah )); FT_TRACE5(( " top side bearing (font units): %d\n", *tsb )); } static FT_Error tt_get_metrics( TT_Loader loader, FT_UInt glyph_index ) { TT_Face face = (TT_Face)loader->face; #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( face ); #endif FT_Error error; FT_Stream stream = loader->stream; FT_Short left_bearing = 0, top_bearing = 0; FT_UShort advance_width = 0, advance_height = 0; /* we must preserve the stream position */ /* (which gets altered by the metrics functions) */ FT_ULong pos = FT_STREAM_POS(); TT_Get_HMetrics( face, glyph_index, &left_bearing, &advance_width ); TT_Get_VMetrics( face, glyph_index, loader->bbox.yMax, &top_bearing, &advance_height ); if ( FT_STREAM_SEEK( pos ) ) return error; loader->left_bearing = left_bearing; loader->advance = advance_width; loader->top_bearing = top_bearing; loader->vadvance = advance_height; #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 ) { if ( loader->exec ) loader->exec->sph_tweak_flags = 0; /* this may not be the right place for this, but it works */ if ( loader->exec && loader->exec->ignore_x_mode ) sph_set_tweaks( loader, glyph_index ); } #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ if ( !loader->linear_def ) { loader->linear_def = 1; loader->linear = advance_width; } return FT_Err_Ok; } #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING #define TT_LOADER_SET_PP( loader ) \ do \ { \ FT_Bool subpixel_ = loader->exec ? loader->exec->subpixel \ : 0; \ FT_Bool grayscale_ = loader->exec ? loader->exec->grayscale \ : 0; \ FT_Bool use_aw_2_ = (FT_Bool)( subpixel_ && grayscale_ ); \ \ \ (loader)->pp1.x = (loader)->bbox.xMin - (loader)->left_bearing; \ (loader)->pp1.y = 0; \ (loader)->pp2.x = (loader)->pp1.x + (loader)->advance; \ (loader)->pp2.y = 0; \ \ (loader)->pp3.x = use_aw_2_ ? (loader)->advance / 2 : 0; \ (loader)->pp3.y = (loader)->bbox.yMax + (loader)->top_bearing; \ (loader)->pp4.x = use_aw_2_ ? (loader)->advance / 2 : 0; \ (loader)->pp4.y = (loader)->pp3.y - (loader)->vadvance; \ } while ( 0 ) #else /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */ #define TT_LOADER_SET_PP( loader ) \ do \ { \ (loader)->pp1.x = (loader)->bbox.xMin - (loader)->left_bearing; \ (loader)->pp1.y = 0; \ (loader)->pp2.x = (loader)->pp1.x + (loader)->advance; \ (loader)->pp2.y = 0; \ \ (loader)->pp3.x = 0; \ (loader)->pp3.y = (loader)->bbox.yMax + (loader)->top_bearing; \ (loader)->pp4.x = 0; \ (loader)->pp4.y = (loader)->pp3.y - (loader)->vadvance; \ } while ( 0 ) #endif /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */ typedef enum GX_TupleCountFlags_ { GX_TC_TUPLES_SHARE_POINT_NUMBERS = 0x8000, GX_TC_RESERVED_TUPLE_FLAGS = 0x7000, GX_TC_TUPLE_COUNT_MASK = 0x0FFF } GX_TupleCountFlags; static FT_UShort* ft_var_readpackedpoints( FT_Stream stream, FT_UInt *point_cnt ) { FT_UShort *points = NULL; FT_Int n; FT_Int runcnt; FT_Int i; FT_Int j; FT_Int first; FT_Memory memory = stream->memory; FT_Error error = FT_Err_Ok; FT_UNUSED( error ); *point_cnt = n = FT_GET_BYTE(); if ( n == 0 ) return ALL_POINTS; if ( n & GX_PT_POINTS_ARE_WORDS ) n = FT_GET_BYTE() | ( ( n & GX_PT_POINT_RUN_COUNT_MASK ) << 8 ); if ( FT_NEW_ARRAY( points, n ) ) return NULL; i = 0; while ( i < n ) { runcnt = FT_GET_BYTE(); if ( runcnt & GX_PT_POINTS_ARE_WORDS ) { runcnt = runcnt & GX_PT_POINT_RUN_COUNT_MASK; first = points[i++] = FT_GET_USHORT(); if ( runcnt < 1 || i + runcnt >= n ) goto Exit; /* first point not included in runcount */ for ( j = 0; j < runcnt; ++j ) points[i++] = (FT_UShort)( first += FT_GET_USHORT() ); } else { first = points[i++] = FT_GET_BYTE(); if ( runcnt < 1 || i + runcnt >= n ) goto Exit; for ( j = 0; j < runcnt; ++j ) points[i++] = (FT_UShort)( first += FT_GET_BYTE() ); } } Exit: return points; } static FT_Fixed ft_var_apply_tuple( GX_Blend blend, FT_UShort tupleIndex, FT_Fixed* tuple_coords, FT_Fixed* im_start_coords, FT_Fixed* im_end_coords ) { FT_UInt i; FT_Fixed apply = 0x10000L; for ( i = 0; i < blend->num_axis; ++i ) { if ( tuple_coords[i] == 0 ) /* It's not clear why (for intermediate tuples) we don't need */ /* to check against start/end -- the documentation says we don't. */ /* Similarly, it's unclear why we don't need to scale along the */ /* axis. */ continue; else if ( blend->normalizedcoords[i] == 0 || ( blend->normalizedcoords[i] < 0 && tuple_coords[i] > 0 ) || ( blend->normalizedcoords[i] > 0 && tuple_coords[i] < 0 ) ) { apply = 0; break; } else if ( !( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) ) /* not an intermediate tuple */ apply = FT_MulFix( apply, blend->normalizedcoords[i] > 0 ? blend->normalizedcoords[i] : -blend->normalizedcoords[i] ); else if ( blend->normalizedcoords[i] <= im_start_coords[i] || blend->normalizedcoords[i] >= im_end_coords[i] ) { apply = 0; break; } else if ( blend->normalizedcoords[i] < tuple_coords[i] ) apply = FT_MulDiv( apply, blend->normalizedcoords[i] - im_start_coords[i], tuple_coords[i] - im_start_coords[i] ); else apply = FT_MulDiv( apply, im_end_coords[i] - blend->normalizedcoords[i], im_end_coords[i] - tuple_coords[i] ); } return apply; } enum { GX_DT_DELTAS_ARE_ZERO = 0x80, GX_DT_DELTAS_ARE_WORDS = 0x40, GX_DT_DELTA_RUN_COUNT_MASK = 0x3F }; static FT_Short* ft_var_readpackeddeltas( FT_Stream stream, FT_Offset delta_cnt ) { FT_Short *deltas = NULL; FT_UInt runcnt; FT_Offset i; FT_UInt j; FT_Memory memory = stream->memory; FT_Error error = FT_Err_Ok; FT_UNUSED( error ); if ( FT_NEW_ARRAY( deltas, delta_cnt ) ) return NULL; i = 0; while ( i < delta_cnt ) { runcnt = FT_GET_BYTE(); if ( runcnt & GX_DT_DELTAS_ARE_ZERO ) { /* runcnt zeroes get added */ for ( j = 0; j <= ( runcnt & GX_DT_DELTA_RUN_COUNT_MASK ) && i < delta_cnt; ++j ) deltas[i++] = 0; } else if ( runcnt & GX_DT_DELTAS_ARE_WORDS ) { /* runcnt shorts from the stack */ for ( j = 0; j <= ( runcnt & GX_DT_DELTA_RUN_COUNT_MASK ) && i < delta_cnt; ++j ) deltas[i++] = FT_GET_SHORT(); } else { /* runcnt signed bytes from the stack */ for ( j = 0; j <= ( runcnt & GX_DT_DELTA_RUN_COUNT_MASK ) && i < delta_cnt; ++j ) deltas[i++] = FT_GET_CHAR(); } if ( j <= ( runcnt & GX_DT_DELTA_RUN_COUNT_MASK ) ) { /* Bad format */ FT_FREE( deltas ); return NULL; } } return deltas; } FT_LOCAL_DEF( FT_Error ) TT_Vary_Get_Glyph_Deltas( TT_Face face, FT_UInt glyph_index, FT_Vector* *deltas, FT_UInt n_points ) { FT_Stream stream = face->root.stream; FT_Memory memory = stream->memory; GX_Blend blend = face->blend; FT_Vector* delta_xy = NULL; FT_Error error; FT_ULong glyph_start; FT_UInt tupleCount; FT_ULong offsetToData; FT_ULong here; FT_UInt i, j; FT_Fixed* tuple_coords = NULL; FT_Fixed* im_start_coords = NULL; FT_Fixed* im_end_coords = NULL; FT_UInt point_count, spoint_count = 0; FT_UShort* sharedpoints = NULL; FT_UShort* localpoints = NULL; FT_UShort* points; FT_Short *deltas_x, *deltas_y; if ( !face->doblend || blend == NULL ) return FT_THROW( Invalid_Argument ); /* to be freed by the caller */ if ( FT_NEW_ARRAY( delta_xy, n_points ) ) goto Exit; *deltas = delta_xy; if ( glyph_index >= blend->gv_glyphcnt || blend->glyphoffsets[glyph_index] == blend->glyphoffsets[glyph_index + 1] ) return FT_Err_Ok; /* no variation data for this glyph */ if ( FT_STREAM_SEEK( blend->glyphoffsets[glyph_index] ) || FT_FRAME_ENTER( blend->glyphoffsets[glyph_index + 1] - blend->glyphoffsets[glyph_index] ) ) goto Fail1; glyph_start = FT_Stream_FTell( stream ); /* each set of glyph variation data is formatted similarly to `cvar' */ /* (except we get shared points and global tuples) */ if ( FT_NEW_ARRAY( tuple_coords, blend->num_axis ) || FT_NEW_ARRAY( im_start_coords, blend->num_axis ) || FT_NEW_ARRAY( im_end_coords, blend->num_axis ) ) goto Fail2; tupleCount = FT_GET_USHORT(); offsetToData = glyph_start + FT_GET_USHORT(); if ( tupleCount & GX_TC_TUPLES_SHARE_POINT_NUMBERS ) { here = FT_Stream_FTell( stream ); FT_Stream_SeekSet( stream, offsetToData ); sharedpoints = ft_var_readpackedpoints( stream, &spoint_count ); offsetToData = FT_Stream_FTell( stream ); FT_Stream_SeekSet( stream, here ); } for ( i = 0; i < ( tupleCount & GX_TC_TUPLE_COUNT_MASK ); ++i ) { FT_UInt tupleDataSize; FT_UInt tupleIndex; FT_Fixed apply; tupleDataSize = FT_GET_USHORT(); tupleIndex = FT_GET_USHORT(); if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD ) { for ( j = 0; j < blend->num_axis; ++j ) tuple_coords[j] = FT_GET_SHORT() << 2; /* convert from */ /* short frac to fixed */ } else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) >= blend->tuplecount ) { error = FT_THROW( Invalid_Table ); goto Fail3; } else { FT_MEM_COPY( tuple_coords, &blend->tuplecoords[(tupleIndex & 0xFFF) * blend->num_axis], blend->num_axis * sizeof ( FT_Fixed ) ); } if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) { for ( j = 0; j < blend->num_axis; ++j ) im_start_coords[j] = FT_GET_SHORT() << 2; for ( j = 0; j < blend->num_axis; ++j ) im_end_coords[j] = FT_GET_SHORT() << 2; } apply = ft_var_apply_tuple( blend, (FT_UShort)tupleIndex, tuple_coords, im_start_coords, im_end_coords ); if ( apply == 0 ) /* tuple isn't active for our blend */ { offsetToData += tupleDataSize; continue; } here = FT_Stream_FTell( stream ); if ( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS ) { FT_Stream_SeekSet( stream, offsetToData ); localpoints = ft_var_readpackedpoints( stream, &point_count ); points = localpoints; } else { points = sharedpoints; point_count = spoint_count; } deltas_x = ft_var_readpackeddeltas( stream, point_count == 0 ? n_points : point_count ); deltas_y = ft_var_readpackeddeltas( stream, point_count == 0 ? n_points : point_count ); if ( points == NULL || deltas_y == NULL || deltas_x == NULL ) ; /* failure, ignore it */ else if ( points == ALL_POINTS ) { /* this means that there are deltas for every point in the glyph */ for ( j = 0; j < n_points; ++j ) { delta_xy[j].x += FT_MulFix( deltas_x[j], apply ); delta_xy[j].y += FT_MulFix( deltas_y[j], apply ); } } else { for ( j = 0; j < point_count; ++j ) { if ( localpoints[j] >= n_points ) continue; delta_xy[localpoints[j]].x += FT_MulFix( deltas_x[j], apply ); delta_xy[localpoints[j]].y += FT_MulFix( deltas_y[j], apply ); } } if ( localpoints != ALL_POINTS ) FT_FREE( localpoints ); FT_FREE( deltas_x ); FT_FREE( deltas_y ); offsetToData += tupleDataSize; FT_Stream_SeekSet( stream, here ); } Fail3: FT_FREE( tuple_coords ); FT_FREE( im_start_coords ); FT_FREE( im_end_coords ); Fail2: FT_FRAME_EXIT(); Fail1: if ( error ) { FT_FREE( delta_xy ); *deltas = NULL; } Exit: return error; } #define IS_HINTED( flags ) ( ( flags & FT_LOAD_NO_HINTING ) == 0 ) static void tt_prepare_zone( TT_GlyphZone zone, FT_GlyphLoad load, FT_UInt start_point, FT_UInt start_contour ) { zone->n_points = (FT_UShort)( load->outline.n_points - start_point ); zone->n_contours = (FT_Short) ( load->outline.n_contours - start_contour ); zone->org = load->extra_points + start_point; zone->cur = load->outline.points + start_point; zone->orus = load->extra_points2 + start_point; zone->tags = (FT_Byte*)load->outline.tags + start_point; zone->contours = (FT_UShort*)load->outline.contours + start_contour; zone->first_point = (FT_UShort)start_point; } static FT_Error TT_Hint_Glyph( TT_Loader loader, FT_Bool is_composite ) { #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING TT_Face face = (TT_Face)loader->face; TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( face ); #endif TT_GlyphZone zone = &loader->zone; #ifdef TT_USE_BYTECODE_INTERPRETER FT_UInt n_ins; #else FT_UNUSED( is_composite ); #endif #ifdef TT_USE_BYTECODE_INTERPRETER if ( loader->glyph->control_len > 0xFFFFL ) { FT_TRACE1(( "TT_Hint_Glyph: too long instructions" )); FT_TRACE1(( " (0x%lx byte) is truncated\n", loader->glyph->control_len )); } n_ins = (FT_UInt)( loader->glyph->control_len ); /* save original point position in org */ if ( n_ins > 0 ) FT_ARRAY_COPY( zone->org, zone->cur, zone->n_points ); /* Reset graphics state. */ loader->exec->GS = ((TT_Size)loader->size)->GS; /* XXX: UNDOCUMENTED! Hinting instructions of a composite glyph */ /* completely refer to the (already) hinted subglyphs. */ if ( is_composite ) { loader->exec->metrics.x_scale = 1 << 16; loader->exec->metrics.y_scale = 1 << 16; FT_ARRAY_COPY( zone->orus, zone->cur, zone->n_points ); } else { loader->exec->metrics.x_scale = ((TT_Size)loader->size)->metrics.x_scale; loader->exec->metrics.y_scale = ((TT_Size)loader->size)->metrics.y_scale; } #endif /* round phantom points */ zone->cur[zone->n_points - 4].x = FT_PIX_ROUND( zone->cur[zone->n_points - 4].x ); zone->cur[zone->n_points - 3].x = FT_PIX_ROUND( zone->cur[zone->n_points - 3].x ); zone->cur[zone->n_points - 2].y = FT_PIX_ROUND( zone->cur[zone->n_points - 2].y ); zone->cur[zone->n_points - 1].y = FT_PIX_ROUND( zone->cur[zone->n_points - 1].y ); #ifdef TT_USE_BYTECODE_INTERPRETER if ( n_ins > 0 ) { FT_Bool debug; FT_Error error; FT_GlyphLoader gloader = loader->gloader; FT_Outline current_outline = gloader->current.outline; error = TT_Set_CodeRange( loader->exec, tt_coderange_glyph, loader->exec->glyphIns, n_ins ); if ( error ) return error; loader->exec->is_composite = is_composite; loader->exec->pts = *zone; debug = FT_BOOL( !( loader->load_flags & FT_LOAD_NO_SCALE ) && ((TT_Size)loader->size)->debug ); error = TT_Run_Context( loader->exec, debug ); if ( error && loader->exec->pedantic_hinting ) return error; /* store drop-out mode in bits 5-7; set bit 2 also as a marker */ current_outline.tags[0] |= ( loader->exec->GS.scan_type << 5 ) | FT_CURVE_TAG_HAS_SCANMODE; } #endif /* save glyph phantom points */ loader->pp1 = zone->cur[zone->n_points - 4]; loader->pp2 = zone->cur[zone->n_points - 3]; loader->pp3 = zone->cur[zone->n_points - 2]; loader->pp4 = zone->cur[zone->n_points - 1]; #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 ) { if ( loader->exec->sph_tweak_flags & SPH_TWEAK_DEEMBOLDEN ) FT_Outline_EmboldenXY( &loader->gloader->current.outline, -24, 0 ); else if ( loader->exec->sph_tweak_flags & SPH_TWEAK_EMBOLDEN ) FT_Outline_EmboldenXY( &loader->gloader->current.outline, 24, 0 ); } #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ return FT_Err_Ok; } static FT_Error TT_Process_Simple_Glyph( TT_Loader loader ) { FT_GlyphLoader gloader = loader->gloader; FT_Error error = FT_Err_Ok; FT_Outline* outline; FT_Int n_points; outline = &gloader->current.outline; n_points = outline->n_points; /* set phantom points */ outline->points[n_points ] = loader->pp1; outline->points[n_points + 1] = loader->pp2; outline->points[n_points + 2] = loader->pp3; outline->points[n_points + 3] = loader->pp4; outline->tags[n_points ] = 0; outline->tags[n_points + 1] = 0; outline->tags[n_points + 2] = 0; outline->tags[n_points + 3] = 0; n_points += 4; #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT if ( ((TT_Face)loader->face)->doblend ) { /* Deltas apply to the unscaled data. */ FT_Vector* deltas; FT_Memory memory = loader->face->memory; FT_Int i; error = TT_Vary_Get_Glyph_Deltas( (TT_Face)(loader->face), loader->glyph_index, &deltas, n_points ); if ( error ) return error; for ( i = 0; i < n_points; ++i ) { outline->points[i].x += deltas[i].x; outline->points[i].y += deltas[i].y; } FT_FREE( deltas ); } #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ if ( IS_HINTED( loader->load_flags ) ) { tt_prepare_zone( &loader->zone, &gloader->current, 0, 0 ); FT_ARRAY_COPY( loader->zone.orus, loader->zone.cur, loader->zone.n_points + 4 ); } { #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING TT_Face face = (TT_Face)loader->face; TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( face ); FT_String* family = face->root.family_name; FT_Int ppem = loader->size->metrics.x_ppem; FT_String* style = face->root.style_name; FT_Int x_scale_factor = 1000; #endif FT_Vector* vec = outline->points; FT_Vector* limit = outline->points + n_points; FT_Fixed x_scale = 0; /* pacify compiler */ FT_Fixed y_scale = 0; FT_Bool do_scale = FALSE; #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 ) { /* scale, but only if enabled and only if TT hinting is being used */ if ( IS_HINTED( loader->load_flags ) ) x_scale_factor = sph_test_tweak_x_scaling( face, family, ppem, style, loader->glyph_index ); /* scale the glyph */ if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 || x_scale_factor != 1000 ) { x_scale = FT_MulDiv( ((TT_Size)loader->size)->metrics.x_scale, x_scale_factor, 1000 ); y_scale = ((TT_Size)loader->size)->metrics.y_scale; /* compensate for any scaling by de/emboldening; */ /* the amount was determined via experimentation */ if ( x_scale_factor != 1000 && ppem > 11 ) FT_Outline_EmboldenXY( outline, FT_MulFix( 1280 * ppem, 1000 - x_scale_factor ), 0 ); do_scale = TRUE; } } else #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ { /* scale the glyph */ if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ) { x_scale = ((TT_Size)loader->size)->metrics.x_scale; y_scale = ((TT_Size)loader->size)->metrics.y_scale; do_scale = TRUE; } } if ( do_scale ) { for ( ; vec < limit; vec++ ) { vec->x = FT_MulFix( vec->x, x_scale ); vec->y = FT_MulFix( vec->y, y_scale ); } loader->pp1 = outline->points[n_points - 4]; loader->pp2 = outline->points[n_points - 3]; loader->pp3 = outline->points[n_points - 2]; loader->pp4 = outline->points[n_points - 1]; } } if ( IS_HINTED( loader->load_flags ) ) { loader->zone.n_points += 4; error = TT_Hint_Glyph( loader, 0 ); } return error; } FT_BASE_DEF( void ) FT_GlyphLoader_Prepare( FT_GlyphLoader loader ) { FT_GlyphLoad current = &loader->current; current->outline.n_points = 0; current->outline.n_contours = 0; current->num_subglyphs = 0; FT_GlyphLoader_Adjust_Points ( loader ); FT_GlyphLoader_Adjust_Subglyphs( loader ); } FT_BASE_DEF( void ) FT_GlyphLoader_Add( FT_GlyphLoader loader ) { FT_GlyphLoad base; FT_GlyphLoad current; FT_UInt n_curr_contours; FT_UInt n_base_points; FT_UInt n; if ( !loader ) return; base = &loader->base; current = &loader->current; n_curr_contours = current->outline.n_contours; n_base_points = base->outline.n_points; base->outline.n_points = (short)( base->outline.n_points + current->outline.n_points ); base->outline.n_contours = (short)( base->outline.n_contours + current->outline.n_contours ); base->num_subglyphs += current->num_subglyphs; /* adjust contours count in newest outline */ for ( n = 0; n < n_curr_contours; n++ ) current->outline.contours[n] = (short)( current->outline.contours[n] + n_base_points ); /* prepare for another new glyph image */ FT_GlyphLoader_Prepare( loader ); } FT_BASE_DEF ( FT_Int ) FT_MSB( FT_UInt32 z ) { FT_Int shift = 0; /* determine msb bit index in `shift' */ if ( z >= ( 1L << 16 ) ) { z >>= 16; shift += 16; } if ( z >= ( 1L << 8 ) ) { z >>= 8; shift += 8; } if ( z >= ( 1L << 4 ) ) { z >>= 4; shift += 4; } if ( z >= ( 1L << 2 ) ) { z >>= 2; shift += 2; } if ( z >= ( 1L << 1 ) ) { /* z >>= 1; */ shift += 1; } return shift; } typedef FT_Fixed FT_Angle; #define FT_ANGLE_PI ( 180L << 16 ) #define FT_ANGLE_PI2 ( FT_ANGLE_PI / 2 ) #define FT_TRIG_MAX_ITERS 23 #define FT_TRIG_SCALE 0xDBD95B16UL /* the highest bit in overflow-safe vector components, */ /* MSB of 0.858785336480436 * sqrt(0.5) * 2^30 */ #define FT_TRIG_SAFE_MSB 29 /* this table was generated for FT_PI = 180L << 16, i.e. degrees */ #define FT_TRIG_MAX_ITERS 23 static const FT_Fixed ft_trig_arctan_table[] = { 1740967L, 919879L, 466945L, 234379L, 117304L, 58666L, 29335L, 14668L, 7334L, 3667L, 1833L, 917L, 458L, 229L, 115L, 57L, 29L, 14L, 7L, 4L, 2L, 1L }; static FT_Int ft_trig_prenorm( FT_Vector* vec ) { FT_Pos x, y; FT_Int shift; x = vec->x; y = vec->y; shift = FT_MSB( FT_ABS( x ) | FT_ABS( y ) ); if ( shift <= FT_TRIG_SAFE_MSB ) { shift = FT_TRIG_SAFE_MSB - shift; vec->x = (FT_Pos)( (FT_ULong)x << shift ); vec->y = (FT_Pos)( (FT_ULong)y << shift ); } else { shift -= FT_TRIG_SAFE_MSB; vec->x = x >> shift; vec->y = y >> shift; shift = -shift; } return shift; } #ifdef FT_LONG64 /* multiply a given value by the CORDIC shrink factor */ static FT_Fixed ft_trig_downscale( FT_Fixed val ) { FT_Fixed s; FT_Int64 v; s = val; val = FT_ABS( val ); v = ( val * (FT_Int64)FT_TRIG_SCALE ) + 0x100000000UL; val = (FT_Fixed)( v >> 32 ); return ( s >= 0 ) ? val : -val; } #else /* !FT_LONG64 */ /* multiply a given value by the CORDIC shrink factor */ static FT_Fixed ft_trig_downscale( FT_Fixed val ) { FT_Fixed s; FT_UInt32 v1, v2, k1, k2, hi, lo1, lo2, lo3; s = val; val = FT_ABS( val ); v1 = (FT_UInt32)val >> 16; v2 = (FT_UInt32)( val & 0xFFFFL ); k1 = (FT_UInt32)FT_TRIG_SCALE >> 16; /* constant */ k2 = (FT_UInt32)( FT_TRIG_SCALE & 0xFFFFL ); /* constant */ hi = k1 * v1; lo1 = k1 * v2 + k2 * v1; /* can't overflow */ lo2 = ( k2 * v2 ) >> 16; lo3 = FT_MAX( lo1, lo2 ); lo1 += lo2; hi += lo1 >> 16; if ( lo1 < lo3 ) hi += (FT_UInt32)0x10000UL; val = (FT_Fixed)hi; return ( s >= 0 ) ? val : -val; } #endif /* !FT_LONG64 */ static void ft_trig_pseudo_polarize( FT_Vector* vec ) { FT_Angle theta; FT_Int i; FT_Fixed x, y, xtemp, b; const FT_Fixed *arctanptr; x = vec->x; y = vec->y; /* Get the vector into [-PI/4,PI/4] sector */ if ( y > x ) { if ( y > -x ) { theta = FT_ANGLE_PI2; xtemp = y; y = -x; x = xtemp; } else { theta = y > 0 ? FT_ANGLE_PI : -FT_ANGLE_PI; x = -x; y = -y; } } else { if ( y < -x ) { theta = -FT_ANGLE_PI2; xtemp = -y; y = x; x = xtemp; } else { theta = 0; } } arctanptr = ft_trig_arctan_table; /* Pseudorotations, with right shifts */ for ( i = 1, b = 1; i < FT_TRIG_MAX_ITERS; b <<= 1, i++ ) { if ( y > 0 ) { xtemp = x + ( ( y + b ) >> i ); y = y - ( ( x + b ) >> i ); x = xtemp; theta += *arctanptr++; } else { xtemp = x - ( ( y + b ) >> i ); y = y + ( ( x + b ) >> i ); x = xtemp; theta -= *arctanptr++; } } /* round theta */ if ( theta >= 0 ) theta = FT_PAD_ROUND( theta, 32 ); else theta = -FT_PAD_ROUND( -theta, 32 ); vec->x = x; vec->y = theta; } FT_EXPORT_DEF( FT_Fixed ) FT_Vector_Length( FT_Vector* vec ) { FT_Int shift; FT_Vector v; v = *vec; /* handle trivial cases */ if ( v.x == 0 ) { return FT_ABS( v.y ); } else if ( v.y == 0 ) { return FT_ABS( v.x ); } /* general case */ shift = ft_trig_prenorm( &v ); ft_trig_pseudo_polarize( &v ); v.x = ft_trig_downscale( v.x ); if ( shift > 0 ) return ( v.x + ( 1 << ( shift - 1 ) ) ) >> shift; return (FT_Fixed)( (FT_UInt32)v.x << -shift ); } FT_BASE_DEF( FT_Fixed ) FT_Hypot( FT_Fixed x, FT_Fixed y ) { FT_Vector v; v.x = x; v.y = y; return FT_Vector_Length( &v ); } static void translate_array( FT_UInt n, FT_Vector* coords, FT_Pos delta_x, FT_Pos delta_y ) { FT_UInt k; if ( delta_x ) for ( k = 0; k < n; k++ ) coords[k].x += delta_x; if ( delta_y ) for ( k = 0; k < n; k++ ) coords[k].y += delta_y; } static FT_Error TT_Process_Composite_Component( TT_Loader loader, FT_SubGlyph subglyph, FT_UInt start_point, FT_UInt num_base_points ) { FT_GlyphLoader gloader = loader->gloader; FT_Vector* base_vec = gloader->base.outline.points; FT_UInt num_points = gloader->base.outline.n_points; FT_Bool have_scale; FT_Pos x, y; have_scale = FT_BOOL( subglyph->flags & ( WE_HAVE_A_SCALE | WE_HAVE_AN_XY_SCALE | WE_HAVE_A_2X2 ) ); /* perform the transform required for this subglyph */ if ( have_scale ) { FT_UInt i; for ( i = num_base_points; i < num_points; i++ ) FT_Vector_Transform( base_vec + i, &subglyph->transform ); } /* get offset */ if ( !( subglyph->flags & ARGS_ARE_XY_VALUES ) ) { FT_UInt k = subglyph->arg1; FT_UInt l = subglyph->arg2; FT_Vector* p1; FT_Vector* p2; /* match l-th point of the newly loaded component to the k-th point */ /* of the previously loaded components. */ /* change to the point numbers used by our outline */ k += start_point; l += num_base_points; if ( k >= num_base_points || l >= num_points ) return FT_THROW( Invalid_Composite ); p1 = gloader->base.outline.points + k; p2 = gloader->base.outline.points + l; x = p1->x - p2->x; y = p1->y - p2->y; } else { x = subglyph->arg1; y = subglyph->arg2; if ( !x && !y ) return FT_Err_Ok; /* Use a default value dependent on */ /* TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED. This is useful for old */ /* TT fonts which don't set the xxx_COMPONENT_OFFSET bit. */ if ( have_scale && #ifdef TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED !( subglyph->flags & UNSCALED_COMPONENT_OFFSET ) ) #else ( subglyph->flags & SCALED_COMPONENT_OFFSET ) ) #endif { #if 0 /*******************************************************************/ /* */ /* This algorithm is what Apple documents. But it doesn't work. */ /* */ int a = subglyph->transform.xx > 0 ? subglyph->transform.xx : -subglyph->transform.xx; int b = subglyph->transform.yx > 0 ? subglyph->transform.yx : -subglyph->transform.yx; int c = subglyph->transform.xy > 0 ? subglyph->transform.xy : -subglyph->transform.xy; int d = subglyph->transform.yy > 0 ? subglyph->transform.yy : -subglyph->transform.yy; int m = a > b ? a : b; int n = c > d ? c : d; if ( a - b <= 33 && a - b >= -33 ) m *= 2; if ( c - d <= 33 && c - d >= -33 ) n *= 2; x = FT_MulFix( x, m ); y = FT_MulFix( y, n ); #else /* 1 */ /*******************************************************************/ /* */ /* This algorithm is a guess and works much better than the above. */ /* */ FT_Fixed mac_xscale = FT_Hypot( subglyph->transform.xx, subglyph->transform.xy ); FT_Fixed mac_yscale = FT_Hypot( subglyph->transform.yy, subglyph->transform.yx ); x = FT_MulFix( x, mac_xscale ); y = FT_MulFix( y, mac_yscale ); #endif /* 1 */ } if ( !( loader->load_flags & FT_LOAD_NO_SCALE ) ) { FT_Fixed x_scale = ((TT_Size)loader->size)->metrics.x_scale; FT_Fixed y_scale = ((TT_Size)loader->size)->metrics.y_scale; x = FT_MulFix( x, x_scale ); y = FT_MulFix( y, y_scale ); if ( subglyph->flags & ROUND_XY_TO_GRID ) { x = FT_PIX_ROUND( x ); y = FT_PIX_ROUND( y ); } } } if ( x || y ) translate_array( num_points - num_base_points, base_vec + num_base_points, x, y ); return FT_Err_Ok; } static FT_Error TT_Process_Composite_Glyph( TT_Loader loader, FT_UInt start_point, FT_UInt start_contour ) { FT_Error error; FT_Outline* outline; FT_UInt i; outline = &loader->gloader->base.outline; /* make room for phantom points */ error = FT_GLYPHLOADER_CHECK_POINTS( loader->gloader, outline->n_points + 4, 0 ); if ( error ) return error; outline->points[outline->n_points ] = loader->pp1; outline->points[outline->n_points + 1] = loader->pp2; outline->points[outline->n_points + 2] = loader->pp3; outline->points[outline->n_points + 3] = loader->pp4; outline->tags[outline->n_points ] = 0; outline->tags[outline->n_points + 1] = 0; outline->tags[outline->n_points + 2] = 0; outline->tags[outline->n_points + 3] = 0; #ifdef TT_USE_BYTECODE_INTERPRETER { FT_Stream stream = loader->stream; FT_UShort n_ins, max_ins; FT_ULong tmp; /* TT_Load_Composite_Glyph only gives us the offset of instructions */ /* so we read them here */ if ( FT_STREAM_SEEK( loader->ins_pos ) || FT_READ_USHORT( n_ins ) ) return error; FT_TRACE5(( " Instructions size = %d\n", n_ins )); /* check it */ max_ins = ((TT_Face)loader->face)->max_profile.maxSizeOfInstructions; if ( n_ins > max_ins ) { /* don't trust `maxSizeOfInstructions'; */ /* only do a rough safety check */ if ( (FT_Int)n_ins > loader->byte_len ) { FT_TRACE1(( "TT_Process_Composite_Glyph:" " too many instructions (%d) for glyph with length %d\n", n_ins, loader->byte_len )); return FT_THROW( Too_Many_Hints ); } tmp = loader->exec->glyphSize; error = Update_Max( loader->exec->memory, &tmp, sizeof ( FT_Byte ), (void*)&loader->exec->glyphIns, n_ins ); loader->exec->glyphSize = (FT_UShort)tmp; if ( error ) return error; } else if ( n_ins == 0 ) return FT_Err_Ok; if ( FT_STREAM_READ( loader->exec->glyphIns, n_ins ) ) return error; loader->glyph->control_data = loader->exec->glyphIns; loader->glyph->control_len = n_ins; } #endif tt_prepare_zone( &loader->zone, &loader->gloader->base, start_point, start_contour ); /* Some points are likely touched during execution of */ /* instructions on components. So let's untouch them. */ for ( i = 0; i < loader->zone.n_points; i++ ) loader->zone.tags[i] &= ~FT_CURVE_TAG_TOUCH_BOTH; loader->zone.n_points += 4; return TT_Hint_Glyph( loader, 1 ); } static FT_Error load_truetype_glyph( TT_Loader loader, FT_UInt glyph_index, FT_UInt recurse_count, FT_Bool header_only ) { FT_Error error = FT_Err_Ok; FT_Fixed x_scale, y_scale; FT_ULong offset; TT_Face face = (TT_Face)loader->face; FT_GlyphLoader gloader = loader->gloader; FT_Bool opened_frame = 0; #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT FT_Vector* deltas = NULL; #endif #ifdef FT_CONFIG_OPTION_INCREMENTAL FT_StreamRec inc_stream; FT_Data glyph_data; FT_Bool glyph_data_loaded = 0; #endif /* some fonts have an incorrect value of `maxComponentDepth', */ /* thus we allow depth 1 to catch the majority of them */ if ( recurse_count > 1 && recurse_count > face->max_profile.maxComponentDepth ) { error = FT_THROW( Invalid_Composite ); goto Exit; } /* check glyph index */ if ( glyph_index >= (FT_UInt)face->root.num_glyphs ) { error = FT_THROW( Invalid_Glyph_Index ); goto Exit; } loader->glyph_index = glyph_index; if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ) { x_scale = ((TT_Size)loader->size)->metrics.x_scale; y_scale = ((TT_Size)loader->size)->metrics.y_scale; } else { x_scale = 0x10000L; y_scale = 0x10000L; } /* Set `offset' to the start of the glyph relative to the start of */ /* the `glyf' table, and `byte_len' to the length of the glyph in */ /* bytes. */ #ifdef FT_CONFIG_OPTION_INCREMENTAL /* If we are loading glyph data via the incremental interface, set */ /* the loader stream to a memory stream reading the data returned */ /* by the interface. */ if ( face->root.internal->incremental_interface ) { error = face->root.internal->incremental_interface->funcs->get_glyph_data( face->root.internal->incremental_interface->object, glyph_index, &glyph_data ); if ( error ) goto Exit; glyph_data_loaded = 1; offset = 0; loader->byte_len = glyph_data.length; FT_MEM_ZERO( &inc_stream, sizeof ( inc_stream ) ); FT_Stream_OpenMemory( &inc_stream, glyph_data.pointer, glyph_data.length ); loader->stream = &inc_stream; } else #endif /* FT_CONFIG_OPTION_INCREMENTAL */ offset = tt_face_get_location( face, glyph_index, (FT_UInt*)&loader->byte_len ); if ( loader->byte_len > 0 ) { #ifdef FT_CONFIG_OPTION_INCREMENTAL /* for the incremental interface, `glyf_offset' is always zero */ if ( !loader->glyf_offset && !face->root.internal->incremental_interface ) #else if ( !loader->glyf_offset ) #endif /* FT_CONFIG_OPTION_INCREMENTAL */ { FT_TRACE2(( "no `glyf' table but non-zero `loca' entry\n" )); error = FT_THROW( Invalid_Table ); goto Exit; } error = face->access_glyph_frame( loader, glyph_index, loader->glyf_offset + offset, loader->byte_len ); if ( error ) goto Exit; opened_frame = 1; /* read glyph header first */ error = face->read_glyph_header( loader ); if ( error ) goto Exit; /* the metrics must be computed after loading the glyph header */ /* since we need the glyph's `yMax' value in case the vertical */ /* metrics must be emulated */ error = tt_get_metrics( loader, glyph_index ); if ( error ) goto Exit; if ( header_only ) goto Exit; } if ( loader->byte_len == 0 || loader->n_contours == 0 ) { loader->bbox.xMin = 0; loader->bbox.xMax = 0; loader->bbox.yMin = 0; loader->bbox.yMax = 0; error = tt_get_metrics( loader, glyph_index ); if ( error ) goto Exit; if ( header_only ) goto Exit; /* must initialize points before (possibly) overriding */ /* glyph metrics from the incremental interface */ TT_LOADER_SET_PP( loader ); #ifdef FT_CONFIG_OPTION_INCREMENTAL tt_get_metrics_incr_overrides( loader, glyph_index ); #endif #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT if ( ((TT_Face)(loader->face))->doblend ) { /* this must be done before scaling */ FT_Memory memory = loader->face->memory; error = TT_Vary_Get_Glyph_Deltas( (TT_Face)(loader->face), glyph_index, &deltas, 4 ); if ( error ) goto Exit; loader->pp1.x += deltas[0].x; loader->pp1.y += deltas[0].y; loader->pp2.x += deltas[1].x; loader->pp2.y += deltas[1].y; loader->pp3.x += deltas[2].x; loader->pp3.y += deltas[2].y; loader->pp4.x += deltas[3].x; loader->pp4.y += deltas[3].y; FT_FREE( deltas ); } #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ /* scale phantom points, if necessary; */ /* they get rounded in `TT_Hint_Glyph' */ if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ) { loader->pp1.x = FT_MulFix( loader->pp1.x, x_scale ); loader->pp2.x = FT_MulFix( loader->pp2.x, x_scale ); /* pp1.y and pp2.y are always zero */ loader->pp3.x = FT_MulFix( loader->pp3.x, x_scale ); loader->pp3.y = FT_MulFix( loader->pp3.y, y_scale ); loader->pp4.x = FT_MulFix( loader->pp4.x, x_scale ); loader->pp4.y = FT_MulFix( loader->pp4.y, y_scale ); } error = FT_Err_Ok; goto Exit; } /* must initialize phantom points before (possibly) overriding */ /* glyph metrics from the incremental interface */ TT_LOADER_SET_PP( loader ); #ifdef FT_CONFIG_OPTION_INCREMENTAL tt_get_metrics_incr_overrides( loader, glyph_index ); #endif /***********************************************************************/ /***********************************************************************/ /***********************************************************************/ /* if it is a simple glyph, load it */ if ( loader->n_contours > 0 ) { error = face->read_simple_glyph( loader ); if ( error ) goto Exit; /* all data have been read */ face->forget_glyph_frame( loader ); opened_frame = 0; error = TT_Process_Simple_Glyph( loader ); if ( error ) goto Exit; FT_GlyphLoader_Add( gloader ); } /***********************************************************************/ /***********************************************************************/ /***********************************************************************/ /* otherwise, load a composite! */ else if ( loader->n_contours == -1 ) { FT_UInt start_point; FT_UInt start_contour; FT_ULong ins_pos; /* position of composite instructions, if any */ start_point = gloader->base.outline.n_points; start_contour = gloader->base.outline.n_contours; /* for each subglyph, read composite header */ error = face->read_composite_glyph( loader ); if ( error ) goto Exit; /* store the offset of instructions */ ins_pos = loader->ins_pos; /* all data we need are read */ face->forget_glyph_frame( loader ); opened_frame = 0; #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT if ( face->doblend ) { FT_Int i, limit; FT_SubGlyph subglyph; FT_Memory memory = face->root.memory; /* this provides additional offsets */ /* for each component's translation */ if ( ( error = TT_Vary_Get_Glyph_Deltas( face, glyph_index, &deltas, gloader->current.num_subglyphs + 4 ) ) != 0 ) goto Exit; subglyph = gloader->current.subglyphs + gloader->base.num_subglyphs; limit = gloader->current.num_subglyphs; for ( i = 0; i < limit; ++i, ++subglyph ) { if ( subglyph->flags & ARGS_ARE_XY_VALUES ) { /* XXX: overflow check for subglyph->{arg1,arg2}. */ /* deltas[i].{x,y} must be within signed 16-bit, */ /* but the restriction of summed delta is not clear */ subglyph->arg1 += (FT_Int16)deltas[i].x; subglyph->arg2 += (FT_Int16)deltas[i].y; } } loader->pp1.x += deltas[i + 0].x; loader->pp1.y += deltas[i + 0].y; loader->pp2.x += deltas[i + 1].x; loader->pp2.y += deltas[i + 1].y; loader->pp3.x += deltas[i + 2].x; loader->pp3.y += deltas[i + 2].y; loader->pp4.x += deltas[i + 3].x; loader->pp4.y += deltas[i + 3].y; FT_FREE( deltas ); } #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ /* scale phantom points, if necessary; */ /* they get rounded in `TT_Hint_Glyph' */ if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ) { loader->pp1.x = FT_MulFix( loader->pp1.x, x_scale ); loader->pp2.x = FT_MulFix( loader->pp2.x, x_scale ); /* pp1.y and pp2.y are always zero */ loader->pp3.x = FT_MulFix( loader->pp3.x, x_scale ); loader->pp3.y = FT_MulFix( loader->pp3.y, y_scale ); loader->pp4.x = FT_MulFix( loader->pp4.x, x_scale ); loader->pp4.y = FT_MulFix( loader->pp4.y, y_scale ); } /* if the flag FT_LOAD_NO_RECURSE is set, we return the subglyph */ /* `as is' in the glyph slot (the client application will be */ /* responsible for interpreting these data)... */ if ( loader->load_flags & FT_LOAD_NO_RECURSE ) { FT_GlyphLoader_Add( gloader ); loader->glyph->format = FT_GLYPH_FORMAT_COMPOSITE; goto Exit; } /*********************************************************************/ /*********************************************************************/ /*********************************************************************/ { FT_UInt n, num_base_points; FT_SubGlyph subglyph = 0; FT_UInt num_points = start_point; FT_UInt num_subglyphs = gloader->current.num_subglyphs; FT_UInt num_base_subgs = gloader->base.num_subglyphs; FT_Stream old_stream = loader->stream; FT_Int old_byte_len = loader->byte_len; FT_GlyphLoader_Add( gloader ); /* read each subglyph independently */ for ( n = 0; n < num_subglyphs; n++ ) { FT_Vector pp[4]; /* Each time we call load_truetype_glyph in this loop, the */ /* value of `gloader.base.subglyphs' can change due to table */ /* reallocations. We thus need to recompute the subglyph */ /* pointer on each iteration. */ subglyph = gloader->base.subglyphs + num_base_subgs + n; pp[0] = loader->pp1; pp[1] = loader->pp2; pp[2] = loader->pp3; pp[3] = loader->pp4; num_base_points = gloader->base.outline.n_points; error = load_truetype_glyph( loader, subglyph->index, recurse_count + 1, FALSE ); if ( error ) goto Exit; /* restore subglyph pointer */ subglyph = gloader->base.subglyphs + num_base_subgs + n; /* restore phantom points if necessary */ if ( !( subglyph->flags & USE_MY_METRICS ) ) { loader->pp1 = pp[0]; loader->pp2 = pp[1]; loader->pp3 = pp[2]; loader->pp4 = pp[3]; } num_points = gloader->base.outline.n_points; if ( num_points == num_base_points ) continue; /* gloader->base.outline consists of three parts: */ /* 0 -(1)-> start_point -(2)-> num_base_points -(3)-> n_points. */ /* */ /* (1): exists from the beginning */ /* (2): components that have been loaded so far */ /* (3): the newly loaded component */ TT_Process_Composite_Component( loader, subglyph, start_point, num_base_points ); } loader->stream = old_stream; loader->byte_len = old_byte_len; /* process the glyph */ loader->ins_pos = ins_pos; if ( IS_HINTED( loader->load_flags ) && #ifdef TT_USE_BYTECODE_INTERPRETER subglyph->flags & WE_HAVE_INSTR && #endif num_points > start_point ) TT_Process_Composite_Glyph( loader, start_point, start_contour ); } } else { /* invalid composite count (negative but not -1) */ error = FT_THROW( Invalid_Outline ); goto Exit; } /***********************************************************************/ /***********************************************************************/ /***********************************************************************/ Exit: if ( opened_frame ) face->forget_glyph_frame( loader ); #ifdef FT_CONFIG_OPTION_INCREMENTAL if ( glyph_data_loaded ) face->root.internal->incremental_interface->funcs->free_glyph_data( face->root.internal->incremental_interface->object, &glyph_data ); #endif return error; } FT_EXPORT_DEF( void ) FT_Outline_Get_CBox( const FT_Outline* outline, FT_BBox *acbox ) { FT_Pos xMin, yMin, xMax, yMax; if ( outline && acbox ) { if ( outline->n_points == 0 ) { xMin = 0; yMin = 0; xMax = 0; yMax = 0; } else { FT_Vector* vec = outline->points; FT_Vector* limit = vec + outline->n_points; xMin = xMax = vec->x; yMin = yMax = vec->y; vec++; for ( ; vec < limit; vec++ ) { FT_Pos x, y; x = vec->x; if ( x < xMin ) xMin = x; if ( x > xMax ) xMax = x; y = vec->y; if ( y < yMin ) yMin = y; if ( y > yMax ) yMax = y; } } acbox->xMin = xMin; acbox->xMax = xMax; acbox->yMin = yMin; acbox->yMax = yMax; } } FT_LOCAL_DEF( FT_Byte* ) tt_face_get_device_metrics( TT_Face face, FT_UInt ppem, FT_UInt gindex ) { FT_UInt nn; FT_Byte* result = NULL; FT_ULong record_size = face->hdmx_record_size; FT_Byte* record = face->hdmx_table + 8; for ( nn = 0; nn < face->hdmx_record_count; nn++ ) if ( face->hdmx_record_sizes[nn] == ppem ) { gindex += 2; if ( gindex < record_size ) result = record + nn * record_size + gindex; break; } return result; } static FT_Error compute_glyph_metrics( TT_Loader loader, FT_UInt glyph_index ) { TT_Face face = (TT_Face)loader->face; #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( face ); #endif FT_BBox bbox; FT_Fixed y_scale; TT_GlyphSlot glyph = loader->glyph; TT_Size size = (TT_Size)loader->size; y_scale = 0x10000L; if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ) y_scale = size->root.metrics.y_scale; if ( glyph->format != FT_GLYPH_FORMAT_COMPOSITE ) FT_Outline_Get_CBox( &glyph->outline, &bbox ); else bbox = loader->bbox; /* get the device-independent horizontal advance; it is scaled later */ /* by the base layer. */ glyph->linearHoriAdvance = loader->linear; glyph->metrics.horiBearingX = bbox.xMin; glyph->metrics.horiBearingY = bbox.yMax; glyph->metrics.horiAdvance = loader->pp2.x - loader->pp1.x; /* adjust advance width to the value contained in the hdmx table */ if ( !face->postscript.isFixedPitch && IS_HINTED( loader->load_flags ) ) { FT_Byte* widthp; widthp = tt_face_get_device_metrics( face, size->root.metrics.x_ppem, glyph_index ); #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 ) { FT_Bool ignore_x_mode; ignore_x_mode = FT_BOOL( FT_LOAD_TARGET_MODE( loader->load_flags ) != FT_RENDER_MODE_MONO ); if ( widthp && ( ( ignore_x_mode && loader->exec->compatible_widths ) || !ignore_x_mode || SPH_OPTION_BITMAP_WIDTHS ) ) glyph->metrics.horiAdvance = *widthp << 6; } else #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ { if ( widthp ) glyph->metrics.horiAdvance = *widthp << 6; } } /* set glyph dimensions */ glyph->metrics.width = bbox.xMax - bbox.xMin; glyph->metrics.height = bbox.yMax - bbox.yMin; /* Now take care of vertical metrics. In the case where there is */ /* no vertical information within the font (relatively common), */ /* create some metrics manually */ { FT_Pos top; /* scaled vertical top side bearing */ FT_Pos advance; /* scaled vertical advance height */ /* Get the unscaled top bearing and advance height. */ if ( face->vertical_info && face->vertical.number_Of_VMetrics > 0 ) { top = (FT_Short)FT_DivFix( loader->pp3.y - bbox.yMax, y_scale ); if ( loader->pp3.y <= loader->pp4.y ) advance = 0; else advance = (FT_UShort)FT_DivFix( loader->pp3.y - loader->pp4.y, y_scale ); } else { FT_Pos height; /* XXX Compute top side bearing and advance height in */ /* Get_VMetrics instead of here. */ /* NOTE: The OS/2 values are the only `portable' ones, */ /* which is why we use them, if there is an OS/2 */ /* table in the font. Otherwise, we use the */ /* values defined in the horizontal header. */ height = (FT_Short)FT_DivFix( bbox.yMax - bbox.yMin, y_scale ); if ( face->os2.version != 0xFFFFU ) advance = (FT_Pos)( face->os2.sTypoAscender - face->os2.sTypoDescender ); else advance = (FT_Pos)( face->horizontal.Ascender - face->horizontal.Descender ); top = ( advance - height ) / 2; } #ifdef FT_CONFIG_OPTION_INCREMENTAL { FT_Incremental_InterfaceRec* incr; FT_Incremental_MetricsRec metrics; FT_Error error; incr = face->root.internal->incremental_interface; /* If this is an incrementally loaded font see if there are */ /* overriding metrics for this glyph. */ if ( incr && incr->funcs->get_glyph_metrics ) { metrics.bearing_x = 0; metrics.bearing_y = top; metrics.advance = advance; error = incr->funcs->get_glyph_metrics( incr->object, glyph_index, TRUE, &metrics ); if ( error ) return error; top = metrics.bearing_y; advance = metrics.advance; } } /* GWW: Do vertical metrics get loaded incrementally too? */ #endif /* FT_CONFIG_OPTION_INCREMENTAL */ glyph->linearVertAdvance = advance; /* scale the metrics */ if ( !( loader->load_flags & FT_LOAD_NO_SCALE ) ) { top = FT_MulFix( top, y_scale ); advance = FT_MulFix( advance, y_scale ); } /* XXX: for now, we have no better algorithm for the lsb, but it */ /* should work fine. */ /* */ glyph->metrics.vertBearingX = glyph->metrics.horiBearingX - glyph->metrics.horiAdvance / 2; glyph->metrics.vertBearingY = top; glyph->metrics.vertAdvance = advance; } return 0; } #define FT_OUTLINE_NONE 0x0 #define FT_OUTLINE_OWNER 0x1 #define FT_OUTLINE_EVEN_ODD_FILL 0x2 #define FT_OUTLINE_REVERSE_FILL 0x4 #define FT_OUTLINE_IGNORE_DROPOUTS 0x8 #define FT_OUTLINE_SMART_DROPOUTS 0x10 #define FT_OUTLINE_INCLUDE_STUBS 0x20 #define FT_OUTLINE_HIGH_PRECISION 0x100 #define FT_OUTLINE_SINGLE_PASS 0x200 FT_LOCAL_DEF( FT_Error ) TT_Load_Glyph( TT_Size size, TT_GlyphSlot glyph, FT_UInt glyph_index, FT_Int32 load_flags ) { FT_Error error; TT_LoaderRec loader; FT_TRACE1(( "TT_Load_Glyph: glyph index %d\n", glyph_index )); #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS /* try to load embedded bitmap if any */ /* */ /* XXX: The convention should be emphasized in */ /* the documents because it can be confusing. */ if ( size->strike_index != 0xFFFFFFFFUL && ( load_flags & FT_LOAD_NO_BITMAP ) == 0 ) { error = load_sbit_image( size, glyph, glyph_index, load_flags ); if ( !error ) { if ( FT_IS_SCALABLE( glyph->face ) ) { /* for the bbox we need the header only */ (void)tt_loader_init( &loader, size, glyph, load_flags, TRUE ); (void)load_truetype_glyph( &loader, glyph_index, 0, TRUE ); glyph->linearHoriAdvance = loader.linear; glyph->linearVertAdvance = loader.top_bearing + loader.bbox.yMax - loader.vadvance; /* sanity check: if `horiAdvance' in the sbit metric */ /* structure isn't set, use `linearHoriAdvance' */ if ( !glyph->metrics.horiAdvance && glyph->linearHoriAdvance ) glyph->metrics.horiAdvance = FT_MulFix( glyph->linearHoriAdvance, size->root.metrics.x_scale ); } return FT_Err_Ok; } } #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ /* if FT_LOAD_NO_SCALE is not set, `ttmetrics' must be valid */ if ( !( load_flags & FT_LOAD_NO_SCALE ) && !size->ttmetrics.valid ) return FT_THROW( Invalid_Size_Handle ); if ( load_flags & FT_LOAD_SBITS_ONLY ) return FT_THROW( Invalid_Argument ); error = tt_loader_init( &loader, size, glyph, load_flags, FALSE ); if ( error ) return error; glyph->format = FT_GLYPH_FORMAT_OUTLINE; glyph->num_subglyphs = 0; glyph->outline.flags = 0; /* main loading loop */ error = load_truetype_glyph( &loader, glyph_index, 0, FALSE ); if ( !error ) { if ( glyph->format == FT_GLYPH_FORMAT_COMPOSITE ) { glyph->num_subglyphs = loader.gloader->base.num_subglyphs; glyph->subglyphs = loader.gloader->base.subglyphs; } else { glyph->outline = loader.gloader->base.outline; glyph->outline.flags &= ~FT_OUTLINE_SINGLE_PASS; /* Translate array so that (0,0) is the glyph's origin. Note */ /* that this behaviour is independent on the value of bit 1 of */ /* the `flags' field in the `head' table -- at least major */ /* applications like Acroread indicate that. */ if ( loader.pp1.x ) FT_Outline_Translate( &glyph->outline, -loader.pp1.x, 0 ); } #ifdef TT_USE_BYTECODE_INTERPRETER if ( IS_HINTED( load_flags ) ) { if ( loader.exec->GS.scan_control ) { /* convert scan conversion mode to FT_OUTLINE_XXX flags */ switch ( loader.exec->GS.scan_type ) { case 0: /* simple drop-outs including stubs */ glyph->outline.flags |= FT_OUTLINE_INCLUDE_STUBS; break; case 1: /* simple drop-outs excluding stubs */ /* nothing; it's the default rendering mode */ break; case 4: /* smart drop-outs including stubs */ glyph->outline.flags |= FT_OUTLINE_SMART_DROPOUTS | FT_OUTLINE_INCLUDE_STUBS; break; case 5: /* smart drop-outs excluding stubs */ glyph->outline.flags |= FT_OUTLINE_SMART_DROPOUTS; break; default: /* no drop-out control */ glyph->outline.flags |= FT_OUTLINE_IGNORE_DROPOUTS; break; } } else glyph->outline.flags |= FT_OUTLINE_IGNORE_DROPOUTS; } #endif /* TT_USE_BYTECODE_INTERPRETER */ compute_glyph_metrics( &loader, glyph_index ); } /* Set the `high precision' bit flag. */ /* This is _critical_ to get correct output for monochrome */ /* TrueType glyphs at all sizes using the bytecode interpreter. */ /* */ if ( !( load_flags & FT_LOAD_NO_SCALE ) && size->root.metrics.y_ppem < 24 ) glyph->outline.flags |= FT_OUTLINE_HIGH_PRECISION; return error; } static FT_Error tt_glyph_load( FT_GlyphSlot ttslot, /* TT_GlyphSlot */ FT_Size ttsize, /* TT_Size */ FT_UInt glyph_index, FT_Int32 load_flags ) { TT_GlyphSlot slot = (TT_GlyphSlot)ttslot; TT_Size size = (TT_Size)ttsize; FT_Face face = ttslot->face; FT_Error error; if ( !slot ) return FT_THROW( Invalid_Slot_Handle ); if ( !size ) return FT_THROW( Invalid_Size_Handle ); if ( !face ) return FT_THROW( Invalid_Argument ); #ifdef FT_CONFIG_OPTION_INCREMENTAL if ( glyph_index >= (FT_UInt)face->num_glyphs && !face->internal->incremental_interface ) #else if ( glyph_index >= (FT_UInt)face->num_glyphs ) #endif return FT_THROW( Invalid_Argument ); if ( load_flags & FT_LOAD_NO_HINTING ) { /* both FT_LOAD_NO_HINTING and FT_LOAD_NO_AUTOHINT */ /* are necessary to disable hinting for tricky fonts */ if ( FT_IS_TRICKY( face ) ) load_flags &= ~FT_LOAD_NO_HINTING; if ( load_flags & FT_LOAD_NO_AUTOHINT ) load_flags |= FT_LOAD_NO_HINTING; } if ( load_flags & ( FT_LOAD_NO_RECURSE | FT_LOAD_NO_SCALE ) ) { load_flags |= FT_LOAD_NO_BITMAP | FT_LOAD_NO_SCALE; if ( !FT_IS_TRICKY( face ) ) load_flags |= FT_LOAD_NO_HINTING; } /* now load the glyph outline if necessary */ error = TT_Load_Glyph( size, slot, glyph_index, load_flags ); /* force drop-out mode to 2 - irrelevant now */ /* slot->outline.dropout_mode = 2; */ return error; } static FT_Error tt_get_kerning( FT_Face ttface, /* TT_Face */ FT_UInt left_glyph, FT_UInt right_glyph, FT_Vector* kerning ) { TT_Face face = (TT_Face)ttface; SFNT_Service sfnt = (SFNT_Service)face->sfnt; kerning->x = 0; kerning->y = 0; if ( sfnt ) kerning->x = sfnt->get_kerning( face, left_glyph, right_glyph ); return 0; } static FT_Error tt_get_advances( FT_Face ttface, FT_UInt start, FT_UInt count, FT_Int32 flags, FT_Fixed *advances ) { FT_UInt nn; TT_Face face = (TT_Face) ttface; /* XXX: TODO: check for sbits */ if ( flags & FT_LOAD_VERTICAL_LAYOUT ) { for ( nn = 0; nn < count; nn++ ) { FT_Short tsb; FT_UShort ah; /* since we don't need `tsb', we use zero for `yMax' parameter */ TT_Get_VMetrics( face, start + nn, 0, &tsb, &ah ); advances[nn] = ah; } } else { for ( nn = 0; nn < count; nn++ ) { FT_Short lsb; FT_UShort aw; TT_Get_HMetrics( face, start + nn, &lsb, &aw ); advances[nn] = aw; } } return FT_Err_Ok; } FT_LOCAL_DEF( FT_Error ) tt_size_reset( TT_Size size ) { TT_Face face; FT_Error error = FT_Err_Ok; FT_Size_Metrics* metrics; size->ttmetrics.valid = FALSE; face = (TT_Face)size->root.face; metrics = &size->metrics; /* copy the result from base layer */ *metrics = size->root.metrics; if ( metrics->x_ppem < 1 || metrics->y_ppem < 1 ) return FT_THROW( Invalid_PPem ); /* This bit flag, if set, indicates that the ppems must be */ /* rounded to integers. Nearly all TrueType fonts have this bit */ /* set, as hinting won't work really well otherwise. */ /* */ if ( face->header.Flags & 8 ) { metrics->x_scale = FT_DivFix( metrics->x_ppem << 6, face->root.units_per_EM ); metrics->y_scale = FT_DivFix( metrics->y_ppem << 6, face->root.units_per_EM ); metrics->ascender = FT_PIX_ROUND( FT_MulFix( face->root.ascender, metrics->y_scale ) ); metrics->descender = FT_PIX_ROUND( FT_MulFix( face->root.descender, metrics->y_scale ) ); metrics->height = FT_PIX_ROUND( FT_MulFix( face->root.height, metrics->y_scale ) ); metrics->max_advance = FT_PIX_ROUND( FT_MulFix( face->root.max_advance_width, metrics->x_scale ) ); } /* compute new transformation */ if ( metrics->x_ppem >= metrics->y_ppem ) { size->ttmetrics.scale = metrics->x_scale; size->ttmetrics.ppem = metrics->x_ppem; size->ttmetrics.x_ratio = 0x10000L; size->ttmetrics.y_ratio = FT_DivFix( metrics->y_ppem, metrics->x_ppem ); } else { size->ttmetrics.scale = metrics->y_scale; size->ttmetrics.ppem = metrics->y_ppem; size->ttmetrics.x_ratio = FT_DivFix( metrics->x_ppem, metrics->y_ppem ); size->ttmetrics.y_ratio = 0x10000L; } #ifdef TT_USE_BYTECODE_INTERPRETER size->cvt_ready = 0; #endif /* TT_USE_BYTECODE_INTERPRETER */ if ( !error ) size->ttmetrics.valid = TRUE; return error; } static FT_Error tt_size_request( FT_Size size, FT_Size_Request req ) { TT_Size ttsize = (TT_Size)size; FT_Error error = FT_Err_Ok; #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS if ( FT_HAS_FIXED_SIZES( size->face ) ) { TT_Face ttface = (TT_Face)size->face; SFNT_Service sfnt = (SFNT_Service) ttface->sfnt; FT_ULong strike_index; error = sfnt->set_sbit_strike( ttface, req, &strike_index ); if ( error ) ttsize->strike_index = 0xFFFFFFFFUL; else return tt_size_select( size, strike_index ); } #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ FT_Request_Metrics( size->face, req ); if ( FT_IS_SCALABLE( size->face ) ) { error = tt_size_reset( ttsize ); ttsize->root.metrics = ttsize->metrics; } return error; } FT_LOCAL_DEF( FT_Error ) T1_Get_Multi_Master( T1_Face face, FT_Multi_Master* master ) { PS_Blend blend = face->blend; FT_UInt n; FT_Error error; error = FT_THROW( Invalid_Argument ); if ( blend ) { master->num_axis = blend->num_axis; master->num_designs = blend->num_designs; for ( n = 0; n < blend->num_axis; n++ ) { FT_MM_Axis* axis = master->axis + n; PS_DesignMap map = blend->design_map + n; axis->name = blend->axis_names[n]; axis->minimum = map->design_points[0]; axis->maximum = map->design_points[map->num_points - 1]; } error = FT_Err_Ok; } return error; } FT_LOCAL_DEF( FT_Error ) T1_Set_MM_Design( T1_Face face, FT_UInt num_coords, FT_Long* coords ) { PS_Blend blend = face->blend; FT_Error error; FT_UInt n, p; error = FT_ERR( Invalid_Argument ); if ( blend && blend->num_axis == num_coords ) { /* compute the blend coordinates through the blend design map */ FT_Fixed final_blends[T1_MAX_MM_DESIGNS]; for ( n = 0; n < blend->num_axis; n++ ) { FT_Long design = coords[n]; FT_Fixed the_blend; PS_DesignMap map = blend->design_map + n; FT_Long* designs = map->design_points; FT_Fixed* blends = map->blend_points; FT_Int before = -1, after = -1; for ( p = 0; p < (FT_UInt)map->num_points; p++ ) { FT_Long p_design = designs[p]; /* exact match? */ if ( design == p_design ) { the_blend = blends[p]; goto Found; } if ( design < p_design ) { after = p; break; } before = p; } /* now interpolate if necessary */ if ( before < 0 ) the_blend = blends[0]; else if ( after < 0 ) the_blend = blends[map->num_points - 1]; else the_blend = FT_MulDiv( design - designs[before], blends [after] - blends [before], designs[after] - designs[before] ); Found: final_blends[n] = the_blend; } error = T1_Set_MM_Blend( face, num_coords, final_blends ); } return error; } FT_LOCAL_DEF( FT_Error ) T1_Set_MM_Blend( T1_Face face, FT_UInt num_coords, FT_Fixed* coords ) { PS_Blend blend = face->blend; FT_Error error; FT_UInt n, m; error = FT_ERR( Invalid_Argument ); if ( blend && blend->num_axis == num_coords ) { /* recompute the weight vector from the blend coordinates */ for ( n = 0; n < blend->num_designs; n++ ) { FT_Fixed result = 0x10000L; /* 1.0 fixed */ for ( m = 0; m < blend->num_axis; m++ ) { FT_Fixed factor; /* get current blend axis position */ factor = coords[m]; if ( factor < 0 ) factor = 0; if ( factor > 0x10000L ) factor = 0x10000L; if ( ( n & ( 1 << m ) ) == 0 ) factor = 0x10000L - factor; result = FT_MulFix( result, factor ); } blend->weight_vector[n] = result; } error = FT_Err_Ok; } return error; } #define INT_TO_F26DOT6( x ) ( (FT_Long)(x) << 6 ) #define INT_TO_F2DOT14( x ) ( (FT_Long)(x) << 14 ) #define INT_TO_FIXED( x ) ( (FT_Long)(x) << 16 ) #define F2DOT14_TO_FIXED( x ) ( (FT_Long)(x) << 2 ) #define FLOAT_TO_FIXED( x ) ( (FT_Long)( x * 65536.0 ) ) #define FIXED_TO_INT( x ) ( FT_RoundFix( x ) >> 16 ) #define ROUND_F26DOT6( x ) ( x >= 0 ? ( ( (x) + 32 ) & -64 ) \ : ( -( ( 32 - (x) ) & -64 ) ) ) FT_LOCAL_DEF( void ) mm_weights_unmap( FT_Fixed* weights, FT_Fixed* axiscoords, FT_UInt axis_count ) { FT_ASSERT( axis_count <= T1_MAX_MM_AXIS ); if ( axis_count == 1 ) axiscoords[0] = weights[1]; else if ( axis_count == 2 ) { axiscoords[0] = weights[3] + weights[1]; axiscoords[1] = weights[3] + weights[2]; } else if ( axis_count == 3 ) { axiscoords[0] = weights[7] + weights[5] + weights[3] + weights[1]; axiscoords[1] = weights[7] + weights[6] + weights[3] + weights[2]; axiscoords[2] = weights[7] + weights[6] + weights[5] + weights[4]; } else { axiscoords[0] = weights[15] + weights[13] + weights[11] + weights[9] + weights[7] + weights[5] + weights[3] + weights[1]; axiscoords[1] = weights[15] + weights[14] + weights[11] + weights[10] + weights[7] + weights[6] + weights[3] + weights[2]; axiscoords[2] = weights[15] + weights[14] + weights[13] + weights[12] + weights[7] + weights[6] + weights[5] + weights[4]; axiscoords[3] = weights[15] + weights[14] + weights[13] + weights[12] + weights[11] + weights[10] + weights[9] + weights[8]; } } FT_LOCAL_DEF( FT_Fixed ) mm_axis_unmap( PS_DesignMap axismap, FT_Fixed ncv ) { int j; if ( ncv <= axismap->blend_points[0] ) return INT_TO_FIXED( axismap->design_points[0] ); for ( j = 1; j < axismap->num_points; ++j ) { if ( ncv <= axismap->blend_points[j] ) return INT_TO_FIXED( axismap->design_points[j - 1] ) + ( axismap->design_points[j] - axismap->design_points[j - 1] ) * FT_DivFix( ncv - axismap->blend_points[j - 1], axismap->blend_points[j] - axismap->blend_points[j - 1] ); } return INT_TO_FIXED( axismap->design_points[axismap->num_points - 1] ); } FT_LOCAL_DEF( FT_Error ) T1_Get_MM_Var( T1_Face face, FT_MM_Var* *master ) { FT_Memory memory = face->root.memory; FT_MM_Var *mmvar = NULL; FT_Multi_Master mmaster; FT_Error error; FT_UInt i; FT_Fixed axiscoords[T1_MAX_MM_AXIS]; PS_Blend blend = face->blend; error = T1_Get_Multi_Master( face, &mmaster ); if ( error ) goto Exit; if ( FT_ALLOC( mmvar, sizeof ( FT_MM_Var ) + mmaster.num_axis * sizeof ( FT_Var_Axis ) ) ) goto Exit; mmvar->num_axis = mmaster.num_axis; mmvar->num_designs = mmaster.num_designs; mmvar->num_namedstyles = ~0U; /* Does not apply */ mmvar->axis = (FT_Var_Axis*)&mmvar[1]; /* Point to axes after MM_Var struct */ mmvar->namedstyle = NULL; for ( i = 0 ; i < mmaster.num_axis; ++i ) { mmvar->axis[i].name = mmaster.axis[i].name; mmvar->axis[i].minimum = INT_TO_FIXED( mmaster.axis[i].minimum); mmvar->axis[i].maximum = INT_TO_FIXED( mmaster.axis[i].maximum); mmvar->axis[i].def = ( mmvar->axis[i].minimum + mmvar->axis[i].maximum ) / 2; /* Does not apply. But this value is in range */ mmvar->axis[i].strid = ~0U; /* Does not apply */ mmvar->axis[i].tag = ~0U; /* Does not apply */ if ( ft_strcmp( mmvar->axis[i].name, "Weight" ) == 0 ) mmvar->axis[i].tag = FT_MAKE_TAG( 'w', 'g', 'h', 't' ); else if ( ft_strcmp( mmvar->axis[i].name, "Width" ) == 0 ) mmvar->axis[i].tag = FT_MAKE_TAG( 'w', 'd', 't', 'h' ); else if ( ft_strcmp( mmvar->axis[i].name, "OpticalSize" ) == 0 ) mmvar->axis[i].tag = FT_MAKE_TAG( 'o', 'p', 's', 'z' ); } if ( blend->num_designs == ( 1U << blend->num_axis ) ) { mm_weights_unmap( blend->default_weight_vector, axiscoords, blend->num_axis ); for ( i = 0; i < mmaster.num_axis; ++i ) mmvar->axis[i].def = mm_axis_unmap( &blend->design_map[i], axiscoords[i] ); } *master = mmvar; Exit: return error; } FT_LOCAL_DEF( FT_Error ) T1_Set_Var_Design( T1_Face face, FT_UInt num_coords, FT_Fixed* coords ) { FT_Long lcoords[4]; /* maximum axis count is 4 */ FT_UInt i; FT_Error error; error = FT_ERR( Invalid_Argument ); if ( num_coords <= 4 && num_coords > 0 ) { for ( i = 0; i < num_coords; ++i ) lcoords[i] = FIXED_TO_INT( coords[i] ); error = T1_Set_MM_Design( face, num_coords, lcoords ); } return error; } typedef struct GX_GVar_Head_ { FT_Long version; FT_UShort axisCount; FT_UShort globalCoordCount; FT_ULong offsetToCoord; FT_UShort glyphCount; FT_UShort flags; FT_ULong offsetToData; } GX_GVar_Head; static FT_Error ft_var_load_gvar( TT_Face face ) { FT_Stream stream = FT_FACE_STREAM(face); FT_Memory memory = stream->memory; GX_Blend blend = face->blend; FT_Error error; FT_UInt i, j; FT_ULong table_len; FT_ULong gvar_start; FT_ULong offsetToData; GX_GVar_Head gvar_head; static const FT_Frame_Field gvar_fields[] = { #undef FT_STRUCTURE #define FT_STRUCTURE GX_GVar_Head FT_FRAME_START( 20 ), FT_FRAME_LONG ( version ), FT_FRAME_USHORT( axisCount ), FT_FRAME_USHORT( globalCoordCount ), FT_FRAME_ULONG ( offsetToCoord ), FT_FRAME_USHORT( glyphCount ), FT_FRAME_USHORT( flags ), FT_FRAME_ULONG ( offsetToData ), FT_FRAME_END }; if ( (error = face->goto_table( face, TTAG_gvar, stream, &table_len )) != 0 ) goto Exit; gvar_start = FT_STREAM_POS( ); if ( FT_STREAM_READ_FIELDS( gvar_fields, &gvar_head ) ) goto Exit; blend->tuplecount = gvar_head.globalCoordCount; blend->gv_glyphcnt = gvar_head.glyphCount; offsetToData = gvar_start + gvar_head.offsetToData; if ( gvar_head.version != (FT_Long)0x00010000L || gvar_head.axisCount != (FT_UShort)blend->mmvar->num_axis ) { error = FT_THROW( Invalid_Table ); goto Exit; } if ( FT_NEW_ARRAY( blend->glyphoffsets, blend->gv_glyphcnt + 1 ) ) goto Exit; if ( gvar_head.flags & 1 ) { /* long offsets (one more offset than glyphs, to mark size of last) */ if ( FT_FRAME_ENTER( ( blend->gv_glyphcnt + 1 ) * 4L ) ) goto Exit; for ( i = 0; i <= blend->gv_glyphcnt; ++i ) blend->glyphoffsets[i] = offsetToData + FT_GET_LONG(); FT_FRAME_EXIT(); } else { /* short offsets (one more offset than glyphs, to mark size of last) */ if ( FT_FRAME_ENTER( ( blend->gv_glyphcnt + 1 ) * 2L ) ) goto Exit; for ( i = 0; i <= blend->gv_glyphcnt; ++i ) blend->glyphoffsets[i] = offsetToData + FT_GET_USHORT() * 2; /* XXX: Undocumented: `*2'! */ FT_FRAME_EXIT(); } if ( blend->tuplecount != 0 ) { if ( FT_NEW_ARRAY( blend->tuplecoords, gvar_head.axisCount * blend->tuplecount ) ) goto Exit; if ( FT_STREAM_SEEK( gvar_start + gvar_head.offsetToCoord ) || FT_FRAME_ENTER( blend->tuplecount * gvar_head.axisCount * 2L ) ) goto Exit; for ( i = 0; i < blend->tuplecount; ++i ) for ( j = 0 ; j < (FT_UInt)gvar_head.axisCount; ++j ) blend->tuplecoords[i * gvar_head.axisCount + j] = FT_GET_SHORT() << 2; /* convert to FT_Fixed */ FT_FRAME_EXIT(); } Exit: return error; } FT_LOCAL_DEF( FT_Error ) TT_Set_MM_Blend( TT_Face face, FT_UInt num_coords, FT_Fixed* coords ) { FT_Error error = FT_Err_Ok; GX_Blend blend; FT_MM_Var* mmvar; FT_UInt i; FT_Memory memory = face->root.memory; enum { mcvt_retain, mcvt_modify, mcvt_load } manageCvt; face->doblend = FALSE; if ( face->blend == NULL ) { if ( (error = TT_Get_MM_Var( face, NULL)) != 0 ) goto Exit; } blend = face->blend; mmvar = blend->mmvar; if ( num_coords != mmvar->num_axis ) { error = FT_THROW( Invalid_Argument ); goto Exit; } for ( i = 0; i < num_coords; ++i ) if ( coords[i] < -0x00010000L || coords[i] > 0x00010000L ) { error = FT_THROW( Invalid_Argument ); goto Exit; } if ( blend->glyphoffsets == NULL ) if ( (error = ft_var_load_gvar( face )) != 0 ) goto Exit; if ( blend->normalizedcoords == NULL ) { if ( FT_NEW_ARRAY( blend->normalizedcoords, num_coords ) ) goto Exit; manageCvt = mcvt_modify; /* If we have not set the blend coordinates before this, then the */ /* cvt table will still be what we read from the `cvt ' table and */ /* we don't need to reload it. We may need to change it though... */ } else { manageCvt = mcvt_retain; for ( i = 0; i < num_coords; ++i ) { if ( blend->normalizedcoords[i] != coords[i] ) { manageCvt = mcvt_load; break; } } /* If we don't change the blend coords then we don't need to do */ /* anything to the cvt table. It will be correct. Otherwise we */ /* no longer have the original cvt (it was modified when we set */ /* the blend last time), so we must reload and then modify it. */ } blend->num_axis = num_coords; FT_MEM_COPY( blend->normalizedcoords, coords, num_coords * sizeof ( FT_Fixed ) ); face->doblend = TRUE; if ( face->cvt != NULL ) { switch ( manageCvt ) { case mcvt_load: /* The cvt table has been loaded already; every time we change the */ /* blend we may need to reload and remodify the cvt table. */ FT_FREE( face->cvt ); face->cvt = NULL; tt_face_load_cvt( face, face->root.stream ); break; case mcvt_modify: /* The original cvt table is in memory. All we need to do is */ /* apply the `cvar' table (if any). */ tt_face_vary_cvt( face, face->root.stream ); break; case mcvt_retain: /* The cvt table is correct for this set of coordinates. */ break; } } Exit: return error; } typedef struct GX_FVar_Head_ { FT_Long version; FT_UShort offsetToData; FT_UShort countSizePairs; FT_UShort axisCount; FT_UShort axisSize; FT_UShort instanceCount; FT_UShort instanceSize; } GX_FVar_Head; typedef struct fvar_axis_ { FT_ULong axisTag; FT_ULong minValue; FT_ULong defaultValue; FT_ULong maxValue; FT_UShort flags; FT_UShort nameID; } GX_FVar_Axis; #define TTAG_wght FT_MAKE_TAG( 'w', 'g', 'h', 't' ) #define TTAG_wdth FT_MAKE_TAG( 'w', 'd', 't', 'h' ) #define TTAG_opsz FT_MAKE_TAG( 'o', 'p', 's', 'z' ) #define TTAG_slnt FT_MAKE_TAG( 's', 'l', 'n', 't' ) FT_LOCAL_DEF( FT_Error ) TT_Get_MM_Var( TT_Face face, FT_MM_Var* *master ) { FT_Stream stream = face->root.stream; FT_Memory memory = face->root.memory; FT_ULong table_len; FT_Error error = FT_Err_Ok; FT_ULong fvar_start; FT_Int i, j; FT_MM_Var* mmvar = NULL; FT_Fixed* next_coords; FT_String* next_name; FT_Var_Axis* a; FT_Var_Named_Style* ns; GX_FVar_Head fvar_head; static const FT_Frame_Field fvar_fields[] = { #undef FT_STRUCTURE #define FT_STRUCTURE GX_FVar_Head FT_FRAME_START( 16 ), FT_FRAME_LONG ( version ), FT_FRAME_USHORT( offsetToData ), FT_FRAME_USHORT( countSizePairs ), FT_FRAME_USHORT( axisCount ), FT_FRAME_USHORT( axisSize ), FT_FRAME_USHORT( instanceCount ), FT_FRAME_USHORT( instanceSize ), FT_FRAME_END }; static const FT_Frame_Field fvaraxis_fields[] = { #undef FT_STRUCTURE #define FT_STRUCTURE GX_FVar_Axis FT_FRAME_START( 20 ), FT_FRAME_ULONG ( axisTag ), FT_FRAME_ULONG ( minValue ), FT_FRAME_ULONG ( defaultValue ), FT_FRAME_ULONG ( maxValue ), FT_FRAME_USHORT( flags ), FT_FRAME_USHORT( nameID ), FT_FRAME_END }; if ( face->blend == NULL ) { /* both `fvar' and `gvar' must be present */ if ( (error = face->goto_table( face, TTAG_gvar, stream, &table_len )) != 0 ) goto Exit; if ( (error = face->goto_table( face, TTAG_fvar, stream, &table_len )) != 0 ) goto Exit; fvar_start = FT_STREAM_POS( ); if ( FT_STREAM_READ_FIELDS( fvar_fields, &fvar_head ) ) goto Exit; if ( fvar_head.version != (FT_Long)0x00010000L || fvar_head.countSizePairs != 2 || fvar_head.axisSize != 20 || /* axisCount limit implied by 16-bit instanceSize */ fvar_head.axisCount > 0x3FFE || fvar_head.instanceSize != 4 + 4 * fvar_head.axisCount || /* instanceCount limit implied by limited range of name IDs */ fvar_head.instanceCount > 0x7EFF || fvar_head.offsetToData + fvar_head.axisCount * 20U + fvar_head.instanceCount * fvar_head.instanceSize > table_len ) { error = FT_THROW( Invalid_Table ); goto Exit; } if ( FT_NEW( face->blend ) ) goto Exit; /* cannot overflow 32-bit arithmetic because of limits above */ face->blend->mmvar_len = sizeof ( FT_MM_Var ) + fvar_head.axisCount * sizeof ( FT_Var_Axis ) + fvar_head.instanceCount * sizeof ( FT_Var_Named_Style ) + fvar_head.instanceCount * fvar_head.axisCount * sizeof ( FT_Fixed ) + 5 * fvar_head.axisCount; if ( FT_ALLOC( mmvar, face->blend->mmvar_len ) ) goto Exit; face->blend->mmvar = mmvar; mmvar->num_axis = fvar_head.axisCount; mmvar->num_designs = ~0U; /* meaningless in this context; each glyph */ /* may have a different number of designs */ /* (or tuples, as called by Apple) */ mmvar->num_namedstyles = fvar_head.instanceCount; mmvar->axis = (FT_Var_Axis*)&(mmvar[1]); mmvar->namedstyle = (FT_Var_Named_Style*)&(mmvar->axis[fvar_head.axisCount]); next_coords = (FT_Fixed*)&(mmvar->namedstyle[fvar_head.instanceCount]); for ( i = 0; i < fvar_head.instanceCount; ++i ) { mmvar->namedstyle[i].coords = next_coords; next_coords += fvar_head.axisCount; } next_name = (FT_String*)next_coords; for ( i = 0; i < fvar_head.axisCount; ++i ) { mmvar->axis[i].name = next_name; next_name += 5; } if ( FT_STREAM_SEEK( fvar_start + fvar_head.offsetToData ) ) goto Exit; a = mmvar->axis; for ( i = 0; i < fvar_head.axisCount; ++i ) { GX_FVar_Axis axis_rec; if ( FT_STREAM_READ_FIELDS( fvaraxis_fields, &axis_rec ) ) goto Exit; a->tag = axis_rec.axisTag; a->minimum = axis_rec.minValue; /* A Fixed */ a->def = axis_rec.defaultValue; /* A Fixed */ a->maximum = axis_rec.maxValue; /* A Fixed */ a->strid = axis_rec.nameID; a->name[0] = (FT_String)( a->tag >> 24 ); a->name[1] = (FT_String)( ( a->tag >> 16 ) & 0xFF ); a->name[2] = (FT_String)( ( a->tag >> 8 ) & 0xFF ); a->name[3] = (FT_String)( ( a->tag ) & 0xFF ); a->name[4] = 0; ++a; } ns = mmvar->namedstyle; for ( i = 0; i < fvar_head.instanceCount; ++i, ++ns ) { if ( FT_FRAME_ENTER( 4L + 4L * fvar_head.axisCount ) ) goto Exit; ns->strid = FT_GET_USHORT(); (void) /* flags = */ FT_GET_USHORT(); for ( j = 0; j < fvar_head.axisCount; ++j ) ns->coords[j] = FT_GET_ULONG(); /* A Fixed */ FT_FRAME_EXIT(); } } if ( master != NULL ) { FT_UInt n; if ( FT_ALLOC( mmvar, face->blend->mmvar_len ) ) goto Exit; FT_MEM_COPY( mmvar, face->blend->mmvar, face->blend->mmvar_len ); mmvar->axis = (FT_Var_Axis*)&(mmvar[1]); mmvar->namedstyle = (FT_Var_Named_Style*)&(mmvar->axis[mmvar->num_axis]); next_coords = (FT_Fixed*)&(mmvar->namedstyle[mmvar->num_namedstyles]); for ( n = 0; n < mmvar->num_namedstyles; ++n ) { mmvar->namedstyle[n].coords = next_coords; next_coords += mmvar->num_axis; } a = mmvar->axis; next_name = (FT_String*)next_coords; for ( n = 0; n < mmvar->num_axis; ++n ) { a->name = next_name; /* standard PostScript names for some standard apple tags */ if ( a->tag == TTAG_wght ) a->name = (char *)"Weight"; else if ( a->tag == TTAG_wdth ) a->name = (char *)"Width"; else if ( a->tag == TTAG_opsz ) a->name = (char *)"OpticalSize"; else if ( a->tag == TTAG_slnt ) a->name = (char *)"Slant"; next_name += 5; ++a; } *master = mmvar; } Exit: return error; } static void ft_var_load_avar( TT_Face face ) { FT_Stream stream = FT_FACE_STREAM(face); FT_Memory memory = stream->memory; GX_Blend blend = face->blend; GX_AVarSegment segment; FT_Error error = FT_Err_Ok; FT_ULong version; FT_Long axisCount; FT_Int i, j; FT_ULong table_len; FT_UNUSED( error ); blend->avar_checked = TRUE; if ( (error = face->goto_table( face, TTAG_avar, stream, &table_len )) != 0 ) return; if ( FT_FRAME_ENTER( table_len ) ) return; version = FT_GET_LONG(); axisCount = FT_GET_LONG(); if ( version != 0x00010000L || axisCount != (FT_Long)blend->mmvar->num_axis ) goto Exit; if ( FT_NEW_ARRAY( blend->avar_segment, axisCount ) ) goto Exit; segment = &blend->avar_segment[0]; for ( i = 0; i < axisCount; ++i, ++segment ) { segment->pairCount = FT_GET_USHORT(); if ( FT_NEW_ARRAY( segment->correspondence, segment->pairCount ) ) { /* Failure. Free everything we have done so far. We must do */ /* it right now since loading the `avar' table is optional. */ for ( j = i - 1; j >= 0; --j ) FT_FREE( blend->avar_segment[j].correspondence ); FT_FREE( blend->avar_segment ); blend->avar_segment = NULL; goto Exit; } for ( j = 0; j < segment->pairCount; ++j ) { segment->correspondence[j].fromCoord = FT_GET_SHORT() << 2; /* convert to Fixed */ segment->correspondence[j].toCoord = FT_GET_SHORT()<<2; /* convert to Fixed */ } } Exit: FT_FRAME_EXIT(); } FT_LOCAL_DEF( FT_Error ) TT_Set_Var_Design( TT_Face face, FT_UInt num_coords, FT_Fixed* coords ) { FT_Error error = FT_Err_Ok; FT_Fixed* normalized = NULL; GX_Blend blend; FT_MM_Var* mmvar; FT_UInt i, j; FT_Var_Axis* a; GX_AVarSegment av; FT_Memory memory = face->root.memory; if ( face->blend == NULL ) { if ( (error = TT_Get_MM_Var( face, NULL )) != 0 ) goto Exit; } blend = face->blend; mmvar = blend->mmvar; if ( num_coords != mmvar->num_axis ) { error = FT_THROW( Invalid_Argument ); goto Exit; } /* Axis normalization is a two stage process. First we normalize */ /* based on the [min,def,max] values for the axis to be [-1,0,1]. */ /* Then, if there's an `avar' table, we renormalize this range. */ if ( FT_NEW_ARRAY( normalized, mmvar->num_axis ) ) goto Exit; a = mmvar->axis; for ( i = 0; i < mmvar->num_axis; ++i, ++a ) { if ( coords[i] > a->maximum || coords[i] < a->minimum ) { error = FT_THROW( Invalid_Argument ); goto Exit; } if ( coords[i] < a->def ) normalized[i] = -FT_DivFix( coords[i] - a->def, a->minimum - a->def ); else if ( a->maximum == a->def ) normalized[i] = 0; else normalized[i] = FT_DivFix( coords[i] - a->def, a->maximum - a->def ); } if ( !blend->avar_checked ) ft_var_load_avar( face ); if ( blend->avar_segment != NULL ) { av = blend->avar_segment; for ( i = 0; i < mmvar->num_axis; ++i, ++av ) { for ( j = 1; j < (FT_UInt)av->pairCount; ++j ) if ( normalized[i] < av->correspondence[j].fromCoord ) { normalized[i] = FT_MulDiv( normalized[i] - av->correspondence[j - 1].fromCoord, av->correspondence[j].toCoord - av->correspondence[j - 1].toCoord, av->correspondence[j].fromCoord - av->correspondence[j - 1].fromCoord ) + av->correspondence[j - 1].toCoord; break; } } } error = TT_Set_MM_Blend( face, num_coords, normalized ); Exit: FT_FREE( normalized ); return error; } #define TT_INTERPRETER_VERSION_35 35 #define TT_INTERPRETER_VERSION_38 38 static FT_Error tt_property_set( FT_Module module, /* TT_Driver */ const char* property_name, const void* value ) { FT_Error error = FT_Err_Ok; TT_Driver driver = (TT_Driver)module; if ( !ft_strcmp( property_name, "interpreter-version" ) ) { FT_UInt* interpreter_version = (FT_UInt*)value; #ifndef TT_CONFIG_OPTION_SUBPIXEL_HINTING if ( *interpreter_version != TT_INTERPRETER_VERSION_35 ) error = FT_ERR( Unimplemented_Feature ); else #endif driver->interpreter_version = *interpreter_version; return error; } FT_TRACE0(( "tt_property_set: missing property `%s'\n", property_name )); return FT_THROW( Missing_Property ); } static FT_Error tt_property_get( FT_Module module, /* TT_Driver */ const char* property_name, const void* value ) { FT_Error error = FT_Err_Ok; TT_Driver driver = (TT_Driver)module; FT_UInt interpreter_version = driver->interpreter_version; if ( !ft_strcmp( property_name, "interpreter-version" ) ) { FT_UInt* val = (FT_UInt*)value; *val = interpreter_version; return error; } FT_TRACE0(( "tt_property_get: missing property `%s'\n", property_name )); return FT_THROW( Missing_Property ); } // ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ #define include_afstyles_h_1 \ META_STYLE_LATIN( cyrl, CYRL, "Cyrillic" ) \ META_STYLE_LATIN( grek, GREK, "Greek" ) \ STYLE( hebr_dflt, HEBR_DFLT, \ "Hebrew default style", \ AF_WRITING_SYSTEM_LATIN, \ AF_SCRIPT_HEBR, \ AF_BLUE_STRINGSET_HEBR, \ AF_COVERAGE_DEFAULT ) \ META_STYLE_LATIN( latn, LATN, "Latin" ) #define include_afstyles_h_2 \ STYLE( ltn2_dflt, LTN2_DFLT, \ "Latin 2 default style", \ AF_WRITING_SYSTEM_LATIN2, \ AF_SCRIPT_LATN, \ AF_BLUE_STRINGSET_LATN, \ AF_COVERAGE_DEFAULT ) #define include_afstyles_h_3 \ STYLE( none_dflt, NONE_DFLT, \ "no style", \ AF_WRITING_SYSTEM_DUMMY, \ AF_SCRIPT_NONE, \ (AF_Blue_Stringset)0, \ AF_COVERAGE_DEFAULT ) #define include_afstyles_h_4 \ STYLE_DEFAULT_INDIC( beng, BENG, "Bengali" ) \ STYLE_DEFAULT_INDIC( deva, DEVA, "Devanagari" ) \ STYLE_DEFAULT_INDIC( gujr, GUJR, "Gujarati" ) \ STYLE_DEFAULT_INDIC( guru, GURU, "Gurmukhi" ) \ STYLE_DEFAULT_INDIC( knda, KNDA, "Kannada" ) \ STYLE_DEFAULT_INDIC( limb, LIMB, "Limbu" ) \ STYLE_DEFAULT_INDIC( mlym, MLYM, "Malayalam" ) \ STYLE_DEFAULT_INDIC( orya, ORYA, "Oriya" ) \ STYLE_DEFAULT_INDIC( sinh, SINH, "Sinhala" ) \ STYLE_DEFAULT_INDIC( sund, SUND, "Sundanese" ) \ STYLE_DEFAULT_INDIC( sylo, SYLO, "Syloti Nagri" ) \ STYLE_DEFAULT_INDIC( taml, TAML, "Tamil" ) \ STYLE_DEFAULT_INDIC( telu, TELU, "Telugu" ) \ STYLE_DEFAULT_INDIC( tibt, TIBT, "Tibetan" ) #define include_afstyles_h_5 \ STYLE( hani_dflt, HANI_DFLT, \ "CJKV ideographs default style", \ AF_WRITING_SYSTEM_CJK, \ AF_SCRIPT_HANI, \ AF_BLUE_STRINGSET_HANI, \ AF_COVERAGE_DEFAULT ) #define include_afscript_h_1 \ SCRIPT( cyrl, CYRL, "Cyrillic", HB_SCRIPT_CYRILLIC, 0x43E, 0x41E, 0x0 ) /* оО */ \ SCRIPT( grek, GREK, "Greek", HB_SCRIPT_GREEK, 0x3BF, 0x39F, 0x0 ) /* οΟ */ \ SCRIPT( hebr, HEBR, "Hebrew", HB_SCRIPT_HEBREW, 0x5DD, 0x0, 0x0 ) /* ם */ \ SCRIPT( latn, LATN, "Latin", HB_SCRIPT_LATIN, 'o', 'O', '0' ) \ SCRIPT( none, NONE, "no script", HB_SCRIPT_INVALID, 0x0, 0x0, 0x0 ) #define include_afscript_h_2 \ SCRIPT( beng, BENG, "Bengali", HB_SCRIPT_BENGALI, 'o', 0x0, 0x0 ) /* XXX */ \ SCRIPT( deva, DEVA, "Devanagari", HB_SCRIPT_DEVANAGARI, 'o', 0x0, 0x0 ) /* XXX */ \ SCRIPT( gujr, GUJR, "Gujarati", HB_SCRIPT_GUJARATI, 'o', 0x0, 0x0 ) /* XXX */ \ SCRIPT( guru, GURU, "Gurmukhi", HB_SCRIPT_GURMUKHI, 'o', 0x0, 0x0 ) /* XXX */ \ SCRIPT( knda, KNDA, "Kannada", HB_SCRIPT_KANNADA, 'o', 0x0, 0x0 ) /* XXX */ \ SCRIPT( limb, LIMB, "Limbu", HB_SCRIPT_LIMBU, 'o', 0x0, 0x0 ) /* XXX */ \ SCRIPT( mlym, MLYM, "Malayalam", HB_SCRIPT_MALAYALAM, 'o', 0x0, 0x0 ) /* XXX */ \ SCRIPT( orya, ORYA, "Oriya", HB_SCRIPT_ORIYA, 'o', 0x0, 0x0 ) /* XXX */ \ SCRIPT( sinh, SINH, "Sinhala", HB_SCRIPT_SINHALA, 'o', 0x0, 0x0 ) /* XXX */ \ SCRIPT( sund, SUND, "Sundanese", HB_SCRIPT_SUNDANESE, 'o', 0x0, 0x0 ) /* XXX */ \ SCRIPT( sylo, SYLO, "Syloti Nagri", HB_SCRIPT_SYLOTI_NAGRI, 'o', 0x0, 0x0 ) /* XXX */ \ SCRIPT( taml, TAML, "Tamil", HB_SCRIPT_TAMIL, 'o', 0x0, 0x0 ) /* XXX */ \ SCRIPT( telu, TELU, "Telugu", HB_SCRIPT_TELUGU, 'o', 0x0, 0x0 ) /* XXX */ \ SCRIPT( tibt, TIBT, "Tibetan", HB_SCRIPT_TIBETAN, 'o', 0x0, 0x0 ) /* XXX */ #define include_afscript_h_3 \ SCRIPT( hani, HANI, "CJKV ideographs", HB_SCRIPT_HAN, 0x7530, 0x56D7, 0x0 ) /* 田囗 */ #define include_afcover_h \ COVERAGE( petite_capitals_from_capitals, PETITE_CAPITALS_FROM_CAPITALS, "petite capitals from capitals", 'c', '2', 'c', 'p' ) \ COVERAGE( small_capitals_from_capitals, SMALL_CAPITALS_FROM_CAPITALS, "small capitals from capitals", 'c', '2', 's', 'c' ) \ COVERAGE( ordinals, ORDINALS, "ordinals", 'o', 'r', 'd', 'n' ) \ COVERAGE( petite_capitals, PETITE_CAPITALS, "petite capitals", 'p', 'c', 'a', 'p' ) \ COVERAGE( ruby, RUBY, "ruby", 'r', 'u', 'b', 'y' ) \ COVERAGE( scientific_inferiors, SCIENTIFIC_INFERIORS, "scientific inferiors", 's', 'i', 'n', 'f' ) \ COVERAGE( small_capitals, SMALL_CAPITALS, "small capitals", 's', 'm', 'c', 'p' ) \ COVERAGE( subscript, SUBSCRIPT, "subscript", 's', 'u', 'b', 's' ) \ COVERAGE( superscript, SUPERSCRIPT, "superscript", 's', 'u', 'p', 's' ) \ COVERAGE( titling, TITLING, "titling", 't', 'i', 't', 'l' ) #define include_afwrtsys_h_1 \ WRITING_SYSTEM( dummy, DUMMY ) \ WRITING_SYSTEM( latin, LATIN ) \ WRITING_SYSTEM( cjk, CJK ) \ WRITING_SYSTEM( indic, INDIC ) #define include_afwrtsys_h_2 \ WRITING_SYSTEM( latin2, LATIN2 ) #undef STYLE_LATIN #define STYLE_LATIN( s, S, f, F, ds, df, C ) \ STYLE( s ## _ ## f, S ## _ ## F, \ ds " " df " style", \ AF_WRITING_SYSTEM_LATIN, \ AF_SCRIPT_ ## S, \ AF_BLUE_STRINGSET_ ## S, \ AF_COVERAGE_ ## C ) #undef META_STYLE_LATIN #define META_STYLE_LATIN( s, S, ds ) \ STYLE_LATIN( s, S, c2cp, C2CP, ds, "petite capticals from capitals", PETITE_CAPITALS_FROM_CAPITALS ) \ STYLE_LATIN( s, S, c2sc, C2SC, ds, "small capticals from capitals", SMALL_CAPITALS_FROM_CAPITALS ) \ STYLE_LATIN( s, S, ordn, ORDN, ds, "ordinals", ORDINALS ) \ STYLE_LATIN( s, S, pcap, PCAP, ds, "petite capitals", PETITE_CAPITALS ) \ STYLE_LATIN( s, S, sinf, SINF, ds, "scientific inferiors", SCIENTIFIC_INFERIORS ) \ STYLE_LATIN( s, S, smcp, SMCP, ds, "small capitals", SMALL_CAPITALS ) \ STYLE_LATIN( s, S, subs, SUBS, ds, "subscript", SUBSCRIPT ) \ STYLE_LATIN( s, S, sups, SUPS, ds, "superscript", SUPERSCRIPT ) \ STYLE_LATIN( s, S, titl, TITL, ds, "titling", TITLING ) \ STYLE_LATIN( s, S, dflt, DFLT, ds, "default", DEFAULT ) #undef STYLE_DEFAULT_INDIC #define STYLE_DEFAULT_INDIC( s, S, d ) \ STYLE( s ## _dflt, S ## _DFLT, \ d " default style", \ AF_WRITING_SYSTEM_INDIC, \ AF_SCRIPT_ ## S, \ (AF_Blue_Stringset)0, \ AF_COVERAGE_DEFAULT ) #define FT_LOCAL_ARRAY( x ) extern const x #define FT_LOCAL_ARRAY_DEF( x ) const x #ifndef FT_CONFIG_OPTION_PIC #define AF_DECLARE_WRITING_SYSTEM_CLASS( writing_system_class ) \ FT_CALLBACK_TABLE const AF_WritingSystemClassRec \ writing_system_class; #define AF_DEFINE_WRITING_SYSTEM_CLASS( \ writing_system_class, \ system, \ m_size, \ m_init, \ m_scale, \ m_done, \ h_init, \ h_apply ) \ FT_CALLBACK_TABLE_DEF \ const AF_WritingSystemClassRec writing_system_class = \ { \ system, \ \ m_size, \ \ m_init, \ m_scale, \ m_done, \ \ h_init, \ h_apply \ }; #define AF_DECLARE_SCRIPT_CLASS( script_class ) \ FT_CALLBACK_TABLE const AF_ScriptClassRec \ script_class; #define AF_DEFINE_SCRIPT_CLASS( \ script_class, \ script, \ ranges, \ std_char1, \ std_char2, \ std_char3 ) \ FT_CALLBACK_TABLE_DEF \ const AF_ScriptClassRec script_class = \ { \ script, \ ranges, \ std_char1, \ std_char2, \ std_char3 \ }; #define AF_DECLARE_STYLE_CLASS( style_class ) \ FT_CALLBACK_TABLE const AF_StyleClassRec \ style_class; #define AF_DEFINE_STYLE_CLASS( style_class, style, writing_system, script, blue_stringset,coverage ) \ FT_CALLBACK_TABLE_DEF \ const AF_StyleClassRec style_class = \ { \ style, \ writing_system, \ script, \ blue_stringset, \ coverage \ }; #else /* FT_CONFIG_OPTION_PIC */ #define AF_DECLARE_WRITING_SYSTEM_CLASS( writing_system_class ) \ FT_LOCAL( void ) \ FT_Init_Class_ ## writing_system_class( AF_WritingSystemClassRec* ac ); #define AF_DEFINE_WRITING_SYSTEM_CLASS( \ writing_system_class, \ system, \ m_size, \ m_init, \ m_scale, \ m_done, \ h_init, \ h_apply ) \ FT_LOCAL_DEF( void ) \ FT_Init_Class_ ## writing_system_class( AF_WritingSystemClassRec* ac ) \ { \ ac->writing_system = system; \ \ ac->style_metrics_size = m_size; \ \ ac->style_metrics_init = m_init; \ ac->style_metrics_scale = m_scale; \ ac->style_metrics_done = m_done; \ \ ac->style_hints_init = h_init; \ ac->style_hints_apply = h_apply; \ } #define AF_DECLARE_SCRIPT_CLASS( script_class ) \ FT_LOCAL( void ) \ FT_Init_Class_ ## script_class( AF_ScriptClassRec* ac ); #define AF_DEFINE_SCRIPT_CLASS( \ script_class, \ script_, \ ranges, \ std_char1, \ std_char2, \ std_char3 ) \ FT_LOCAL_DEF( void ) \ FT_Init_Class_ ## script_class( AF_ScriptClassRec* ac ) \ { \ ac->script = script_; \ ac->script_uni_ranges = ranges; \ ac->standard_char1 = std_char1; \ ac->standard_char2 = std_char2; \ ac->standard_char3 = std_char3; \ } #define AF_DECLARE_STYLE_CLASS( style_class ) \ FT_LOCAL( void ) \ FT_Init_Class_ ## style_class( AF_StyleClassRec* ac ); #define AF_DEFINE_STYLE_CLASS( \ style_class, \ style_, \ writing_system_, \ script_, \ blue_stringset_, \ coverage_ ) \ FT_LOCAL_DEF( void ) \ FT_Init_Class_ ## style_class( AF_StyleClassRec* ac ) \ { \ ac->style = style_; \ ac->writing_system = writing_system_; \ ac->script = script_; \ ac->blue_stringset = blue_stringset_; \ ac->coverage = coverage_; \ } #endif /* FT_CONFIG_OPTION_PIC */ //////////////////////////////////////////////////////////////////////////////// #undef STYLE #define STYLE( s, S, d, ws, sc, ss, c ) AF_STYLE_ ## S, typedef enum AF_Style_ { include_afstyles_h_1 #ifdef FT_OPTION_AUTOFIT2 include_afstyles_h_2 #endif include_afstyles_h_3 #ifdef AF_CONFIG_OPTION_INDIC include_afstyles_h_4 #endif #ifdef AF_CONFIG_OPTION_CJK include_afstyles_h_5 #endif AF_STYLE_MAX /* do not remove */ } AF_Style; //////////////////////////////////////////////////////////////////////////////// #undef SCRIPT #define SCRIPT( s, S, d, h, sc1, sc2, sc3 ) AF_SCRIPT_ ## S, /* The list of known scripts. */ typedef enum AF_Script_ { include_afscript_h_1 #ifdef AF_CONFIG_OPTION_INDIC include_afscript_h_2 #endif #ifdef AF_CONFIG_OPTION_CJK include_afscript_h_3 #endif AF_SCRIPT_MAX /* do not remove */ } AF_Script; //////////////////////////////////////////////////////////////////////////////// #undef COVERAGE #define COVERAGE( name, NAME, description, tag1, tag2, tag3, tag4 ) AF_COVERAGE_ ## NAME, typedef enum AF_Coverage_ { include_afcover_h AF_COVERAGE_DEFAULT } AF_Coverage; //////////////////////////////////////////////////////////////////////////////// #undef WRITING_SYSTEM #define WRITING_SYSTEM( ws, WS ) AF_WRITING_SYSTEM_ ## WS, /* The list of known writing systems. */ typedef enum AF_WritingSystem_ { include_afwrtsys_h_1 #ifdef FT_OPTION_AUTOFIT2 include_afwrtsys_h_2 #endif AF_WRITING_SYSTEM_MAX /* do not remove */ } AF_WritingSystem; typedef struct AF_ScalerRec_ { FT_Face face; /* source font face */ FT_Fixed x_scale; /* from font units to 1/64th device pixels */ FT_Fixed y_scale; /* from font units to 1/64th device pixels */ FT_Pos x_delta; /* in 1/64th device pixels */ FT_Pos y_delta; /* in 1/64th device pixels */ FT_Render_Mode render_mode; /* monochrome, anti-aliased, LCD, etc. */ FT_UInt32 flags; /* additional control flags, see above */ } AF_ScalerRec, *AF_Scaler; typedef enum AF_Blue_Stringset_ { AF_BLUE_STRINGSET_LATN = 0, AF_BLUE_STRINGSET_GREK = 7, AF_BLUE_STRINGSET_CYRL = 14, AF_BLUE_STRINGSET_HEBR = 20, af_blue_2_1 = 24, #ifdef AF_CONFIG_OPTION_CJK AF_BLUE_STRINGSET_HANI = af_blue_2_1 + 0, af_blue_2_1_1 = af_blue_2_1 + 4, #ifdef AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT af_blue_2_1_2 = af_blue_2_1_1 + 4, #else af_blue_2_1_2 = af_blue_2_1_1 + 0, #endif /* AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT */ af_blue_2_2 = af_blue_2_1_2 + 1, #else af_blue_2_2 = af_blue_2_1 + 0, #endif /* AF_CONFIG_OPTION_CJK */ AF_BLUE_STRINGSET_MAX /* do not remove */ } AF_Blue_Stringset; typedef struct AF_StyleClassRec_ { AF_Style style; AF_WritingSystem writing_system; AF_Script script; AF_Blue_Stringset blue_stringset; AF_Coverage coverage; } AF_StyleClassRec; typedef const AF_StyleClassRec* AF_StyleClass; typedef struct AF_Script_UniRangeRec_ { FT_UInt32 first; FT_UInt32 last; } AF_Script_UniRangeRec; typedef const AF_Script_UniRangeRec* AF_Script_UniRange; typedef struct AF_ScriptClassRec_ { AF_Script script; AF_Script_UniRange script_uni_ranges; /* last must be { 0, 0 } */ FT_UInt32 standard_char1; /* for default width and height */ FT_UInt32 standard_char2; /* ditto */ FT_UInt32 standard_char3; /* ditto */ } AF_ScriptClassRec; typedef const AF_ScriptClassRec* AF_ScriptClass; typedef struct AF_FaceGlobalsRec_* AF_FaceGlobals; typedef struct AF_StyleMetricsRec_* AF_StyleMetrics; typedef struct AF_GlyphHintsRec_* AF_GlyphHints; typedef FT_Error (*AF_WritingSystem_InitMetricsFunc)( AF_StyleMetrics metrics, FT_Face face ); typedef void (*AF_WritingSystem_ScaleMetricsFunc)( AF_StyleMetrics metrics, AF_Scaler scaler ); typedef void (*AF_WritingSystem_DoneMetricsFunc)( AF_StyleMetrics metrics ); typedef FT_Error (*AF_WritingSystem_InitHintsFunc)( AF_GlyphHints hints, AF_StyleMetrics metrics ); typedef void (*AF_WritingSystem_ApplyHintsFunc)( AF_GlyphHints hints, FT_Outline* outline, AF_StyleMetrics metrics ); typedef struct AF_WritingSystemClassRec_ { AF_WritingSystem writing_system; FT_Offset style_metrics_size; AF_WritingSystem_InitMetricsFunc style_metrics_init; AF_WritingSystem_ScaleMetricsFunc style_metrics_scale; AF_WritingSystem_DoneMetricsFunc style_metrics_done; AF_WritingSystem_InitHintsFunc style_hints_init; AF_WritingSystem_ApplyHintsFunc style_hints_apply; } AF_WritingSystemClassRec; typedef const AF_WritingSystemClassRec* AF_WritingSystemClass; //////////////////////////////////////////////////////////////////////////////// #undef STYLE #define STYLE( s, S, d, ws, sc, ss, c ) \ AF_DEFINE_STYLE_CLASS( \ af_ ## s ## _style_class, \ AF_STYLE_ ## S, \ ws, \ sc, \ ss, \ c ) include_afstyles_h_1 #ifdef FT_OPTION_AUTOFIT2 include_afstyles_h_2 #endif include_afstyles_h_3 #ifdef AF_CONFIG_OPTION_INDIC include_afstyles_h_4 #endif #ifdef AF_CONFIG_OPTION_CJK include_afstyles_h_5 #endif //////////////////////////////////////////////////////////////////////////////// #undef STYLE #define STYLE( s, S, d, ws, sc, ss, c ) &af_ ## s ## _style_class, FT_LOCAL_ARRAY_DEF( AF_StyleClass ) af_style_classes[] = { include_afstyles_h_1 #ifdef FT_OPTION_AUTOFIT2 include_afstyles_h_2 #endif include_afstyles_h_3 #ifdef AF_CONFIG_OPTION_INDIC include_afstyles_h_4 #endif #ifdef AF_CONFIG_OPTION_CJK include_afstyles_h_5 #endif NULL /* do not remove */ }; //////////////////////////////////////////////////////////////////////////////// #undef STYLE #define STYLE( s, S, d, ws, sc, ss, c ) #s, FT_LOCAL_ARRAY_DEF( char* ) af_style_names[] = { include_afstyles_h_1 #ifdef FT_OPTION_AUTOFIT2 include_afstyles_h_2 #endif include_afstyles_h_3 #ifdef AF_CONFIG_OPTION_INDIC include_afstyles_h_4 #endif #ifdef AF_CONFIG_OPTION_CJK include_afstyles_h_5 #endif }; //////////////////////////////////////////////////////////////////////////////// #undef STYLE #define STYLE( s, S, d, ws, sc, ss, c ) AF_DECLARE_STYLE_CLASS( af_ ## s ## _style_class ) include_afstyles_h_1 #ifdef FT_OPTION_AUTOFIT2 include_afstyles_h_2 #endif include_afstyles_h_3 #ifdef AF_CONFIG_OPTION_INDIC include_afstyles_h_4 #endif #ifdef AF_CONFIG_OPTION_CJK include_afstyles_h_5 #endif FT_LOCAL_ARRAY( AF_StyleClass ) af_style_classes[]; //////////////////////////////////////////////////////////////////////////////// #undef SCRIPT #define SCRIPT( s, S, d, h, sc1, sc2, sc3 ) extern const AF_Script_UniRangeRec af_ ## s ## _uniranges[]; include_afscript_h_1 #ifdef AF_CONFIG_OPTION_INDIC include_afscript_h_2 #endif #ifdef AF_CONFIG_OPTION_CJK include_afscript_h_3 #endif //////////////////////////////////////////////////////////////////////////////// #undef SCRIPT #define SCRIPT( s, S, d, h, sc1, sc2, sc3 ) \ AF_DEFINE_SCRIPT_CLASS( \ af_ ## s ## _script_class, \ AF_SCRIPT_ ## S, \ af_ ## s ## _uniranges, \ sc1, sc2, sc3 ) include_afscript_h_1 #ifdef AF_CONFIG_OPTION_INDIC include_afscript_h_2 #endif #ifdef AF_CONFIG_OPTION_CJK include_afscript_h_3 #endif //////////////////////////////////////////////////////////////////////////////// #undef SCRIPT #define SCRIPT( s, S, d, h, sc1, sc2, sc3 ) &af_ ## s ## _script_class, FT_LOCAL_ARRAY_DEF( AF_ScriptClass ) af_script_classes[] = { include_afscript_h_1 #ifdef AF_CONFIG_OPTION_INDIC include_afscript_h_2 #endif #ifdef AF_CONFIG_OPTION_CJK include_afscript_h_3 #endif NULL /* do not remove */ }; //////////////////////////////////////////////////////////////////////////////// #undef SCRIPT #define SCRIPT( s, S, d, h, sc1, sc2, sc3 ) AF_DECLARE_SCRIPT_CLASS( af_ ## s ## _script_class ) include_afscript_h_1 #ifdef AF_CONFIG_OPTION_INDIC include_afscript_h_2 #endif #ifdef AF_CONFIG_OPTION_CJK include_afscript_h_3 #endif FT_LOCAL_ARRAY( AF_ScriptClass ) af_script_classes[]; //////////////////////////////////////////////////////////////////////////////// #undef WRITING_SYSTEM #define WRITING_SYSTEM( ws, WS ) /* empty */ include_afwrtsys_h_1 #ifdef FT_OPTION_AUTOFIT2 include_afwrtsys_h_2 #endif //////////////////////////////////////////////////////////////////////////////// AF_DECLARE_WRITING_SYSTEM_CLASS( af_dummy_writing_system_class ) AF_DECLARE_WRITING_SYSTEM_CLASS( af_latin_writing_system_class ) AF_DECLARE_WRITING_SYSTEM_CLASS( af_cjk_writing_system_class ) AF_DECLARE_WRITING_SYSTEM_CLASS( af_indic_writing_system_class ) #undef WRITING_SYSTEM #define WRITING_SYSTEM( ws, WS ) &af_ ## ws ## _writing_system_class, FT_LOCAL_ARRAY_DEF( AF_WritingSystemClass ) af_writing_system_classes[] = { include_afwrtsys_h_1 #ifdef FT_OPTION_AUTOFIT2 include_afwrtsys_h_2 #endif NULL /* do not remove */ }; typedef enum AF_Flags_ { AF_FLAG_NONE = 0, /* point type flags */ AF_FLAG_CONIC = 1 << 0, AF_FLAG_CUBIC = 1 << 1, AF_FLAG_CONTROL = AF_FLAG_CONIC | AF_FLAG_CUBIC, /* point extremum flags */ AF_FLAG_EXTREMA_X = 1 << 2, AF_FLAG_EXTREMA_Y = 1 << 3, /* point roundness flags */ AF_FLAG_ROUND_X = 1 << 4, AF_FLAG_ROUND_Y = 1 << 5, /* point touch flags */ AF_FLAG_TOUCH_X = 1 << 6, AF_FLAG_TOUCH_Y = 1 << 7, /* candidates for weak interpolation have this flag set */ AF_FLAG_WEAK_INTERPOLATION = 1 << 8, /* all inflection points in the outline have this flag set */ AF_FLAG_INFLECTION = 1 << 9, /* the current point is very near to another one */ AF_FLAG_NEAR = 1 << 10 } AF_Flags; /* edge hint flags */ typedef enum AF_Edge_Flags_ { AF_EDGE_NORMAL = 0, AF_EDGE_ROUND = 1 << 0, AF_EDGE_SERIF = 1 << 1, AF_EDGE_DONE = 1 << 2 } AF_Edge_Flags; typedef struct AF_StyleMetricsRec_ { AF_StyleClass style_class; AF_ScalerRec scaler; FT_Bool digits_have_same_width; AF_FaceGlobals globals; /* to access properties */ } AF_StyleMetricsRec; typedef struct AF_ModuleRec_* AF_Module; typedef struct AF_FaceGlobalsRec_ { FT_Face face; FT_Long glyph_count; /* same as face->num_glyphs */ FT_Byte* glyph_styles; #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ hb_font_t* hb_font; #endif /* per-face auto-hinter properties */ FT_UInt increase_x_height; AF_StyleMetrics metrics[AF_STYLE_MAX]; AF_Module module; /* to access global properties */ } AF_FaceGlobalsRec; typedef struct AF_PointRec_ { FT_UShort flags; /* point flags used by hinter */ FT_Char in_dir; /* direction of inwards vector */ FT_Char out_dir; /* direction of outwards vector */ FT_Pos ox, oy; /* original, scaled position */ FT_Short fx, fy; /* original, unscaled position (in font units) */ FT_Pos x, y; /* current position */ FT_Pos u, v; /* current (x,y) or (y,x) depending on context */ AF_PointRec_* next; /* next point in contour */ AF_PointRec_* prev; /* previous point in contour */ } AF_PointRec, *AF_Point; typedef enum AF_Dimension_ { AF_DIMENSION_HORZ = 0, /* x coordinates, */ /* i.e., vertical segments & edges */ AF_DIMENSION_VERT = 1, /* y coordinates, */ /* i.e., horizontal segments & edges */ AF_DIMENSION_MAX /* do not remove */ } AF_Dimension; typedef struct AF_EdgeRec_* AF_Edge; typedef struct AF_SegmentRec_* AF_Segment; typedef struct AF_WidthRec_ { FT_Pos org; /* original position/width in font units */ FT_Pos cur; /* current/scaled position/width in device sub-pixels */ FT_Pos fit; /* current/fitted position/width in device sub-pixels */ } AF_WidthRec, *AF_Width; typedef struct AF_EdgeRec_ { FT_Short fpos; /* original, unscaled position (in font units) */ FT_Pos opos; /* original, scaled position */ FT_Pos pos; /* current position */ FT_Byte flags; /* edge flags */ FT_Char dir; /* edge direction */ FT_Fixed scale; /* used to speed up interpolation between edges */ AF_Width blue_edge; /* non-NULL if this is a blue edge */ AF_Edge link; /* link edge */ AF_Edge serif; /* primary edge for serifs */ FT_Short num_linked; /* number of linked edges */ FT_Int score; /* used during stem matching */ AF_Segment first; /* first segment in edge */ AF_Segment last; /* last segment in edge */ } AF_EdgeRec; typedef struct AF_SegmentRec_ { FT_Byte flags; /* edge/segment flags for this segment */ FT_Char dir; /* segment direction */ FT_Short pos; /* position of segment */ FT_Short min_coord; /* minimum coordinate of segment */ FT_Short max_coord; /* maximum coordinate of segment */ FT_Short height; /* the hinted segment height */ AF_Edge edge; /* the segment's parent edge */ AF_Segment edge_next; /* link to next segment in parent edge */ AF_Segment link; /* (stem) link segment */ AF_Segment serif; /* primary segment for serifs */ FT_Pos num_linked; /* number of linked segments */ FT_Pos score; /* used during stem matching */ FT_Pos len; /* used during stem matching */ AF_Point first; /* first point in edge segment */ AF_Point last; /* last point in edge segment */ } AF_SegmentRec; typedef enum AF_Direction_ { AF_DIR_NONE = 4, AF_DIR_RIGHT = 1, AF_DIR_LEFT = -1, AF_DIR_UP = 2, AF_DIR_DOWN = -2 } AF_Direction; typedef struct AF_AxisHintsRec_ { FT_Int num_segments; /* number of used segments */ FT_Int max_segments; /* number of allocated segments */ AF_Segment segments; /* segments array */ #ifdef AF_SORT_SEGMENTS FT_Int mid_segments; #endif FT_Int num_edges; /* number of used edges */ FT_Int max_edges; /* number of allocated edges */ AF_Edge edges; /* edges array */ AF_Direction major_dir; /* either vertical or horizontal */ } AF_AxisHintsRec, *AF_AxisHints; typedef struct AF_GlyphHintsRec_ { FT_Memory memory; FT_Fixed x_scale; FT_Pos x_delta; FT_Fixed y_scale; FT_Pos y_delta; FT_Int max_points; /* number of allocated points */ FT_Int num_points; /* number of used points */ AF_Point points; /* points array */ FT_Int max_contours; /* number of allocated contours */ FT_Int num_contours; /* number of used contours */ AF_Point* contours; /* contours array */ AF_AxisHintsRec axis[AF_DIMENSION_MAX]; FT_UInt32 scaler_flags; /* copy of scaler flags */ FT_UInt32 other_flags; /* free for style-specific */ /* implementations */ AF_StyleMetrics metrics; FT_Pos xmin_delta; /* used for warping */ FT_Pos xmax_delta; } AF_GlyphHintsRec; static void af_glyph_hints_rescale( AF_GlyphHints hints, AF_StyleMetrics metrics ) { hints->metrics = metrics; hints->scaler_flags = metrics->scaler.flags; } static FT_Error af_dummy_hints_init( AF_GlyphHints hints, AF_StyleMetrics metrics ) { af_glyph_hints_rescale( hints, metrics ); hints->x_scale = metrics->scaler.x_scale; hints->y_scale = metrics->scaler.y_scale; hints->x_delta = metrics->scaler.x_delta; hints->y_delta = metrics->scaler.y_delta; return FT_Err_Ok; } typedef enum FT_Orientation_ { FT_ORIENTATION_TRUETYPE = 0, FT_ORIENTATION_POSTSCRIPT = 1, FT_ORIENTATION_FILL_RIGHT = FT_ORIENTATION_TRUETYPE, FT_ORIENTATION_FILL_LEFT = FT_ORIENTATION_POSTSCRIPT, FT_ORIENTATION_NONE } FT_Orientation; FT_EXPORT_DEF( FT_Orientation ) FT_Outline_Get_Orientation( FT_Outline* outline ) { FT_BBox cbox; FT_Int xshift, yshift; FT_Vector* points; FT_Vector v_prev, v_cur; FT_Int c, n, first; FT_Pos area = 0; if ( !outline || outline->n_points <= 0 ) return FT_ORIENTATION_TRUETYPE; /* We use the nonzero winding rule to find the orientation. */ /* Since glyph outlines behave much more `regular' than arbitrary */ /* cubic or quadratic curves, this test deals with the polygon */ /* only which is spanned up by the control points. */ FT_Outline_Get_CBox( outline, &cbox ); xshift = FT_MSB( FT_ABS( cbox.xMax ) | FT_ABS( cbox.xMin ) ) - 14; xshift = FT_MAX( xshift, 0 ); yshift = FT_MSB( cbox.yMax - cbox.yMin ) - 14; yshift = FT_MAX( yshift, 0 ); points = outline->points; first = 0; for ( c = 0; c < outline->n_contours; c++ ) { FT_Int last = outline->contours[c]; v_prev = points[last]; for ( n = first; n <= last; n++ ) { v_cur = points[n]; area += ( ( v_cur.y - v_prev.y ) >> yshift ) * ( ( v_cur.x + v_prev.x ) >> xshift ); v_prev = v_cur; } first = last + 1; } if ( area > 0 ) return FT_ORIENTATION_POSTSCRIPT; else if ( area < 0 ) return FT_ORIENTATION_TRUETYPE; else return FT_ORIENTATION_NONE; } typedef int (*FT_Outline_MoveToFunc)( const FT_Vector* to, void* user ); #define FT_Outline_MoveTo_Func FT_Outline_MoveToFunc typedef int (*FT_Outline_LineToFunc)( const FT_Vector* to, void* user ); #define FT_Outline_LineTo_Func FT_Outline_LineToFunc typedef int (*FT_Outline_ConicToFunc)( const FT_Vector* control, const FT_Vector* to, void* user ); #define FT_Outline_ConicTo_Func FT_Outline_ConicToFunc typedef int (*FT_Outline_CubicToFunc)( const FT_Vector* control1, const FT_Vector* control2, const FT_Vector* to, void* user ); #define FT_Outline_CubicTo_Func FT_Outline_CubicToFunc typedef struct FT_Outline_Funcs_ { FT_Outline_MoveToFunc move_to; FT_Outline_LineToFunc line_to; FT_Outline_ConicToFunc conic_to; FT_Outline_CubicToFunc cubic_to; int shift; FT_Pos delta; } FT_Outline_Funcs; FT_EXPORT_DEF( FT_Error ) FT_Outline_Decompose( FT_Outline* outline, const FT_Outline_Funcs* func_interface, void* user ) { #undef SCALED #define SCALED( x ) ( ( (x) << shift ) - delta ) FT_Vector v_last; FT_Vector v_control; FT_Vector v_start; FT_Vector* point; FT_Vector* limit; char* tags; FT_Error error; FT_Int n; /* index of contour in outline */ FT_UInt first; /* index of first point in contour */ FT_Int tag; /* current point's state */ FT_Int shift; FT_Pos delta; if ( !outline || !func_interface ) return FT_THROW( Invalid_Argument ); shift = func_interface->shift; delta = func_interface->delta; first = 0; for ( n = 0; n < outline->n_contours; n++ ) { FT_Int last; /* index of last point in contour */ FT_TRACE5(( "FT_Outline_Decompose: Outline %d\n", n )); last = outline->contours[n]; if ( last < 0 ) goto Invalid_Outline; limit = outline->points + last; v_start = outline->points[first]; v_start.x = SCALED( v_start.x ); v_start.y = SCALED( v_start.y ); v_last = outline->points[last]; v_last.x = SCALED( v_last.x ); v_last.y = SCALED( v_last.y ); v_control = v_start; point = outline->points + first; tags = outline->tags + first; tag = FT_CURVE_TAG( tags[0] ); /* A contour cannot start with a cubic control point! */ if ( tag == FT_CURVE_TAG_CUBIC ) goto Invalid_Outline; /* check first point to determine origin */ if ( tag == FT_CURVE_TAG_CONIC ) { /* first point is conic control. Yes, this happens. */ if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON ) { /* start at last point if it is on the curve */ v_start = v_last; limit--; } else { /* if both first and last points are conic, */ /* start at their middle and record its position */ /* for closure */ v_start.x = ( v_start.x + v_last.x ) / 2; v_start.y = ( v_start.y + v_last.y ) / 2; /* v_last = v_start; */ } point--; tags--; } FT_TRACE5(( " move to (%.2f, %.2f)\n", v_start.x / 64.0, v_start.y / 64.0 )); error = func_interface->move_to( &v_start, user ); if ( error ) goto Exit; while ( point < limit ) { point++; tags++; tag = FT_CURVE_TAG( tags[0] ); switch ( tag ) { case FT_CURVE_TAG_ON: /* emit a single line_to */ { FT_Vector vec; vec.x = SCALED( point->x ); vec.y = SCALED( point->y ); FT_TRACE5(( " line to (%.2f, %.2f)\n", vec.x / 64.0, vec.y / 64.0 )); error = func_interface->line_to( &vec, user ); if ( error ) goto Exit; continue; } case FT_CURVE_TAG_CONIC: /* consume conic arcs */ v_control.x = SCALED( point->x ); v_control.y = SCALED( point->y ); Do_Conic: if ( point < limit ) { FT_Vector vec; FT_Vector v_middle; point++; tags++; tag = FT_CURVE_TAG( tags[0] ); vec.x = SCALED( point->x ); vec.y = SCALED( point->y ); if ( tag == FT_CURVE_TAG_ON ) { FT_TRACE5(( " conic to (%.2f, %.2f)" " with control (%.2f, %.2f)\n", vec.x / 64.0, vec.y / 64.0, v_control.x / 64.0, v_control.y / 64.0 )); error = func_interface->conic_to( &v_control, &vec, user ); if ( error ) goto Exit; continue; } if ( tag != FT_CURVE_TAG_CONIC ) goto Invalid_Outline; v_middle.x = ( v_control.x + vec.x ) / 2; v_middle.y = ( v_control.y + vec.y ) / 2; FT_TRACE5(( " conic to (%.2f, %.2f)" " with control (%.2f, %.2f)\n", v_middle.x / 64.0, v_middle.y / 64.0, v_control.x / 64.0, v_control.y / 64.0 )); error = func_interface->conic_to( &v_control, &v_middle, user ); if ( error ) goto Exit; v_control = vec; goto Do_Conic; } FT_TRACE5(( " conic to (%.2f, %.2f)" " with control (%.2f, %.2f)\n", v_start.x / 64.0, v_start.y / 64.0, v_control.x / 64.0, v_control.y / 64.0 )); error = func_interface->conic_to( &v_control, &v_start, user ); goto Close; default: /* FT_CURVE_TAG_CUBIC */ { FT_Vector vec1, vec2; if ( point + 1 > limit || FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC ) goto Invalid_Outline; point += 2; tags += 2; vec1.x = SCALED( point[-2].x ); vec1.y = SCALED( point[-2].y ); vec2.x = SCALED( point[-1].x ); vec2.y = SCALED( point[-1].y ); if ( point <= limit ) { FT_Vector vec; vec.x = SCALED( point->x ); vec.y = SCALED( point->y ); FT_TRACE5(( " cubic to (%.2f, %.2f)" " with controls (%.2f, %.2f) and (%.2f, %.2f)\n", vec.x / 64.0, vec.y / 64.0, vec1.x / 64.0, vec1.y / 64.0, vec2.x / 64.0, vec2.y / 64.0 )); error = func_interface->cubic_to( &vec1, &vec2, &vec, user ); if ( error ) goto Exit; continue; } FT_TRACE5(( " cubic to (%.2f, %.2f)" " with controls (%.2f, %.2f) and (%.2f, %.2f)\n", v_start.x / 64.0, v_start.y / 64.0, vec1.x / 64.0, vec1.y / 64.0, vec2.x / 64.0, vec2.y / 64.0 )); error = func_interface->cubic_to( &vec1, &vec2, &v_start, user ); goto Close; } } } /* close the contour with a line segment */ FT_TRACE5(( " line to (%.2f, %.2f)\n", v_start.x / 64.0, v_start.y / 64.0 )); error = func_interface->line_to( &v_start, user ); Close: if ( error ) goto Exit; first = last + 1; } FT_TRACE5(( "FT_Outline_Decompose: Done\n", n )); return FT_Err_Ok; Exit: FT_TRACE5(( "FT_Outline_Decompose: Error %d\n", error )); return error; Invalid_Outline: return FT_THROW( Invalid_Outline ); } static AF_Direction af_direction_compute(FT_Pos dx, FT_Pos dy) { FT_Pos ll, ss; /* long and short arm lengths */ AF_Direction dir; /* candidate direction */ if(dy >= dx) { if(dy >= -dx) { dir = AF_DIR_UP; ll = dy; ss = dx; } else { dir = AF_DIR_LEFT; ll = -dx; ss = dy; } } else /* dy < dx */ { if(dy >= -dx) { dir = AF_DIR_RIGHT; ll = dx; ss = dy; } else { dir = AF_DIR_DOWN; ll = dy; ss = dx; } } /* return no direction if arm lengths differ too much */ /* (value 14 is heuristic, corresponding to approx. 4.1 degrees) */ ss *= 14; if(FT_ABS(ll) <= FT_ABS(ss)) dir = AF_DIR_NONE; return dir; } FT_BASE_DEF( FT_Int ) ft_corner_is_flat( FT_Pos in_x, FT_Pos in_y, FT_Pos out_x, FT_Pos out_y ) { FT_Pos ax = in_x; FT_Pos ay = in_y; FT_Pos d_in, d_out, d_corner; /* We approximate the Euclidean metric (sqrt(x^2 + y^2)) with */ /* the Taxicab metric (|x| + |y|), which can be computed much */ /* faster. If one of the two vectors is much longer than the */ /* other one, the direction of the shorter vector doesn't */ /* influence the result any more. */ /* */ /* corner */ /* x---------------------------x */ /* \ / */ /* \ / */ /* in \ / out */ /* \ / */ /* o */ /* Point */ /* */ if ( ax < 0 ) ax = -ax; if ( ay < 0 ) ay = -ay; d_in = ax + ay; /* d_in = || in || */ ax = out_x; if ( ax < 0 ) ax = -ax; ay = out_y; if ( ay < 0 ) ay = -ay; d_out = ax + ay; /* d_out = || out || */ ax = out_x + in_x; if ( ax < 0 ) ax = -ax; ay = out_y + in_y; if ( ay < 0 ) ay = -ay; d_corner = ax + ay; /* d_corner = || in + out || */ /* now do a simple length comparison: */ /* */ /* d_in + d_out < 17/16 d_corner */ return ( d_in + d_out - d_corner ) < ( d_corner >> 4 ); } FT_LOCAL_DEF( FT_Error ) af_glyph_hints_reload( AF_GlyphHints hints, FT_Outline* outline ) { FT_Error error = FT_Err_Ok; AF_Point points; FT_UInt old_max, new_max; FT_Fixed x_scale = hints->x_scale; FT_Fixed y_scale = hints->y_scale; FT_Pos x_delta = hints->x_delta; FT_Pos y_delta = hints->y_delta; FT_Memory memory = hints->memory; hints->num_points = 0; hints->num_contours = 0; hints->axis[0].num_segments = 0; hints->axis[0].num_edges = 0; hints->axis[1].num_segments = 0; hints->axis[1].num_edges = 0; /* first of all, reallocate the contours array if necessary */ new_max = (FT_UInt)outline->n_contours; old_max = hints->max_contours; if ( new_max > old_max ) { new_max = ( new_max + 3 ) & ~3; /* round up to a multiple of 4 */ if ( FT_RENEW_ARRAY( hints->contours, old_max, new_max ) ) goto Exit; hints->max_contours = new_max; } /* * then reallocate the points arrays if necessary -- * note that we reserve two additional point positions, used to * hint metrics appropriately */ new_max = (FT_UInt)( outline->n_points + 2 ); old_max = hints->max_points; if ( new_max > old_max ) { new_max = ( new_max + 2 + 7 ) & ~7; /* round up to a multiple of 8 */ if ( FT_RENEW_ARRAY( hints->points, old_max, new_max ) ) goto Exit; hints->max_points = new_max; } hints->num_points = outline->n_points; hints->num_contours = outline->n_contours; /* We can't rely on the value of `FT_Outline.flags' to know the fill */ /* direction used for a glyph, given that some fonts are broken (e.g., */ /* the Arphic ones). We thus recompute it each time we need to. */ /* */ hints->axis[AF_DIMENSION_HORZ].major_dir = AF_DIR_UP; hints->axis[AF_DIMENSION_VERT].major_dir = AF_DIR_LEFT; if ( FT_Outline_Get_Orientation( outline ) == FT_ORIENTATION_POSTSCRIPT ) { hints->axis[AF_DIMENSION_HORZ].major_dir = AF_DIR_DOWN; hints->axis[AF_DIMENSION_VERT].major_dir = AF_DIR_RIGHT; } hints->x_scale = x_scale; hints->y_scale = y_scale; hints->x_delta = x_delta; hints->y_delta = y_delta; hints->xmin_delta = 0; hints->xmax_delta = 0; points = hints->points; if ( hints->num_points == 0 ) goto Exit; { AF_Point point; AF_Point point_limit = points + hints->num_points; /* compute coordinates & Bezier flags, next and prev */ { FT_Vector* vec = outline->points; char* tag = outline->tags; AF_Point end = points + outline->contours[0]; AF_Point prev = end; FT_Int contour_index = 0; for ( point = points; point < point_limit; point++, vec++, tag++ ) { point->fx = (FT_Short)vec->x; point->fy = (FT_Short)vec->y; point->ox = point->x = FT_MulFix( vec->x, x_scale ) + x_delta; point->oy = point->y = FT_MulFix( vec->y, y_scale ) + y_delta; switch ( FT_CURVE_TAG( *tag ) ) { case FT_CURVE_TAG_CONIC: point->flags = AF_FLAG_CONIC; break; case FT_CURVE_TAG_CUBIC: point->flags = AF_FLAG_CUBIC; break; default: point->flags = AF_FLAG_NONE; } point->prev = prev; prev->next = point; prev = point; if ( point == end ) { if ( ++contour_index < outline->n_contours ) { end = points + outline->contours[contour_index]; prev = end; } } } } /* set up the contours array */ { AF_Point* contour = hints->contours; AF_Point* contour_limit = contour + hints->num_contours; short* end = outline->contours; short idx = 0; for ( ; contour < contour_limit; contour++, end++ ) { contour[0] = points + idx; idx = (short)( end[0] + 1 ); } } /* compute directions of in & out vectors */ { AF_Point first = points; AF_Point prev = NULL; FT_Pos in_x = 0; FT_Pos in_y = 0; AF_Direction in_dir = AF_DIR_NONE; FT_Pos last_good_in_x = 0; FT_Pos last_good_in_y = 0; FT_UInt units_per_em = hints->metrics->scaler.face->units_per_EM; FT_Int near_limit = 20 * units_per_em / 2048; for ( point = points; point < point_limit; point++ ) { AF_Point next; FT_Pos out_x, out_y; if ( point == first ) { prev = first->prev; in_x = first->fx - prev->fx; in_y = first->fy - prev->fy; last_good_in_x = in_x; last_good_in_y = in_y; if ( FT_ABS( in_x ) + FT_ABS( in_y ) < near_limit ) { /* search first non-near point to get a good `in_dir' value */ AF_Point point_ = prev; while ( point_ != first ) { AF_Point prev_ = point_->prev; FT_Pos in_x_ = point_->fx - prev_->fx; FT_Pos in_y_ = point_->fy - prev_->fy; if ( FT_ABS( in_x_ ) + FT_ABS( in_y_ ) >= near_limit ) { last_good_in_x = in_x_; last_good_in_y = in_y_; break; } point_ = prev_; } } in_dir = af_direction_compute( in_x, in_y ); first = prev + 1; } point->in_dir = (FT_Char)in_dir; /* check whether the current point is near to the previous one */ /* (value 20 in `near_limit' is heuristic; we use Taxicab */ /* metrics for the test) */ if ( FT_ABS( in_x ) + FT_ABS( in_y ) < near_limit ) point->flags |= AF_FLAG_NEAR; else { last_good_in_x = in_x; last_good_in_y = in_y; } next = point->next; out_x = next->fx - point->fx; out_y = next->fy - point->fy; in_dir = af_direction_compute( out_x, out_y ); point->out_dir = (FT_Char)in_dir; /* Check for weak points. The remaining points not collected */ /* in edges are then implicitly classified as strong points. */ if ( point->flags & AF_FLAG_CONTROL ) { /* control points are always weak */ Is_Weak_Point: point->flags |= AF_FLAG_WEAK_INTERPOLATION; } else if ( point->out_dir == point->in_dir ) { if ( point->out_dir != AF_DIR_NONE ) { /* current point lies on a horizontal or */ /* vertical segment (but doesn't start or end it) */ goto Is_Weak_Point; } /* test whether `in' and `out' direction is approximately */ /* the same (and use the last good `in' vector in case */ /* the current point is near to the previous one) */ if ( ft_corner_is_flat( point->flags & AF_FLAG_NEAR ? last_good_in_x : in_x, point->flags & AF_FLAG_NEAR ? last_good_in_y : in_y, out_x, out_y ) ) { /* current point lies on a straight, diagonal line */ /* (more or less) */ goto Is_Weak_Point; } } else if ( point->in_dir == -point->out_dir ) { /* current point forms a spike */ goto Is_Weak_Point; } in_x = out_x; in_y = out_y; } } } Exit: return error; } static void af_glyph_hints_save( AF_GlyphHints hints, FT_Outline* outline ) { AF_Point point = hints->points; AF_Point limit = point + hints->num_points; FT_Vector* vec = outline->points; char* tag = outline->tags; for ( ; point < limit; point++, vec++, tag++ ) { vec->x = point->x; vec->y = point->y; if ( point->flags & AF_FLAG_CONIC ) tag[0] = FT_CURVE_TAG_CONIC; else if ( point->flags & AF_FLAG_CUBIC ) tag[0] = FT_CURVE_TAG_CUBIC; else tag[0] = FT_CURVE_TAG_ON; } } static FT_Error af_dummy_hints_apply( AF_GlyphHints hints, FT_Outline* outline ) { FT_Error error; error = af_glyph_hints_reload( hints, outline ); if ( !error ) af_glyph_hints_save( hints, outline ); return error; } #ifndef FT_CONFIG_OPTION_PIC #define AF_SERVICES_GET af_services #define AF_SERVICE_PROPERTIES_GET af_service_properties #define AF_WRITING_SYSTEM_CLASSES_GET af_writing_system_classes #define AF_SCRIPT_CLASSES_GET af_script_classes #define AF_STYLE_CLASSES_GET af_style_classes #define AF_INTERFACE_GET af_autofitter_interface #else /* FT_CONFIG_OPTION_PIC */ /* some include files required for members of AFModulePIC */ #include FT_SERVICE_PROPERTIES_H #include "aftypes.h" typedef struct AFModulePIC_ { FT_ServiceDescRec* af_services; FT_Service_PropertiesRec af_service_properties; AF_WritingSystemClass af_writing_system_classes [AF_WRITING_SYSTEM_MAX + 1]; AF_WritingSystemClassRec af_writing_system_classes_rec [AF_WRITING_SYSTEM_MAX]; AF_ScriptClass af_script_classes [AF_SCRIPT_MAX + 1]; AF_ScriptClassRec af_script_classes_rec [AF_SCRIPT_MAX]; AF_StyleClass af_style_classes [AF_STYLE_MAX + 1]; AF_StyleClassRec af_style_classes_rec [AF_STYLE_MAX]; FT_AutoHinter_InterfaceRec af_autofitter_interface; } AFModulePIC; #define GET_PIC( lib ) \ ( (AFModulePIC*)((lib)->pic_container.autofit) ) #define AF_SERVICES_GET \ ( GET_PIC( library )->af_services ) #define AF_SERVICE_PROPERTIES_GET \ ( GET_PIC( library )->af_service_properties ) #define AF_WRITING_SYSTEM_CLASSES_GET \ ( GET_PIC( FT_FACE_LIBRARY( globals->face ) )->af_writing_system_classes ) #define AF_SCRIPT_CLASSES_GET \ ( GET_PIC( FT_FACE_LIBRARY( globals->face ) )->af_script_classes ) #define AF_STYLE_CLASSES_GET \ ( GET_PIC( FT_FACE_LIBRARY( globals->face ) )->af_style_classes ) #define AF_INTERFACE_GET \ ( GET_PIC( library )->af_autofitter_interface ) /* see afpic.c for the implementation */ void autofit_module_class_pic_free( FT_Library library ); FT_Error autofit_module_class_pic_init( FT_Library library ); #endif /* FT_CONFIG_OPTION_PIC */ static void af_glyph_hints_init( AF_GlyphHints hints, FT_Memory memory ) { FT_ZERO( hints ); hints->memory = memory; } FT_Error af_get_char_index( AF_StyleMetrics metrics, FT_ULong charcode, FT_ULong *codepoint, FT_Long *y_offset ) { FT_Face face; if ( !metrics ) return FT_THROW( Invalid_Argument ); face = metrics->globals->face; *codepoint = FT_Get_Char_Index( face, charcode ); *y_offset = 0; return FT_Err_Ok; } FT_LOCAL_DEF( FT_Error ) af_axis_hints_new_segment( AF_AxisHints axis, FT_Memory memory, AF_Segment *asegment ) { FT_Error error = FT_Err_Ok; AF_Segment segment = NULL; if ( axis->num_segments >= axis->max_segments ) { FT_Int old_max = axis->max_segments; FT_Int new_max = old_max; FT_Int big_max = (FT_Int)( FT_INT_MAX / sizeof ( *segment ) ); if ( old_max >= big_max ) { error = FT_THROW( Out_Of_Memory ); goto Exit; } new_max += ( new_max >> 2 ) + 4; if ( new_max < old_max || new_max > big_max ) new_max = big_max; if ( FT_RENEW_ARRAY( axis->segments, old_max, new_max ) ) goto Exit; axis->max_segments = new_max; } segment = axis->segments + axis->num_segments++; Exit: *asegment = segment; return error; } FT_LOCAL_DEF( FT_Error ) af_latin_hints_compute_segments( AF_GlyphHints hints, AF_Dimension dim ) { AF_AxisHints axis = &hints->axis[dim]; FT_Memory memory = hints->memory; FT_Error error = FT_Err_Ok; AF_Segment segment = NULL; AF_SegmentRec seg0; AF_Point* contour = hints->contours; AF_Point* contour_limit = contour + hints->num_contours; AF_Direction major_dir, segment_dir; FT_ZERO( &seg0 ); seg0.score = 32000; seg0.flags = AF_EDGE_NORMAL; major_dir = (AF_Direction)FT_ABS( axis->major_dir ); segment_dir = major_dir; axis->num_segments = 0; /* set up (u,v) in each point */ if ( dim == AF_DIMENSION_HORZ ) { AF_Point point = hints->points; AF_Point limit = point + hints->num_points; for ( ; point < limit; point++ ) { point->u = point->fx; point->v = point->fy; } } else { AF_Point point = hints->points; AF_Point limit = point + hints->num_points; for ( ; point < limit; point++ ) { point->u = point->fy; point->v = point->fx; } } /* do each contour separately */ for ( ; contour < contour_limit; contour++ ) { AF_Point point = contour[0]; AF_Point last = point->prev; int on_edge = 0; FT_Pos min_pos = 32000; /* minimum segment pos != min_coord */ FT_Pos max_pos = -32000; /* maximum segment pos != max_coord */ FT_Bool passed; if ( point == last ) /* skip singletons -- just in case */ continue; if ( FT_ABS( last->out_dir ) == major_dir && FT_ABS( point->out_dir ) == major_dir ) { /* we are already on an edge, try to locate its start */ last = point; for (;;) { point = point->prev; if ( FT_ABS( point->out_dir ) != major_dir ) { point = point->next; break; } if ( point == last ) break; } } last = point; passed = 0; for (;;) { FT_Pos u, v; if ( on_edge ) { u = point->u; if ( u < min_pos ) min_pos = u; if ( u > max_pos ) max_pos = u; if ( point->out_dir != segment_dir || point == last ) { /* we are just leaving an edge; record a new segment! */ segment->last = point; segment->pos = (FT_Short)( ( min_pos + max_pos ) >> 1 ); /* a segment is round if either its first or last point */ /* is a control point */ if ( ( segment->first->flags | point->flags ) & AF_FLAG_CONTROL ) segment->flags |= AF_EDGE_ROUND; /* compute segment size */ min_pos = max_pos = point->v; v = segment->first->v; if ( v < min_pos ) min_pos = v; if ( v > max_pos ) max_pos = v; segment->min_coord = (FT_Short)min_pos; segment->max_coord = (FT_Short)max_pos; segment->height = (FT_Short)( segment->max_coord - segment->min_coord ); on_edge = 0; segment = NULL; /* fall through */ } } /* now exit if we are at the start/end point */ if ( point == last ) { if ( passed ) break; passed = 1; } if ( !on_edge && FT_ABS( point->out_dir ) == major_dir ) { /* this is the start of a new segment! */ segment_dir = (AF_Direction)point->out_dir; /* clear all segment fields */ error = af_axis_hints_new_segment( axis, memory, &segment ); if ( error ) goto Exit; segment[0] = seg0; segment->dir = (FT_Char)segment_dir; min_pos = max_pos = point->u; segment->first = point; segment->last = point; on_edge = 1; } point = point->next; } } /* contours */ /* now slightly increase the height of segments if this makes */ /* sense -- this is used to better detect and ignore serifs */ { AF_Segment segments = axis->segments; AF_Segment segments_end = segments + axis->num_segments; for ( segment = segments; segment < segments_end; segment++ ) { AF_Point first = segment->first; AF_Point last = segment->last; FT_Pos first_v = first->v; FT_Pos last_v = last->v; if ( first == last ) continue; if ( first_v < last_v ) { AF_Point p; p = first->prev; if ( p->v < first_v ) segment->height = (FT_Short)( segment->height + ( ( first_v - p->v ) >> 1 ) ); p = last->next; if ( p->v > last_v ) segment->height = (FT_Short)( segment->height + ( ( p->v - last_v ) >> 1 ) ); } else { AF_Point p; p = first->prev; if ( p->v > first_v ) segment->height = (FT_Short)( segment->height + ( ( p->v - first_v ) >> 1 ) ); p = last->next; if ( p->v < last_v ) segment->height = (FT_Short)( segment->height + ( ( last_v - p->v ) >> 1 ) ); } } } Exit: return error; } #define AF_LATIN_MAX_WIDTHS 16 typedef struct AF_LatinBlueRec_ { AF_WidthRec ref; AF_WidthRec shoot; FT_UInt flags; } AF_LatinBlueRec, *AF_LatinBlue; typedef struct AF_LatinAxisRec_ { FT_Fixed scale; FT_Pos delta; FT_UInt width_count; /* number of used widths */ AF_WidthRec widths[AF_LATIN_MAX_WIDTHS]; /* widths array */ FT_Pos edge_distance_threshold; /* used for creating edges */ FT_Pos standard_width; /* the default stem thickness */ FT_Bool extra_light; /* is standard width very light? */ /* ignored for horizontal metrics */ FT_UInt blue_count; AF_LatinBlueRec blues[AF_BLUE_STRINGSET_MAX]; FT_Fixed org_scale; FT_Pos org_delta; } AF_LatinAxisRec, *AF_LatinAxis; #define AF_LATIN_CONSTANT( metrics, c ) \ ( ( (c) * (FT_Long)( (AF_LatinMetrics)(metrics) )->units_per_em ) / 2048 ) typedef struct AF_LatinMetricsRec_ { AF_StyleMetricsRec root; FT_UInt units_per_em; AF_LatinAxisRec axis[AF_DIMENSION_MAX]; } AF_LatinMetricsRec, *AF_LatinMetrics; FT_LOCAL_DEF( void ) af_latin_hints_link_segments( AF_GlyphHints hints, AF_Dimension dim ) { AF_AxisHints axis = &hints->axis[dim]; AF_Segment segments = axis->segments; AF_Segment segment_limit = segments + axis->num_segments; FT_Pos len_threshold, len_score; AF_Segment seg1, seg2; len_threshold = AF_LATIN_CONSTANT( hints->metrics, 8 ); if ( len_threshold == 0 ) len_threshold = 1; len_score = AF_LATIN_CONSTANT( hints->metrics, 6000 ); /* now compare each segment to the others */ for ( seg1 = segments; seg1 < segment_limit; seg1++ ) { /* the fake segments are introduced to hint the metrics -- */ /* we must never link them to anything */ if ( seg1->dir != axis->major_dir || seg1->first == seg1->last ) continue; /* search for stems having opposite directions, */ /* with seg1 to the `left' of seg2 */ for ( seg2 = segments; seg2 < segment_limit; seg2++ ) { FT_Pos pos1 = seg1->pos; FT_Pos pos2 = seg2->pos; if ( seg1->dir + seg2->dir == 0 && pos2 > pos1 ) { /* compute distance between the two segments */ FT_Pos dist = pos2 - pos1; FT_Pos min = seg1->min_coord; FT_Pos max = seg1->max_coord; FT_Pos len, score; if ( min < seg2->min_coord ) min = seg2->min_coord; if ( max > seg2->max_coord ) max = seg2->max_coord; /* compute maximum coordinate difference of the two segments */ len = max - min; if ( len >= len_threshold ) { /* small coordinate differences cause a higher score, and */ /* segments with a greater distance cause a higher score also */ score = dist + len_score / len; /* and we search for the smallest score */ /* of the sum of the two values */ if ( score < seg1->score ) { seg1->score = score; seg1->link = seg2; } if ( score < seg2->score ) { seg2->score = score; seg2->link = seg1; } } } } } /* now compute the `serif' segments, cf. explanations in `afhints.h' */ for ( seg1 = segments; seg1 < segment_limit; seg1++ ) { seg2 = seg1->link; if ( seg2 ) { if ( seg2->link != seg1 ) { seg1->link = 0; seg1->serif = seg2->link; } } } } FT_LOCAL_DEF( void ) af_sort_and_quantize_widths( FT_UInt* count, AF_Width table, FT_Pos threshold ) { FT_UInt i, j; FT_UInt cur_idx; FT_Pos cur_val; FT_Pos sum; AF_WidthRec swap; if ( *count == 1 ) return; /* sort */ for ( i = 1; i < *count; i++ ) { for ( j = i; j > 0; j-- ) { if ( table[j].org >= table[j - 1].org ) break; swap = table[j]; table[j] = table[j - 1]; table[j - 1] = swap; } } cur_idx = 0; cur_val = table[cur_idx].org; /* compute and use mean values for clusters not larger than */ /* `threshold'; this is very primitive and might not yield */ /* the best result, but normally, using reference character */ /* `o', `*count' is 2, so the code below is fully sufficient */ for ( i = 1; i < *count; i++ ) { if ( table[i].org - cur_val > threshold || i == *count - 1 ) { sum = 0; /* fix loop for end of array */ if ( table[i].org - cur_val <= threshold && i == *count - 1 ) i++; for ( j = cur_idx; j < i; j++ ) { sum += table[j].org; table[j].org = 0; } table[cur_idx].org = sum / j; if ( i < *count - 1 ) { cur_idx = i + 1; cur_val = table[cur_idx].org; } } } cur_idx = 1; /* compress array to remove zero values */ for ( i = 1; i < *count; i++ ) { if ( table[i].org ) table[cur_idx++] = table[i]; } *count = cur_idx; } FT_LOCAL_DEF( void ) af_glyph_hints_done( AF_GlyphHints hints ) { FT_Memory memory = hints->memory; int dim; if ( !( hints && hints->memory ) ) return; /* * note that we don't need to free the segment and edge * buffers since they are really within the hints->points array */ for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) { AF_AxisHints axis = &hints->axis[dim]; axis->num_segments = 0; axis->max_segments = 0; FT_FREE( axis->segments ); axis->num_edges = 0; axis->max_edges = 0; FT_FREE( axis->edges ); } FT_FREE( hints->contours ); hints->max_contours = 0; hints->num_contours = 0; FT_FREE( hints->points ); hints->num_points = 0; hints->max_points = 0; hints->memory = NULL; } FT_LOCAL_DEF( void ) af_latin_metrics_init_widths( AF_LatinMetrics metrics, FT_Face face ) { /* scan the array of segments in each direction */ AF_GlyphHintsRec hints[1]; FT_TRACE5(( "\n" "latin standard widths computation (style `%s')\n" "=====================================================\n" "\n", af_style_names[metrics->root.style_class->style] )); af_glyph_hints_init( hints, face->memory ); metrics->axis[AF_DIMENSION_HORZ].width_count = 0; metrics->axis[AF_DIMENSION_VERT].width_count = 0; { FT_Error error; FT_ULong glyph_index; FT_Long y_offset; int dim; AF_LatinMetricsRec dummy[1]; AF_Scaler scaler = &dummy->root.scaler; #ifdef FT_CONFIG_OPTION_PIC AF_FaceGlobals globals = metrics->root.globals; #endif AF_StyleClass style_class = metrics->root.style_class; AF_ScriptClass script_class = AF_SCRIPT_CLASSES_GET [style_class->script]; FT_UInt32 standard_char; /* * We check more than a single standard character to catch features * like `c2sc' (small caps from caps) that don't contain lowercase * letters by definition, or other features that mainly operate on * numerals. */ standard_char = script_class->standard_char1; af_get_char_index( &metrics->root, standard_char, &glyph_index, &y_offset ); if ( !glyph_index ) { if ( script_class->standard_char2 ) { standard_char = script_class->standard_char2; af_get_char_index( &metrics->root, standard_char, &glyph_index, &y_offset ); if ( !glyph_index ) { if ( script_class->standard_char3 ) { standard_char = script_class->standard_char3; af_get_char_index( &metrics->root, standard_char, &glyph_index, &y_offset ); if ( !glyph_index ) goto Exit; } else goto Exit; } } else goto Exit; } FT_TRACE5(( "standard character: U+%04lX (glyph index %d)\n", standard_char, glyph_index )); error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE ); if ( error || face->glyph->outline.n_points <= 0 ) goto Exit; FT_ZERO( dummy ); dummy->units_per_em = metrics->units_per_em; scaler->x_scale = 0x10000L; scaler->y_scale = 0x10000L; scaler->x_delta = 0; scaler->y_delta = 0; scaler->face = face; scaler->render_mode = FT_RENDER_MODE_NORMAL; scaler->flags = 0; af_glyph_hints_rescale( hints, (AF_StyleMetrics)dummy ); error = af_glyph_hints_reload( hints, &face->glyph->outline ); if ( error ) goto Exit; for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) { AF_LatinAxis axis = &metrics->axis[dim]; AF_AxisHints axhints = &hints->axis[dim]; AF_Segment seg, limit, link; FT_UInt num_widths = 0; error = af_latin_hints_compute_segments( hints, (AF_Dimension)dim ); if ( error ) goto Exit; af_latin_hints_link_segments( hints, (AF_Dimension)dim ); seg = axhints->segments; limit = seg + axhints->num_segments; for ( ; seg < limit; seg++ ) { link = seg->link; /* we only consider stem segments there! */ if ( link && link->link == seg && link > seg ) { FT_Pos dist; dist = seg->pos - link->pos; if ( dist < 0 ) dist = -dist; if ( num_widths < AF_LATIN_MAX_WIDTHS ) axis->widths[num_widths++].org = dist; } } /* this also replaces multiple almost identical stem widths */ /* with a single one (the value 100 is heuristic) */ af_sort_and_quantize_widths( &num_widths, axis->widths, dummy->units_per_em / 100 ); axis->width_count = num_widths; } Exit: for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) { AF_LatinAxis axis = &metrics->axis[dim]; FT_Pos stdw; stdw = ( axis->width_count > 0 ) ? axis->widths[0].org : AF_LATIN_CONSTANT( metrics, 50 ); /* let's try 20% of the smallest width */ axis->edge_distance_threshold = stdw / 5; axis->standard_width = stdw; axis->extra_light = 0; #ifdef FT_DEBUG_LEVEL_TRACE { FT_UInt i; FT_TRACE5(( "%s widths:\n", dim == AF_DIMENSION_VERT ? "horizontal" : "vertical" )); FT_TRACE5(( " %d (standard)", axis->standard_width )); for ( i = 1; i < axis->width_count; i++ ) FT_TRACE5(( " %d", axis->widths[i].org )); FT_TRACE5(( "\n" )); } #endif } } FT_TRACE5(( "\n" )); af_glyph_hints_done( hints ); } #define AF_LATIN_IS_TOP_BLUE( b ) \ ( (b)->properties & AF_BLUE_PROPERTY_LATIN_TOP ) #define AF_LATIN_IS_X_HEIGHT_BLUE( b ) \ ( (b)->properties & AF_BLUE_PROPERTY_LATIN_X_HEIGHT ) #define AF_LATIN_IS_LONG_BLUE( b ) \ ( (b)->properties & AF_BLUE_PROPERTY_LATIN_LONG ) #define AF_LATIN_MAX_WIDTHS 16 #define AF_BLUE_PROPERTY_LATIN_TOP ( 1 << 0 ) #define AF_BLUE_PROPERTY_LATIN_X_HEIGHT ( 1 << 1 ) #define AF_BLUE_PROPERTY_LATIN_LONG ( 1 << 2 ) #define AF_BLUE_PROPERTY_CJK_HORIZ ( 1 << 0 ) #define AF_BLUE_PROPERTY_CJK_TOP ( 1 << 1 ) #define AF_BLUE_PROPERTY_CJK_FILL ( 1 << 2 ) #define AF_BLUE_PROPERTY_CJK_RIGHT AF_BLUE_PROPERTY_CJK_TOP #define AF_BLUE_STRINGSET_MAX_LEN 9 #define AF_BLUE_STRING_MAX_LEN 25 typedef enum AF_Blue_String_ { AF_BLUE_STRING_LATIN_CAPITAL_TOP = 0, AF_BLUE_STRING_LATIN_CAPITAL_BOTTOM = 9, AF_BLUE_STRING_LATIN_SMALL_F_TOP = 18, AF_BLUE_STRING_LATIN_SMALL = 26, AF_BLUE_STRING_LATIN_SMALL_DESCENDER = 34, AF_BLUE_STRING_GREEK_CAPITAL_TOP = 40, AF_BLUE_STRING_GREEK_CAPITAL_BOTTOM = 55, AF_BLUE_STRING_GREEK_SMALL_BETA_TOP = 68, AF_BLUE_STRING_GREEK_SMALL = 81, AF_BLUE_STRING_GREEK_SMALL_DESCENDER = 98, AF_BLUE_STRING_CYRILLIC_CAPITAL_TOP = 115, AF_BLUE_STRING_CYRILLIC_CAPITAL_BOTTOM = 132, AF_BLUE_STRING_CYRILLIC_SMALL = 149, AF_BLUE_STRING_CYRILLIC_SMALL_DESCENDER = 166, AF_BLUE_STRING_HEBREW_TOP = 173, AF_BLUE_STRING_HEBREW_BOTTOM = 190, AF_BLUE_STRING_HEBREW_DESCENDER = 203, af_blue_1_1 = 213, #ifdef AF_CONFIG_OPTION_CJK AF_BLUE_STRING_CJK_TOP_FILL = af_blue_1_1 + 1, AF_BLUE_STRING_CJK_TOP_UNFILL = af_blue_1_1 + 77, AF_BLUE_STRING_CJK_BOTTOM_FILL = af_blue_1_1 + 153, AF_BLUE_STRING_CJK_BOTTOM_UNFILL = af_blue_1_1 + 229, af_blue_1_1_1 = af_blue_1_1 + 304, #ifdef AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT AF_BLUE_STRING_CJK_LEFT_FILL = af_blue_1_1_1 + 1, AF_BLUE_STRING_CJK_LEFT_UNFILL = af_blue_1_1_1 + 77, AF_BLUE_STRING_CJK_RIGHT_FILL = af_blue_1_1_1 + 153, AF_BLUE_STRING_CJK_RIGHT_UNFILL = af_blue_1_1_1 + 229, af_blue_1_1_2 = af_blue_1_1_1 + 304, #else af_blue_1_1_2 = af_blue_1_1_1 + 0, #endif /* AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT */ af_blue_1_2 = af_blue_1_1_2 + 0, #else af_blue_1_2 = af_blue_1_1 + 0, #endif /* AF_CONFIG_OPTION_CJK */ AF_BLUE_STRING_MAX /* do not remove */ } AF_Blue_String; typedef struct AF_Blue_StringRec_ { AF_Blue_String string; FT_UShort properties; } AF_Blue_StringRec; #define GET_UTF8_CHAR( ch, p ) \ ch = (unsigned char)*p++; \ if ( ch >= 0x80 ) \ { \ FT_UInt len; \ \ \ if ( ch < 0xE0 ) \ { \ len = 1; \ ch &= 0x1F; \ } \ else if ( ch < 0xF0 ) \ { \ len = 2; \ ch &= 0x0F; \ } \ else \ { \ len = 3; \ ch &= 0x07; \ } \ \ for ( ; len > 0; len-- ) \ ch = ( ch << 6 ) | ( *p++ & 0x3F ); \ } enum { AF_LATIN_BLUE_ACTIVE = 1 << 0, /* set if zone height is <= 3/4px */ AF_LATIN_BLUE_TOP = 1 << 1, /* result of AF_LATIN_IS_TOP_BLUE */ AF_LATIN_BLUE_ADJUSTMENT = 1 << 2, /* used for scale adjustment */ /* optimization */ AF_LATIN_BLUE_FLAG_MAX }; FT_LOCAL_ARRAY_DEF( char ) af_blue_strings[] = { /* */ 'T', 'H', 'E', 'Z', 'O', 'C', 'Q', 'S', /* THEZOCQS */ '\0', 'H', 'E', 'Z', 'L', 'O', 'C', 'U', 'S', /* HEZLOCUS */ '\0', 'f', 'i', 'j', 'k', 'd', 'b', 'h', /* fijkdbh */ '\0', 'x', 'z', 'r', 'o', 'e', 's', 'c', /* xzroesc */ '\0', 'p', 'q', 'g', 'j', 'y', /* pqgjy */ '\0', '\xCE', '\x93', '\xCE', '\x92', '\xCE', '\x95', '\xCE', '\x96', '\xCE', '\x98', '\xCE', '\x9F', '\xCE', '\xA9', /* ΓΒΕΖΘΟΩ */ '\0', '\xCE', '\x92', '\xCE', '\x94', '\xCE', '\x96', '\xCE', '\x9E', '\xCE', '\x98', '\xCE', '\x9F', /* ΒΔΖΞΘΟ */ '\0', '\xCE', '\xB2', '\xCE', '\xB8', '\xCE', '\xB4', '\xCE', '\xB6', '\xCE', '\xBB', '\xCE', '\xBE', /* βθδζλξ */ '\0', '\xCE', '\xB1', '\xCE', '\xB5', '\xCE', '\xB9', '\xCE', '\xBF', '\xCF', '\x80', '\xCF', '\x83', '\xCF', '\x84', '\xCF', '\x89', /* αειοπστω */ '\0', '\xCE', '\xB2', '\xCE', '\xB3', '\xCE', '\xB7', '\xCE', '\xBC', '\xCF', '\x81', '\xCF', '\x86', '\xCF', '\x87', '\xCF', '\x88', /* βγημρφχψ */ '\0', '\xD0', '\x91', '\xD0', '\x92', '\xD0', '\x95', '\xD0', '\x9F', '\xD0', '\x97', '\xD0', '\x9E', '\xD0', '\xA1', '\xD0', '\xAD', /* БВЕПЗОСЭ */ '\0', '\xD0', '\x91', '\xD0', '\x92', '\xD0', '\x95', '\xD0', '\xA8', '\xD0', '\x97', '\xD0', '\x9E', '\xD0', '\xA1', '\xD0', '\xAD', /* БВЕШЗОСЭ */ '\0', '\xD1', '\x85', '\xD0', '\xBF', '\xD0', '\xBD', '\xD1', '\x88', '\xD0', '\xB5', '\xD0', '\xB7', '\xD0', '\xBE', '\xD1', '\x81', /* хпншезос */ '\0', '\xD1', '\x80', '\xD1', '\x83', '\xD1', '\x84', /* руф */ '\0', '\xD7', '\x91', '\xD7', '\x93', '\xD7', '\x94', '\xD7', '\x97', '\xD7', '\x9A', '\xD7', '\x9B', '\xD7', '\x9D', '\xD7', '\xA1', /* בדהחךכםס */ '\0', '\xD7', '\x91', '\xD7', '\x98', '\xD7', '\x9B', '\xD7', '\x9D', '\xD7', '\xA1', '\xD7', '\xA6', /* בטכםסצ */ '\0', '\xD7', '\xA7', '\xD7', '\x9A', '\xD7', '\x9F', '\xD7', '\xA3', '\xD7', '\xA5', /* קךןףץ */ #ifdef AF_CONFIG_OPTION_CJK '\0', '\xE4', '\xBB', '\x96', '\xE4', '\xBB', '\xAC', '\xE4', '\xBD', '\xA0', '\xE4', '\xBE', '\x86', '\xE5', '\x80', '\x91', '\xE5', '\x88', '\xB0', '\xE5', '\x92', '\x8C', '\xE5', '\x9C', '\xB0', /* 他们你來們到和地 */ '\xE5', '\xAF', '\xB9', '\xE5', '\xB0', '\x8D', '\xE5', '\xB0', '\xB1', '\xE5', '\xB8', '\xAD', '\xE6', '\x88', '\x91', '\xE6', '\x97', '\xB6', '\xE6', '\x99', '\x82', '\xE6', '\x9C', '\x83', /* 对對就席我时時會 */ '\xE6', '\x9D', '\xA5', '\xE7', '\x82', '\xBA', '\xE8', '\x83', '\xBD', '\xE8', '\x88', '\xB0', '\xE8', '\xAA', '\xAA', '\xE8', '\xAF', '\xB4', '\xE8', '\xBF', '\x99', '\xE9', '\x80', '\x99', /* 来為能舰說说这這 */ '\xE9', '\xBD', '\x8A', /* 齊 */ '\0', '\xE5', '\x86', '\x9B', '\xE5', '\x90', '\x8C', '\xE5', '\xB7', '\xB2', '\xE6', '\x84', '\xBF', '\xE6', '\x97', '\xA2', '\xE6', '\x98', '\x9F', '\xE6', '\x98', '\xAF', '\xE6', '\x99', '\xAF', /* 军同已愿既星是景 */ '\xE6', '\xB0', '\x91', '\xE7', '\x85', '\xA7', '\xE7', '\x8E', '\xB0', '\xE7', '\x8F', '\xBE', '\xE7', '\x90', '\x86', '\xE7', '\x94', '\xA8', '\xE7', '\xBD', '\xAE', '\xE8', '\xA6', '\x81', /* 民照现現理用置要 */ '\xE8', '\xBB', '\x8D', '\xE9', '\x82', '\xA3', '\xE9', '\x85', '\x8D', '\xE9', '\x87', '\x8C', '\xE9', '\x96', '\x8B', '\xE9', '\x9B', '\xB7', '\xE9', '\x9C', '\xB2', '\xE9', '\x9D', '\xA2', /* 軍那配里開雷露面 */ '\xE9', '\xA1', '\xBE', /* 顾 */ '\0', '\xE4', '\xB8', '\xAA', '\xE4', '\xB8', '\xBA', '\xE4', '\xBA', '\xBA', '\xE4', '\xBB', '\x96', '\xE4', '\xBB', '\xA5', '\xE4', '\xBB', '\xAC', '\xE4', '\xBD', '\xA0', '\xE4', '\xBE', '\x86', /* 个为人他以们你來 */ '\xE5', '\x80', '\x8B', '\xE5', '\x80', '\x91', '\xE5', '\x88', '\xB0', '\xE5', '\x92', '\x8C', '\xE5', '\xA4', '\xA7', '\xE5', '\xAF', '\xB9', '\xE5', '\xB0', '\x8D', '\xE5', '\xB0', '\xB1', /* 個們到和大对對就 */ '\xE6', '\x88', '\x91', '\xE6', '\x97', '\xB6', '\xE6', '\x99', '\x82', '\xE6', '\x9C', '\x89', '\xE6', '\x9D', '\xA5', '\xE7', '\x82', '\xBA', '\xE8', '\xA6', '\x81', '\xE8', '\xAA', '\xAA', /* 我时時有来為要說 */ '\xE8', '\xAF', '\xB4', /* 说 */ '\0', '\xE4', '\xB8', '\xBB', '\xE4', '\xBA', '\x9B', '\xE5', '\x9B', '\xA0', '\xE5', '\xAE', '\x83', '\xE6', '\x83', '\xB3', '\xE6', '\x84', '\x8F', '\xE7', '\x90', '\x86', '\xE7', '\x94', '\x9F', /* 主些因它想意理生 */ '\xE7', '\x95', '\xB6', '\xE7', '\x9C', '\x8B', '\xE7', '\x9D', '\x80', '\xE7', '\xBD', '\xAE', '\xE8', '\x80', '\x85', '\xE8', '\x87', '\xAA', '\xE8', '\x91', '\x97', '\xE8', '\xA3', '\xA1', /* 當看着置者自著裡 */ '\xE8', '\xBF', '\x87', '\xE8', '\xBF', '\x98', '\xE8', '\xBF', '\x9B', '\xE9', '\x80', '\xB2', '\xE9', '\x81', '\x8E', '\xE9', '\x81', '\x93', '\xE9', '\x82', '\x84', '\xE9', '\x87', '\x8C', /* 过还进進過道還里 */ '\xE9', '\x9D', '\xA2', /* 面 */ #ifdef AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT '\0', '\xE4', '\xBA', '\x9B', '\xE4', '\xBB', '\xAC', '\xE4', '\xBD', '\xA0', '\xE4', '\xBE', '\x86', '\xE5', '\x80', '\x91', '\xE5', '\x88', '\xB0', '\xE5', '\x92', '\x8C', '\xE5', '\x9C', '\xB0', /* 些们你來們到和地 */ '\xE5', '\xA5', '\xB9', '\xE5', '\xB0', '\x86', '\xE5', '\xB0', '\x87', '\xE5', '\xB0', '\xB1', '\xE5', '\xB9', '\xB4', '\xE5', '\xBE', '\x97', '\xE6', '\x83', '\x85', '\xE6', '\x9C', '\x80', /* 她将將就年得情最 */ '\xE6', '\xA0', '\xB7', '\xE6', '\xA8', '\xA3', '\xE7', '\x90', '\x86', '\xE8', '\x83', '\xBD', '\xE8', '\xAA', '\xAA', '\xE8', '\xAF', '\xB4', '\xE8', '\xBF', '\x99', '\xE9', '\x80', '\x99', /* 样樣理能說说这這 */ '\xE9', '\x80', '\x9A', /* 通 */ '\0', '\xE5', '\x8D', '\xB3', '\xE5', '\x90', '\x97', '\xE5', '\x90', '\xA7', '\xE5', '\x90', '\xAC', '\xE5', '\x91', '\xA2', '\xE5', '\x93', '\x81', '\xE5', '\x93', '\x8D', '\xE5', '\x97', '\x8E', /* 即吗吧听呢品响嗎 */ '\xE5', '\xB8', '\x88', '\xE5', '\xB8', '\xAB', '\xE6', '\x94', '\xB6', '\xE6', '\x96', '\xAD', '\xE6', '\x96', '\xB7', '\xE6', '\x98', '\x8E', '\xE7', '\x9C', '\xBC', '\xE9', '\x96', '\x93', /* 师師收断斷明眼間 */ '\xE9', '\x97', '\xB4', '\xE9', '\x99', '\x85', '\xE9', '\x99', '\x88', '\xE9', '\x99', '\x90', '\xE9', '\x99', '\xA4', '\xE9', '\x99', '\xB3', '\xE9', '\x9A', '\x8F', '\xE9', '\x9A', '\x9B', /* 间际陈限除陳随際 */ '\xE9', '\x9A', '\xA8', /* 隨 */ '\0', '\xE4', '\xBA', '\x8B', '\xE5', '\x89', '\x8D', '\xE5', '\xAD', '\xB8', '\xE5', '\xB0', '\x86', '\xE5', '\xB0', '\x87', '\xE6', '\x83', '\x85', '\xE6', '\x83', '\xB3', '\xE6', '\x88', '\x96', /* 事前學将將情想或 */ '\xE6', '\x94', '\xBF', '\xE6', '\x96', '\xAF', '\xE6', '\x96', '\xB0', '\xE6', '\xA0', '\xB7', '\xE6', '\xA8', '\xA3', '\xE6', '\xB0', '\x91', '\xE6', '\xB2', '\x92', '\xE6', '\xB2', '\xA1', /* 政斯新样樣民沒没 */ '\xE7', '\x84', '\xB6', '\xE7', '\x89', '\xB9', '\xE7', '\x8E', '\xB0', '\xE7', '\x8F', '\xBE', '\xE7', '\x90', '\x83', '\xE7', '\xAC', '\xAC', '\xE7', '\xB6', '\x93', '\xE8', '\xB0', '\x81', /* 然特现現球第經谁 */ '\xE8', '\xB5', '\xB7', /* 起 */ '\0', '\xE4', '\xBE', '\x8B', '\xE5', '\x88', '\xA5', '\xE5', '\x88', '\xAB', '\xE5', '\x88', '\xB6', '\xE5', '\x8A', '\xA8', '\xE5', '\x8B', '\x95', '\xE5', '\x90', '\x97', '\xE5', '\x97', '\x8E', /* 例別别制动動吗嗎 */ '\xE5', '\xA2', '\x9E', '\xE6', '\x8C', '\x87', '\xE6', '\x98', '\x8E', '\xE6', '\x9C', '\x9D', '\xE6', '\x9C', '\x9F', '\xE6', '\x9E', '\x84', '\xE7', '\x89', '\xA9', '\xE7', '\xA1', '\xAE', /* 增指明朝期构物确 */ '\xE7', '\xA7', '\x8D', '\xE8', '\xAA', '\xBF', '\xE8', '\xB0', '\x83', '\xE8', '\xB2', '\xBB', '\xE8', '\xB4', '\xB9', '\xE9', '\x82', '\xA3', '\xE9', '\x83', '\xBD', '\xE9', '\x96', '\x93', /* 种調调費费那都間 */ '\xE9', '\x97', '\xB4', /* 间 */ #endif /* AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT */ #endif /* AF_CONFIG_OPTION_CJK */ '\0', }; FT_LOCAL_ARRAY_DEF( AF_Blue_StringRec ) af_blue_stringsets[] = { /* */ { AF_BLUE_STRING_LATIN_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_LATIN_CAPITAL_BOTTOM, 0 }, { AF_BLUE_STRING_LATIN_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_LATIN_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, { AF_BLUE_STRING_LATIN_SMALL, 0 }, { AF_BLUE_STRING_LATIN_SMALL_DESCENDER, 0 }, { AF_BLUE_STRING_MAX, 0 }, { AF_BLUE_STRING_GREEK_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_GREEK_CAPITAL_BOTTOM, 0 }, { AF_BLUE_STRING_GREEK_SMALL_BETA_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_GREEK_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, { AF_BLUE_STRING_GREEK_SMALL, 0 }, { AF_BLUE_STRING_GREEK_SMALL_DESCENDER, 0 }, { AF_BLUE_STRING_MAX, 0 }, { AF_BLUE_STRING_CYRILLIC_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_CYRILLIC_CAPITAL_BOTTOM, 0 }, { AF_BLUE_STRING_CYRILLIC_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, { AF_BLUE_STRING_CYRILLIC_SMALL, 0 }, { AF_BLUE_STRING_CYRILLIC_SMALL_DESCENDER, 0 }, { AF_BLUE_STRING_MAX, 0 }, { AF_BLUE_STRING_HEBREW_TOP, AF_BLUE_PROPERTY_LATIN_TOP | AF_BLUE_PROPERTY_LATIN_LONG }, { AF_BLUE_STRING_HEBREW_BOTTOM, 0 }, { AF_BLUE_STRING_HEBREW_DESCENDER, 0 }, { AF_BLUE_STRING_MAX, 0 }, #ifdef AF_CONFIG_OPTION_CJK { AF_BLUE_STRING_CJK_TOP_FILL, AF_BLUE_PROPERTY_CJK_TOP | AF_BLUE_PROPERTY_CJK_FILL }, { AF_BLUE_STRING_CJK_TOP_UNFILL, AF_BLUE_PROPERTY_CJK_TOP }, { AF_BLUE_STRING_CJK_BOTTOM_FILL, AF_BLUE_PROPERTY_CJK_FILL }, { AF_BLUE_STRING_CJK_BOTTOM_UNFILL, 0 }, #ifdef AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT { AF_BLUE_STRING_CJK_LEFT_FILL, AF_BLUE_PROPERTY_CJK_HORIZ | AF_BLUE_PROPERTY_CJK_FILL }, { AF_BLUE_STRING_CJK_LEFT_UNFILL, AF_BLUE_PROPERTY_CJK_HORIZ }, { AF_BLUE_STRING_CJK_RIGHT_FILL, AF_BLUE_PROPERTY_CJK_HORIZ | AF_BLUE_PROPERTY_CJK_RIGHT | AF_BLUE_PROPERTY_CJK_FILL }, { AF_BLUE_STRING_CJK_RIGHT_UNFILL, AF_BLUE_PROPERTY_CJK_HORIZ | AF_BLUE_PROPERTY_CJK_RIGHT }, #endif /* AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT */ { AF_BLUE_STRING_MAX, 0 }, #endif /* AF_CONFIG_OPTION_CJK */ }; FT_LOCAL_DEF( void ) af_sort_pos( FT_UInt count, FT_Pos* table ) { FT_UInt i, j; FT_Pos swap; for ( i = 1; i < count; i++ ) { for ( j = i; j > 0; j-- ) { if ( table[j] >= table[j - 1] ) break; swap = table[j]; table[j] = table[j - 1]; table[j - 1] = swap; } } } static void af_latin_metrics_init_blues( AF_LatinMetrics metrics, FT_Face face ) { FT_Pos flats [AF_BLUE_STRING_MAX_LEN]; FT_Pos rounds[AF_BLUE_STRING_MAX_LEN]; FT_Int num_flats; FT_Int num_rounds; AF_LatinBlue blue; FT_Error error; AF_LatinAxis axis = &metrics->axis[AF_DIMENSION_VERT]; FT_Outline outline; AF_StyleClass sc = metrics->root.style_class; AF_Blue_Stringset bss = sc->blue_stringset; const AF_Blue_StringRec* bs = &af_blue_stringsets[bss]; /* we walk over the blue character strings as specified in the */ /* style's entry in the `af_blue_stringset' array */ FT_TRACE5(( "latin blue zones computation\n" "============================\n" "\n" )); for ( ; bs->string != AF_BLUE_STRING_MAX; bs++ ) { const char* p = &af_blue_strings[bs->string]; FT_Pos* blue_ref; FT_Pos* blue_shoot; #ifdef FT_DEBUG_LEVEL_TRACE { FT_Bool have_flag = 0; FT_TRACE5(( "blue zone %d", axis->blue_count )); if ( bs->properties ) { FT_TRACE5(( " (" )); if ( AF_LATIN_IS_TOP_BLUE( bs ) ) { FT_TRACE5(( "top" )); have_flag = 1; } if ( AF_LATIN_IS_X_HEIGHT_BLUE( bs ) ) { if ( have_flag ) FT_TRACE5(( ", " )); FT_TRACE5(( "small top" )); have_flag = 1; } if ( AF_LATIN_IS_LONG_BLUE( bs ) ) { if ( have_flag ) FT_TRACE5(( ", " )); FT_TRACE5(( "long" )); } FT_TRACE5(( ")" )); } FT_TRACE5(( ":\n" )); } #endif /* FT_DEBUG_LEVEL_TRACE */ num_flats = 0; num_rounds = 0; while ( *p ) { FT_ULong ch; FT_ULong glyph_index; FT_Long y_offset; FT_Pos best_y; /* same as points.y */ FT_Int best_point, best_contour_first, best_contour_last; FT_Vector* points; FT_Bool round = 0; GET_UTF8_CHAR( ch, p ); /* load the character in the face -- skip unknown or empty ones */ af_get_char_index( &metrics->root, ch, &glyph_index, &y_offset ); if ( glyph_index == 0 ) { FT_TRACE5(( " U+%04lX unavailable\n", ch )); continue; } error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE ); outline = face->glyph->outline; if ( error || outline.n_points <= 0 ) { FT_TRACE5(( " U+%04lX contains no outlines\n", ch )); continue; } /* now compute min or max point indices and coordinates */ points = outline.points; best_point = -1; best_y = 0; /* make compiler happy */ best_contour_first = 0; /* ditto */ best_contour_last = 0; /* ditto */ { FT_Int nn; FT_Int first = 0; FT_Int last = -1; for ( nn = 0; nn < outline.n_contours; first = last + 1, nn++ ) { FT_Int old_best_point = best_point; FT_Int pp; last = outline.contours[nn]; /* Avoid single-point contours since they are never rasterized. */ /* In some fonts, they correspond to mark attachment points */ /* that are way outside of the glyph's real outline. */ if ( last <= first ) continue; if ( AF_LATIN_IS_TOP_BLUE( bs ) ) { for ( pp = first; pp <= last; pp++ ) if ( best_point < 0 || points[pp].y > best_y ) { best_point = pp; best_y = points[pp].y; } } else { for ( pp = first; pp <= last; pp++ ) if ( best_point < 0 || points[pp].y < best_y ) { best_point = pp; best_y = points[pp].y; } } if ( best_point != old_best_point ) { best_contour_first = first; best_contour_last = last; } } } /* now check whether the point belongs to a straight or round */ /* segment; we first need to find in which contour the extremum */ /* lies, then inspect its previous and next points */ if ( best_point >= 0 ) { FT_Pos best_x = points[best_point].x; FT_Int prev, next; FT_Int best_segment_first, best_segment_last; FT_Int best_on_point_first, best_on_point_last; FT_Pos dist; best_segment_first = best_point; best_segment_last = best_point; if ( FT_CURVE_TAG( outline.tags[best_point] ) == FT_CURVE_TAG_ON ) { best_on_point_first = best_point; best_on_point_last = best_point; } else { best_on_point_first = -1; best_on_point_last = -1; } /* look for the previous and next points on the contour */ /* that are not on the same Y coordinate, then threshold */ /* the `closeness'... */ prev = best_point; next = prev; do { if ( prev > best_contour_first ) prev--; else prev = best_contour_last; dist = FT_ABS( points[prev].y - best_y ); /* accept a small distance or a small angle (both values are */ /* heuristic; value 20 corresponds to approx. 2.9 degrees) */ if ( dist > 5 ) if ( FT_ABS( points[prev].x - best_x ) <= 20 * dist ) break; best_segment_first = prev; if ( FT_CURVE_TAG( outline.tags[prev] ) == FT_CURVE_TAG_ON ) { best_on_point_first = prev; if ( best_on_point_last < 0 ) best_on_point_last = prev; } } while ( prev != best_point ); do { if ( next < best_contour_last ) next++; else next = best_contour_first; dist = FT_ABS( points[next].y - best_y ); if ( dist > 5 ) if ( FT_ABS( points[next].x - best_x ) <= 20 * dist ) break; best_segment_last = next; if ( FT_CURVE_TAG( outline.tags[next] ) == FT_CURVE_TAG_ON ) { best_on_point_last = next; if ( best_on_point_first < 0 ) best_on_point_first = next; } } while ( next != best_point ); if ( AF_LATIN_IS_LONG_BLUE( bs ) ) { /* If this flag is set, we have an additional constraint to */ /* get the blue zone distance: Find a segment of the topmost */ /* (or bottommost) contour that is longer than a heuristic */ /* threshold. This ensures that small bumps in the outline */ /* are ignored (for example, the `vertical serifs' found in */ /* many Hebrew glyph designs). */ /* If this segment is long enough, we are done. Otherwise, */ /* search the segment next to the extremum that is long */ /* enough, has the same direction, and a not too large */ /* vertical distance from the extremum. Note that the */ /* algorithm doesn't check whether the found segment is */ /* actually the one (vertically) nearest to the extremum. */ /* heuristic threshold value */ FT_Pos length_threshold = metrics->units_per_em / 25; dist = FT_ABS( points[best_segment_last].x - points[best_segment_first].x ); if ( dist < length_threshold && best_segment_last - best_segment_first + 2 <= best_contour_last - best_contour_first ) { /* heuristic threshold value */ FT_Pos height_threshold = metrics->units_per_em / 4; FT_Int first; FT_Int last; FT_Bool hit; FT_Bool left2right; /* compute direction */ prev = best_point; do { if ( prev > best_contour_first ) prev--; else prev = best_contour_last; if ( points[prev].x != best_x ) break; } while ( prev != best_point ); /* skip glyph for the degenerate case */ if ( prev == best_point ) continue; left2right = FT_BOOL( points[prev].x < points[best_point].x ); first = best_segment_last; last = first; hit = 0; do { FT_Bool l2r; FT_Pos d; FT_Int p_first, p_last; if ( !hit ) { /* no hit; adjust first point */ first = last; /* also adjust first and last on point */ if ( FT_CURVE_TAG( outline.tags[first] ) == FT_CURVE_TAG_ON ) { p_first = first; p_last = first; } else { p_first = -1; p_last = -1; } hit = 1; } if ( last < best_contour_last ) last++; else last = best_contour_first; if ( FT_ABS( best_y - points[first].y ) > height_threshold ) { /* vertical distance too large */ hit = 0; continue; } /* same test as above */ dist = FT_ABS( points[last].y - points[first].y ); if ( dist > 5 ) if ( FT_ABS( points[last].x - points[first].x ) <= 20 * dist ) { hit = 0; continue; } if ( FT_CURVE_TAG( outline.tags[last] ) == FT_CURVE_TAG_ON ) { p_last = last; if ( p_first < 0 ) p_first = last; } l2r = FT_BOOL( points[first].x < points[last].x ); d = FT_ABS( points[last].x - points[first].x ); if ( l2r == left2right && d >= length_threshold ) { /* all constraints are met; update segment after finding */ /* its end */ do { if ( last < best_contour_last ) last++; else last = best_contour_first; d = FT_ABS( points[last].y - points[first].y ); if ( d > 5 ) if ( FT_ABS( points[next].x - points[first].x ) <= 20 * dist ) { if ( last > best_contour_first ) last--; else last = best_contour_last; break; } p_last = last; if ( FT_CURVE_TAG( outline.tags[last] ) == FT_CURVE_TAG_ON ) { p_last = last; if ( p_first < 0 ) p_first = last; } } while ( last != best_segment_first ); best_y = points[first].y; best_segment_first = first; best_segment_last = last; best_on_point_first = p_first; best_on_point_last = p_last; break; } } while ( last != best_segment_first ); } } /* for computing blue zones, we add the y offset as returned */ /* by the currently used OpenType feature -- for example, */ /* superscript glyphs might be identical to subscript glyphs */ /* with a vertical shift */ best_y += y_offset; FT_TRACE5(( " U+%04lX: best_y = %5ld", ch, best_y )); /* now set the `round' flag depending on the segment's kind: */ /* */ /* - if the horizontal distance between the first and last */ /* `on' point is larger than upem/8 (value 8 is heuristic) */ /* we have a flat segment */ /* - if either the first or the last point of the segment is */ /* an `off' point, the segment is round, otherwise it is */ /* flat */ if ( best_on_point_first >= 0 && best_on_point_last >= 0 && (FT_UInt)( FT_ABS( points[best_on_point_last].x - points[best_on_point_first].x ) ) > metrics->units_per_em / 8 ) round = 0; else round = FT_BOOL( FT_CURVE_TAG( outline.tags[best_segment_first] ) != FT_CURVE_TAG_ON || FT_CURVE_TAG( outline.tags[best_segment_last] ) != FT_CURVE_TAG_ON ); FT_TRACE5(( " (%s)\n", round ? "round" : "flat" )); } if ( round ) rounds[num_rounds++] = best_y; else flats[num_flats++] = best_y; } if ( num_flats == 0 && num_rounds == 0 ) { /* * we couldn't find a single glyph to compute this blue zone, * we will simply ignore it then */ FT_TRACE5(( " empty\n" )); continue; } /* we have computed the contents of the `rounds' and `flats' tables, */ /* now determine the reference and overshoot position of the blue -- */ /* we simply take the median value after a simple sort */ af_sort_pos( num_rounds, rounds ); af_sort_pos( num_flats, flats ); blue = &axis->blues[axis->blue_count]; blue_ref = &blue->ref.org; blue_shoot = &blue->shoot.org; axis->blue_count++; if ( num_flats == 0 ) { *blue_ref = *blue_shoot = rounds[num_rounds / 2]; } else if ( num_rounds == 0 ) { *blue_ref = *blue_shoot = flats[num_flats / 2]; } else { *blue_ref = flats [num_flats / 2]; *blue_shoot = rounds[num_rounds / 2]; } /* there are sometimes problems: if the overshoot position of top */ /* zones is under its reference position, or the opposite for bottom */ /* zones. We must thus check everything there and correct the errors */ if ( *blue_shoot != *blue_ref ) { FT_Pos ref = *blue_ref; FT_Pos shoot = *blue_shoot; FT_Bool over_ref = FT_BOOL( shoot > ref ); if ( AF_LATIN_IS_TOP_BLUE( bs ) ^ over_ref ) { *blue_ref = *blue_shoot = ( shoot + ref ) / 2; FT_TRACE5(( " [overshoot smaller than reference," " taking mean value]\n" )); } } blue->flags = 0; if ( AF_LATIN_IS_TOP_BLUE( bs ) ) blue->flags |= AF_LATIN_BLUE_TOP; /* * The following flag is used later to adjust the y and x scales * in order to optimize the pixel grid alignment of the top of small * letters. */ if ( AF_LATIN_IS_X_HEIGHT_BLUE( bs ) ) blue->flags |= AF_LATIN_BLUE_ADJUSTMENT; FT_TRACE5(( " -> reference = %ld\n" " overshoot = %ld\n", *blue_ref, *blue_shoot )); } FT_TRACE5(( "\n" )); return; } #define LOAD_ADVANCE_FAST_CHECK( flags ) \ ( flags & ( FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING ) || \ FT_LOAD_TARGET_MODE( flags ) == FT_RENDER_MODE_LIGHT ) static FT_Error _ft_face_scale_advances( FT_Face face, FT_Fixed* advances, FT_UInt count, FT_Int32 flags ) { FT_Fixed scale; FT_UInt nn; if ( flags & FT_LOAD_NO_SCALE ) return FT_Err_Ok; if ( face->size == NULL ) return FT_THROW( Invalid_Size_Handle ); if ( flags & FT_LOAD_VERTICAL_LAYOUT ) scale = face->size->metrics.y_scale; else scale = face->size->metrics.x_scale; /* this must be the same scaling as to get linear{Hori,Vert}Advance */ /* (see `FT_Load_Glyph' implementation in src/base/ftobjs.c) */ for ( nn = 0; nn < count; nn++ ) advances[nn] = FT_MulDiv( advances[nn], scale, 64 ); return FT_Err_Ok; } FT_EXPORT_DEF( FT_Error ) FT_Get_Advances( FT_Face face, FT_UInt start, FT_UInt count, FT_Int32 flags, FT_Fixed *padvances ) { FT_Face_GetAdvancesFunc func; FT_UInt num, end, nn; FT_Error error = FT_Err_Ok; if ( !face ) return FT_THROW( Invalid_Face_Handle ); num = (FT_UInt)face->num_glyphs; end = start + count; if ( start >= num || end < start || end > num ) return FT_THROW( Invalid_Glyph_Index ); if ( count == 0 ) return FT_Err_Ok; func = face->driver->clazz->get_advances; if ( func && LOAD_ADVANCE_FAST_CHECK( flags ) ) { error = func( face, start, count, flags, padvances ); if ( !error ) return _ft_face_scale_advances( face, padvances, count, flags ); if ( FT_ERR_NEQ( error, Unimplemented_Feature ) ) return error; } error = FT_Err_Ok; if ( flags & FT_ADVANCE_FLAG_FAST_ONLY ) return FT_THROW( Unimplemented_Feature ); flags |= (FT_UInt32)FT_LOAD_ADVANCE_ONLY; for ( nn = 0; nn < count; nn++ ) { error = FT_Load_Glyph( face, start + nn, flags ); if ( error ) break; /* scale from 26.6 to 16.16 */ padvances[nn] = ( flags & FT_LOAD_VERTICAL_LAYOUT ) ? face->glyph->advance.y << 10 : face->glyph->advance.x << 10; } return error; } FT_EXPORT_DEF( FT_Error ) FT_Get_Advance( FT_Face face, FT_UInt gindex, FT_Int32 flags, FT_Fixed *padvance ) { FT_Face_GetAdvancesFunc func; if ( !face ) return FT_THROW( Invalid_Face_Handle ); if ( gindex >= (FT_UInt)face->num_glyphs ) return FT_THROW( Invalid_Glyph_Index ); func = face->driver->clazz->get_advances; if ( func && LOAD_ADVANCE_FAST_CHECK( flags ) ) { FT_Error error; error = func( face, gindex, 1, flags, padvance ); if ( !error ) return _ft_face_scale_advances( face, padvance, 1, flags ); if ( FT_ERR_NEQ( error, Unimplemented_Feature ) ) return error; } return FT_Get_Advances( face, gindex, 1, flags, padvance ); } FT_LOCAL_DEF( void ) af_latin_metrics_check_digits( AF_LatinMetrics metrics, FT_Face face ) { FT_UInt i; FT_Bool started = 0, same_width = 1; FT_Fixed advance, old_advance = 0; /* digit `0' is 0x30 in all supported charmaps */ for ( i = 0x30; i <= 0x39; i++ ) { FT_ULong glyph_index; FT_Long y_offset; af_get_char_index( &metrics->root, i, &glyph_index, &y_offset ); if ( glyph_index == 0 ) continue; if ( FT_Get_Advance( face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_IGNORE_TRANSFORM, &advance ) ) continue; if ( started ) { if ( advance != old_advance ) { same_width = 0; break; } } else { old_advance = advance; started = 1; } } metrics->root.digits_have_same_width = same_width; } FT_LOCAL_DEF( FT_Error ) af_latin_metrics_init( AF_LatinMetrics metrics, FT_Face face ) { FT_CharMap oldmap = face->charmap; metrics->units_per_em = face->units_per_EM; if ( !FT_Select_Charmap( face, FT_ENCODING_UNICODE ) ) { af_latin_metrics_init_widths( metrics, face ); af_latin_metrics_init_blues( metrics, face ); af_latin_metrics_check_digits( metrics, face ); } FT_Set_Charmap( face, oldmap ); return FT_Err_Ok; } typedef struct AF_LoaderRec_ { /* current face data */ FT_Face face; AF_FaceGlobals globals; /* current glyph data */ FT_GlyphLoader gloader; AF_GlyphHintsRec hints; AF_StyleMetrics metrics; FT_Bool transformed; FT_Matrix trans_matrix; FT_Vector trans_delta; FT_Vector pp1; FT_Vector pp2; /* we don't handle vertical phantom points */ } AF_LoaderRec, *AF_Loader; typedef struct AF_ModuleRec_ { FT_ModuleRec root; FT_UInt fallback_style; FT_UInt default_script; AF_LoaderRec loader[1]; } AF_ModuleRec; /* index of fallback style in `af_style_classes' */ #ifdef AF_CONFIG_OPTION_CJK #define AF_STYLE_FALLBACK AF_STYLE_HANI_DFLT #else #define AF_STYLE_FALLBACK AF_STYLE_NONE_DFLT #endif /* default script for OpenType; ignored if HarfBuzz isn't used */ #define AF_SCRIPT_DEFAULT AF_SCRIPT_LATN /* a bit mask indicating an uncovered glyph */ #define AF_STYLE_UNASSIGNED 0x7F /* if this flag is set, we have an ASCII digit */ #define AF_DIGIT 0x80 /* `increase-x-height' property */ #define AF_PROP_INCREASE_X_HEIGHT_MIN 6 #define AF_PROP_INCREASE_X_HEIGHT_MAX 0 FT_Error af_get_coverage( AF_FaceGlobals globals, AF_StyleClass style_class, FT_Byte* gstyles ) { FT_UNUSED( globals ); FT_UNUSED( style_class ); FT_UNUSED( gstyles ); return FT_Err_Ok; } static FT_Error af_face_globals_compute_style_coverage( AF_FaceGlobals globals ) { FT_Error error; FT_Face face = globals->face; FT_CharMap old_charmap = face->charmap; FT_Byte* gstyles = globals->glyph_styles; FT_UInt ss; FT_UInt i; FT_UInt dflt = -1; /* the value AF_STYLE_UNASSIGNED means `uncovered glyph' */ FT_MEM_SET( globals->glyph_styles, AF_STYLE_UNASSIGNED, globals->glyph_count ); error = FT_Select_Charmap( face, FT_ENCODING_UNICODE ); if ( error ) { /* * Ignore this error; we simply use the fallback style. * XXX: Shouldn't we rather disable hinting? */ error = FT_Err_Ok; goto Exit; } /* scan each style in a Unicode charmap */ for ( ss = 0; AF_STYLE_CLASSES_GET[ss]; ss++ ) { AF_StyleClass style_class = AF_STYLE_CLASSES_GET[ss]; AF_ScriptClass script_class = AF_SCRIPT_CLASSES_GET[style_class->script]; AF_Script_UniRange range; if ( script_class->script_uni_ranges == NULL ) continue; /* * Scan all Unicode points in the range and set the corresponding * glyph style index. */ if ( style_class->coverage == AF_COVERAGE_DEFAULT ) { if ( style_class->script == globals->module->default_script ) dflt = ss; for ( range = script_class->script_uni_ranges; range->first != 0; range++ ) { FT_ULong charcode = range->first; FT_UInt gindex; gindex = FT_Get_Char_Index( face, charcode ); if ( gindex != 0 && gindex < (FT_ULong)globals->glyph_count && gstyles[gindex] == AF_STYLE_UNASSIGNED ) gstyles[gindex] = (FT_Byte)ss; for (;;) { charcode = FT_Get_Next_Char( face, charcode, &gindex ); if ( gindex == 0 || charcode > range->last ) break; if ( gindex < (FT_ULong)globals->glyph_count && gstyles[gindex] == AF_STYLE_UNASSIGNED ) gstyles[gindex] = (FT_Byte)ss; } } } else { /* get glyphs not directly addressable by cmap */ af_get_coverage( globals, style_class, gstyles ); } } /* handle the default OpenType features of the default script ... */ af_get_coverage( globals, AF_STYLE_CLASSES_GET[dflt], gstyles ); /* ... and the remaining default OpenType features */ for ( ss = 0; AF_STYLE_CLASSES_GET[ss]; ss++ ) { AF_StyleClass style_class = AF_STYLE_CLASSES_GET[ss]; if ( ss != dflt && style_class->coverage == AF_COVERAGE_DEFAULT ) af_get_coverage( globals, style_class, gstyles ); } /* mark ASCII digits */ for ( i = 0x30; i <= 0x39; i++ ) { FT_UInt gindex = FT_Get_Char_Index( face, i ); if ( gindex != 0 && gindex < (FT_ULong)globals->glyph_count ) gstyles[gindex] |= AF_DIGIT; } Exit: /* * By default, all uncovered glyphs are set to the fallback style. * XXX: Shouldn't we disable hinting or do something similar? */ if ( globals->module->fallback_style != AF_STYLE_UNASSIGNED ) { FT_Long nn; for ( nn = 0; nn < globals->glyph_count; nn++ ) { if ( ( gstyles[nn] & ~AF_DIGIT ) == AF_STYLE_UNASSIGNED ) { gstyles[nn] &= ~AF_STYLE_UNASSIGNED; gstyles[nn] |= globals->module->fallback_style; } } } #ifdef FT_DEBUG_LEVEL_TRACE FT_TRACE4(( "\n" "style coverage\n" "==============\n" "\n" )); for ( ss = 0; AF_STYLE_CLASSES_GET[ss]; ss++ ) { AF_StyleClass style_class = AF_STYLE_CLASSES_GET[ss]; FT_UInt count = 0; FT_Long idx; FT_TRACE4(( "%s:\n", af_style_names[style_class->style] )); for ( idx = 0; idx < globals->glyph_count; idx++ ) { if ( ( gstyles[idx] & ~AF_DIGIT ) == style_class->style ) { if ( !( count % 10 ) ) FT_TRACE4(( " " )); FT_TRACE4(( " %d", idx )); count++; if ( !( count % 10 ) ) FT_TRACE4(( "\n" )); } } if ( !count ) FT_TRACE4(( " (none)\n" )); if ( count % 10 ) FT_TRACE4(( "\n" )); } #endif /* FT_DEBUG_LEVEL_TRACE */ FT_Set_Charmap( face, old_charmap ); return error; } FT_LOCAL_DEF( void ) af_face_globals_free( AF_FaceGlobals globals ) { if ( globals ) { FT_Memory memory = globals->face->memory; FT_UInt nn; for ( nn = 0; nn < AF_STYLE_MAX; nn++ ) { if ( globals->metrics[nn] ) { AF_StyleClass style_class = AF_STYLE_CLASSES_GET[nn]; AF_WritingSystemClass writing_system_class = AF_WRITING_SYSTEM_CLASSES_GET[style_class->writing_system]; if ( writing_system_class->style_metrics_done ) writing_system_class->style_metrics_done( globals->metrics[nn] ); FT_FREE( globals->metrics[nn] ); } } #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ hb_font_destroy( globals->hb_font ); globals->hb_font = NULL; #endif globals->glyph_count = 0; globals->glyph_styles = NULL; /* no need to free this one! */ globals->face = NULL; FT_FREE( globals ); } } FT_LOCAL_DEF( FT_Error ) af_face_globals_new( FT_Face face, AF_FaceGlobals *aglobals, AF_Module module ) { FT_Error error; FT_Memory memory; AF_FaceGlobals globals = NULL; memory = face->memory; if ( FT_ALLOC( globals, sizeof ( *globals ) + face->num_glyphs * sizeof ( FT_Byte ) ) ) goto Exit; globals->face = face; globals->glyph_count = face->num_glyphs; globals->glyph_styles = (FT_Byte*)( globals + 1 ); globals->module = module; #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ globals->hb_font = hb_ft_font_create( face, NULL ); #endif error = af_face_globals_compute_style_coverage( globals ); if ( error ) { af_face_globals_free( globals ); globals = NULL; } globals->increase_x_height = AF_PROP_INCREASE_X_HEIGHT_MAX; Exit: *aglobals = globals; return error; } FT_LOCAL_DEF( FT_Error ) af_loader_reset( AF_Module module, FT_Face face ) { FT_Error error = FT_Err_Ok; AF_Loader loader = module->loader; loader->face = face; loader->globals = (AF_FaceGlobals)face->autohint.data; FT_GlyphLoader_Rewind( loader->gloader ); if ( loader->globals == NULL ) { error = af_face_globals_new( face, &loader->globals, module ); if ( !error ) { face->autohint.data = (FT_Pointer)loader->globals; face->autohint.finalizer = (FT_Generic_Finalizer)af_face_globals_free; } } return error; } FT_LOCAL_DEF( FT_Error ) af_face_globals_get_metrics( AF_FaceGlobals globals, FT_UInt gindex, FT_UInt options, AF_StyleMetrics *ametrics ) { AF_StyleMetrics metrics = NULL; AF_Style style = (AF_Style)options; AF_WritingSystemClass writing_system_class; AF_StyleClass style_class; FT_Error error = FT_Err_Ok; if ( gindex >= (FT_ULong)globals->glyph_count ) { error = FT_THROW( Invalid_Argument ); goto Exit; } /* if we have a forced style (via `options'), use it, */ /* otherwise look into `glyph_styles' array */ if ( style == AF_STYLE_NONE_DFLT || style + 1 >= AF_STYLE_MAX ) style = (AF_Style)( globals->glyph_styles[gindex] & AF_STYLE_UNASSIGNED ); style_class = AF_STYLE_CLASSES_GET[style]; writing_system_class = AF_WRITING_SYSTEM_CLASSES_GET [style_class->writing_system]; metrics = globals->metrics[style]; if ( metrics == NULL ) { /* create the global metrics object if necessary */ FT_Memory memory = globals->face->memory; if ( FT_ALLOC( metrics, writing_system_class->style_metrics_size ) ) goto Exit; metrics->style_class = style_class; metrics->globals = globals; if ( writing_system_class->style_metrics_init ) { error = writing_system_class->style_metrics_init( metrics, globals->face ); if ( error ) { if ( writing_system_class->style_metrics_done ) writing_system_class->style_metrics_done( metrics ); FT_FREE( metrics ); goto Exit; } } globals->metrics[style] = metrics; } Exit: *ametrics = metrics; return error; } #define AF_HINTS_TEST_SCALER( h, f ) ( (h)->scaler_flags & (f) ) #define AF_HINTS_TEST_OTHER( h, f ) ( (h)->other_flags & (f) ) #define AF_HINTS_DO_HORIZONTAL( h ) \ !AF_HINTS_TEST_SCALER( h, AF_SCALER_FLAG_NO_HORIZONTAL ) #define AF_HINTS_DO_VERTICAL( h ) \ !AF_HINTS_TEST_SCALER( h, AF_SCALER_FLAG_NO_VERTICAL ) #define AF_HINTS_DO_ADVANCE( h ) \ !AF_HINTS_TEST_SCALER( h, AF_SCALER_FLAG_NO_ADVANCE ) #define AF_HINTS_DO_BLUES( h ) 1 #define FT_IS_FIXED_WIDTH( face ) \ ( face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ) typedef enum AF_ScalerFlags_ { AF_SCALER_FLAG_NO_HORIZONTAL = 1, /* disable horizontal hinting */ AF_SCALER_FLAG_NO_VERTICAL = 2, /* disable vertical hinting */ AF_SCALER_FLAG_NO_ADVANCE = 4 /* disable advance hinting */ } AF_ScalerFlags; enum { AF_LATIN_HINTS_HORZ_SNAP = 1 << 0, /* enable stem width snapping */ AF_LATIN_HINTS_VERT_SNAP = 1 << 1, /* enable stem height snapping */ AF_LATIN_HINTS_STEM_ADJUST = 1 << 2, /* enable stem width/height */ /* adjustment */ AF_LATIN_HINTS_MONO = 1 << 3 /* indicate monochrome */ /* rendering */ }; #define FT_STYLE_FLAG_ITALIC ( 1 << 0 ) #define FT_STYLE_FLAG_BOLD ( 1 << 1 ) FT_EXPORT_DEF( FT_Error ) FT_Matrix_Invert( FT_Matrix* matrix ) { FT_Pos delta, xx, yy; if ( !matrix ) return FT_THROW( Invalid_Argument ); /* compute discriminant */ delta = FT_MulFix( matrix->xx, matrix->yy ) - FT_MulFix( matrix->xy, matrix->yx ); if ( !delta ) return FT_THROW( Invalid_Argument ); /* matrix can't be inverted */ matrix->xy = - FT_DivFix( matrix->xy, delta ); matrix->yx = - FT_DivFix( matrix->yx, delta ); xx = matrix->xx; yy = matrix->yy; matrix->xx = FT_DivFix( yy, delta ); matrix->yy = FT_DivFix( xx, delta ); return FT_Err_Ok; } FT_BASE_DEF( FT_Error ) FT_GlyphLoader_CopyPoints( FT_GlyphLoader target, FT_GlyphLoader source ) { FT_Error error; FT_UInt num_points = source->base.outline.n_points; FT_UInt num_contours = source->base.outline.n_contours; error = FT_GlyphLoader_CheckPoints( target, num_points, num_contours ); if ( !error ) { FT_Outline* out = &target->base.outline; FT_Outline* in = &source->base.outline; FT_ARRAY_COPY( out->points, in->points, num_points ); FT_ARRAY_COPY( out->tags, in->tags, num_points ); FT_ARRAY_COPY( out->contours, in->contours, num_contours ); /* do we need to copy the extra points? */ if ( target->use_extra && source->use_extra ) { FT_ARRAY_COPY( target->base.extra_points, source->base.extra_points, num_points ); FT_ARRAY_COPY( target->base.extra_points2, source->base.extra_points2, num_points ); } out->n_points = (short)num_points; out->n_contours = (short)num_contours; FT_GlyphLoader_Adjust_Points( target ); } return error; } FT_LOCAL_DEF( FT_Bool ) af_face_globals_is_digit( AF_FaceGlobals globals, FT_UInt gindex ) { if ( gindex < (FT_ULong)globals->glyph_count ) return (FT_Bool)( globals->glyph_styles[gindex] & AF_DIGIT ); return (FT_Bool)0; } static FT_Error af_loader_load_g( AF_Loader loader, AF_Scaler scaler, FT_UInt glyph_index, FT_Int32 load_flags, FT_UInt depth ) { FT_Error error; FT_Face face = loader->face; FT_GlyphLoader gloader = loader->gloader; AF_StyleMetrics metrics = loader->metrics; AF_GlyphHints hints = &loader->hints; FT_GlyphSlot slot = face->glyph; FT_Slot_Internal internal = slot->internal; FT_Int32 flags; flags = load_flags | FT_LOAD_LINEAR_DESIGN; error = FT_Load_Glyph( face, glyph_index, flags ); if ( error ) goto Exit; loader->transformed = internal->glyph_transformed; if ( loader->transformed ) { FT_Matrix inverse; loader->trans_matrix = internal->glyph_matrix; loader->trans_delta = internal->glyph_delta; inverse = loader->trans_matrix; FT_Matrix_Invert( &inverse ); FT_Vector_Transform( &loader->trans_delta, &inverse ); } switch ( slot->format ) { case FT_GLYPH_FORMAT_OUTLINE: /* translate the loaded glyph when an internal transform is needed */ if ( loader->transformed ) FT_Outline_Translate( &slot->outline, loader->trans_delta.x, loader->trans_delta.y ); /* copy the outline points in the loader's current */ /* extra points which are used to keep original glyph coordinates */ error = FT_GLYPHLOADER_CHECK_POINTS( gloader, slot->outline.n_points + 4, slot->outline.n_contours ); if ( error ) goto Exit; FT_ARRAY_COPY( gloader->current.outline.points, slot->outline.points, slot->outline.n_points ); FT_ARRAY_COPY( gloader->current.outline.contours, slot->outline.contours, slot->outline.n_contours ); FT_ARRAY_COPY( gloader->current.outline.tags, slot->outline.tags, slot->outline.n_points ); gloader->current.outline.n_points = slot->outline.n_points; gloader->current.outline.n_contours = slot->outline.n_contours; /* compute original horizontal phantom points (and ignore */ /* vertical ones) */ loader->pp1.x = hints->x_delta; loader->pp1.y = hints->y_delta; loader->pp2.x = FT_MulFix( slot->metrics.horiAdvance, hints->x_scale ) + hints->x_delta; loader->pp2.y = hints->y_delta; /* be sure to check for spacing glyphs */ if ( slot->outline.n_points == 0 ) goto Hint_Metrics; /* now load the slot image into the auto-outline and run the */ /* automatic hinting process */ { #ifdef FT_CONFIG_OPTION_PIC AF_FaceGlobals globals = loader->globals; #endif AF_StyleClass style_class = metrics->style_class; AF_WritingSystemClass writing_system_class = AF_WRITING_SYSTEM_CLASSES_GET[style_class->writing_system]; if ( writing_system_class->style_hints_apply ) writing_system_class->style_hints_apply( hints, &gloader->current.outline, metrics ); } /* we now need to adjust the metrics according to the change in */ /* width/positioning that occurred during the hinting process */ if ( scaler->render_mode != FT_RENDER_MODE_LIGHT ) { FT_Pos old_rsb, old_lsb, new_lsb; FT_Pos pp1x_uh, pp2x_uh; AF_AxisHints axis = &hints->axis[AF_DIMENSION_HORZ]; AF_Edge edge1 = axis->edges; /* leftmost edge */ AF_Edge edge2 = edge1 + axis->num_edges - 1; /* rightmost edge */ if ( axis->num_edges > 1 && AF_HINTS_DO_ADVANCE( hints ) ) { old_rsb = loader->pp2.x - edge2->opos; old_lsb = edge1->opos; new_lsb = edge1->pos; /* remember unhinted values to later account */ /* for rounding errors */ pp1x_uh = new_lsb - old_lsb; pp2x_uh = edge2->pos + old_rsb; /* prefer too much space over too little space */ /* for very small sizes */ if ( old_lsb < 24 ) pp1x_uh -= 8; if ( old_rsb < 24 ) pp2x_uh += 8; loader->pp1.x = FT_PIX_ROUND( pp1x_uh ); loader->pp2.x = FT_PIX_ROUND( pp2x_uh ); if ( loader->pp1.x >= new_lsb && old_lsb > 0 ) loader->pp1.x -= 64; if ( loader->pp2.x <= edge2->pos && old_rsb > 0 ) loader->pp2.x += 64; slot->lsb_delta = loader->pp1.x - pp1x_uh; slot->rsb_delta = loader->pp2.x - pp2x_uh; } else { FT_Pos pp1x = loader->pp1.x; FT_Pos pp2x = loader->pp2.x; loader->pp1.x = FT_PIX_ROUND( pp1x ); loader->pp2.x = FT_PIX_ROUND( pp2x ); slot->lsb_delta = loader->pp1.x - pp1x; slot->rsb_delta = loader->pp2.x - pp2x; } } else { FT_Pos pp1x = loader->pp1.x; FT_Pos pp2x = loader->pp2.x; loader->pp1.x = FT_PIX_ROUND( pp1x + hints->xmin_delta ); loader->pp2.x = FT_PIX_ROUND( pp2x + hints->xmax_delta ); slot->lsb_delta = loader->pp1.x - pp1x; slot->rsb_delta = loader->pp2.x - pp2x; } /* good, we simply add the glyph to our loader's base */ FT_GlyphLoader_Add( gloader ); break; case FT_GLYPH_FORMAT_COMPOSITE: { FT_UInt nn, num_subglyphs = slot->num_subglyphs; FT_UInt num_base_subgs, start_point; FT_SubGlyph subglyph; start_point = gloader->base.outline.n_points; /* first of all, copy the subglyph descriptors in the glyph loader */ error = FT_GlyphLoader_CheckSubGlyphs( gloader, num_subglyphs ); if ( error ) goto Exit; FT_ARRAY_COPY( gloader->current.subglyphs, slot->subglyphs, num_subglyphs ); gloader->current.num_subglyphs = num_subglyphs; num_base_subgs = gloader->base.num_subglyphs; /* now read each subglyph independently */ for ( nn = 0; nn < num_subglyphs; nn++ ) { FT_Vector pp1, pp2; FT_Pos x, y; FT_UInt num_points, num_new_points, num_base_points; /* gloader.current.subglyphs can change during glyph loading due */ /* to re-allocation -- we must recompute the current subglyph on */ /* each iteration */ subglyph = gloader->base.subglyphs + num_base_subgs + nn; pp1 = loader->pp1; pp2 = loader->pp2; num_base_points = gloader->base.outline.n_points; error = af_loader_load_g( loader, scaler, subglyph->index, load_flags, depth + 1 ); if ( error ) goto Exit; /* recompute subglyph pointer */ subglyph = gloader->base.subglyphs + num_base_subgs + nn; if ( !( subglyph->flags & FT_SUBGLYPH_FLAG_USE_MY_METRICS ) ) { loader->pp1 = pp1; loader->pp2 = pp2; } num_points = gloader->base.outline.n_points; num_new_points = num_points - num_base_points; /* now perform the transformation required for this subglyph */ if ( subglyph->flags & ( FT_SUBGLYPH_FLAG_SCALE | FT_SUBGLYPH_FLAG_XY_SCALE | FT_SUBGLYPH_FLAG_2X2 ) ) { FT_Vector* cur = gloader->base.outline.points + num_base_points; FT_Vector* limit = cur + num_new_points; for ( ; cur < limit; cur++ ) FT_Vector_Transform( cur, &subglyph->transform ); } /* apply offset */ if ( !( subglyph->flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES ) ) { FT_Int k = subglyph->arg1; FT_UInt l = subglyph->arg2; FT_Vector* p1; FT_Vector* p2; if ( start_point + k >= num_base_points || l >= (FT_UInt)num_new_points ) { error = FT_THROW( Invalid_Composite ); goto Exit; } l += num_base_points; /* for now, only use the current point coordinates; */ /* we eventually may consider another approach */ p1 = gloader->base.outline.points + start_point + k; p2 = gloader->base.outline.points + start_point + l; x = p1->x - p2->x; y = p1->y - p2->y; } else { x = FT_MulFix( subglyph->arg1, hints->x_scale ) + hints->x_delta; y = FT_MulFix( subglyph->arg2, hints->y_scale ) + hints->y_delta; x = FT_PIX_ROUND( x ); y = FT_PIX_ROUND( y ); } { FT_Outline dummy = gloader->base.outline; dummy.points += num_base_points; dummy.n_points = (short)num_new_points; FT_Outline_Translate( &dummy, x, y ); } } } break; default: /* we don't support other formats (yet?) */ error = FT_THROW( Unimplemented_Feature ); } Hint_Metrics: if ( depth == 0 ) { FT_BBox bbox; FT_Vector vvector; vvector.x = slot->metrics.vertBearingX - slot->metrics.horiBearingX; vvector.y = slot->metrics.vertBearingY - slot->metrics.horiBearingY; vvector.x = FT_MulFix( vvector.x, metrics->scaler.x_scale ); vvector.y = FT_MulFix( vvector.y, metrics->scaler.y_scale ); /* transform the hinted outline if needed */ if ( loader->transformed ) { FT_Outline_Transform( &gloader->base.outline, &loader->trans_matrix ); FT_Vector_Transform( &vvector, &loader->trans_matrix ); } #if 1 /* we must translate our final outline by -pp1.x and compute */ /* the new metrics */ if ( loader->pp1.x ) FT_Outline_Translate( &gloader->base.outline, -loader->pp1.x, 0 ); #endif FT_Outline_Get_CBox( &gloader->base.outline, &bbox ); bbox.xMin = FT_PIX_FLOOR( bbox.xMin ); bbox.yMin = FT_PIX_FLOOR( bbox.yMin ); bbox.xMax = FT_PIX_CEIL( bbox.xMax ); bbox.yMax = FT_PIX_CEIL( bbox.yMax ); slot->metrics.width = bbox.xMax - bbox.xMin; slot->metrics.height = bbox.yMax - bbox.yMin; slot->metrics.horiBearingX = bbox.xMin; slot->metrics.horiBearingY = bbox.yMax; slot->metrics.vertBearingX = FT_PIX_FLOOR( bbox.xMin + vvector.x ); slot->metrics.vertBearingY = FT_PIX_FLOOR( bbox.yMax + vvector.y ); /* for mono-width fonts (like Andale, Courier, etc.) we need */ /* to keep the original rounded advance width; ditto for */ /* digits if all have the same advance width */ #if 0 if ( !FT_IS_FIXED_WIDTH( slot->face ) ) slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x; else slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance, x_scale ); #else if ( scaler->render_mode != FT_RENDER_MODE_LIGHT && ( FT_IS_FIXED_WIDTH( slot->face ) || ( af_face_globals_is_digit( loader->globals, glyph_index ) && metrics->digits_have_same_width ) ) ) { slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance, metrics->scaler.x_scale ); /* Set delta values to 0. Otherwise code that uses them is */ /* going to ruin the fixed advance width. */ slot->lsb_delta = 0; slot->rsb_delta = 0; } else { /* non-spacing glyphs must stay as-is */ if ( slot->metrics.horiAdvance ) slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x; } #endif slot->metrics.vertAdvance = FT_MulFix( slot->metrics.vertAdvance, metrics->scaler.y_scale ); slot->metrics.horiAdvance = FT_PIX_ROUND( slot->metrics.horiAdvance ); slot->metrics.vertAdvance = FT_PIX_ROUND( slot->metrics.vertAdvance ); /* now copy outline into glyph slot */ FT_GlyphLoader_Rewind( internal->loader ); error = FT_GlyphLoader_CopyPoints( internal->loader, gloader ); if ( error ) goto Exit; /* reassign all outline fields except flags to protect them */ slot->outline.n_contours = internal->loader->base.outline.n_contours; slot->outline.n_points = internal->loader->base.outline.n_points; slot->outline.points = internal->loader->base.outline.points; slot->outline.tags = internal->loader->base.outline.tags; slot->outline.contours = internal->loader->base.outline.contours; slot->format = FT_GLYPH_FORMAT_OUTLINE; } Exit: return error; } FT_LOCAL_DEF( FT_Error ) af_loader_load_glyph( AF_Module module, FT_Face face, FT_UInt gindex, FT_Int32 load_flags ) { FT_Error error; FT_Size size = face->size; AF_Loader loader = module->loader; AF_ScalerRec scaler; if ( !size ) return FT_THROW( Invalid_Argument ); FT_ZERO( &scaler ); scaler.face = face; scaler.x_scale = size->metrics.x_scale; scaler.x_delta = 0; /* XXX: TODO: add support for sub-pixel hinting */ scaler.y_scale = size->metrics.y_scale; scaler.y_delta = 0; /* XXX: TODO: add support for sub-pixel hinting */ scaler.render_mode = FT_LOAD_TARGET_MODE( load_flags ); scaler.flags = 0; /* XXX: fix this */ error = af_loader_reset( module, face ); if ( !error ) { AF_StyleMetrics metrics; FT_UInt options = AF_STYLE_NONE_DFLT; #ifdef FT_OPTION_AUTOFIT2 /* XXX: undocumented hook to activate the latin2 writing system */ if ( load_flags & ( 1UL << 20 ) ) options = AF_STYLE_LTN2_DFLT; #endif error = af_face_globals_get_metrics( loader->globals, gindex, options, &metrics ); if ( !error ) { #ifdef FT_CONFIG_OPTION_PIC AF_FaceGlobals globals = loader->globals; #endif AF_StyleClass style_class = metrics->style_class; AF_WritingSystemClass writing_system_class = AF_WRITING_SYSTEM_CLASSES_GET[style_class->writing_system]; loader->metrics = metrics; if ( writing_system_class->style_metrics_scale ) writing_system_class->style_metrics_scale( metrics, &scaler ); else metrics->scaler = scaler; load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_TRANSFORM; load_flags &= ~FT_LOAD_RENDER; if ( writing_system_class->style_hints_init ) { error = writing_system_class->style_hints_init( &loader->hints, metrics ); if ( error ) goto Exit; } error = af_loader_load_g( loader, &scaler, gindex, load_flags, 0 ); } } Exit: return error; } FT_CALLBACK_DEF( FT_Error ) af_autofitter_load_glyph( AF_Module module, FT_GlyphSlot slot, FT_Size size, FT_UInt glyph_index, FT_Int32 load_flags ) { FT_UNUSED( size ); return af_loader_load_glyph( module, slot->face, glyph_index, load_flags ); } FT_LOCAL_DEF( FT_Error ) af_loader_init( AF_Module module ) { AF_Loader loader = module->loader; FT_Memory memory = module->root.library->memory; FT_ZERO( loader ); af_glyph_hints_init( &loader->hints, memory ); #ifdef FT_DEBUG_AUTOFIT _af_debug_hints = &loader->hints; #endif return FT_GlyphLoader_New( memory, &loader->gloader ); } FT_CALLBACK_DEF( FT_Error ) af_autofitter_init( FT_Module ft_module ) /* AF_Module */ { AF_Module module = (AF_Module)ft_module; module->fallback_style = AF_STYLE_FALLBACK; module->default_script = AF_SCRIPT_DEFAULT; return af_loader_init( module ); } FT_LOCAL_DEF( void ) af_loader_done( AF_Module module ) { AF_Loader loader = module->loader; af_glyph_hints_done( &loader->hints ); loader->face = NULL; loader->globals = NULL; #ifdef FT_DEBUG_AUTOFIT _af_debug_hints = NULL; #endif FT_GlyphLoader_Done( loader->gloader ); loader->gloader = NULL; } FT_CALLBACK_DEF( void ) af_autofitter_done( FT_Module ft_module ) /* AF_Module */ { AF_Module module = (AF_Module)ft_module; af_loader_done( module ); } #ifndef FT_CONFIG_OPTION_PIC #define FT_DEFINE_SERVICEDESCREC1( class_, \ serv_id_1, serv_data_1 ) \ static const FT_ServiceDescRec class_[] = \ { \ { serv_id_1, serv_data_1 }, \ { NULL, NULL } \ }; #else /* FT_CONFIG_OPTION_PIC */ #define FT_DEFINE_SERVICEDESCREC1( class_, \ serv_id_1, serv_data_1 ) \ void \ FT_Destroy_Class_ ## class_( FT_Library library, \ FT_ServiceDescRec* clazz ) \ { \ FT_Memory memory = library->memory; \ \ \ if ( clazz ) \ FT_FREE( clazz ); \ } \ \ FT_Error \ FT_Create_Class_ ## class_( FT_Library library, \ FT_ServiceDescRec** output_class ) \ { \ FT_ServiceDescRec* clazz = NULL; \ FT_Error error; \ FT_Memory memory = library->memory; \ \ \ if ( FT_ALLOC( clazz, sizeof ( *clazz ) * 2 ) ) \ return error; \ \ clazz[0].serv_id = serv_id_1; \ clazz[0].serv_data = serv_data_1; \ clazz[1].serv_id = NULL; \ clazz[1].serv_data = NULL; \ \ *output_class = clazz; \ \ return FT_Err_Ok; \ } #endif static FT_Error af_property_get_face_globals( FT_Face face, AF_FaceGlobals* aglobals, AF_Module module ) { FT_Error error = FT_Err_Ok; AF_FaceGlobals globals; if ( !face ) return FT_THROW( Invalid_Argument ); globals = (AF_FaceGlobals)face->autohint.data; if ( !globals ) { /* trigger computation of the global style data */ /* in case it hasn't been done yet */ error = af_face_globals_new( face, &globals, module ); if ( !error ) { face->autohint.data = (FT_Pointer)globals; face->autohint.finalizer = (FT_Generic_Finalizer)af_face_globals_free; } } if ( !error ) *aglobals = globals; return error; } typedef struct FT_Prop_IncreaseXHeight_ { FT_Face face; FT_UInt limit; } FT_Prop_IncreaseXHeight; static FT_Error af_property_set( FT_Module ft_module, const char* property_name, const void* value ) { FT_Error error = FT_Err_Ok; AF_Module module = (AF_Module)ft_module; if ( !ft_strcmp( property_name, "fallback-script" ) ) { FT_UInt* fallback_script = (FT_UInt*)value; FT_UInt ss; /* We translate the fallback script to a fallback style that uses */ /* `fallback-script' as its script and `AF_COVERAGE_NONE' as its */ /* coverage value. */ for ( ss = 0; AF_STYLE_CLASSES_GET[ss]; ss++ ) { AF_StyleClass style_class = AF_STYLE_CLASSES_GET[ss]; if ( style_class->script == *fallback_script && style_class->coverage == AF_COVERAGE_DEFAULT ) { module->fallback_style = ss; break; } } if ( !AF_STYLE_CLASSES_GET[ss] ) { FT_TRACE0(( "af_property_set: Invalid value %d for property `%s'\n", fallback_script, property_name )); return FT_THROW( Invalid_Argument ); } return error; } else if ( !ft_strcmp( property_name, "default-script" ) ) { FT_UInt* default_script = (FT_UInt*)value; module->default_script = *default_script; return error; } else if ( !ft_strcmp( property_name, "increase-x-height" ) ) { FT_Prop_IncreaseXHeight* prop = (FT_Prop_IncreaseXHeight*)value; AF_FaceGlobals globals; error = af_property_get_face_globals( prop->face, &globals, module ); if ( !error ) globals->increase_x_height = prop->limit; return error; } FT_TRACE0(( "af_property_set: missing property `%s'\n", property_name )); return FT_THROW( Missing_Property ); } #ifndef FT_CONFIG_OPTION_PIC #define FT_DEFINE_SERVICE_PROPERTIESREC( class_, \ set_property_, \ get_property_ ) \ static const FT_Service_PropertiesRec class_ = \ { \ set_property_, \ get_property_ \ }; #else /* FT_CONFIG_OPTION_PIC */ #define FT_DEFINE_SERVICE_PROPERTIESREC( class_, \ set_property_, \ get_property_ ) \ void \ FT_Init_Class_ ## class_( FT_Service_PropertiesRec* clazz ) \ { \ clazz->set_property = set_property_; \ clazz->get_property = get_property_; \ } #endif /* FT_CONFIG_OPTION_PIC */ typedef struct FT_Prop_GlyphToScriptMap_ { FT_Face face; FT_Byte* map; } FT_Prop_GlyphToScriptMap; static FT_Error af_property_get( FT_Module ft_module, const char* property_name, void* value ) { FT_Error error = FT_Err_Ok; AF_Module module = (AF_Module)ft_module; FT_UInt fallback_style = module->fallback_style; FT_UInt default_script = module->default_script; if ( !ft_strcmp( property_name, "glyph-to-script-map" ) ) { FT_Prop_GlyphToScriptMap* prop = (FT_Prop_GlyphToScriptMap*)value; AF_FaceGlobals globals; error = af_property_get_face_globals( prop->face, &globals, module ); if ( !error ) prop->map = globals->glyph_styles; return error; } else if ( !ft_strcmp( property_name, "fallback-script" ) ) { FT_UInt* val = (FT_UInt*)value; AF_StyleClass style_class = AF_STYLE_CLASSES_GET[fallback_style]; *val = style_class->script; return error; } else if ( !ft_strcmp( property_name, "default-script" ) ) { FT_UInt* val = (FT_UInt*)value; *val = default_script; return error; } else if ( !ft_strcmp( property_name, "increase-x-height" ) ) { FT_Prop_IncreaseXHeight* prop = (FT_Prop_IncreaseXHeight*)value; AF_FaceGlobals globals; error = af_property_get_face_globals( prop->face, &globals, module ); if ( !error ) prop->limit = globals->increase_x_height; return error; } FT_TRACE0(( "af_property_get: missing property `%s'\n", property_name )); return FT_THROW( Missing_Property ); } FT_DEFINE_SERVICE_PROPERTIESREC( af_service_properties, (FT_Properties_SetFunc)af_property_set, (FT_Properties_GetFunc)af_property_get ) FT_DEFINE_SERVICEDESCREC1( af_services, FT_SERVICE_ID_PROPERTIES, &AF_SERVICE_PROPERTIES_GET ) FT_CALLBACK_DEF( FT_Module_Interface ) af_get_interface( FT_Module module, const char* module_interface ) { /* AF_SERVICES_GET derefers `library' in PIC mode */ #ifdef FT_CONFIG_OPTION_PIC FT_Library library; if ( !module ) return NULL; library = module->library; if ( !library ) return NULL; #else FT_UNUSED( module ); #endif return ft_service_list_lookup( AF_SERVICES_GET, module_interface ); } static void af_latin_metrics_scale_dim( AF_LatinMetrics metrics, AF_Scaler scaler, AF_Dimension dim ) { FT_Fixed scale; FT_Pos delta; AF_LatinAxis axis; FT_UInt nn; if ( dim == AF_DIMENSION_HORZ ) { scale = scaler->x_scale; delta = scaler->x_delta; } else { scale = scaler->y_scale; delta = scaler->y_delta; } axis = &metrics->axis[dim]; if ( axis->org_scale == scale && axis->org_delta == delta ) return; axis->org_scale = scale; axis->org_delta = delta; /* * correct X and Y scale to optimize the alignment of the top of small * letters to the pixel grid */ { AF_LatinAxis Axis = &metrics->axis[AF_DIMENSION_VERT]; AF_LatinBlue blue = NULL; for ( nn = 0; nn < Axis->blue_count; nn++ ) { if ( Axis->blues[nn].flags & AF_LATIN_BLUE_ADJUSTMENT ) { blue = &Axis->blues[nn]; break; } } if ( blue ) { FT_Pos scaled; FT_Pos threshold; FT_Pos fitted; FT_UInt limit; FT_UInt ppem; scaled = FT_MulFix( blue->shoot.org, scaler->y_scale ); ppem = metrics->root.scaler.face->size->metrics.x_ppem; limit = metrics->root.globals->increase_x_height; threshold = 40; /* if the `increase-x-height' property is active, */ /* we round up much more often */ if ( limit && ppem <= limit && ppem >= AF_PROP_INCREASE_X_HEIGHT_MIN ) threshold = 52; fitted = ( scaled + threshold ) & ~63; if ( scaled != fitted ) { #if 0 if ( dim == AF_DIMENSION_HORZ ) { if ( fitted < scaled ) scale -= scale / 50; /* scale *= 0.98 */ } else #endif if ( dim == AF_DIMENSION_VERT ) { scale = FT_MulDiv( scale, fitted, scaled ); FT_TRACE5(( "af_latin_metrics_scale_dim:" " x height alignment (style `%s'):\n" " " " vertical scaling changed from %.4f to %.4f (by %d%%)\n" "\n", af_style_names[metrics->root.style_class->style], axis->org_scale / 65536.0, scale / 65536.0, ( fitted - scaled ) * 100 / scaled )); } } } } axis->scale = scale; axis->delta = delta; if ( dim == AF_DIMENSION_HORZ ) { metrics->root.scaler.x_scale = scale; metrics->root.scaler.x_delta = delta; } else { metrics->root.scaler.y_scale = scale; metrics->root.scaler.y_delta = delta; } FT_TRACE5(( "%s widths (style `%s')\n", dim == AF_DIMENSION_HORZ ? "horizontal" : "vertical", af_style_names[metrics->root.style_class->style] )); /* scale the widths */ for ( nn = 0; nn < axis->width_count; nn++ ) { AF_Width width = axis->widths + nn; width->cur = FT_MulFix( width->org, scale ); width->fit = width->cur; FT_TRACE5(( " %d scaled to %.2f\n", width->org, width->cur / 64.0 )); } FT_TRACE5(( "\n" )); /* an extra-light axis corresponds to a standard width that is */ /* smaller than 5/8 pixels */ axis->extra_light = (FT_Bool)( FT_MulFix( axis->standard_width, scale ) < 32 + 8 ); #ifdef FT_DEBUG_LEVEL_TRACE if ( axis->extra_light ) FT_TRACE5(( "`%s' style is extra light (at current resolution)\n" "\n", af_style_names[metrics->root.style_class->style] )); #endif if ( dim == AF_DIMENSION_VERT ) { FT_TRACE5(( "blue zones (style `%s')\n", af_style_names[metrics->root.style_class->style] )); /* scale the blue zones */ for ( nn = 0; nn < axis->blue_count; nn++ ) { AF_LatinBlue blue = &axis->blues[nn]; FT_Pos dist; blue->ref.cur = FT_MulFix( blue->ref.org, scale ) + delta; blue->ref.fit = blue->ref.cur; blue->shoot.cur = FT_MulFix( blue->shoot.org, scale ) + delta; blue->shoot.fit = blue->shoot.cur; blue->flags &= ~AF_LATIN_BLUE_ACTIVE; /* a blue zone is only active if it is less than 3/4 pixels tall */ dist = FT_MulFix( blue->ref.org - blue->shoot.org, scale ); if ( dist <= 48 && dist >= -48 ) { #if 0 FT_Pos delta1; #endif FT_Pos delta2; /* use discrete values for blue zone widths */ #if 0 /* generic, original code */ delta1 = blue->shoot.org - blue->ref.org; delta2 = delta1; if ( delta1 < 0 ) delta2 = -delta2; delta2 = FT_MulFix( delta2, scale ); if ( delta2 < 32 ) delta2 = 0; else if ( delta2 < 64 ) delta2 = 32 + ( ( ( delta2 - 32 ) + 16 ) & ~31 ); else delta2 = FT_PIX_ROUND( delta2 ); if ( delta1 < 0 ) delta2 = -delta2; blue->ref.fit = FT_PIX_ROUND( blue->ref.cur ); blue->shoot.fit = blue->ref.fit + delta2; #else /* simplified version due to abs(dist) <= 48 */ delta2 = dist; if ( dist < 0 ) delta2 = -delta2; if ( delta2 < 32 ) delta2 = 0; else if ( delta2 < 48 ) delta2 = 32; else delta2 = 64; if ( dist < 0 ) delta2 = -delta2; blue->ref.fit = FT_PIX_ROUND( blue->ref.cur ); blue->shoot.fit = blue->ref.fit - delta2; #endif blue->flags |= AF_LATIN_BLUE_ACTIVE; FT_TRACE5(( " reference %d: %d scaled to %.2f%s\n" " overshoot %d: %d scaled to %.2f%s\n", nn, blue->ref.org, blue->ref.fit / 64.0, blue->flags & AF_LATIN_BLUE_ACTIVE ? "" : " (inactive)", nn, blue->shoot.org, blue->shoot.fit / 64.0, blue->flags & AF_LATIN_BLUE_ACTIVE ? "" : " (inactive)" )); } } } } FT_LOCAL_DEF( void ) af_latin_metrics_scale( AF_LatinMetrics metrics, AF_Scaler scaler ) { metrics->root.scaler.render_mode = scaler->render_mode; metrics->root.scaler.face = scaler->face; metrics->root.scaler.flags = scaler->flags; af_latin_metrics_scale_dim( metrics, scaler, AF_DIMENSION_HORZ ); af_latin_metrics_scale_dim( metrics, scaler, AF_DIMENSION_VERT ); } static FT_Error af_latin_hints_init( AF_GlyphHints hints, AF_LatinMetrics metrics ) { FT_Render_Mode mode; FT_UInt32 scaler_flags, other_flags; FT_Face face = metrics->root.scaler.face; af_glyph_hints_rescale( hints, (AF_StyleMetrics)metrics ); /* * correct x_scale and y_scale if needed, since they may have * been modified by `af_latin_metrics_scale_dim' above */ hints->x_scale = metrics->axis[AF_DIMENSION_HORZ].scale; hints->x_delta = metrics->axis[AF_DIMENSION_HORZ].delta; hints->y_scale = metrics->axis[AF_DIMENSION_VERT].scale; hints->y_delta = metrics->axis[AF_DIMENSION_VERT].delta; /* compute flags depending on render mode, etc. */ mode = metrics->root.scaler.render_mode; #if 0 /* #ifdef AF_CONFIG_OPTION_USE_WARPER */ if ( mode == FT_RENDER_MODE_LCD || mode == FT_RENDER_MODE_LCD_V ) metrics->root.scaler.render_mode = mode = FT_RENDER_MODE_NORMAL; #endif scaler_flags = hints->scaler_flags; other_flags = 0; /* * We snap the width of vertical stems for the monochrome and * horizontal LCD rendering targets only. */ if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD ) other_flags |= AF_LATIN_HINTS_HORZ_SNAP; /* * We snap the width of horizontal stems for the monochrome and * vertical LCD rendering targets only. */ if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD_V ) other_flags |= AF_LATIN_HINTS_VERT_SNAP; /* * We adjust stems to full pixels only if we don't use the `light' mode. */ if ( mode != FT_RENDER_MODE_LIGHT ) other_flags |= AF_LATIN_HINTS_STEM_ADJUST; if ( mode == FT_RENDER_MODE_MONO ) other_flags |= AF_LATIN_HINTS_MONO; /* * In `light' hinting mode we disable horizontal hinting completely. * We also do it if the face is italic. */ if ( mode == FT_RENDER_MODE_LIGHT || ( face->style_flags & FT_STYLE_FLAG_ITALIC ) != 0 ) scaler_flags |= AF_SCALER_FLAG_NO_HORIZONTAL; hints->scaler_flags = scaler_flags; hints->other_flags = other_flags; return FT_Err_Ok; } FT_LOCAL( FT_Error ) af_axis_hints_new_edge( AF_AxisHints axis, FT_Int fpos, AF_Direction dir, FT_Memory memory, AF_Edge *anedge ) { FT_Error error = FT_Err_Ok; AF_Edge edge = NULL; AF_Edge edges; if ( axis->num_edges >= axis->max_edges ) { FT_Int old_max = axis->max_edges; FT_Int new_max = old_max; FT_Int big_max = (FT_Int)( FT_INT_MAX / sizeof ( *edge ) ); if ( old_max >= big_max ) { error = FT_THROW( Out_Of_Memory ); goto Exit; } new_max += ( new_max >> 2 ) + 4; if ( new_max < old_max || new_max > big_max ) new_max = big_max; if ( FT_RENEW_ARRAY( axis->edges, old_max, new_max ) ) goto Exit; axis->max_edges = new_max; } edges = axis->edges; edge = edges + axis->num_edges; while ( edge > edges ) { if ( edge[-1].fpos < fpos ) break; /* we want the edge with same position and minor direction */ /* to appear before those in the major one in the list */ if ( edge[-1].fpos == fpos && dir == axis->major_dir ) break; edge[0] = edge[-1]; edge--; } axis->num_edges++; FT_ZERO( edge ); edge->fpos = (FT_Short)fpos; edge->dir = (FT_Char)dir; Exit: *anedge = edge; return error; } FT_LOCAL_DEF( FT_Error ) af_latin_hints_compute_edges( AF_GlyphHints hints, AF_Dimension dim ) { AF_AxisHints axis = &hints->axis[dim]; FT_Error error = FT_Err_Ok; FT_Memory memory = hints->memory; AF_LatinAxis laxis = &((AF_LatinMetrics)hints->metrics)->axis[dim]; AF_Segment segments = axis->segments; AF_Segment segment_limit = segments + axis->num_segments; AF_Segment seg; #if 0 AF_Direction up_dir; #endif FT_Fixed scale; FT_Pos edge_distance_threshold; FT_Pos segment_length_threshold; axis->num_edges = 0; scale = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale : hints->y_scale; #if 0 up_dir = ( dim == AF_DIMENSION_HORZ ) ? AF_DIR_UP : AF_DIR_RIGHT; #endif /* * We ignore all segments that are less than 1 pixel in length * to avoid many problems with serif fonts. We compute the * corresponding threshold in font units. */ if ( dim == AF_DIMENSION_HORZ ) segment_length_threshold = FT_DivFix( 64, hints->y_scale ); else segment_length_threshold = 0; /*********************************************************************/ /* */ /* We begin by generating a sorted table of edges for the current */ /* direction. To do so, we simply scan each segment and try to find */ /* an edge in our table that corresponds to its position. */ /* */ /* If no edge is found, we create and insert a new edge in the */ /* sorted table. Otherwise, we simply add the segment to the edge's */ /* list which gets processed in the second step to compute the */ /* edge's properties. */ /* */ /* Note that the table of edges is sorted along the segment/edge */ /* position. */ /* */ /*********************************************************************/ /* assure that edge distance threshold is at most 0.25px */ edge_distance_threshold = FT_MulFix( laxis->edge_distance_threshold, scale ); if ( edge_distance_threshold > 64 / 4 ) edge_distance_threshold = 64 / 4; edge_distance_threshold = FT_DivFix( edge_distance_threshold, scale ); for ( seg = segments; seg < segment_limit; seg++ ) { AF_Edge found = NULL; FT_Int ee; if ( seg->height < segment_length_threshold ) continue; /* A special case for serif edges: If they are smaller than */ /* 1.5 pixels we ignore them. */ if ( seg->serif && 2 * seg->height < 3 * segment_length_threshold ) continue; /* look for an edge corresponding to the segment */ for ( ee = 0; ee < axis->num_edges; ee++ ) { AF_Edge edge = axis->edges + ee; FT_Pos dist; dist = seg->pos - edge->fpos; if ( dist < 0 ) dist = -dist; if ( dist < edge_distance_threshold && edge->dir == seg->dir ) { found = edge; break; } } if ( !found ) { AF_Edge edge; /* insert a new edge in the list and */ /* sort according to the position */ error = af_axis_hints_new_edge( axis, seg->pos, (AF_Direction)seg->dir, memory, &edge ); if ( error ) goto Exit; /* add the segment to the new edge's list */ FT_ZERO( edge ); edge->first = seg; edge->last = seg; edge->dir = seg->dir; edge->fpos = seg->pos; edge->opos = FT_MulFix( seg->pos, scale ); edge->pos = edge->opos; seg->edge_next = seg; } else { /* if an edge was found, simply add the segment to the edge's */ /* list */ seg->edge_next = found->first; found->last->edge_next = seg; found->last = seg; } } /******************************************************************/ /* */ /* Good, we now compute each edge's properties according to the */ /* segments found on its position. Basically, these are */ /* */ /* - the edge's main direction */ /* - stem edge, serif edge or both (which defaults to stem then) */ /* - rounded edge, straight or both (which defaults to straight) */ /* - link for edge */ /* */ /******************************************************************/ /* first of all, set the `edge' field in each segment -- this is */ /* required in order to compute edge links */ /* * Note that removing this loop and setting the `edge' field of each * segment directly in the code above slows down execution speed for * some reasons on platforms like the Sun. */ { AF_Edge edges = axis->edges; AF_Edge edge_limit = edges + axis->num_edges; AF_Edge edge; for ( edge = edges; edge < edge_limit; edge++ ) { seg = edge->first; if ( seg ) do { seg->edge = edge; seg = seg->edge_next; } while ( seg != edge->first ); } /* now compute each edge properties */ for ( edge = edges; edge < edge_limit; edge++ ) { FT_Int is_round = 0; /* does it contain round segments? */ FT_Int is_straight = 0; /* does it contain straight segments? */ #if 0 FT_Pos ups = 0; /* number of upwards segments */ FT_Pos downs = 0; /* number of downwards segments */ #endif seg = edge->first; do { FT_Bool is_serif; /* check for roundness of segment */ if ( seg->flags & AF_EDGE_ROUND ) is_round++; else is_straight++; #if 0 /* check for segment direction */ if ( seg->dir == up_dir ) ups += seg->max_coord - seg->min_coord; else downs += seg->max_coord - seg->min_coord; #endif /* check for links -- if seg->serif is set, then seg->link must */ /* be ignored */ is_serif = (FT_Bool)( seg->serif && seg->serif->edge && seg->serif->edge != edge ); if ( ( seg->link && seg->link->edge != NULL ) || is_serif ) { AF_Edge edge2; AF_Segment seg2; edge2 = edge->link; seg2 = seg->link; if ( is_serif ) { seg2 = seg->serif; edge2 = edge->serif; } if ( edge2 ) { FT_Pos edge_delta; FT_Pos seg_delta; edge_delta = edge->fpos - edge2->fpos; if ( edge_delta < 0 ) edge_delta = -edge_delta; seg_delta = seg->pos - seg2->pos; if ( seg_delta < 0 ) seg_delta = -seg_delta; if ( seg_delta < edge_delta ) edge2 = seg2->edge; } else edge2 = seg2->edge; if ( is_serif ) { edge->serif = edge2; edge2->flags |= AF_EDGE_SERIF; } else edge->link = edge2; } seg = seg->edge_next; } while ( seg != edge->first ); /* set the round/straight flags */ edge->flags = AF_EDGE_NORMAL; if ( is_round > 0 && is_round >= is_straight ) edge->flags |= AF_EDGE_ROUND; #if 0 /* set the edge's main direction */ edge->dir = AF_DIR_NONE; if ( ups > downs ) edge->dir = (FT_Char)up_dir; else if ( ups < downs ) edge->dir = (FT_Char)-up_dir; else if ( ups == downs ) edge->dir = 0; /* both up and down! */ #endif /* get rid of serifs if link is set */ /* XXX: This gets rid of many unpleasant artefacts! */ /* Example: the `c' in cour.pfa at size 13 */ if ( edge->serif && edge->link ) edge->serif = 0; } } Exit: return error; } FT_LOCAL_DEF( FT_Error ) af_latin_hints_detect_features( AF_GlyphHints hints, AF_Dimension dim ) { FT_Error error; error = af_latin_hints_compute_segments( hints, dim ); if ( !error ) { af_latin_hints_link_segments( hints, dim ); error = af_latin_hints_compute_edges( hints, dim ); } return error; } static FT_Pos af_latin_snap_width( AF_Width widths, FT_Int count, FT_Pos width ) { int n; FT_Pos best = 64 + 32 + 2; FT_Pos reference = width; FT_Pos scaled; for ( n = 0; n < count; n++ ) { FT_Pos w; FT_Pos dist; w = widths[n].cur; dist = width - w; if ( dist < 0 ) dist = -dist; if ( dist < best ) { best = dist; reference = w; } } scaled = FT_PIX_ROUND( reference ); if ( width >= reference ) { if ( width < scaled + 48 ) width = reference; } else { if ( width > scaled - 48 ) width = reference; } return width; } #define AF_LATIN_HINTS_DO_HORZ_SNAP( h ) \ AF_HINTS_TEST_OTHER( h, AF_LATIN_HINTS_HORZ_SNAP ) #define AF_LATIN_HINTS_DO_VERT_SNAP( h ) \ AF_HINTS_TEST_OTHER( h, AF_LATIN_HINTS_VERT_SNAP ) #define AF_LATIN_HINTS_DO_STEM_ADJUST( h ) \ AF_HINTS_TEST_OTHER( h, AF_LATIN_HINTS_STEM_ADJUST ) #define AF_LATIN_HINTS_DO_MONO( h ) \ AF_HINTS_TEST_OTHER( h, AF_LATIN_HINTS_MONO ) static FT_Pos af_latin_compute_stem_width( AF_GlyphHints hints, AF_Dimension dim, FT_Pos width, AF_Edge_Flags base_flags, AF_Edge_Flags stem_flags ) { AF_LatinMetrics metrics = (AF_LatinMetrics)hints->metrics; AF_LatinAxis axis = &metrics->axis[dim]; FT_Pos dist = width; FT_Int sign = 0; FT_Int vertical = ( dim == AF_DIMENSION_VERT ); if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) || axis->extra_light ) return width; if ( dist < 0 ) { dist = -width; sign = 1; } if ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) || ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) ) { /* smooth hinting process: very lightly quantize the stem width */ /* leave the widths of serifs alone */ if ( ( stem_flags & AF_EDGE_SERIF ) && vertical && ( dist < 3 * 64 ) ) goto Done_Width; else if ( base_flags & AF_EDGE_ROUND ) { if ( dist < 80 ) dist = 64; } else if ( dist < 56 ) dist = 56; if ( axis->width_count > 0 ) { FT_Pos delta; /* compare to standard width */ delta = dist - axis->widths[0].cur; if ( delta < 0 ) delta = -delta; if ( delta < 40 ) { dist = axis->widths[0].cur; if ( dist < 48 ) dist = 48; goto Done_Width; } if ( dist < 3 * 64 ) { delta = dist & 63; dist &= -64; if ( delta < 10 ) dist += delta; else if ( delta < 32 ) dist += 10; else if ( delta < 54 ) dist += 54; else dist += delta; } else dist = ( dist + 32 ) & ~63; } } else { /* strong hinting process: snap the stem width to integer pixels */ FT_Pos org_dist = dist; dist = af_latin_snap_width( axis->widths, axis->width_count, dist ); if ( vertical ) { /* in the case of vertical hinting, always round */ /* the stem heights to integer pixels */ if ( dist >= 64 ) dist = ( dist + 16 ) & ~63; else dist = 64; } else { if ( AF_LATIN_HINTS_DO_MONO( hints ) ) { /* monochrome horizontal hinting: snap widths to integer pixels */ /* with a different threshold */ if ( dist < 64 ) dist = 64; else dist = ( dist + 32 ) & ~63; } else { /* for horizontal anti-aliased hinting, we adopt a more subtle */ /* approach: we strengthen small stems, round stems whose size */ /* is between 1 and 2 pixels to an integer, otherwise nothing */ if ( dist < 48 ) dist = ( dist + 64 ) >> 1; else if ( dist < 128 ) { /* We only round to an integer width if the corresponding */ /* distortion is less than 1/4 pixel. Otherwise this */ /* makes everything worse since the diagonals, which are */ /* not hinted, appear a lot bolder or thinner than the */ /* vertical stems. */ FT_Pos delta; dist = ( dist + 22 ) & ~63; delta = dist - org_dist; if ( delta < 0 ) delta = -delta; if ( delta >= 16 ) { dist = org_dist; if ( dist < 48 ) dist = ( dist + 64 ) >> 1; } } else /* round otherwise to prevent color fringes in LCD mode */ dist = ( dist + 32 ) & ~63; } } } Done_Width: if ( sign ) dist = -dist; return dist; } FT_LOCAL_DEF( void ) af_latin_hints_compute_blue_edges( AF_GlyphHints hints, AF_LatinMetrics metrics ) { AF_AxisHints axis = &hints->axis[AF_DIMENSION_VERT]; AF_Edge edge = axis->edges; AF_Edge edge_limit = edge + axis->num_edges; AF_LatinAxis latin = &metrics->axis[AF_DIMENSION_VERT]; FT_Fixed scale = latin->scale; /* compute which blue zones are active, i.e. have their scaled */ /* size < 3/4 pixels */ /* for each horizontal edge search the blue zone which is closest */ for ( ; edge < edge_limit; edge++ ) { FT_UInt bb; AF_Width best_blue = NULL; FT_Pos best_dist; /* initial threshold */ /* compute the initial threshold as a fraction of the EM size */ /* (the value 40 is heuristic) */ best_dist = FT_MulFix( metrics->units_per_em / 40, scale ); /* assure a minimum distance of 0.5px */ if ( best_dist > 64 / 2 ) best_dist = 64 / 2; for ( bb = 0; bb < latin->blue_count; bb++ ) { AF_LatinBlue blue = latin->blues + bb; FT_Bool is_top_blue, is_major_dir; /* skip inactive blue zones (i.e., those that are too large) */ if ( !( blue->flags & AF_LATIN_BLUE_ACTIVE ) ) continue; /* if it is a top zone, check for right edges -- if it is a bottom */ /* zone, check for left edges */ /* */ /* of course, that's for TrueType */ is_top_blue = (FT_Byte)( ( blue->flags & AF_LATIN_BLUE_TOP ) != 0 ); is_major_dir = FT_BOOL( edge->dir == axis->major_dir ); /* if it is a top zone, the edge must be against the major */ /* direction; if it is a bottom zone, it must be in the major */ /* direction */ if ( is_top_blue ^ is_major_dir ) { FT_Pos dist; /* first of all, compare it to the reference position */ dist = edge->fpos - blue->ref.org; if ( dist < 0 ) dist = -dist; dist = FT_MulFix( dist, scale ); if ( dist < best_dist ) { best_dist = dist; best_blue = &blue->ref; } /* now compare it to the overshoot position and check whether */ /* the edge is rounded, and whether the edge is over the */ /* reference position of a top zone, or under the reference */ /* position of a bottom zone */ if ( edge->flags & AF_EDGE_ROUND && dist != 0 ) { FT_Bool is_under_ref = FT_BOOL( edge->fpos < blue->ref.org ); if ( is_top_blue ^ is_under_ref ) { dist = edge->fpos - blue->shoot.org; if ( dist < 0 ) dist = -dist; dist = FT_MulFix( dist, scale ); if ( dist < best_dist ) { best_dist = dist; best_blue = &blue->shoot; } } } } } if ( best_blue ) edge->blue_edge = best_blue; } } static void af_latin_align_linked_edge( AF_GlyphHints hints, AF_Dimension dim, AF_Edge base_edge, AF_Edge stem_edge ) { FT_Pos dist = stem_edge->opos - base_edge->opos; FT_Pos fitted_width = af_latin_compute_stem_width( hints, dim, dist, (AF_Edge_Flags)base_edge->flags, (AF_Edge_Flags)stem_edge->flags ); stem_edge->pos = base_edge->pos + fitted_width; FT_TRACE5(( " LINK: edge %d (opos=%.2f) linked to %.2f," " dist was %.2f, now %.2f\n", stem_edge-hints->axis[dim].edges, stem_edge->opos / 64.0, stem_edge->pos / 64.0, dist / 64.0, fitted_width / 64.0 )); } static void af_latin_align_serif_edge( AF_GlyphHints hints, AF_Edge base, AF_Edge serif ) { FT_UNUSED( hints ); serif->pos = base->pos + ( serif->opos - base->opos ); } FT_LOCAL_DEF( void ) af_latin_hint_edges( AF_GlyphHints hints, AF_Dimension dim ) { AF_AxisHints axis = &hints->axis[dim]; AF_Edge edges = axis->edges; AF_Edge edge_limit = edges + axis->num_edges; FT_PtrDist n_edges; AF_Edge edge; AF_Edge anchor = NULL; FT_Int has_serifs = 0; #ifdef FT_DEBUG_LEVEL_TRACE FT_UInt num_actions = 0; #endif FT_TRACE5(( "latin %s edge hinting (style `%s')\n", dim == AF_DIMENSION_VERT ? "horizontal" : "vertical", af_style_names[hints->metrics->style_class->style] )); /* we begin by aligning all stems relative to the blue zone */ /* if needed -- that's only for horizontal edges */ if ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_BLUES( hints ) ) { for ( edge = edges; edge < edge_limit; edge++ ) { AF_Width blue; AF_Edge edge1, edge2; /* these edges form the stem to check */ if ( edge->flags & AF_EDGE_DONE ) continue; blue = edge->blue_edge; edge1 = NULL; edge2 = edge->link; if ( blue ) edge1 = edge; /* flip edges if the other stem is aligned to a blue zone */ else if ( edge2 && edge2->blue_edge ) { blue = edge2->blue_edge; edge1 = edge2; edge2 = edge; } if ( !edge1 ) continue; #ifdef FT_DEBUG_LEVEL_TRACE if ( !anchor ) FT_TRACE5(( " BLUE_ANCHOR: edge %d (opos=%.2f) snapped to %.2f," " was %.2f (anchor=edge %d)\n", edge1 - edges, edge1->opos / 64.0, blue->fit / 64.0, edge1->pos / 64.0, edge - edges )); else FT_TRACE5(( " BLUE: edge %d (opos=%.2f) snapped to %.2f," " was %.2f\n", edge1 - edges, edge1->opos / 64.0, blue->fit / 64.0, edge1->pos / 64.0 )); num_actions++; #endif edge1->pos = blue->fit; edge1->flags |= AF_EDGE_DONE; if ( edge2 && !edge2->blue_edge ) { af_latin_align_linked_edge( hints, dim, edge1, edge2 ); edge2->flags |= AF_EDGE_DONE; #ifdef FT_DEBUG_LEVEL_TRACE num_actions++; #endif } if ( !anchor ) anchor = edge; } } /* now we align all other stem edges, trying to maintain the */ /* relative order of stems in the glyph */ for ( edge = edges; edge < edge_limit; edge++ ) { AF_Edge edge2; if ( edge->flags & AF_EDGE_DONE ) continue; /* skip all non-stem edges */ edge2 = edge->link; if ( !edge2 ) { has_serifs++; continue; } /* now align the stem */ /* this should not happen, but it's better to be safe */ if ( edge2->blue_edge ) { FT_TRACE5(( " ASSERTION FAILED for edge %d\n", edge2-edges )); af_latin_align_linked_edge( hints, dim, edge2, edge ); edge->flags |= AF_EDGE_DONE; #ifdef FT_DEBUG_LEVEL_TRACE num_actions++; #endif continue; } if ( !anchor ) { /* if we reach this if clause, no stem has been aligned yet */ FT_Pos org_len, org_center, cur_len; FT_Pos cur_pos1, error1, error2, u_off, d_off; org_len = edge2->opos - edge->opos; cur_len = af_latin_compute_stem_width( hints, dim, org_len, (AF_Edge_Flags)edge->flags, (AF_Edge_Flags)edge2->flags ); /* some voodoo to specially round edges for small stem widths; */ /* the idea is to align the center of a stem, then shifting */ /* the stem edges to suitable positions */ if ( cur_len <= 64 ) { /* width <= 1px */ u_off = 32; d_off = 32; } else { /* 1px < width < 1.5px */ u_off = 38; d_off = 26; } if ( cur_len < 96 ) { org_center = edge->opos + ( org_len >> 1 ); cur_pos1 = FT_PIX_ROUND( org_center ); error1 = org_center - ( cur_pos1 - u_off ); if ( error1 < 0 ) error1 = -error1; error2 = org_center - ( cur_pos1 + d_off ); if ( error2 < 0 ) error2 = -error2; if ( error1 < error2 ) cur_pos1 -= u_off; else cur_pos1 += d_off; edge->pos = cur_pos1 - cur_len / 2; edge2->pos = edge->pos + cur_len; } else edge->pos = FT_PIX_ROUND( edge->opos ); anchor = edge; edge->flags |= AF_EDGE_DONE; FT_TRACE5(( " ANCHOR: edge %d (opos=%.2f) and %d (opos=%.2f)" " snapped to %.2f and %.2f\n", edge - edges, edge->opos / 64.0, edge2 - edges, edge2->opos / 64.0, edge->pos / 64.0, edge2->pos / 64.0 )); af_latin_align_linked_edge( hints, dim, edge, edge2 ); #ifdef FT_DEBUG_LEVEL_TRACE num_actions += 2; #endif } else { FT_Pos org_pos, org_len, org_center, cur_len; FT_Pos cur_pos1, cur_pos2, delta1, delta2; org_pos = anchor->pos + ( edge->opos - anchor->opos ); org_len = edge2->opos - edge->opos; org_center = org_pos + ( org_len >> 1 ); cur_len = af_latin_compute_stem_width( hints, dim, org_len, (AF_Edge_Flags)edge->flags, (AF_Edge_Flags)edge2->flags ); if ( edge2->flags & AF_EDGE_DONE ) { FT_TRACE5(( " ADJUST: edge %d (pos=%.2f) moved to %.2f\n", edge - edges, edge->pos / 64.0, ( edge2->pos - cur_len ) / 64.0 )); edge->pos = edge2->pos - cur_len; } else if ( cur_len < 96 ) { FT_Pos u_off, d_off; cur_pos1 = FT_PIX_ROUND( org_center ); if ( cur_len <= 64 ) { u_off = 32; d_off = 32; } else { u_off = 38; d_off = 26; } delta1 = org_center - ( cur_pos1 - u_off ); if ( delta1 < 0 ) delta1 = -delta1; delta2 = org_center - ( cur_pos1 + d_off ); if ( delta2 < 0 ) delta2 = -delta2; if ( delta1 < delta2 ) cur_pos1 -= u_off; else cur_pos1 += d_off; edge->pos = cur_pos1 - cur_len / 2; edge2->pos = cur_pos1 + cur_len / 2; FT_TRACE5(( " STEM: edge %d (opos=%.2f) linked to %d (opos=%.2f)" " snapped to %.2f and %.2f\n", edge - edges, edge->opos / 64.0, edge2 - edges, edge2->opos / 64.0, edge->pos / 64.0, edge2->pos / 64.0 )); } else { org_pos = anchor->pos + ( edge->opos - anchor->opos ); org_len = edge2->opos - edge->opos; org_center = org_pos + ( org_len >> 1 ); cur_len = af_latin_compute_stem_width( hints, dim, org_len, (AF_Edge_Flags)edge->flags, (AF_Edge_Flags)edge2->flags ); cur_pos1 = FT_PIX_ROUND( org_pos ); delta1 = cur_pos1 + ( cur_len >> 1 ) - org_center; if ( delta1 < 0 ) delta1 = -delta1; cur_pos2 = FT_PIX_ROUND( org_pos + org_len ) - cur_len; delta2 = cur_pos2 + ( cur_len >> 1 ) - org_center; if ( delta2 < 0 ) delta2 = -delta2; edge->pos = ( delta1 < delta2 ) ? cur_pos1 : cur_pos2; edge2->pos = edge->pos + cur_len; FT_TRACE5(( " STEM: edge %d (opos=%.2f) linked to %d (opos=%.2f)" " snapped to %.2f and %.2f\n", edge - edges, edge->opos / 64.0, edge2 - edges, edge2->opos / 64.0, edge->pos / 64.0, edge2->pos / 64.0 )); } #ifdef FT_DEBUG_LEVEL_TRACE num_actions++; #endif edge->flags |= AF_EDGE_DONE; edge2->flags |= AF_EDGE_DONE; if ( edge > edges && edge->pos < edge[-1].pos ) { #ifdef FT_DEBUG_LEVEL_TRACE FT_TRACE5(( " BOUND: edge %d (pos=%.2f) moved to %.2f\n", edge - edges, edge->pos / 64.0, edge[-1].pos / 64.0 )); num_actions++; #endif edge->pos = edge[-1].pos; } } } /* make sure that lowercase m's maintain their symmetry */ /* In general, lowercase m's have six vertical edges if they are sans */ /* serif, or twelve if they are with serifs. This implementation is */ /* based on that assumption, and seems to work very well with most */ /* faces. However, if for a certain face this assumption is not */ /* true, the m is just rendered like before. In addition, any stem */ /* correction will only be applied to symmetrical glyphs (even if the */ /* glyph is not an m), so the potential for unwanted distortion is */ /* relatively low. */ /* We don't handle horizontal edges since we can't easily assure that */ /* the third (lowest) stem aligns with the base line; it might end up */ /* one pixel higher or lower. */ n_edges = edge_limit - edges; if ( dim == AF_DIMENSION_HORZ && ( n_edges == 6 || n_edges == 12 ) ) { AF_Edge edge1, edge2, edge3; FT_Pos dist1, dist2, span, delta; if ( n_edges == 6 ) { edge1 = edges; edge2 = edges + 2; edge3 = edges + 4; } else { edge1 = edges + 1; edge2 = edges + 5; edge3 = edges + 9; } dist1 = edge2->opos - edge1->opos; dist2 = edge3->opos - edge2->opos; span = dist1 - dist2; if ( span < 0 ) span = -span; if ( span < 8 ) { delta = edge3->pos - ( 2 * edge2->pos - edge1->pos ); edge3->pos -= delta; if ( edge3->link ) edge3->link->pos -= delta; /* move the serifs along with the stem */ if ( n_edges == 12 ) { ( edges + 8 )->pos -= delta; ( edges + 11 )->pos -= delta; } edge3->flags |= AF_EDGE_DONE; if ( edge3->link ) edge3->link->flags |= AF_EDGE_DONE; } } if ( has_serifs || !anchor ) { /* * now hint the remaining edges (serifs and single) in order * to complete our processing */ for ( edge = edges; edge < edge_limit; edge++ ) { FT_Pos delta; if ( edge->flags & AF_EDGE_DONE ) continue; delta = 1000; if ( edge->serif ) { delta = edge->serif->opos - edge->opos; if ( delta < 0 ) delta = -delta; } if ( delta < 64 + 16 ) { af_latin_align_serif_edge( hints, edge->serif, edge ); FT_TRACE5(( " SERIF: edge %d (opos=%.2f) serif to %d (opos=%.2f)" " aligned to %.2f\n", edge - edges, edge->opos / 64.0, edge->serif - edges, edge->serif->opos / 64.0, edge->pos / 64.0 )); } else if ( !anchor ) { edge->pos = FT_PIX_ROUND( edge->opos ); anchor = edge; FT_TRACE5(( " SERIF_ANCHOR: edge %d (opos=%.2f)" " snapped to %.2f\n", edge-edges, edge->opos / 64.0, edge->pos / 64.0 )); } else { AF_Edge before, after; for ( before = edge - 1; before >= edges; before-- ) if ( before->flags & AF_EDGE_DONE ) break; for ( after = edge + 1; after < edge_limit; after++ ) if ( after->flags & AF_EDGE_DONE ) break; if ( before >= edges && before < edge && after < edge_limit && after > edge ) { if ( after->opos == before->opos ) edge->pos = before->pos; else edge->pos = before->pos + FT_MulDiv( edge->opos - before->opos, after->pos - before->pos, after->opos - before->opos ); FT_TRACE5(( " SERIF_LINK1: edge %d (opos=%.2f) snapped to %.2f" " from %d (opos=%.2f)\n", edge - edges, edge->opos / 64.0, edge->pos / 64.0, before - edges, before->opos / 64.0 )); } else { edge->pos = anchor->pos + ( ( edge->opos - anchor->opos + 16 ) & ~31 ); FT_TRACE5(( " SERIF_LINK2: edge %d (opos=%.2f)" " snapped to %.2f\n", edge - edges, edge->opos / 64.0, edge->pos / 64.0 )); } } #ifdef FT_DEBUG_LEVEL_TRACE num_actions++; #endif edge->flags |= AF_EDGE_DONE; if ( edge > edges && edge->pos < edge[-1].pos ) { #ifdef FT_DEBUG_LEVEL_TRACE FT_TRACE5(( " BOUND: edge %d (pos=%.2f) moved to %.2f\n", edge - edges, edge->pos / 64.0, edge[-1].pos / 64.0 )); num_actions++; #endif edge->pos = edge[-1].pos; } if ( edge + 1 < edge_limit && edge[1].flags & AF_EDGE_DONE && edge->pos > edge[1].pos ) { #ifdef FT_DEBUG_LEVEL_TRACE FT_TRACE5(( " BOUND: edge %d (pos=%.2f) moved to %.2f\n", edge - edges, edge->pos / 64.0, edge[1].pos / 64.0 )); num_actions++; #endif edge->pos = edge[1].pos; } } } #ifdef FT_DEBUG_LEVEL_TRACE if ( !num_actions ) FT_TRACE5(( " (none)\n" )); FT_TRACE5(( "\n" )); #endif } FT_LOCAL_DEF( void ) af_glyph_hints_align_edge_points( AF_GlyphHints hints, AF_Dimension dim ) { AF_AxisHints axis = & hints->axis[dim]; AF_Segment segments = axis->segments; AF_Segment segment_limit = segments + axis->num_segments; AF_Segment seg; if ( dim == AF_DIMENSION_HORZ ) { for ( seg = segments; seg < segment_limit; seg++ ) { AF_Edge edge = seg->edge; AF_Point point, first, last; if ( edge == NULL ) continue; first = seg->first; last = seg->last; point = first; for (;;) { point->x = edge->pos; point->flags |= AF_FLAG_TOUCH_X; if ( point == last ) break; point = point->next; } } } else { for ( seg = segments; seg < segment_limit; seg++ ) { AF_Edge edge = seg->edge; AF_Point point, first, last; if ( edge == NULL ) continue; first = seg->first; last = seg->last; point = first; for (;;) { point->y = edge->pos; point->flags |= AF_FLAG_TOUCH_Y; if ( point == last ) break; point = point->next; } } } } FT_LOCAL_DEF( void ) af_glyph_hints_align_strong_points( AF_GlyphHints hints, AF_Dimension dim ) { AF_Point points = hints->points; AF_Point point_limit = points + hints->num_points; AF_AxisHints axis = &hints->axis[dim]; AF_Edge edges = axis->edges; AF_Edge edge_limit = edges + axis->num_edges; AF_Flags touch_flag; if ( dim == AF_DIMENSION_HORZ ) touch_flag = AF_FLAG_TOUCH_X; else touch_flag = AF_FLAG_TOUCH_Y; if ( edges < edge_limit ) { AF_Point point; AF_Edge edge; for ( point = points; point < point_limit; point++ ) { FT_Pos u, ou, fu; /* point position */ FT_Pos delta; if ( point->flags & touch_flag ) continue; /* if this point is candidate to weak interpolation, we */ /* interpolate it after all strong points have been processed */ if ( ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) && !( point->flags & AF_FLAG_INFLECTION ) ) continue; if ( dim == AF_DIMENSION_VERT ) { u = point->fy; ou = point->oy; } else { u = point->fx; ou = point->ox; } fu = u; /* is the point before the first edge? */ edge = edges; delta = edge->fpos - u; if ( delta >= 0 ) { u = edge->pos - ( edge->opos - ou ); goto Store_Point; } /* is the point after the last edge? */ edge = edge_limit - 1; delta = u - edge->fpos; if ( delta >= 0 ) { u = edge->pos + ( ou - edge->opos ); goto Store_Point; } { FT_PtrDist min, max, mid; FT_Pos fpos; /* find enclosing edges */ min = 0; max = edge_limit - edges; #if 1 /* for a small number of edges, a linear search is better */ if ( max <= 8 ) { FT_PtrDist nn; for ( nn = 0; nn < max; nn++ ) if ( edges[nn].fpos >= u ) break; if ( edges[nn].fpos == u ) { u = edges[nn].pos; goto Store_Point; } min = nn; } else #endif while ( min < max ) { mid = ( max + min ) >> 1; edge = edges + mid; fpos = edge->fpos; if ( u < fpos ) max = mid; else if ( u > fpos ) min = mid + 1; else { /* we are on the edge */ u = edge->pos; goto Store_Point; } } /* point is not on an edge */ { AF_Edge before = edges + min - 1; AF_Edge after = edges + min + 0; /* assert( before && after && before != after ) */ if ( before->scale == 0 ) before->scale = FT_DivFix( after->pos - before->pos, after->fpos - before->fpos ); u = before->pos + FT_MulFix( fu - before->fpos, before->scale ); } } Store_Point: /* save the point position */ if ( dim == AF_DIMENSION_HORZ ) point->x = u; else point->y = u; point->flags |= touch_flag; } } } static void af_iup_interp( AF_Point p1, AF_Point p2, AF_Point ref1, AF_Point ref2 ) { AF_Point p; FT_Pos u; FT_Pos v1 = ref1->v; FT_Pos v2 = ref2->v; FT_Pos d1 = ref1->u - v1; FT_Pos d2 = ref2->u - v2; if ( p1 > p2 ) return; if ( v1 == v2 ) { for ( p = p1; p <= p2; p++ ) { u = p->v; if ( u <= v1 ) u += d1; else u += d2; p->u = u; } return; } if ( v1 < v2 ) { for ( p = p1; p <= p2; p++ ) { u = p->v; if ( u <= v1 ) u += d1; else if ( u >= v2 ) u += d2; else u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 ); p->u = u; } } else { for ( p = p1; p <= p2; p++ ) { u = p->v; if ( u <= v2 ) u += d2; else if ( u >= v1 ) u += d1; else u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 ); p->u = u; } } } static void af_iup_shift( AF_Point p1, AF_Point p2, AF_Point ref ) { AF_Point p; FT_Pos delta = ref->u - ref->v; if ( delta == 0 ) return; for ( p = p1; p < ref; p++ ) p->u = p->v + delta; for ( p = ref + 1; p <= p2; p++ ) p->u = p->v + delta; } FT_LOCAL_DEF( void ) af_glyph_hints_align_weak_points( AF_GlyphHints hints, AF_Dimension dim ) { AF_Point points = hints->points; AF_Point point_limit = points + hints->num_points; AF_Point* contour = hints->contours; AF_Point* contour_limit = contour + hints->num_contours; AF_Flags touch_flag; AF_Point point; AF_Point end_point; AF_Point first_point; /* PASS 1: Move segment points to edge positions */ if ( dim == AF_DIMENSION_HORZ ) { touch_flag = AF_FLAG_TOUCH_X; for ( point = points; point < point_limit; point++ ) { point->u = point->x; point->v = point->ox; } } else { touch_flag = AF_FLAG_TOUCH_Y; for ( point = points; point < point_limit; point++ ) { point->u = point->y; point->v = point->oy; } } for ( ; contour < contour_limit; contour++ ) { AF_Point first_touched, last_touched; point = *contour; end_point = point->prev; first_point = point; /* find first touched point */ for (;;) { if ( point > end_point ) /* no touched point in contour */ goto NextContour; if ( point->flags & touch_flag ) break; point++; } first_touched = point; for (;;) { FT_ASSERT( point <= end_point && ( point->flags & touch_flag ) != 0 ); /* skip any touched neighbours */ while ( point < end_point && ( point[1].flags & touch_flag ) != 0 ) point++; last_touched = point; /* find the next touched point, if any */ point++; for (;;) { if ( point > end_point ) goto EndContour; if ( ( point->flags & touch_flag ) != 0 ) break; point++; } /* interpolate between last_touched and point */ af_iup_interp( last_touched + 1, point - 1, last_touched, point ); } EndContour: /* special case: only one point was touched */ if ( last_touched == first_touched ) af_iup_shift( first_point, end_point, first_touched ); else /* interpolate the last part */ { if ( last_touched < end_point ) af_iup_interp( last_touched + 1, end_point, last_touched, first_touched ); if ( first_touched > points ) af_iup_interp( first_point, first_touched - 1, last_touched, first_touched ); } NextContour: ; } /* now save the interpolated values back to x/y */ if ( dim == AF_DIMENSION_HORZ ) { for ( point = points; point < point_limit; point++ ) point->x = point->u; } else { for ( point = points; point < point_limit; point++ ) point->y = point->u; } } static FT_Error af_latin_hints_apply( AF_GlyphHints hints, FT_Outline* outline, AF_LatinMetrics metrics ) { FT_Error error; int dim; error = af_glyph_hints_reload( hints, outline ); if ( error ) goto Exit; /* analyze glyph outline */ #ifdef AF_CONFIG_OPTION_USE_WARPER if ( metrics->root.scaler.render_mode == FT_RENDER_MODE_LIGHT || AF_HINTS_DO_HORIZONTAL( hints ) ) #else if ( AF_HINTS_DO_HORIZONTAL( hints ) ) #endif { error = af_latin_hints_detect_features( hints, AF_DIMENSION_HORZ ); if ( error ) goto Exit; } if ( AF_HINTS_DO_VERTICAL( hints ) ) { error = af_latin_hints_detect_features( hints, AF_DIMENSION_VERT ); if ( error ) goto Exit; af_latin_hints_compute_blue_edges( hints, metrics ); } /* grid-fit the outline */ for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) { #ifdef AF_CONFIG_OPTION_USE_WARPER if ( dim == AF_DIMENSION_HORZ && metrics->root.scaler.render_mode == FT_RENDER_MODE_LIGHT ) { AF_WarperRec warper; FT_Fixed scale; FT_Pos delta; af_warper_compute( &warper, hints, (AF_Dimension)dim, &scale, &delta ); af_glyph_hints_scale_dim( hints, (AF_Dimension)dim, scale, delta ); continue; } #endif if ( ( dim == AF_DIMENSION_HORZ && AF_HINTS_DO_HORIZONTAL( hints ) ) || ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_VERTICAL( hints ) ) ) { af_latin_hint_edges( hints, (AF_Dimension)dim ); af_glyph_hints_align_edge_points( hints, (AF_Dimension)dim ); af_glyph_hints_align_strong_points( hints, (AF_Dimension)dim ); af_glyph_hints_align_weak_points( hints, (AF_Dimension)dim ); } } af_glyph_hints_save( hints, outline ); Exit: return error; } // ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ FT_DEFINE_AUTOHINTER_INTERFACE( af_autofitter_interface, NULL, /* reset_face */ NULL, /* get_global_hints */ NULL, /* done_global_hints */ (FT_AutoHinter_GlyphLoadFunc)af_autofitter_load_glyph ) /* load_glyph */ FT_DEFINE_MODULE ( autofit_module_class, FT_MODULE_HINTER, sizeof ( AF_ModuleRec ), "autofitter", 0x10000L, /* version 1.0 of the autofitter */ 0x20000L, /* requires FreeType 2.0 or above */ (const void*)&AF_INTERFACE_GET, (FT_Module_Constructor)af_autofitter_init, (FT_Module_Destructor) af_autofitter_done, (FT_Module_Requester) af_get_interface ) AF_DEFINE_WRITING_SYSTEM_CLASS ( af_dummy_writing_system_class, AF_WRITING_SYSTEM_DUMMY, sizeof ( AF_StyleMetricsRec ), (AF_WritingSystem_InitMetricsFunc) NULL, (AF_WritingSystem_ScaleMetricsFunc)NULL, (AF_WritingSystem_DoneMetricsFunc) NULL, (AF_WritingSystem_InitHintsFunc) af_dummy_hints_init, (AF_WritingSystem_ApplyHintsFunc) af_dummy_hints_apply ) AF_DEFINE_WRITING_SYSTEM_CLASS ( af_latin_writing_system_class, AF_WRITING_SYSTEM_LATIN, sizeof ( AF_LatinMetricsRec ), (AF_WritingSystem_InitMetricsFunc) af_latin_metrics_init, (AF_WritingSystem_ScaleMetricsFunc)af_latin_metrics_scale, (AF_WritingSystem_DoneMetricsFunc) NULL, (AF_WritingSystem_InitHintsFunc) af_latin_hints_init, (AF_WritingSystem_ApplyHintsFunc) af_latin_hints_apply ) // ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ #ifndef FT_CONFIG_OPTION_PIC #define FT_DEFINE_TT_CMAP( class_, \ size_, \ init_, \ done_, \ char_index_, \ char_next_, \ char_var_index_, \ char_var_default_, \ variant_list_, \ charvariant_list_, \ variantchar_list_, \ format_, \ validate_, \ get_cmap_info_ ) \ FT_CALLBACK_TABLE_DEF \ const TT_CMap_ClassRec class_ = \ { \ { size_, \ init_, \ done_, \ char_index_, \ char_next_, \ char_var_index_, \ char_var_default_, \ variant_list_, \ charvariant_list_, \ variantchar_list_ \ }, \ \ format_, \ validate_, \ get_cmap_info_ \ }; #else /* FT_CONFIG_OPTION_PIC */ #define FT_DEFINE_TT_CMAP( class_, \ size_, \ init_, \ done_, \ char_index_, \ char_next_, \ char_var_index_, \ char_var_default_, \ variant_list_, \ charvariant_list_, \ variantchar_list_, \ format_, \ validate_, \ get_cmap_info_ ) \ void \ FT_Init_Class_ ## class_( TT_CMap_ClassRec* clazz ) \ { \ clazz->clazz.size = size_; \ clazz->clazz.init = init_; \ clazz->clazz.done = done_; \ clazz->clazz.char_index = char_index_; \ clazz->clazz.char_next = char_next_; \ clazz->clazz.char_var_index = char_var_index_; \ clazz->clazz.char_var_default = char_var_default_; \ clazz->clazz.variant_list = variant_list_; \ clazz->clazz.charvariant_list = charvariant_list_; \ clazz->clazz.variantchar_list = variantchar_list_; \ clazz->format = format_; \ clazz->validate = validate_; \ clazz->get_cmap_info = get_cmap_info_; \ } #endif /* FT_CONFIG_OPTION_PIC */ #define TT_PEEK_SHORT FT_PEEK_SHORT #define TT_PEEK_USHORT FT_PEEK_USHORT #define TT_PEEK_UINT24 FT_PEEK_UOFF3 #define TT_PEEK_LONG FT_PEEK_LONG #define TT_PEEK_ULONG FT_PEEK_ULONG #define TT_NEXT_SHORT FT_NEXT_SHORT #define TT_NEXT_USHORT FT_NEXT_USHORT #define TT_NEXT_UINT24 FT_NEXT_UOFF3 #define TT_NEXT_LONG FT_NEXT_LONG #define TT_NEXT_ULONG FT_NEXT_ULONG #define FT_INVALID( _prefix, _error ) FT_INVALID_( _prefix, _error ) #define FT_INVALID_( _prefix, _error ) \ ft_validator_error( valid, _prefix ## _error ) /* called when a broken table is detected */ #define FT_INVALID_TOO_SHORT \ FT_INVALID( FT_ERR_PREFIX, Invalid_Table ) /* called when an invalid offset is detected */ #define FT_INVALID_OFFSET \ FT_INVALID( FT_ERR_PREFIX, Invalid_Offset ) /* called when an invalid format/value is detected */ #define FT_INVALID_FORMAT \ FT_INVALID( FT_ERR_PREFIX, Invalid_Table ) /* called when an invalid glyph index is detected */ #define FT_INVALID_GLYPH_ID \ FT_INVALID( FT_ERR_PREFIX, Invalid_Glyph_Index ) /* called when an invalid field value is detected */ #define FT_INVALID_DATA \ FT_INVALID( FT_ERR_PREFIX, Invalid_Table ) #define TT_VALIDATOR( x ) ( (TT_Validator)( x ) ) #define TT_VALID_GLYPH_COUNT( x ) TT_VALIDATOR( x )->num_glyphs typedef struct TT_CMapRec_ { FT_CMapRec cmap; FT_Byte* data; /* pointer to in-memory cmap table */ FT_Int flags; /* for format 4 only */ } TT_CMapRec, *TT_CMap; FT_CALLBACK_DEF( FT_Error ) tt_cmap_init( TT_CMap cmap, FT_Byte* table ) { cmap->data = table; return FT_Err_Ok; } typedef enum FT_ValidationLevel_ { FT_VALIDATE_DEFAULT = 0, FT_VALIDATE_TIGHT, FT_VALIDATE_PARANOID } FT_ValidationLevel; typedef struct FT_ValidatorRec_ { const FT_Byte* base; /* address of table in memory */ const FT_Byte* limit; /* `base' + sizeof(table) in memory */ FT_ValidationLevel level; /* validation level */ FT_Error error; /* error returned. 0 means success */ ft_jmp_buf jump_buffer; /* used for exception handling */ } FT_ValidatorRec; typedef struct TT_ValidatorRec_ { FT_ValidatorRec validator; FT_UInt num_glyphs; } TT_ValidatorRec, *TT_Validator; #define FT_VALIDATOR( x ) ( (FT_Validator)( x ) ) #define TT_KERN_INDEX( g1, g2 ) ( ( (FT_ULong)(g1) << 16 ) | (g2) ) FT_BASE_DEF( void ) ft_validator_init( FT_Validator valid, const FT_Byte* base, const FT_Byte* limit, FT_ValidationLevel level ) { valid->base = base; valid->limit = limit; valid->level = level; valid->error = FT_Err_Ok; } FT_BASE_DEF( FT_Int ) ft_validator_run( FT_Validator valid ) { /* This function doesn't work! None should call it. */ FT_UNUSED( valid ); return -1; } FT_BASE_DEF( void ) ft_validator_error( FT_Validator valid, FT_Error error ) { /* since the cast below also disables the compiler's */ /* type check, we introduce a dummy variable, which */ /* will be optimized away */ volatile ft_jmp_buf* jump_buffer = &valid->jump_buffer; valid->error = error; /* throw away volatileness; use `jump_buffer' or the */ /* compiler may warn about an unused local variable */ ft_longjmp( *(ft_jmp_buf*) jump_buffer, 1 ); } /*************************************************************************/ /*************************************************************************/ /***** *****/ /***** FORMAT 0 *****/ /***** *****/ /*************************************************************************/ /*************************************************************************/ /*************************************************************************/ /* */ /* TABLE OVERVIEW */ /* -------------- */ /* */ /* NAME OFFSET TYPE DESCRIPTION */ /* */ /* format 0 USHORT must be 0 */ /* length 2 USHORT table length in bytes */ /* language 4 USHORT Mac language code */ /* glyph_ids 6 BYTE[256] array of glyph indices */ /* 262 */ /* */ #ifdef TT_CONFIG_CMAP_FORMAT_0 FT_CALLBACK_DEF( FT_Error ) tt_cmap0_validate( FT_Byte* table, FT_Validator valid ) { FT_Byte* p; FT_UInt length; if ( table + 2 + 2 > valid->limit ) FT_INVALID_TOO_SHORT; p = table + 2; /* skip format */ length = TT_NEXT_USHORT( p ); if ( table + length > valid->limit || length < 262 ) FT_INVALID_TOO_SHORT; /* check glyph indices whenever necessary */ if ( valid->level >= FT_VALIDATE_TIGHT ) { FT_UInt n, idx; p = table + 6; for ( n = 0; n < 256; n++ ) { idx = *p++; if ( idx >= TT_VALID_GLYPH_COUNT( valid ) ) FT_INVALID_GLYPH_ID; } } return FT_Err_Ok; } FT_CALLBACK_DEF( FT_UInt ) tt_cmap0_char_index( TT_CMap cmap, FT_UInt32 char_code ) { FT_Byte* table = cmap->data; return char_code < 256 ? table[6 + char_code] : 0; } FT_CALLBACK_DEF( FT_UInt32 ) tt_cmap0_char_next( TT_CMap cmap, FT_UInt32 *pchar_code ) { FT_Byte* table = cmap->data; FT_UInt32 charcode = *pchar_code; FT_UInt32 result = 0; FT_UInt gindex = 0; table += 6; /* go to glyph IDs */ while ( ++charcode < 256 ) { gindex = table[charcode]; if ( gindex != 0 ) { result = charcode; break; } } *pchar_code = result; return gindex; } FT_CALLBACK_DEF( FT_Error ) tt_cmap0_get_info( TT_CMap cmap, TT_CMapInfo *cmap_info ) { FT_Byte* p = cmap->data + 4; cmap_info->format = 0; cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p ); return FT_Err_Ok; } FT_DEFINE_TT_CMAP( tt_cmap0_class_rec, sizeof ( TT_CMapRec ), (FT_CMap_InitFunc) tt_cmap_init, (FT_CMap_DoneFunc) NULL, (FT_CMap_CharIndexFunc)tt_cmap0_char_index, (FT_CMap_CharNextFunc) tt_cmap0_char_next, NULL, NULL, NULL, NULL, NULL, 0, (TT_CMap_ValidateFunc)tt_cmap0_validate, (TT_CMap_Info_GetFunc)tt_cmap0_get_info ) #endif /* TT_CONFIG_CMAP_FORMAT_0 */ /*************************************************************************/ /*************************************************************************/ /***** *****/ /***** FORMAT 2 *****/ /***** *****/ /***** This is used for certain CJK encodings that encode text in a *****/ /***** mixed 8/16 bits encoding along the following lines: *****/ /***** *****/ /***** * Certain byte values correspond to an 8-bit character code *****/ /***** (typically in the range 0..127 for ASCII compatibility). *****/ /***** *****/ /***** * Certain byte values signal the first byte of a 2-byte *****/ /***** character code (but these values are also valid as the *****/ /***** second byte of a 2-byte character). *****/ /***** *****/ /***** The following charmap lookup and iteration functions all *****/ /***** assume that the value "charcode" correspond to following: *****/ /***** *****/ /***** - For one byte characters, "charcode" is simply the *****/ /***** character code. *****/ /***** *****/ /***** - For two byte characters, "charcode" is the 2-byte *****/ /***** character code in big endian format. More exactly: *****/ /***** *****/ /***** (charcode >> 8) is the first byte value *****/ /***** (charcode & 0xFF) is the second byte value *****/ /***** *****/ /***** Note that not all values of "charcode" are valid according *****/ /***** to these rules, and the function moderately check the *****/ /***** arguments. *****/ /***** *****/ /*************************************************************************/ /*************************************************************************/ /*************************************************************************/ /* */ /* TABLE OVERVIEW */ /* -------------- */ /* */ /* NAME OFFSET TYPE DESCRIPTION */ /* */ /* format 0 USHORT must be 2 */ /* length 2 USHORT table length in bytes */ /* language 4 USHORT Mac language code */ /* keys 6 USHORT[256] sub-header keys */ /* subs 518 SUBHEAD[NSUBS] sub-headers array */ /* glyph_ids 518+NSUB*8 USHORT[] glyph ID array */ /* */ /* The `keys' table is used to map charcode high-bytes to sub-headers. */ /* The value of `NSUBS' is the number of sub-headers defined in the */ /* table and is computed by finding the maximum of the `keys' table. */ /* */ /* Note that for any n, `keys[n]' is a byte offset within the `subs' */ /* table, i.e., it is the corresponding sub-header index multiplied */ /* by 8. */ /* */ /* Each sub-header has the following format: */ /* */ /* NAME OFFSET TYPE DESCRIPTION */ /* */ /* first 0 USHORT first valid low-byte */ /* count 2 USHORT number of valid low-bytes */ /* delta 4 SHORT see below */ /* offset 6 USHORT see below */ /* */ /* A sub-header defines, for each high-byte, the range of valid */ /* low-bytes within the charmap. Note that the range defined by `first' */ /* and `count' must be completely included in the interval [0..255] */ /* according to the specification. */ /* */ /* If a character code is contained within a given sub-header, then */ /* mapping it to a glyph index is done as follows: */ /* */ /* * The value of `offset' is read. This is a _byte_ distance from the */ /* location of the `offset' field itself into a slice of the */ /* `glyph_ids' table. Let's call it `slice' (it is a USHORT[] too). */ /* */ /* * The value `slice[char.lo - first]' is read. If it is 0, there is */ /* no glyph for the charcode. Otherwise, the value of `delta' is */ /* added to it (modulo 65536) to form a new glyph index. */ /* */ /* It is up to the validation routine to check that all offsets fall */ /* within the glyph IDs table (and not within the `subs' table itself or */ /* outside of the CMap). */ /* */ #ifdef TT_CONFIG_CMAP_FORMAT_2 FT_CALLBACK_DEF( FT_Error ) tt_cmap2_validate( FT_Byte* table, FT_Validator valid ) { FT_Byte* p; FT_UInt length; FT_UInt n, max_subs; FT_Byte* keys; /* keys table */ FT_Byte* subs; /* sub-headers */ FT_Byte* glyph_ids; /* glyph ID array */ if ( table + 2 + 2 > valid->limit ) FT_INVALID_TOO_SHORT; p = table + 2; /* skip format */ length = TT_NEXT_USHORT( p ); if ( table + length > valid->limit || length < 6 + 512 ) FT_INVALID_TOO_SHORT; keys = table + 6; /* parse keys to compute sub-headers count */ p = keys; max_subs = 0; for ( n = 0; n < 256; n++ ) { FT_UInt idx = TT_NEXT_USHORT( p ); /* value must be multiple of 8 */ if ( valid->level >= FT_VALIDATE_PARANOID && ( idx & 7 ) != 0 ) FT_INVALID_DATA; idx >>= 3; if ( idx > max_subs ) max_subs = idx; } FT_ASSERT( p == table + 518 ); subs = p; glyph_ids = subs + (max_subs + 1) * 8; if ( glyph_ids > valid->limit ) FT_INVALID_TOO_SHORT; /* parse sub-headers */ for ( n = 0; n <= max_subs; n++ ) { FT_UInt first_code, code_count, offset; FT_Int delta; first_code = TT_NEXT_USHORT( p ); code_count = TT_NEXT_USHORT( p ); delta = TT_NEXT_SHORT( p ); offset = TT_NEXT_USHORT( p ); /* many Dynalab fonts have empty sub-headers */ if ( code_count == 0 ) continue; /* check range within 0..255 */ if ( valid->level >= FT_VALIDATE_PARANOID ) { if ( first_code >= 256 || first_code + code_count > 256 ) FT_INVALID_DATA; } /* check offset */ if ( offset != 0 ) { FT_Byte* ids; ids = p - 2 + offset; if ( ids < glyph_ids || ids + code_count*2 > table + length ) FT_INVALID_OFFSET; /* check glyph IDs */ if ( valid->level >= FT_VALIDATE_TIGHT ) { FT_Byte* limit = p + code_count * 2; FT_UInt idx; for ( ; p < limit; ) { idx = TT_NEXT_USHORT( p ); if ( idx != 0 ) { idx = ( idx + delta ) & 0xFFFFU; if ( idx >= TT_VALID_GLYPH_COUNT( valid ) ) FT_INVALID_GLYPH_ID; } } } } } return FT_Err_Ok; } /* return sub header corresponding to a given character code */ /* NULL on invalid charcode */ static FT_Byte* tt_cmap2_get_subheader( FT_Byte* table, FT_UInt32 char_code ) { FT_Byte* result = NULL; if ( char_code < 0x10000UL ) { FT_UInt char_lo = (FT_UInt)( char_code & 0xFF ); FT_UInt char_hi = (FT_UInt)( char_code >> 8 ); FT_Byte* p = table + 6; /* keys table */ FT_Byte* subs = table + 518; /* subheaders table */ FT_Byte* sub; if ( char_hi == 0 ) { /* an 8-bit character code -- we use subHeader 0 in this case */ /* to test whether the character code is in the charmap */ /* */ sub = subs; /* jump to first sub-header */ /* check that the sub-header for this byte is 0, which */ /* indicates that it is really a valid one-byte value */ /* Otherwise, return 0 */ /* */ p += char_lo * 2; if ( TT_PEEK_USHORT( p ) != 0 ) goto Exit; } else { /* a 16-bit character code */ /* jump to key entry */ p += char_hi * 2; /* jump to sub-header */ sub = subs + ( FT_PAD_FLOOR( TT_PEEK_USHORT( p ), 8 ) ); /* check that the high byte isn't a valid one-byte value */ if ( sub == subs ) goto Exit; } result = sub; } Exit: return result; } FT_CALLBACK_DEF( FT_UInt ) tt_cmap2_char_index( TT_CMap cmap, FT_UInt32 char_code ) { FT_Byte* table = cmap->data; FT_UInt result = 0; FT_Byte* subheader; subheader = tt_cmap2_get_subheader( table, char_code ); if ( subheader ) { FT_Byte* p = subheader; FT_UInt idx = (FT_UInt)(char_code & 0xFF); FT_UInt start, count; FT_Int delta; FT_UInt offset; start = TT_NEXT_USHORT( p ); count = TT_NEXT_USHORT( p ); delta = TT_NEXT_SHORT ( p ); offset = TT_PEEK_USHORT( p ); idx -= start; if ( idx < count && offset != 0 ) { p += offset + 2 * idx; idx = TT_PEEK_USHORT( p ); if ( idx != 0 ) result = (FT_UInt)( idx + delta ) & 0xFFFFU; } } return result; } FT_CALLBACK_DEF( FT_UInt32 ) tt_cmap2_char_next( TT_CMap cmap, FT_UInt32 *pcharcode ) { FT_Byte* table = cmap->data; FT_UInt gindex = 0; FT_UInt32 result = 0; FT_UInt32 charcode = *pcharcode + 1; FT_Byte* subheader; while ( charcode < 0x10000UL ) { subheader = tt_cmap2_get_subheader( table, charcode ); if ( subheader ) { FT_Byte* p = subheader; FT_UInt start = TT_NEXT_USHORT( p ); FT_UInt count = TT_NEXT_USHORT( p ); FT_Int delta = TT_NEXT_SHORT ( p ); FT_UInt offset = TT_PEEK_USHORT( p ); FT_UInt char_lo = (FT_UInt)( charcode & 0xFF ); FT_UInt pos, idx; if ( offset == 0 ) goto Next_SubHeader; if ( char_lo < start ) { char_lo = start; pos = 0; } else pos = (FT_UInt)( char_lo - start ); p += offset + pos * 2; charcode = FT_PAD_FLOOR( charcode, 256 ) + char_lo; for ( ; pos < count; pos++, charcode++ ) { idx = TT_NEXT_USHORT( p ); if ( idx != 0 ) { gindex = ( idx + delta ) & 0xFFFFU; if ( gindex != 0 ) { result = charcode; goto Exit; } } } } /* jump to next sub-header, i.e. higher byte value */ Next_SubHeader: charcode = FT_PAD_FLOOR( charcode, 256 ) + 256; } Exit: *pcharcode = result; return gindex; } FT_CALLBACK_DEF( FT_Error ) tt_cmap2_get_info( TT_CMap cmap, TT_CMapInfo *cmap_info ) { FT_Byte* p = cmap->data + 4; cmap_info->format = 2; cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p ); return FT_Err_Ok; } FT_DEFINE_TT_CMAP( tt_cmap2_class_rec, sizeof ( TT_CMapRec ), (FT_CMap_InitFunc) tt_cmap_init, (FT_CMap_DoneFunc) NULL, (FT_CMap_CharIndexFunc)tt_cmap2_char_index, (FT_CMap_CharNextFunc) tt_cmap2_char_next, NULL, NULL, NULL, NULL, NULL, 2, (TT_CMap_ValidateFunc)tt_cmap2_validate, (TT_CMap_Info_GetFunc)tt_cmap2_get_info ) #endif /* TT_CONFIG_CMAP_FORMAT_2 */ /*************************************************************************/ /*************************************************************************/ /***** *****/ /***** FORMAT 4 *****/ /***** *****/ /*************************************************************************/ /*************************************************************************/ /*************************************************************************/ /* */ /* TABLE OVERVIEW */ /* -------------- */ /* */ /* NAME OFFSET TYPE DESCRIPTION */ /* */ /* format 0 USHORT must be 4 */ /* length 2 USHORT table length */ /* in bytes */ /* language 4 USHORT Mac language code */ /* */ /* segCountX2 6 USHORT 2*NUM_SEGS */ /* searchRange 8 USHORT 2*(1 << LOG_SEGS) */ /* entrySelector 10 USHORT LOG_SEGS */ /* rangeShift 12 USHORT segCountX2 - */ /* searchRange */ /* */ /* endCount 14 USHORT[NUM_SEGS] end charcode for */ /* each segment; last */ /* is 0xFFFF */ /* */ /* pad 14+NUM_SEGS*2 USHORT padding */ /* */ /* startCount 16+NUM_SEGS*2 USHORT[NUM_SEGS] first charcode for */ /* each segment */ /* */ /* idDelta 16+NUM_SEGS*4 SHORT[NUM_SEGS] delta for each */ /* segment */ /* idOffset 16+NUM_SEGS*6 SHORT[NUM_SEGS] range offset for */ /* each segment; can be */ /* zero */ /* */ /* glyphIds 16+NUM_SEGS*8 USHORT[] array of glyph ID */ /* ranges */ /* */ /* Character codes are modelled by a series of ordered (increasing) */ /* intervals called segments. Each segment has start and end codes, */ /* provided by the `startCount' and `endCount' arrays. Segments must */ /* not overlap, and the last segment should always contain the value */ /* 0xFFFF for `endCount'. */ /* */ /* The fields `searchRange', `entrySelector' and `rangeShift' are better */ /* ignored (they are traces of over-engineering in the TrueType */ /* specification). */ /* */ /* Each segment also has a signed `delta', as well as an optional offset */ /* within the `glyphIds' table. */ /* */ /* If a segment's idOffset is 0, the glyph index corresponding to any */ /* charcode within the segment is obtained by adding the value of */ /* `idDelta' directly to the charcode, modulo 65536. */ /* */ /* Otherwise, a glyph index is taken from the glyph IDs sub-array for */ /* the segment, and the value of `idDelta' is added to it. */ /* */ /* */ /* Finally, note that a lot of fonts contain an invalid last segment, */ /* where `start' and `end' are correctly set to 0xFFFF but both `delta' */ /* and `offset' are incorrect (e.g., `opens___.ttf' which comes with */ /* OpenOffice.org). We need special code to deal with them correctly. */ /* */ #ifdef TT_CONFIG_CMAP_FORMAT_4 typedef struct TT_CMap4Rec_ { TT_CMapRec cmap; FT_UInt32 cur_charcode; /* current charcode */ FT_UInt cur_gindex; /* current glyph index */ FT_UInt num_ranges; FT_UInt cur_range; FT_UInt cur_start; FT_UInt cur_end; FT_Int cur_delta; FT_Byte* cur_values; } TT_CMap4Rec, *TT_CMap4; FT_CALLBACK_DEF( FT_Error ) tt_cmap4_init( TT_CMap4 cmap, FT_Byte* table ) { FT_Byte* p; cmap->cmap.data = table; p = table + 6; cmap->num_ranges = FT_PEEK_USHORT( p ) >> 1; cmap->cur_charcode = (FT_UInt32)0xFFFFFFFFUL; cmap->cur_gindex = 0; return FT_Err_Ok; } static FT_Int tt_cmap4_set_range( TT_CMap4 cmap, FT_UInt range_index ) { FT_Byte* table = cmap->cmap.data; FT_Byte* p; FT_UInt num_ranges = cmap->num_ranges; while ( range_index < num_ranges ) { FT_UInt offset; p = table + 14 + range_index * 2; cmap->cur_end = FT_PEEK_USHORT( p ); p += 2 + num_ranges * 2; cmap->cur_start = FT_PEEK_USHORT( p ); p += num_ranges * 2; cmap->cur_delta = FT_PEEK_SHORT( p ); p += num_ranges * 2; offset = FT_PEEK_USHORT( p ); /* some fonts have an incorrect last segment; */ /* we have to catch it */ if ( range_index >= num_ranges - 1 && cmap->cur_start == 0xFFFFU && cmap->cur_end == 0xFFFFU ) { TT_Face face = (TT_Face)cmap->cmap.cmap.charmap.face; FT_Byte* limit = face->cmap_table + face->cmap_size; if ( offset && p + offset + 2 > limit ) { cmap->cur_delta = 1; offset = 0; } } if ( offset != 0xFFFFU ) { cmap->cur_values = offset ? p + offset : NULL; cmap->cur_range = range_index; return 0; } /* we skip empty segments */ range_index++; } return -1; } /* search the index of the charcode next to cmap->cur_charcode; */ /* caller should call tt_cmap4_set_range with proper range */ /* before calling this function */ /* */ static void tt_cmap4_next( TT_CMap4 cmap ) { FT_UInt charcode; if ( cmap->cur_charcode >= 0xFFFFUL ) goto Fail; charcode = (FT_UInt)cmap->cur_charcode + 1; if ( charcode < cmap->cur_start ) charcode = cmap->cur_start; for ( ;; ) { FT_Byte* values = cmap->cur_values; FT_UInt end = cmap->cur_end; FT_Int delta = cmap->cur_delta; if ( charcode <= end ) { if ( values ) { FT_Byte* p = values + 2 * ( charcode - cmap->cur_start ); do { FT_UInt gindex = FT_NEXT_USHORT( p ); if ( gindex != 0 ) { gindex = (FT_UInt)( ( gindex + delta ) & 0xFFFFU ); if ( gindex != 0 ) { cmap->cur_charcode = charcode; cmap->cur_gindex = gindex; return; } } } while ( ++charcode <= end ); } else { do { FT_UInt gindex = (FT_UInt)( ( charcode + delta ) & 0xFFFFU ); if ( gindex != 0 ) { cmap->cur_charcode = charcode; cmap->cur_gindex = gindex; return; } } while ( ++charcode <= end ); } } /* we need to find another range */ if ( tt_cmap4_set_range( cmap, cmap->cur_range + 1 ) < 0 ) break; if ( charcode < cmap->cur_start ) charcode = cmap->cur_start; } Fail: cmap->cur_charcode = (FT_UInt32)0xFFFFFFFFUL; cmap->cur_gindex = 0; } FT_CALLBACK_DEF( FT_Error ) tt_cmap4_validate( FT_Byte* table, FT_Validator valid ) { FT_Byte* p; FT_UInt length; FT_Byte *ends, *starts, *offsets, *deltas, *glyph_ids; FT_UInt num_segs; FT_Error error = FT_Err_Ok; if ( table + 2 + 2 > valid->limit ) FT_INVALID_TOO_SHORT; p = table + 2; /* skip format */ length = TT_NEXT_USHORT( p ); if ( length < 16 ) FT_INVALID_TOO_SHORT; /* in certain fonts, the `length' field is invalid and goes */ /* out of bound. We try to correct this here... */ if ( table + length > valid->limit ) { if ( valid->level >= FT_VALIDATE_TIGHT ) FT_INVALID_TOO_SHORT; length = (FT_UInt)( valid->limit - table ); } p = table + 6; num_segs = TT_NEXT_USHORT( p ); /* read segCountX2 */ if ( valid->level >= FT_VALIDATE_PARANOID ) { /* check that we have an even value here */ if ( num_segs & 1 ) FT_INVALID_DATA; } num_segs /= 2; if ( length < 16 + num_segs * 2 * 4 ) FT_INVALID_TOO_SHORT; /* check the search parameters - even though we never use them */ /* */ if ( valid->level >= FT_VALIDATE_PARANOID ) { /* check the values of `searchRange', `entrySelector', `rangeShift' */ FT_UInt search_range = TT_NEXT_USHORT( p ); FT_UInt entry_selector = TT_NEXT_USHORT( p ); FT_UInt range_shift = TT_NEXT_USHORT( p ); if ( ( search_range | range_shift ) & 1 ) /* must be even values */ FT_INVALID_DATA; search_range /= 2; range_shift /= 2; /* `search range' is the greatest power of 2 that is <= num_segs */ if ( search_range > num_segs || search_range * 2 < num_segs || search_range + range_shift != num_segs || search_range != ( 1U << entry_selector ) ) FT_INVALID_DATA; } ends = table + 14; starts = table + 16 + num_segs * 2; deltas = starts + num_segs * 2; offsets = deltas + num_segs * 2; glyph_ids = offsets + num_segs * 2; /* check last segment; its end count value must be 0xFFFF */ if ( valid->level >= FT_VALIDATE_PARANOID ) { p = ends + ( num_segs - 1 ) * 2; if ( TT_PEEK_USHORT( p ) != 0xFFFFU ) FT_INVALID_DATA; } { FT_UInt start, end, offset, n; FT_UInt last_start = 0, last_end = 0; FT_Int delta; FT_Byte* p_start = starts; FT_Byte* p_end = ends; FT_Byte* p_delta = deltas; FT_Byte* p_offset = offsets; for ( n = 0; n < num_segs; n++ ) { p = p_offset; start = TT_NEXT_USHORT( p_start ); end = TT_NEXT_USHORT( p_end ); delta = TT_NEXT_SHORT( p_delta ); offset = TT_NEXT_USHORT( p_offset ); if ( start > end ) FT_INVALID_DATA; /* this test should be performed at default validation level; */ /* unfortunately, some popular Asian fonts have overlapping */ /* ranges in their charmaps */ /* */ if ( start <= last_end && n > 0 ) { if ( valid->level >= FT_VALIDATE_TIGHT ) FT_INVALID_DATA; else { /* allow overlapping segments, provided their start points */ /* and end points, respectively, are in ascending order */ /* */ if ( last_start > start || last_end > end ) error |= TT_CMAP_FLAG_UNSORTED; else error |= TT_CMAP_FLAG_OVERLAPPING; } } if ( offset && offset != 0xFFFFU ) { p += offset; /* start of glyph ID array */ /* check that we point within the glyph IDs table only */ if ( valid->level >= FT_VALIDATE_TIGHT ) { if ( p < glyph_ids || p + ( end - start + 1 ) * 2 > table + length ) FT_INVALID_DATA; } /* Some fonts handle the last segment incorrectly. In */ /* theory, 0xFFFF might point to an ordinary glyph -- */ /* a cmap 4 is versatile and could be used for any */ /* encoding, not only Unicode. However, reality shows */ /* that far too many fonts are sloppy and incorrectly */ /* set all fields but `start' and `end' for the last */ /* segment if it contains only a single character. */ /* */ /* We thus omit the test here, delaying it to the */ /* routines which actually access the cmap. */ else if ( n != num_segs - 1 || !( start == 0xFFFFU && end == 0xFFFFU ) ) { if ( p < glyph_ids || p + ( end - start + 1 ) * 2 > valid->limit ) FT_INVALID_DATA; } /* check glyph indices within the segment range */ if ( valid->level >= FT_VALIDATE_TIGHT ) { FT_UInt i, idx; for ( i = start; i < end; i++ ) { idx = FT_NEXT_USHORT( p ); if ( idx != 0 ) { idx = (FT_UInt)( idx + delta ) & 0xFFFFU; if ( idx >= TT_VALID_GLYPH_COUNT( valid ) ) FT_INVALID_GLYPH_ID; } } } } else if ( offset == 0xFFFFU ) { /* some fonts (erroneously?) use a range offset of 0xFFFF */ /* to mean missing glyph in cmap table */ /* */ if ( valid->level >= FT_VALIDATE_PARANOID || n != num_segs - 1 || !( start == 0xFFFFU && end == 0xFFFFU ) ) FT_INVALID_DATA; } last_start = start; last_end = end; } } return error; } static FT_UInt tt_cmap4_char_map_linear( TT_CMap cmap, FT_UInt32* pcharcode, FT_Bool next ) { FT_UInt num_segs2, start, end, offset; FT_Int delta; FT_UInt i, num_segs; FT_UInt32 charcode = *pcharcode; FT_UInt gindex = 0; FT_Byte* p; p = cmap->data + 6; num_segs2 = FT_PAD_FLOOR( TT_PEEK_USHORT( p ), 2 ); num_segs = num_segs2 >> 1; if ( !num_segs ) return 0; if ( next ) charcode++; /* linear search */ for ( ; charcode <= 0xFFFFU; charcode++ ) { FT_Byte* q; p = cmap->data + 14; /* ends table */ q = cmap->data + 16 + num_segs2; /* starts table */ for ( i = 0; i < num_segs; i++ ) { end = TT_NEXT_USHORT( p ); start = TT_NEXT_USHORT( q ); if ( charcode >= start && charcode <= end ) { p = q - 2 + num_segs2; delta = TT_PEEK_SHORT( p ); p += num_segs2; offset = TT_PEEK_USHORT( p ); /* some fonts have an incorrect last segment; */ /* we have to catch it */ if ( i >= num_segs - 1 && start == 0xFFFFU && end == 0xFFFFU ) { TT_Face face = (TT_Face)cmap->cmap.charmap.face; FT_Byte* limit = face->cmap_table + face->cmap_size; if ( offset && p + offset + 2 > limit ) { delta = 1; offset = 0; } } if ( offset == 0xFFFFU ) continue; if ( offset ) { p += offset + ( charcode - start ) * 2; gindex = TT_PEEK_USHORT( p ); if ( gindex != 0 ) gindex = (FT_UInt)( gindex + delta ) & 0xFFFFU; } else gindex = (FT_UInt)( charcode + delta ) & 0xFFFFU; break; } } if ( !next || gindex ) break; } if ( next && gindex ) *pcharcode = charcode; return gindex; } static FT_UInt tt_cmap4_char_map_binary( TT_CMap cmap, FT_UInt32* pcharcode, FT_Bool next ) { FT_UInt num_segs2, start, end, offset; FT_Int delta; FT_UInt max, min, mid, num_segs; FT_UInt charcode = (FT_UInt)*pcharcode; FT_UInt gindex = 0; FT_Byte* p; p = cmap->data + 6; num_segs2 = FT_PAD_FLOOR( TT_PEEK_USHORT( p ), 2 ); if ( !num_segs2 ) return 0; num_segs = num_segs2 >> 1; /* make compiler happy */ mid = num_segs; end = 0xFFFFU; if ( next ) charcode++; min = 0; max = num_segs; /* binary search */ while ( min < max ) { mid = ( min + max ) >> 1; p = cmap->data + 14 + mid * 2; end = TT_PEEK_USHORT( p ); p += 2 + num_segs2; start = TT_PEEK_USHORT( p ); if ( charcode < start ) max = mid; else if ( charcode > end ) min = mid + 1; else { p += num_segs2; delta = TT_PEEK_SHORT( p ); p += num_segs2; offset = TT_PEEK_USHORT( p ); /* some fonts have an incorrect last segment; */ /* we have to catch it */ if ( mid >= num_segs - 1 && start == 0xFFFFU && end == 0xFFFFU ) { TT_Face face = (TT_Face)cmap->cmap.charmap.face; FT_Byte* limit = face->cmap_table + face->cmap_size; if ( offset && p + offset + 2 > limit ) { delta = 1; offset = 0; } } /* search the first segment containing `charcode' */ if ( cmap->flags & TT_CMAP_FLAG_OVERLAPPING ) { FT_UInt i; /* call the current segment `max' */ max = mid; if ( offset == 0xFFFFU ) mid = max + 1; /* search in segments before the current segment */ for ( i = max ; i > 0; i-- ) { FT_UInt prev_end; FT_Byte* old_p; old_p = p; p = cmap->data + 14 + ( i - 1 ) * 2; prev_end = TT_PEEK_USHORT( p ); if ( charcode > prev_end ) { p = old_p; break; } end = prev_end; p += 2 + num_segs2; start = TT_PEEK_USHORT( p ); p += num_segs2; delta = TT_PEEK_SHORT( p ); p += num_segs2; offset = TT_PEEK_USHORT( p ); if ( offset != 0xFFFFU ) mid = i - 1; } /* no luck */ if ( mid == max + 1 ) { if ( i != max ) { p = cmap->data + 14 + max * 2; end = TT_PEEK_USHORT( p ); p += 2 + num_segs2; start = TT_PEEK_USHORT( p ); p += num_segs2; delta = TT_PEEK_SHORT( p ); p += num_segs2; offset = TT_PEEK_USHORT( p ); } mid = max; /* search in segments after the current segment */ for ( i = max + 1; i < num_segs; i++ ) { FT_UInt next_end, next_start; p = cmap->data + 14 + i * 2; next_end = TT_PEEK_USHORT( p ); p += 2 + num_segs2; next_start = TT_PEEK_USHORT( p ); if ( charcode < next_start ) break; end = next_end; start = next_start; p += num_segs2; delta = TT_PEEK_SHORT( p ); p += num_segs2; offset = TT_PEEK_USHORT( p ); if ( offset != 0xFFFFU ) mid = i; } i--; /* still no luck */ if ( mid == max ) { mid = i; break; } } /* end, start, delta, and offset are for the i'th segment */ if ( mid != i ) { p = cmap->data + 14 + mid * 2; end = TT_PEEK_USHORT( p ); p += 2 + num_segs2; start = TT_PEEK_USHORT( p ); p += num_segs2; delta = TT_PEEK_SHORT( p ); p += num_segs2; offset = TT_PEEK_USHORT( p ); } } else { if ( offset == 0xFFFFU ) break; } if ( offset ) { p += offset + ( charcode - start ) * 2; gindex = TT_PEEK_USHORT( p ); if ( gindex != 0 ) gindex = (FT_UInt)( gindex + delta ) & 0xFFFFU; } else gindex = (FT_UInt)( charcode + delta ) & 0xFFFFU; break; } } if ( next ) { TT_CMap4 cmap4 = (TT_CMap4)cmap; /* if `charcode' is not in any segment, then `mid' is */ /* the segment nearest to `charcode' */ /* */ if ( charcode > end ) { mid++; if ( mid == num_segs ) return 0; } if ( tt_cmap4_set_range( cmap4, mid ) ) { if ( gindex ) *pcharcode = charcode; } else { cmap4->cur_charcode = charcode; if ( gindex ) cmap4->cur_gindex = gindex; else { cmap4->cur_charcode = charcode; tt_cmap4_next( cmap4 ); gindex = cmap4->cur_gindex; } if ( gindex ) *pcharcode = cmap4->cur_charcode; } } return gindex; } FT_CALLBACK_DEF( FT_UInt ) tt_cmap4_char_index( TT_CMap cmap, FT_UInt32 char_code ) { if ( char_code >= 0x10000UL ) return 0; if ( cmap->flags & TT_CMAP_FLAG_UNSORTED ) return tt_cmap4_char_map_linear( cmap, &char_code, 0 ); else return tt_cmap4_char_map_binary( cmap, &char_code, 0 ); } FT_CALLBACK_DEF( FT_UInt32 ) tt_cmap4_char_next( TT_CMap cmap, FT_UInt32 *pchar_code ) { FT_UInt gindex; if ( *pchar_code >= 0xFFFFU ) return 0; if ( cmap->flags & TT_CMAP_FLAG_UNSORTED ) gindex = tt_cmap4_char_map_linear( cmap, pchar_code, 1 ); else { TT_CMap4 cmap4 = (TT_CMap4)cmap; /* no need to search */ if ( *pchar_code == cmap4->cur_charcode ) { tt_cmap4_next( cmap4 ); gindex = cmap4->cur_gindex; if ( gindex ) *pchar_code = cmap4->cur_charcode; } else gindex = tt_cmap4_char_map_binary( cmap, pchar_code, 1 ); } return gindex; } FT_CALLBACK_DEF( FT_Error ) tt_cmap4_get_info( TT_CMap cmap, TT_CMapInfo *cmap_info ) { FT_Byte* p = cmap->data + 4; cmap_info->format = 4; cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p ); return FT_Err_Ok; } FT_DEFINE_TT_CMAP( tt_cmap4_class_rec, sizeof ( TT_CMap4Rec ), (FT_CMap_InitFunc) tt_cmap4_init, (FT_CMap_DoneFunc) NULL, (FT_CMap_CharIndexFunc)tt_cmap4_char_index, (FT_CMap_CharNextFunc) tt_cmap4_char_next, NULL, NULL, NULL, NULL, NULL, 4, (TT_CMap_ValidateFunc)tt_cmap4_validate, (TT_CMap_Info_GetFunc)tt_cmap4_get_info ) #endif /* TT_CONFIG_CMAP_FORMAT_4 */ /*************************************************************************/ /*************************************************************************/ /***** *****/ /***** FORMAT 6 *****/ /***** *****/ /*************************************************************************/ /*************************************************************************/ /*************************************************************************/ /* */ /* TABLE OVERVIEW */ /* -------------- */ /* */ /* NAME OFFSET TYPE DESCRIPTION */ /* */ /* format 0 USHORT must be 4 */ /* length 2 USHORT table length in bytes */ /* language 4 USHORT Mac language code */ /* */ /* first 6 USHORT first segment code */ /* count 8 USHORT segment size in chars */ /* glyphIds 10 USHORT[count] glyph IDs */ /* */ /* A very simplified segment mapping. */ /* */ #ifdef TT_CONFIG_CMAP_FORMAT_6 FT_CALLBACK_DEF( FT_Error ) tt_cmap6_validate( FT_Byte* table, FT_Validator valid ) { FT_Byte* p; FT_UInt length, count; if ( table + 10 > valid->limit ) FT_INVALID_TOO_SHORT; p = table + 2; length = TT_NEXT_USHORT( p ); p = table + 8; /* skip language and start index */ count = TT_NEXT_USHORT( p ); if ( table + length > valid->limit || length < 10 + count * 2 ) FT_INVALID_TOO_SHORT; /* check glyph indices */ if ( valid->level >= FT_VALIDATE_TIGHT ) { FT_UInt gindex; for ( ; count > 0; count-- ) { gindex = TT_NEXT_USHORT( p ); if ( gindex >= TT_VALID_GLYPH_COUNT( valid ) ) FT_INVALID_GLYPH_ID; } } return FT_Err_Ok; } FT_CALLBACK_DEF( FT_UInt ) tt_cmap6_char_index( TT_CMap cmap, FT_UInt32 char_code ) { FT_Byte* table = cmap->data; FT_UInt result = 0; FT_Byte* p = table + 6; FT_UInt start = TT_NEXT_USHORT( p ); FT_UInt count = TT_NEXT_USHORT( p ); FT_UInt idx = (FT_UInt)( char_code - start ); if ( idx < count ) { p += 2 * idx; result = TT_PEEK_USHORT( p ); } return result; } FT_CALLBACK_DEF( FT_UInt32 ) tt_cmap6_char_next( TT_CMap cmap, FT_UInt32 *pchar_code ) { FT_Byte* table = cmap->data; FT_UInt32 result = 0; FT_UInt32 char_code = *pchar_code + 1; FT_UInt gindex = 0; FT_Byte* p = table + 6; FT_UInt start = TT_NEXT_USHORT( p ); FT_UInt count = TT_NEXT_USHORT( p ); FT_UInt idx; if ( char_code >= 0x10000UL ) goto Exit; if ( char_code < start ) char_code = start; idx = (FT_UInt)( char_code - start ); p += 2 * idx; for ( ; idx < count; idx++ ) { gindex = TT_NEXT_USHORT( p ); if ( gindex != 0 ) { result = char_code; break; } char_code++; } Exit: *pchar_code = result; return gindex; } FT_CALLBACK_DEF( FT_Error ) tt_cmap6_get_info( TT_CMap cmap, TT_CMapInfo *cmap_info ) { FT_Byte* p = cmap->data + 4; cmap_info->format = 6; cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p ); return FT_Err_Ok; } FT_DEFINE_TT_CMAP( tt_cmap6_class_rec, sizeof ( TT_CMapRec ), (FT_CMap_InitFunc) tt_cmap_init, (FT_CMap_DoneFunc) NULL, (FT_CMap_CharIndexFunc)tt_cmap6_char_index, (FT_CMap_CharNextFunc) tt_cmap6_char_next, NULL, NULL, NULL, NULL, NULL, 6, (TT_CMap_ValidateFunc)tt_cmap6_validate, (TT_CMap_Info_GetFunc)tt_cmap6_get_info ) #endif /* TT_CONFIG_CMAP_FORMAT_6 */ /*************************************************************************/ /*************************************************************************/ /***** *****/ /***** FORMAT 8 *****/ /***** *****/ /***** It is hard to completely understand what the OpenType spec *****/ /***** says about this format, but here is my conclusion. *****/ /***** *****/ /***** The purpose of this format is to easily map UTF-16 text to *****/ /***** glyph indices. Basically, the `char_code' must be in one of *****/ /***** the following formats: *****/ /***** *****/ /***** - A 16-bit value that isn't part of the Unicode Surrogates *****/ /***** Area (i.e. U+D800-U+DFFF). *****/ /***** *****/ /***** - A 32-bit value, made of two surrogate values, i.e.. if *****/ /***** `char_code = (char_hi << 16) | char_lo', then both *****/ /***** `char_hi' and `char_lo' must be in the Surrogates Area. *****/ /***** Area. *****/ /***** *****/ /***** The `is32' table embedded in the charmap indicates whether a *****/ /***** given 16-bit value is in the surrogates area or not. *****/ /***** *****/ /***** So, for any given `char_code', we can assert the following: *****/ /***** *****/ /***** If `char_hi == 0' then we must have `is32[char_lo] == 0'. *****/ /***** *****/ /***** If `char_hi != 0' then we must have both *****/ /***** `is32[char_hi] != 0' and `is32[char_lo] != 0'. *****/ /***** *****/ /*************************************************************************/ /*************************************************************************/ /*************************************************************************/ /* */ /* TABLE OVERVIEW */ /* -------------- */ /* */ /* NAME OFFSET TYPE DESCRIPTION */ /* */ /* format 0 USHORT must be 8 */ /* reserved 2 USHORT reserved */ /* length 4 ULONG length in bytes */ /* language 8 ULONG Mac language code */ /* is32 12 BYTE[8192] 32-bitness bitmap */ /* count 8204 ULONG number of groups */ /* */ /* This header is followed by `count' groups of the following format: */ /* */ /* start 0 ULONG first charcode */ /* end 4 ULONG last charcode */ /* startId 8 ULONG start glyph ID for the group */ /* */ #ifdef TT_CONFIG_CMAP_FORMAT_8 FT_CALLBACK_DEF( FT_Error ) tt_cmap8_validate( FT_Byte* table, FT_Validator valid ) { FT_Byte* p = table + 4; FT_Byte* is32; FT_UInt32 length; FT_UInt32 num_groups; if ( table + 16 + 8192 > valid->limit ) FT_INVALID_TOO_SHORT; length = TT_NEXT_ULONG( p ); if ( length > (FT_UInt32)( valid->limit - table ) || length < 8192 + 16 ) FT_INVALID_TOO_SHORT; is32 = table + 12; p = is32 + 8192; /* skip `is32' array */ num_groups = TT_NEXT_ULONG( p ); if ( p + num_groups * 12 > valid->limit ) FT_INVALID_TOO_SHORT; /* check groups, they must be in increasing order */ { FT_UInt32 n, start, end, start_id, count, last = 0; for ( n = 0; n < num_groups; n++ ) { FT_UInt hi, lo; start = TT_NEXT_ULONG( p ); end = TT_NEXT_ULONG( p ); start_id = TT_NEXT_ULONG( p ); if ( start > end ) FT_INVALID_DATA; if ( n > 0 && start <= last ) FT_INVALID_DATA; if ( valid->level >= FT_VALIDATE_TIGHT ) { if ( start_id + end - start >= TT_VALID_GLYPH_COUNT( valid ) ) FT_INVALID_GLYPH_ID; count = (FT_UInt32)( end - start + 1 ); if ( start & ~0xFFFFU ) { /* start_hi != 0; check that is32[i] is 1 for each i in */ /* the `hi' and `lo' of the range [start..end] */ for ( ; count > 0; count--, start++ ) { hi = (FT_UInt)( start >> 16 ); lo = (FT_UInt)( start & 0xFFFFU ); if ( (is32[hi >> 3] & ( 0x80 >> ( hi & 7 ) ) ) == 0 ) FT_INVALID_DATA; if ( (is32[lo >> 3] & ( 0x80 >> ( lo & 7 ) ) ) == 0 ) FT_INVALID_DATA; } } else { /* start_hi == 0; check that is32[i] is 0 for each i in */ /* the range [start..end] */ /* end_hi cannot be != 0! */ if ( end & ~0xFFFFU ) FT_INVALID_DATA; for ( ; count > 0; count--, start++ ) { lo = (FT_UInt)( start & 0xFFFFU ); if ( (is32[lo >> 3] & ( 0x80 >> ( lo & 7 ) ) ) != 0 ) FT_INVALID_DATA; } } } last = end; } } return FT_Err_Ok; } FT_CALLBACK_DEF( FT_UInt ) tt_cmap8_char_index( TT_CMap cmap, FT_UInt32 char_code ) { FT_Byte* table = cmap->data; FT_UInt result = 0; FT_Byte* p = table + 8204; FT_UInt32 num_groups = TT_NEXT_ULONG( p ); FT_UInt32 start, end, start_id; for ( ; num_groups > 0; num_groups-- ) { start = TT_NEXT_ULONG( p ); end = TT_NEXT_ULONG( p ); start_id = TT_NEXT_ULONG( p ); if ( char_code < start ) break; if ( char_code <= end ) { result = (FT_UInt)( start_id + char_code - start ); break; } } return result; } FT_CALLBACK_DEF( FT_UInt32 ) tt_cmap8_char_next( TT_CMap cmap, FT_UInt32 *pchar_code ) { FT_UInt32 result = 0; FT_UInt32 char_code = *pchar_code + 1; FT_UInt gindex = 0; FT_Byte* table = cmap->data; FT_Byte* p = table + 8204; FT_UInt32 num_groups = TT_NEXT_ULONG( p ); FT_UInt32 start, end, start_id; p = table + 8208; for ( ; num_groups > 0; num_groups-- ) { start = TT_NEXT_ULONG( p ); end = TT_NEXT_ULONG( p ); start_id = TT_NEXT_ULONG( p ); if ( char_code < start ) char_code = start; if ( char_code <= end ) { gindex = (FT_UInt)( char_code - start + start_id ); if ( gindex != 0 ) { result = char_code; goto Exit; } } } Exit: *pchar_code = result; return gindex; } FT_CALLBACK_DEF( FT_Error ) tt_cmap8_get_info( TT_CMap cmap, TT_CMapInfo *cmap_info ) { FT_Byte* p = cmap->data + 8; cmap_info->format = 8; cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p ); return FT_Err_Ok; } FT_DEFINE_TT_CMAP( tt_cmap8_class_rec, sizeof ( TT_CMapRec ), (FT_CMap_InitFunc) tt_cmap_init, (FT_CMap_DoneFunc) NULL, (FT_CMap_CharIndexFunc)tt_cmap8_char_index, (FT_CMap_CharNextFunc) tt_cmap8_char_next, NULL, NULL, NULL, NULL, NULL, 8, (TT_CMap_ValidateFunc)tt_cmap8_validate, (TT_CMap_Info_GetFunc)tt_cmap8_get_info ) #endif /* TT_CONFIG_CMAP_FORMAT_8 */ /*************************************************************************/ /*************************************************************************/ /***** *****/ /***** FORMAT 10 *****/ /***** *****/ /*************************************************************************/ /*************************************************************************/ /*************************************************************************/ /* */ /* TABLE OVERVIEW */ /* -------------- */ /* */ /* NAME OFFSET TYPE DESCRIPTION */ /* */ /* format 0 USHORT must be 10 */ /* reserved 2 USHORT reserved */ /* length 4 ULONG length in bytes */ /* language 8 ULONG Mac language code */ /* */ /* start 12 ULONG first char in range */ /* count 16 ULONG number of chars in range */ /* glyphIds 20 USHORT[count] glyph indices covered */ /* */ #ifdef TT_CONFIG_CMAP_FORMAT_10 FT_CALLBACK_DEF( FT_Error ) tt_cmap10_validate( FT_Byte* table, FT_Validator valid ) { FT_Byte* p = table + 4; FT_ULong length, count; if ( table + 20 > valid->limit ) FT_INVALID_TOO_SHORT; length = TT_NEXT_ULONG( p ); p = table + 16; count = TT_NEXT_ULONG( p ); if ( length > (FT_ULong)( valid->limit - table ) || length < 20 + count * 2 ) FT_INVALID_TOO_SHORT; /* check glyph indices */ if ( valid->level >= FT_VALIDATE_TIGHT ) { FT_UInt gindex; for ( ; count > 0; count-- ) { gindex = TT_NEXT_USHORT( p ); if ( gindex >= TT_VALID_GLYPH_COUNT( valid ) ) FT_INVALID_GLYPH_ID; } } return FT_Err_Ok; } FT_CALLBACK_DEF( FT_UInt ) tt_cmap10_char_index( TT_CMap cmap, FT_UInt32 char_code ) { FT_Byte* table = cmap->data; FT_UInt result = 0; FT_Byte* p = table + 12; FT_UInt32 start = TT_NEXT_ULONG( p ); FT_UInt32 count = TT_NEXT_ULONG( p ); FT_UInt32 idx = (FT_ULong)( char_code - start ); if ( idx < count ) { p += 2 * idx; result = TT_PEEK_USHORT( p ); } return result; } FT_CALLBACK_DEF( FT_UInt32 ) tt_cmap10_char_next( TT_CMap cmap, FT_UInt32 *pchar_code ) { FT_Byte* table = cmap->data; FT_UInt32 char_code = *pchar_code + 1; FT_UInt gindex = 0; FT_Byte* p = table + 12; FT_UInt32 start = TT_NEXT_ULONG( p ); FT_UInt32 count = TT_NEXT_ULONG( p ); FT_UInt32 idx; if ( char_code < start ) char_code = start; idx = (FT_UInt32)( char_code - start ); p += 2 * idx; for ( ; idx < count; idx++ ) { gindex = TT_NEXT_USHORT( p ); if ( gindex != 0 ) break; char_code++; } *pchar_code = char_code; return gindex; } FT_CALLBACK_DEF( FT_Error ) tt_cmap10_get_info( TT_CMap cmap, TT_CMapInfo *cmap_info ) { FT_Byte* p = cmap->data + 8; cmap_info->format = 10; cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p ); return FT_Err_Ok; } FT_DEFINE_TT_CMAP( tt_cmap10_class_rec, sizeof ( TT_CMapRec ), (FT_CMap_InitFunc) tt_cmap_init, (FT_CMap_DoneFunc) NULL, (FT_CMap_CharIndexFunc)tt_cmap10_char_index, (FT_CMap_CharNextFunc) tt_cmap10_char_next, NULL, NULL, NULL, NULL, NULL, 10, (TT_CMap_ValidateFunc)tt_cmap10_validate, (TT_CMap_Info_GetFunc)tt_cmap10_get_info ) #endif /* TT_CONFIG_CMAP_FORMAT_10 */ /*************************************************************************/ /*************************************************************************/ /***** *****/ /***** FORMAT 12 *****/ /***** *****/ /*************************************************************************/ /*************************************************************************/ /*************************************************************************/ /* */ /* TABLE OVERVIEW */ /* -------------- */ /* */ /* NAME OFFSET TYPE DESCRIPTION */ /* */ /* format 0 USHORT must be 12 */ /* reserved 2 USHORT reserved */ /* length 4 ULONG length in bytes */ /* language 8 ULONG Mac language code */ /* count 12 ULONG number of groups */ /* 16 */ /* */ /* This header is followed by `count' groups of the following format: */ /* */ /* start 0 ULONG first charcode */ /* end 4 ULONG last charcode */ /* startId 8 ULONG start glyph ID for the group */ /* */ #ifdef TT_CONFIG_CMAP_FORMAT_12 typedef struct TT_CMap12Rec_ { TT_CMapRec cmap; FT_Bool valid; FT_ULong cur_charcode; FT_UInt cur_gindex; FT_ULong cur_group; FT_ULong num_groups; } TT_CMap12Rec, *TT_CMap12; FT_CALLBACK_DEF( FT_Error ) tt_cmap12_init( TT_CMap12 cmap, FT_Byte* table ) { cmap->cmap.data = table; table += 12; cmap->num_groups = FT_PEEK_ULONG( table ); cmap->valid = 0; return FT_Err_Ok; } FT_CALLBACK_DEF( FT_Error ) tt_cmap12_validate( FT_Byte* table, FT_Validator valid ) { FT_Byte* p; FT_ULong length; FT_ULong num_groups; if ( table + 16 > valid->limit ) FT_INVALID_TOO_SHORT; p = table + 4; length = TT_NEXT_ULONG( p ); p = table + 12; num_groups = TT_NEXT_ULONG( p ); if ( length > (FT_ULong)( valid->limit - table ) || length < 16 + 12 * num_groups ) FT_INVALID_TOO_SHORT; /* check groups, they must be in increasing order */ { FT_ULong n, start, end, start_id, last = 0; for ( n = 0; n < num_groups; n++ ) { start = TT_NEXT_ULONG( p ); end = TT_NEXT_ULONG( p ); start_id = TT_NEXT_ULONG( p ); if ( start > end ) FT_INVALID_DATA; if ( n > 0 && start <= last ) FT_INVALID_DATA; if ( valid->level >= FT_VALIDATE_TIGHT ) { if ( start_id + end - start >= TT_VALID_GLYPH_COUNT( valid ) ) FT_INVALID_GLYPH_ID; } last = end; } } return FT_Err_Ok; } /* search the index of the charcode next to cmap->cur_charcode */ /* cmap->cur_group should be set up properly by caller */ /* */ static void tt_cmap12_next( TT_CMap12 cmap ) { FT_Byte* p; FT_ULong start, end, start_id, char_code; FT_ULong n; FT_UInt gindex; if ( cmap->cur_charcode >= 0xFFFFFFFFUL ) goto Fail; char_code = cmap->cur_charcode + 1; for ( n = cmap->cur_group; n < cmap->num_groups; n++ ) { p = cmap->cmap.data + 16 + 12 * n; start = TT_NEXT_ULONG( p ); end = TT_NEXT_ULONG( p ); start_id = TT_PEEK_ULONG( p ); if ( char_code < start ) char_code = start; for ( ; char_code <= end; char_code++ ) { gindex = (FT_UInt)( start_id + char_code - start ); if ( gindex ) { cmap->cur_charcode = char_code;; cmap->cur_gindex = gindex; cmap->cur_group = n; return; } } } Fail: cmap->valid = 0; } static FT_UInt tt_cmap12_char_map_binary( TT_CMap cmap, FT_UInt32* pchar_code, FT_Bool next ) { FT_UInt gindex = 0; FT_Byte* p = cmap->data + 12; FT_UInt32 num_groups = TT_PEEK_ULONG( p ); FT_UInt32 char_code = *pchar_code; FT_UInt32 start, end, start_id; FT_UInt32 max, min, mid; if ( !num_groups ) return 0; /* make compiler happy */ mid = num_groups; end = 0xFFFFFFFFUL; if ( next ) char_code++; min = 0; max = num_groups; /* binary search */ while ( min < max ) { mid = ( min + max ) >> 1; p = cmap->data + 16 + 12 * mid; start = TT_NEXT_ULONG( p ); end = TT_NEXT_ULONG( p ); if ( char_code < start ) max = mid; else if ( char_code > end ) min = mid + 1; else { start_id = TT_PEEK_ULONG( p ); gindex = (FT_UInt)( start_id + char_code - start ); break; } } if ( next ) { TT_CMap12 cmap12 = (TT_CMap12)cmap; /* if `char_code' is not in any group, then `mid' is */ /* the group nearest to `char_code' */ /* */ if ( char_code > end ) { mid++; if ( mid == num_groups ) return 0; } cmap12->valid = 1; cmap12->cur_charcode = char_code; cmap12->cur_group = mid; if ( !gindex ) { tt_cmap12_next( cmap12 ); if ( cmap12->valid ) gindex = cmap12->cur_gindex; } else cmap12->cur_gindex = gindex; if ( gindex ) *pchar_code = cmap12->cur_charcode; } return gindex; } FT_CALLBACK_DEF( FT_UInt ) tt_cmap12_char_index( TT_CMap cmap, FT_UInt32 char_code ) { return tt_cmap12_char_map_binary( cmap, &char_code, 0 ); } FT_CALLBACK_DEF( FT_UInt32 ) tt_cmap12_char_next( TT_CMap cmap, FT_UInt32 *pchar_code ) { TT_CMap12 cmap12 = (TT_CMap12)cmap; FT_ULong gindex; if ( cmap12->cur_charcode >= 0xFFFFFFFFUL ) return 0; /* no need to search */ if ( cmap12->valid && cmap12->cur_charcode == *pchar_code ) { tt_cmap12_next( cmap12 ); if ( cmap12->valid ) { gindex = cmap12->cur_gindex; /* XXX: check cur_charcode overflow is expected */ if ( gindex ) *pchar_code = (FT_UInt32)cmap12->cur_charcode; } else gindex = 0; } else gindex = tt_cmap12_char_map_binary( cmap, pchar_code, 1 ); /* XXX: check gindex overflow is expected */ return (FT_UInt32)gindex; } FT_CALLBACK_DEF( FT_Error ) tt_cmap12_get_info( TT_CMap cmap, TT_CMapInfo *cmap_info ) { FT_Byte* p = cmap->data + 8; cmap_info->format = 12; cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p ); return FT_Err_Ok; } FT_DEFINE_TT_CMAP( tt_cmap12_class_rec, sizeof ( TT_CMap12Rec ), (FT_CMap_InitFunc) tt_cmap12_init, (FT_CMap_DoneFunc) NULL, (FT_CMap_CharIndexFunc)tt_cmap12_char_index, (FT_CMap_CharNextFunc) tt_cmap12_char_next, NULL, NULL, NULL, NULL, NULL, 12, (TT_CMap_ValidateFunc)tt_cmap12_validate, (TT_CMap_Info_GetFunc)tt_cmap12_get_info ) #endif /* TT_CONFIG_CMAP_FORMAT_12 */ /*************************************************************************/ /*************************************************************************/ /***** *****/ /***** FORMAT 13 *****/ /***** *****/ /*************************************************************************/ /*************************************************************************/ /*************************************************************************/ /* */ /* TABLE OVERVIEW */ /* -------------- */ /* */ /* NAME OFFSET TYPE DESCRIPTION */ /* */ /* format 0 USHORT must be 13 */ /* reserved 2 USHORT reserved */ /* length 4 ULONG length in bytes */ /* language 8 ULONG Mac language code */ /* count 12 ULONG number of groups */ /* 16 */ /* */ /* This header is followed by `count' groups of the following format: */ /* */ /* start 0 ULONG first charcode */ /* end 4 ULONG last charcode */ /* glyphId 8 ULONG glyph ID for the whole group */ /* */ #ifdef TT_CONFIG_CMAP_FORMAT_13 typedef struct TT_CMap13Rec_ { TT_CMapRec cmap; FT_Bool valid; FT_ULong cur_charcode; FT_UInt cur_gindex; FT_ULong cur_group; FT_ULong num_groups; } TT_CMap13Rec, *TT_CMap13; FT_CALLBACK_DEF( FT_Error ) tt_cmap13_init( TT_CMap13 cmap, FT_Byte* table ) { cmap->cmap.data = table; table += 12; cmap->num_groups = FT_PEEK_ULONG( table ); cmap->valid = 0; return FT_Err_Ok; } FT_CALLBACK_DEF( FT_Error ) tt_cmap13_validate( FT_Byte* table, FT_Validator valid ) { FT_Byte* p; FT_ULong length; FT_ULong num_groups; if ( table + 16 > valid->limit ) FT_INVALID_TOO_SHORT; p = table + 4; length = TT_NEXT_ULONG( p ); p = table + 12; num_groups = TT_NEXT_ULONG( p ); if ( length > (FT_ULong)( valid->limit - table ) || length < 16 + 12 * num_groups ) FT_INVALID_TOO_SHORT; /* check groups, they must be in increasing order */ { FT_ULong n, start, end, glyph_id, last = 0; for ( n = 0; n < num_groups; n++ ) { start = TT_NEXT_ULONG( p ); end = TT_NEXT_ULONG( p ); glyph_id = TT_NEXT_ULONG( p ); if ( start > end ) FT_INVALID_DATA; if ( n > 0 && start <= last ) FT_INVALID_DATA; if ( valid->level >= FT_VALIDATE_TIGHT ) { if ( glyph_id >= TT_VALID_GLYPH_COUNT( valid ) ) FT_INVALID_GLYPH_ID; } last = end; } } return FT_Err_Ok; } /* search the index of the charcode next to cmap->cur_charcode */ /* cmap->cur_group should be set up properly by caller */ /* */ static void tt_cmap13_next( TT_CMap13 cmap ) { FT_Byte* p; FT_ULong start, end, glyph_id, char_code; FT_ULong n; FT_UInt gindex; if ( cmap->cur_charcode >= 0xFFFFFFFFUL ) goto Fail; char_code = cmap->cur_charcode + 1; for ( n = cmap->cur_group; n < cmap->num_groups; n++ ) { p = cmap->cmap.data + 16 + 12 * n; start = TT_NEXT_ULONG( p ); end = TT_NEXT_ULONG( p ); glyph_id = TT_PEEK_ULONG( p ); if ( char_code < start ) char_code = start; if ( char_code <= end ) { gindex = (FT_UInt)glyph_id; if ( gindex ) { cmap->cur_charcode = char_code;; cmap->cur_gindex = gindex; cmap->cur_group = n; return; } } } Fail: cmap->valid = 0; } static FT_UInt tt_cmap13_char_map_binary( TT_CMap cmap, FT_UInt32* pchar_code, FT_Bool next ) { FT_UInt gindex = 0; FT_Byte* p = cmap->data + 12; FT_UInt32 num_groups = TT_PEEK_ULONG( p ); FT_UInt32 char_code = *pchar_code; FT_UInt32 start, end; FT_UInt32 max, min, mid; if ( !num_groups ) return 0; /* make compiler happy */ mid = num_groups; end = 0xFFFFFFFFUL; if ( next ) char_code++; min = 0; max = num_groups; /* binary search */ while ( min < max ) { mid = ( min + max ) >> 1; p = cmap->data + 16 + 12 * mid; start = TT_NEXT_ULONG( p ); end = TT_NEXT_ULONG( p ); if ( char_code < start ) max = mid; else if ( char_code > end ) min = mid + 1; else { gindex = (FT_UInt)TT_PEEK_ULONG( p ); break; } } if ( next ) { TT_CMap13 cmap13 = (TT_CMap13)cmap; /* if `char_code' is not in any group, then `mid' is */ /* the group nearest to `char_code' */ if ( char_code > end ) { mid++; if ( mid == num_groups ) return 0; } cmap13->valid = 1; cmap13->cur_charcode = char_code; cmap13->cur_group = mid; if ( !gindex ) { tt_cmap13_next( cmap13 ); if ( cmap13->valid ) gindex = cmap13->cur_gindex; } else cmap13->cur_gindex = gindex; if ( gindex ) *pchar_code = cmap13->cur_charcode; } return gindex; } FT_CALLBACK_DEF( FT_UInt ) tt_cmap13_char_index( TT_CMap cmap, FT_UInt32 char_code ) { return tt_cmap13_char_map_binary( cmap, &char_code, 0 ); } FT_CALLBACK_DEF( FT_UInt32 ) tt_cmap13_char_next( TT_CMap cmap, FT_UInt32 *pchar_code ) { TT_CMap13 cmap13 = (TT_CMap13)cmap; FT_UInt gindex; if ( cmap13->cur_charcode >= 0xFFFFFFFFUL ) return 0; /* no need to search */ if ( cmap13->valid && cmap13->cur_charcode == *pchar_code ) { tt_cmap13_next( cmap13 ); if ( cmap13->valid ) { gindex = cmap13->cur_gindex; if ( gindex ) *pchar_code = cmap13->cur_charcode; } else gindex = 0; } else gindex = tt_cmap13_char_map_binary( cmap, pchar_code, 1 ); return gindex; } FT_CALLBACK_DEF( FT_Error ) tt_cmap13_get_info( TT_CMap cmap, TT_CMapInfo *cmap_info ) { FT_Byte* p = cmap->data + 8; cmap_info->format = 13; cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p ); return FT_Err_Ok; } FT_DEFINE_TT_CMAP( tt_cmap13_class_rec, sizeof ( TT_CMap13Rec ), (FT_CMap_InitFunc) tt_cmap13_init, (FT_CMap_DoneFunc) NULL, (FT_CMap_CharIndexFunc)tt_cmap13_char_index, (FT_CMap_CharNextFunc) tt_cmap13_char_next, NULL, NULL, NULL, NULL, NULL, 13, (TT_CMap_ValidateFunc)tt_cmap13_validate, (TT_CMap_Info_GetFunc)tt_cmap13_get_info ) #endif /* TT_CONFIG_CMAP_FORMAT_13 */ /*************************************************************************/ /*************************************************************************/ /***** *****/ /***** FORMAT 14 *****/ /***** *****/ /*************************************************************************/ /*************************************************************************/ /*************************************************************************/ /* */ /* TABLE OVERVIEW */ /* -------------- */ /* */ /* NAME OFFSET TYPE DESCRIPTION */ /* */ /* format 0 USHORT must be 14 */ /* length 2 ULONG table length in bytes */ /* numSelector 6 ULONG number of variation sel. records */ /* */ /* Followed by numSelector records, each of which looks like */ /* */ /* varSelector 0 UINT24 Unicode codepoint of sel. */ /* defaultOff 3 ULONG offset to a default UVS table */ /* describing any variants to be found in */ /* the normal Unicode subtable. */ /* nonDefOff 7 ULONG offset to a non-default UVS table */ /* describing any variants not in the */ /* standard cmap, with GIDs here */ /* (either offset may be 0 NULL) */ /* */ /* Selectors are sorted by code point. */ /* */ /* A default Unicode Variation Selector (UVS) subtable is just a list of */ /* ranges of code points which are to be found in the standard cmap. No */ /* glyph IDs (GIDs) here. */ /* */ /* numRanges 0 ULONG number of ranges following */ /* */ /* A range looks like */ /* */ /* uniStart 0 UINT24 code point of the first character in */ /* this range */ /* additionalCnt 3 UBYTE count of additional characters in this */ /* range (zero means a range of a single */ /* character) */ /* */ /* Ranges are sorted by `uniStart'. */ /* */ /* A non-default Unicode Variation Selector (UVS) subtable is a list of */ /* mappings from codepoint to GID. */ /* */ /* numMappings 0 ULONG number of mappings */ /* */ /* A range looks like */ /* */ /* uniStart 0 UINT24 code point of the first character in */ /* this range */ /* GID 3 USHORT and its GID */ /* */ /* Ranges are sorted by `uniStart'. */ #ifdef TT_CONFIG_CMAP_FORMAT_14 typedef struct TT_CMap14Rec_ { TT_CMapRec cmap; FT_ULong num_selectors; /* This array is used to store the results of various * cmap 14 query functions. The data is overwritten * on each call to these functions. */ FT_UInt32 max_results; FT_UInt32* results; FT_Memory memory; } TT_CMap14Rec, *TT_CMap14; FT_CALLBACK_DEF( void ) tt_cmap14_done( TT_CMap14 cmap ) { FT_Memory memory = cmap->memory; cmap->max_results = 0; if ( memory != NULL && cmap->results != NULL ) FT_FREE( cmap->results ); } static FT_Error tt_cmap14_ensure( TT_CMap14 cmap, FT_UInt32 num_results, FT_Memory memory ) { FT_UInt32 old_max = cmap->max_results; FT_Error error = FT_Err_Ok; if ( num_results > cmap->max_results ) { cmap->memory = memory; if ( FT_QRENEW_ARRAY( cmap->results, old_max, num_results ) ) return error; cmap->max_results = num_results; } return error; } FT_CALLBACK_DEF( FT_Error ) tt_cmap14_init( TT_CMap14 cmap, FT_Byte* table ) { cmap->cmap.data = table; table += 6; cmap->num_selectors = FT_PEEK_ULONG( table ); cmap->max_results = 0; cmap->results = NULL; return FT_Err_Ok; } FT_CALLBACK_DEF( FT_Error ) tt_cmap14_validate( FT_Byte* table, FT_Validator valid ) { FT_Byte* p; FT_ULong length; FT_ULong num_selectors; if ( table + 2 + 4 + 4 > valid->limit ) FT_INVALID_TOO_SHORT; p = table + 2; length = TT_NEXT_ULONG( p ); num_selectors = TT_NEXT_ULONG( p ); if ( length > (FT_ULong)( valid->limit - table ) || length < 10 + 11 * num_selectors ) FT_INVALID_TOO_SHORT; /* check selectors, they must be in increasing order */ { /* we start lastVarSel at 1 because a variant selector value of 0 * isn't valid. */ FT_ULong n, lastVarSel = 1; for ( n = 0; n < num_selectors; n++ ) { FT_ULong varSel = TT_NEXT_UINT24( p ); FT_ULong defOff = TT_NEXT_ULONG( p ); FT_ULong nondefOff = TT_NEXT_ULONG( p ); if ( defOff >= length || nondefOff >= length ) FT_INVALID_TOO_SHORT; if ( varSel < lastVarSel ) FT_INVALID_DATA; lastVarSel = varSel + 1; /* check the default table (these glyphs should be reached */ /* through the normal Unicode cmap, no GIDs, just check order) */ if ( defOff != 0 ) { FT_Byte* defp = table + defOff; FT_ULong numRanges = TT_NEXT_ULONG( defp ); FT_ULong i; FT_ULong lastBase = 0; if ( defp + numRanges * 4 > valid->limit ) FT_INVALID_TOO_SHORT; for ( i = 0; i < numRanges; ++i ) { FT_ULong base = TT_NEXT_UINT24( defp ); FT_ULong cnt = FT_NEXT_BYTE( defp ); if ( base + cnt >= 0x110000UL ) /* end of Unicode */ FT_INVALID_DATA; if ( base < lastBase ) FT_INVALID_DATA; lastBase = base + cnt + 1U; } } /* and the non-default table (these glyphs are specified here) */ if ( nondefOff != 0 ) { FT_Byte* ndp = table + nondefOff; FT_ULong numMappings = TT_NEXT_ULONG( ndp ); FT_ULong i, lastUni = 0; if ( numMappings * 4 > (FT_ULong)( valid->limit - ndp ) ) FT_INVALID_TOO_SHORT; for ( i = 0; i < numMappings; ++i ) { FT_ULong uni = TT_NEXT_UINT24( ndp ); FT_ULong gid = TT_NEXT_USHORT( ndp ); if ( uni >= 0x110000UL ) /* end of Unicode */ FT_INVALID_DATA; if ( uni < lastUni ) FT_INVALID_DATA; lastUni = uni + 1U; if ( valid->level >= FT_VALIDATE_TIGHT && gid >= TT_VALID_GLYPH_COUNT( valid ) ) FT_INVALID_GLYPH_ID; } } } } return FT_Err_Ok; } FT_CALLBACK_DEF( FT_UInt ) tt_cmap14_char_index( TT_CMap cmap, FT_UInt32 char_code ) { FT_UNUSED( cmap ); FT_UNUSED( char_code ); /* This can't happen */ return 0; } FT_CALLBACK_DEF( FT_UInt32 ) tt_cmap14_char_next( TT_CMap cmap, FT_UInt32 *pchar_code ) { FT_UNUSED( cmap ); /* This can't happen */ *pchar_code = 0; return 0; } FT_CALLBACK_DEF( FT_Error ) tt_cmap14_get_info( TT_CMap cmap, TT_CMapInfo *cmap_info ) { FT_UNUSED( cmap ); cmap_info->format = 14; /* subtable 14 does not define a language field */ cmap_info->language = 0xFFFFFFFFUL; return FT_Err_Ok; } static FT_UInt tt_cmap14_char_map_def_binary( FT_Byte *base, FT_UInt32 char_code ) { FT_UInt32 numRanges = TT_PEEK_ULONG( base ); FT_UInt32 max, min; min = 0; max = numRanges; base += 4; /* binary search */ while ( min < max ) { FT_UInt32 mid = ( min + max ) >> 1; FT_Byte* p = base + 4 * mid; FT_ULong start = TT_NEXT_UINT24( p ); FT_UInt cnt = FT_NEXT_BYTE( p ); if ( char_code < start ) max = mid; else if ( char_code > start+cnt ) min = mid + 1; else return TRUE; } return FALSE; } static FT_UInt tt_cmap14_char_map_nondef_binary( FT_Byte *base, FT_UInt32 char_code ) { FT_UInt32 numMappings = TT_PEEK_ULONG( base ); FT_UInt32 max, min; min = 0; max = numMappings; base += 4; /* binary search */ while ( min < max ) { FT_UInt32 mid = ( min + max ) >> 1; FT_Byte* p = base + 5 * mid; FT_UInt32 uni = (FT_UInt32)TT_NEXT_UINT24( p ); if ( char_code < uni ) max = mid; else if ( char_code > uni ) min = mid + 1; else return TT_PEEK_USHORT( p ); } return 0; } static FT_Byte* tt_cmap14_find_variant( FT_Byte *base, FT_UInt32 variantCode ) { FT_UInt32 numVar = TT_PEEK_ULONG( base ); FT_UInt32 max, min; min = 0; max = numVar; base += 4; /* binary search */ while ( min < max ) { FT_UInt32 mid = ( min + max ) >> 1; FT_Byte* p = base + 11 * mid; FT_ULong varSel = TT_NEXT_UINT24( p ); if ( variantCode < varSel ) max = mid; else if ( variantCode > varSel ) min = mid + 1; else return p; } return NULL; } FT_CALLBACK_DEF( FT_UInt ) tt_cmap14_char_var_index( TT_CMap cmap, TT_CMap ucmap, FT_UInt32 charcode, FT_UInt32 variantSelector ) { FT_Byte* p = tt_cmap14_find_variant( cmap->data + 6, variantSelector ); FT_ULong defOff; FT_ULong nondefOff; if ( !p ) return 0; defOff = TT_NEXT_ULONG( p ); nondefOff = TT_PEEK_ULONG( p ); if ( defOff != 0 && tt_cmap14_char_map_def_binary( cmap->data + defOff, charcode ) ) { /* This is the default variant of this charcode. GID not stored */ /* here; stored in the normal Unicode charmap instead. */ return ucmap->cmap.clazz->char_index( &ucmap->cmap, charcode ); } if ( nondefOff != 0 ) return tt_cmap14_char_map_nondef_binary( cmap->data + nondefOff, charcode ); return 0; } FT_CALLBACK_DEF( FT_Int ) tt_cmap14_char_var_isdefault( TT_CMap cmap, FT_UInt32 charcode, FT_UInt32 variantSelector ) { FT_Byte* p = tt_cmap14_find_variant( cmap->data + 6, variantSelector ); FT_ULong defOff; FT_ULong nondefOff; if ( !p ) return -1; defOff = TT_NEXT_ULONG( p ); nondefOff = TT_NEXT_ULONG( p ); if ( defOff != 0 && tt_cmap14_char_map_def_binary( cmap->data + defOff, charcode ) ) return 1; if ( nondefOff != 0 && tt_cmap14_char_map_nondef_binary( cmap->data + nondefOff, charcode ) != 0 ) return 0; return -1; } FT_CALLBACK_DEF( FT_UInt32* ) tt_cmap14_variants( TT_CMap cmap, FT_Memory memory ) { TT_CMap14 cmap14 = (TT_CMap14)cmap; FT_UInt32 count = cmap14->num_selectors; FT_Byte* p = cmap->data + 10; FT_UInt32* result; FT_UInt32 i; if ( tt_cmap14_ensure( cmap14, ( count + 1 ), memory ) ) return NULL; result = cmap14->results; for ( i = 0; i < count; ++i ) { result[i] = (FT_UInt32)TT_NEXT_UINT24( p ); p += 8; } result[i] = 0; return result; } FT_CALLBACK_DEF( FT_UInt32 * ) tt_cmap14_char_variants( TT_CMap cmap, FT_Memory memory, FT_UInt32 charCode ) { TT_CMap14 cmap14 = (TT_CMap14) cmap; FT_UInt32 count = cmap14->num_selectors; FT_Byte* p = cmap->data + 10; FT_UInt32* q; if ( tt_cmap14_ensure( cmap14, ( count + 1 ), memory ) ) return NULL; for ( q = cmap14->results; count > 0; --count ) { FT_UInt32 varSel = TT_NEXT_UINT24( p ); FT_ULong defOff = TT_NEXT_ULONG( p ); FT_ULong nondefOff = TT_NEXT_ULONG( p ); if ( ( defOff != 0 && tt_cmap14_char_map_def_binary( cmap->data + defOff, charCode ) ) || ( nondefOff != 0 && tt_cmap14_char_map_nondef_binary( cmap->data + nondefOff, charCode ) != 0 ) ) { q[0] = varSel; q++; } } q[0] = 0; return cmap14->results; } static FT_UInt tt_cmap14_def_char_count( FT_Byte *p ) { FT_UInt32 numRanges = (FT_UInt32)TT_NEXT_ULONG( p ); FT_UInt tot = 0; p += 3; /* point to the first `cnt' field */ for ( ; numRanges > 0; numRanges-- ) { tot += 1 + p[0]; p += 4; } return tot; } static FT_UInt32* tt_cmap14_get_def_chars( TT_CMap cmap, FT_Byte* p, FT_Memory memory ) { TT_CMap14 cmap14 = (TT_CMap14) cmap; FT_UInt32 numRanges; FT_UInt cnt; FT_UInt32* q; cnt = tt_cmap14_def_char_count( p ); numRanges = (FT_UInt32)TT_NEXT_ULONG( p ); if ( tt_cmap14_ensure( cmap14, ( cnt + 1 ), memory ) ) return NULL; for ( q = cmap14->results; numRanges > 0; --numRanges ) { FT_UInt32 uni = (FT_UInt32)TT_NEXT_UINT24( p ); cnt = FT_NEXT_BYTE( p ) + 1; do { q[0] = uni; uni += 1; q += 1; } while ( --cnt != 0 ); } q[0] = 0; return cmap14->results; } static FT_UInt32* tt_cmap14_get_nondef_chars( TT_CMap cmap, FT_Byte *p, FT_Memory memory ) { TT_CMap14 cmap14 = (TT_CMap14) cmap; FT_UInt32 numMappings; FT_UInt i; FT_UInt32 *ret; numMappings = (FT_UInt32)TT_NEXT_ULONG( p ); if ( tt_cmap14_ensure( cmap14, ( numMappings + 1 ), memory ) ) return NULL; ret = cmap14->results; for ( i = 0; i < numMappings; ++i ) { ret[i] = (FT_UInt32)TT_NEXT_UINT24( p ); p += 2; } ret[i] = 0; return ret; } FT_CALLBACK_DEF( FT_UInt32 * ) tt_cmap14_variant_chars( TT_CMap cmap, FT_Memory memory, FT_UInt32 variantSelector ) { FT_Byte *p = tt_cmap14_find_variant( cmap->data + 6, variantSelector ); FT_Int i; FT_ULong defOff; FT_ULong nondefOff; if ( !p ) return NULL; defOff = TT_NEXT_ULONG( p ); nondefOff = TT_NEXT_ULONG( p ); if ( defOff == 0 && nondefOff == 0 ) return NULL; if ( defOff == 0 ) return tt_cmap14_get_nondef_chars( cmap, cmap->data + nondefOff, memory ); else if ( nondefOff == 0 ) return tt_cmap14_get_def_chars( cmap, cmap->data + defOff, memory ); else { /* Both a default and a non-default glyph set? That's probably not */ /* good font design, but the spec allows for it... */ TT_CMap14 cmap14 = (TT_CMap14) cmap; FT_UInt32 numRanges; FT_UInt32 numMappings; FT_UInt32 duni; FT_UInt32 dcnt; FT_UInt32 nuni; FT_Byte* dp; FT_UInt di, ni, k; FT_UInt32 *ret; p = cmap->data + nondefOff; dp = cmap->data + defOff; numMappings = (FT_UInt32)TT_NEXT_ULONG( p ); dcnt = tt_cmap14_def_char_count( dp ); numRanges = (FT_UInt32)TT_NEXT_ULONG( dp ); if ( numMappings == 0 ) return tt_cmap14_get_def_chars( cmap, cmap->data + defOff, memory ); if ( dcnt == 0 ) return tt_cmap14_get_nondef_chars( cmap, cmap->data + nondefOff, memory ); if ( tt_cmap14_ensure( cmap14, ( dcnt + numMappings + 1 ), memory ) ) return NULL; ret = cmap14->results; duni = (FT_UInt32)TT_NEXT_UINT24( dp ); dcnt = FT_NEXT_BYTE( dp ); di = 1; nuni = (FT_UInt32)TT_NEXT_UINT24( p ); p += 2; ni = 1; i = 0; for ( ;; ) { if ( nuni > duni + dcnt ) { for ( k = 0; k <= dcnt; ++k ) ret[i++] = duni + k; ++di; if ( di > numRanges ) break; duni = (FT_UInt32)TT_NEXT_UINT24( dp ); dcnt = FT_NEXT_BYTE( dp ); } else { if ( nuni < duni ) ret[i++] = nuni; /* If it is within the default range then ignore it -- */ /* that should not have happened */ ++ni; if ( ni > numMappings ) break; nuni = (FT_UInt32)TT_NEXT_UINT24( p ); p += 2; } } if ( ni <= numMappings ) { /* If we get here then we have run out of all default ranges. */ /* We have read one non-default mapping which we haven't stored */ /* and there may be others that need to be read. */ ret[i++] = nuni; while ( ni < numMappings ) { ret[i++] = (FT_UInt32)TT_NEXT_UINT24( p ); p += 2; ++ni; } } else if ( di <= numRanges ) { /* If we get here then we have run out of all non-default */ /* mappings. We have read one default range which we haven't */ /* stored and there may be others that need to be read. */ for ( k = 0; k <= dcnt; ++k ) ret[i++] = duni + k; while ( di < numRanges ) { duni = (FT_UInt32)TT_NEXT_UINT24( dp ); dcnt = FT_NEXT_BYTE( dp ); for ( k = 0; k <= dcnt; ++k ) ret[i++] = duni + k; ++di; } } ret[i] = 0; return ret; } } FT_DEFINE_TT_CMAP( tt_cmap14_class_rec, sizeof ( TT_CMap14Rec ), (FT_CMap_InitFunc) tt_cmap14_init, (FT_CMap_DoneFunc) tt_cmap14_done, (FT_CMap_CharIndexFunc)tt_cmap14_char_index, (FT_CMap_CharNextFunc) tt_cmap14_char_next, /* Format 14 extension functions */ (FT_CMap_CharVarIndexFunc) tt_cmap14_char_var_index, (FT_CMap_CharVarIsDefaultFunc)tt_cmap14_char_var_isdefault, (FT_CMap_VariantListFunc) tt_cmap14_variants, (FT_CMap_CharVariantListFunc) tt_cmap14_char_variants, (FT_CMap_VariantCharListFunc) tt_cmap14_variant_chars, 14, (TT_CMap_ValidateFunc)tt_cmap14_validate, (TT_CMap_Info_GetFunc)tt_cmap14_get_info ) #endif /* TT_CONFIG_CMAP_FORMAT_14 */ #ifndef FT_CONFIG_OPTION_PIC static const TT_CMap_Class tt_cmap_classes[] = { #define TTCMAPCITEM( a ) &a, #ifdef TT_CONFIG_CMAP_FORMAT_0 TTCMAPCITEM( tt_cmap0_class_rec ) #endif #ifdef TT_CONFIG_CMAP_FORMAT_2 TTCMAPCITEM( tt_cmap2_class_rec ) #endif #ifdef TT_CONFIG_CMAP_FORMAT_4 TTCMAPCITEM( tt_cmap4_class_rec ) #endif #ifdef TT_CONFIG_CMAP_FORMAT_6 TTCMAPCITEM( tt_cmap6_class_rec ) #endif #ifdef TT_CONFIG_CMAP_FORMAT_8 TTCMAPCITEM( tt_cmap8_class_rec ) #endif #ifdef TT_CONFIG_CMAP_FORMAT_10 TTCMAPCITEM( tt_cmap10_class_rec ) #endif #ifdef TT_CONFIG_CMAP_FORMAT_12 TTCMAPCITEM( tt_cmap12_class_rec ) #endif #ifdef TT_CONFIG_CMAP_FORMAT_13 TTCMAPCITEM( tt_cmap13_class_rec ) #endif #ifdef TT_CONFIG_CMAP_FORMAT_14 TTCMAPCITEM( tt_cmap14_class_rec ) #endif NULL, }; #endif #ifndef FT_CONFIG_OPTION_PIC #define SFNT_SERVICES_GET sfnt_services #define SFNT_SERVICE_GLYPH_DICT_GET sfnt_service_glyph_dict #define SFNT_SERVICE_PS_NAME_GET sfnt_service_ps_name #define TT_SERVICE_CMAP_INFO_GET tt_service_get_cmap_info #define SFNT_SERVICES_GET sfnt_services #define TT_CMAP_CLASSES_GET tt_cmap_classes #define SFNT_SERVICE_SFNT_TABLE_GET sfnt_service_sfnt_table #define SFNT_SERVICE_BDF_GET sfnt_service_bdf #define SFNT_INTERFACE_GET sfnt_interface #define FT_DEFINE_SFNT_INTERFACE( \ class_, \ goto_table_, \ init_face_, \ load_face_, \ done_face_, \ get_interface_, \ load_any_, \ load_head_, \ load_hhea_, \ load_cmap_, \ load_maxp_, \ load_os2_, \ load_post_, \ load_name_, \ free_name_, \ load_kern_, \ load_gasp_, \ load_pclt_, \ load_bhed_, \ load_sbit_image_, \ get_psname_, \ free_psnames_, \ get_kerning_, \ load_font_dir_, \ load_hmtx_, \ load_eblc_, \ free_eblc_, \ set_sbit_strike_, \ load_strike_metrics_, \ get_metrics_ ) \ static const SFNT_Interface class_ = \ { \ goto_table_, \ init_face_, \ load_face_, \ done_face_, \ get_interface_, \ load_any_, \ load_head_, \ load_hhea_, \ load_cmap_, \ load_maxp_, \ load_os2_, \ load_post_, \ load_name_, \ free_name_, \ load_kern_, \ load_gasp_, \ load_pclt_, \ load_bhed_, \ load_sbit_image_, \ get_psname_, \ free_psnames_, \ get_kerning_, \ load_font_dir_, \ load_hmtx_, \ load_eblc_, \ free_eblc_, \ set_sbit_strike_, \ load_strike_metrics_, \ get_metrics_, \ }; #endif #define FT_FACE_FIND_GLOBAL_SERVICE( face, ptr, id ) \ FT_BEGIN_STMNT \ FT_Module module = FT_MODULE( FT_FACE( face )->driver ); \ FT_Pointer _tm__; \ FT_Pointer* _pptr_ = (FT_Pointer*)&(ptr); \ \ \ _tm__ = ft_module_get_service( module, FT_SERVICE_ID_ ## id ); \ *_pptr_ = _tm__; \ FT_END_STMNT #define FT_SERVICE_ID_POSTSCRIPT_CMAPS "postscript-cmaps" #define FT_PARAM_TAG_IGNORE_PREFERRED_FAMILY FT_MAKE_TAG( 'i', 'g', 'p', 'f' ) #define FT_PARAM_TAG_IGNORE_PREFERRED_SUBFAMILY FT_MAKE_TAG( 'i', 'g', 'p', 's' ) #define LOAD_( x ) \ do \ { \ FT_TRACE2(( "`" #x "' " )); \ FT_TRACE3(( "-->\n" )); \ \ error = sfnt->load_ ## x( face, stream ); \ \ FT_TRACE2(( "%s\n", ( !error ) \ ? "loaded" \ : FT_ERR_EQ( error, Table_Missing ) \ ? "missing" \ : "failed to load" )); \ FT_TRACE3(( "\n" )); \ } while ( 0 ) #define LOADM_( x, vertical ) \ do \ { \ FT_TRACE2(( "`%s" #x "' ", \ vertical ? "vertical " : "" )); \ FT_TRACE3(( "-->\n" )); \ \ error = sfnt->load_ ## x( face, stream, vertical ); \ \ FT_TRACE2(( "%s\n", ( !error ) \ ? "loaded" \ : FT_ERR_EQ( error, Table_Missing ) \ ? "missing" \ : "failed to load" )); \ FT_TRACE3(( "\n" )); \ } while ( 0 ) #define GET_NAME( id, field ) \ do \ { \ error = tt_face_get_name( face, TT_NAME_ID_ ## id, field ); \ if ( error ) \ goto Exit; \ } while ( 0 ) #define TT_NAME_ID_COPYRIGHT 0 #define TT_NAME_ID_FONT_FAMILY 1 #define TT_NAME_ID_FONT_SUBFAMILY 2 #define TT_NAME_ID_UNIQUE_ID 3 #define TT_NAME_ID_FULL_NAME 4 #define TT_NAME_ID_VERSION_STRING 5 #define TT_NAME_ID_PS_NAME 6 #define TT_NAME_ID_TRADEMARK 7 /* the following values are from the OpenType spec */ #define TT_NAME_ID_MANUFACTURER 8 #define TT_NAME_ID_DESIGNER 9 #define TT_NAME_ID_DESCRIPTION 10 #define TT_NAME_ID_VENDOR_URL 11 #define TT_NAME_ID_DESIGNER_URL 12 #define TT_NAME_ID_LICENSE 13 #define TT_NAME_ID_LICENSE_URL 14 /* number 15 is reserved */ #define TT_NAME_ID_PREFERRED_FAMILY 16 #define TT_NAME_ID_PREFERRED_SUBFAMILY 17 #define TT_NAME_ID_MAC_FULL_NAME 18 /* The following code is new as of 2000-01-21 */ #define TT_NAME_ID_SAMPLE_TEXT 19 /* This is new in OpenType 1.3 */ #define TT_NAME_ID_CID_FINDFONT_NAME 20 /* This is new in OpenType 1.5 */ #define TT_NAME_ID_WWS_FAMILY 21 #define TT_NAME_ID_WWS_SUBFAMILY 22 #define TT_FACE_HAS_KERNING( face ) ( (face)->kern_avail_bits != 0 ) #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS #define PUT_EMBEDDED_BITMAPS( a ) a #else #define PUT_EMBEDDED_BITMAPS( a ) NULL #endif #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES #define PUT_PS_NAMES( a ) a #else #define PUT_PS_NAMES( a ) NULL #endif FT_BASE_DEF( FT_Error ) FT_CMap_New( FT_CMap_Class clazz, FT_Pointer init_data, FT_CharMap charmap, FT_CMap *acmap ) { FT_Error error = FT_Err_Ok; FT_Face face; FT_Memory memory; FT_CMap cmap = NULL; if ( clazz == NULL || charmap == NULL || charmap->face == NULL ) return FT_THROW( Invalid_Argument ); face = charmap->face; memory = FT_FACE_MEMORY( face ); if ( !FT_ALLOC( cmap, clazz->size ) ) { cmap->charmap = *charmap; cmap->clazz = clazz; if ( clazz->init ) { error = clazz->init( cmap, init_data ); if ( error ) goto Fail; } /* add it to our list of charmaps */ if ( FT_RENEW_ARRAY( face->charmaps, face->num_charmaps, face->num_charmaps + 1 ) ) goto Fail; face->charmaps[face->num_charmaps++] = (FT_CharMap)cmap; } Exit: if ( acmap ) *acmap = cmap; return error; Fail: ft_cmap_done_internal( cmap ); cmap = NULL; goto Exit; } FT_BASE_DEF( FT_Pointer ) ft_module_get_service( FT_Module module, const char* service_id ) { FT_Pointer result = NULL; if ( module ) { FT_ASSERT( module->clazz && module->clazz->get_interface ); /* first, look for the service in the module */ if ( module->clazz->get_interface ) result = module->clazz->get_interface( module, service_id ); if ( result == NULL ) { /* we didn't find it, look in all other modules then */ FT_Library library = module->library; FT_Module* cur = library->modules; FT_Module* limit = cur + library->num_modules; for ( ; cur < limit; cur++ ) { if ( cur[0] != module ) { FT_ASSERT( cur[0]->clazz ); if ( cur[0]->clazz->get_interface ) { result = cur[0]->clazz->get_interface( cur[0], service_id ); if ( result != NULL ) break; } } } } } return result; } typedef struct WOFF_HeaderRec_ { FT_ULong signature; FT_ULong flavor; FT_ULong length; FT_UShort num_tables; FT_UShort reserved; FT_ULong totalSfntSize; FT_UShort majorVersion; FT_UShort minorVersion; FT_ULong metaOffset; FT_ULong metaLength; FT_ULong metaOrigLength; FT_ULong privOffset; FT_ULong privLength; } WOFF_HeaderRec, *WOFF_Header; typedef struct WOFF_TableRec_ { FT_ULong Tag; /* table ID */ FT_ULong Offset; /* table file offset */ FT_ULong CompLength; /* compressed table length */ FT_ULong OrigLength; /* uncompressed table length */ FT_ULong CheckSum; /* uncompressed checksum */ FT_ULong OrigOffset; /* uncompressed table file offset */ /* (not in the WOFF file) */ } WOFF_TableRec, *WOFF_Table; #define WRITE_BYTE( p, v ) \ do \ { \ *(p)++ = (v) >> 0; \ \ } while ( 0 ) #define WRITE_USHORT( p, v ) \ do \ { \ *(p)++ = (v) >> 8; \ *(p)++ = (v) >> 0; \ \ } while ( 0 ) #define WRITE_ULONG( p, v ) \ do \ { \ *(p)++ = (v) >> 24; \ *(p)++ = (v) >> 16; \ *(p)++ = (v) >> 8; \ *(p)++ = (v) >> 0; \ \ } while ( 0 ) FT_CALLBACK_DEF( int ) compare_offsets( const void* a, const void* b ) { WOFF_Table table1 = *(WOFF_Table*)a; WOFF_Table table2 = *(WOFF_Table*)b; FT_ULong offset1 = table1->Offset; FT_ULong offset2 = table2->Offset; if ( offset1 > offset2 ) return 1; else if ( offset1 < offset2 ) return -1; else return 0; } static void sfnt_stream_close( FT_Stream stream ) { FT_Memory memory = stream->memory; FT_FREE( stream->base ); stream->size = 0; stream->base = 0; stream->close = 0; } static FT_Error woff_open_font( FT_Stream stream, TT_Face face ) { FT_Memory memory = stream->memory; FT_Error error = FT_Err_Ok; WOFF_HeaderRec woff; WOFF_Table tables = NULL; WOFF_Table* indices = NULL; FT_ULong woff_offset; FT_Byte* sfnt = NULL; FT_Stream sfnt_stream = NULL; FT_Byte* sfnt_header; FT_ULong sfnt_offset; FT_Int nn; FT_ULong old_tag = 0; static const FT_Frame_Field woff_header_fields[] = { #undef FT_STRUCTURE #define FT_STRUCTURE WOFF_HeaderRec FT_FRAME_START( 44 ), FT_FRAME_ULONG ( signature ), FT_FRAME_ULONG ( flavor ), FT_FRAME_ULONG ( length ), FT_FRAME_USHORT( num_tables ), FT_FRAME_USHORT( reserved ), FT_FRAME_ULONG ( totalSfntSize ), FT_FRAME_USHORT( majorVersion ), FT_FRAME_USHORT( minorVersion ), FT_FRAME_ULONG ( metaOffset ), FT_FRAME_ULONG ( metaLength ), FT_FRAME_ULONG ( metaOrigLength ), FT_FRAME_ULONG ( privOffset ), FT_FRAME_ULONG ( privLength ), FT_FRAME_END }; FT_ASSERT( stream == face->root.stream ); FT_ASSERT( FT_STREAM_POS() == 0 ); if ( FT_STREAM_READ_FIELDS( woff_header_fields, &woff ) ) return error; /* Make sure we don't recurse back here or hit TTC code. */ if ( woff.flavor == TTAG_wOFF || woff.flavor == TTAG_ttcf ) return FT_THROW( Invalid_Table ); /* Miscellaneous checks. */ if ( woff.length != stream->size || woff.num_tables == 0 || 44 + woff.num_tables * 20UL >= woff.length || 12 + woff.num_tables * 16UL >= woff.totalSfntSize || ( woff.totalSfntSize & 3 ) != 0 || ( woff.metaOffset == 0 && ( woff.metaLength != 0 || woff.metaOrigLength != 0 ) ) || ( woff.metaLength != 0 && woff.metaOrigLength == 0 ) || ( woff.privOffset == 0 && woff.privLength != 0 ) ) return FT_THROW( Invalid_Table ); if ( FT_ALLOC( sfnt, woff.totalSfntSize ) || FT_NEW( sfnt_stream ) ) goto Exit; sfnt_header = sfnt; /* Write sfnt header. */ { FT_UInt searchRange, entrySelector, rangeShift, x; x = woff.num_tables; entrySelector = 0; while ( x ) { x >>= 1; entrySelector += 1; } entrySelector--; searchRange = ( 1 << entrySelector ) * 16; rangeShift = woff.num_tables * 16 - searchRange; WRITE_ULONG ( sfnt_header, woff.flavor ); WRITE_USHORT( sfnt_header, woff.num_tables ); WRITE_USHORT( sfnt_header, searchRange ); WRITE_USHORT( sfnt_header, entrySelector ); WRITE_USHORT( sfnt_header, rangeShift ); } /* While the entries in the sfnt header must be sorted by the */ /* tag value, the tables themselves are not. We thus have to */ /* sort them by offset and check that they don't overlap. */ if ( FT_NEW_ARRAY( tables, woff.num_tables ) || FT_NEW_ARRAY( indices, woff.num_tables ) ) goto Exit; FT_TRACE2(( "\n" " tag offset compLen origLen checksum\n" " -------------------------------------------\n" )); if ( FT_FRAME_ENTER( 20L * woff.num_tables ) ) goto Exit; for ( nn = 0; nn < woff.num_tables; nn++ ) { WOFF_Table table = tables + nn; table->Tag = FT_GET_TAG4(); table->Offset = FT_GET_ULONG(); table->CompLength = FT_GET_ULONG(); table->OrigLength = FT_GET_ULONG(); table->CheckSum = FT_GET_ULONG(); FT_TRACE2(( " %c%c%c%c %08lx %08lx %08lx %08lx\n", (FT_Char)( table->Tag >> 24 ), (FT_Char)( table->Tag >> 16 ), (FT_Char)( table->Tag >> 8 ), (FT_Char)( table->Tag ), table->Offset, table->CompLength, table->OrigLength, table->CheckSum )); if ( table->Tag <= old_tag ) { FT_FRAME_EXIT(); error = FT_THROW( Invalid_Table ); goto Exit; } old_tag = table->Tag; indices[nn] = table; } FT_FRAME_EXIT(); /* Sort by offset. */ ft_qsort( indices, woff.num_tables, sizeof ( WOFF_Table ), compare_offsets ); /* Check offsets and lengths. */ woff_offset = 44 + woff.num_tables * 20L; sfnt_offset = 12 + woff.num_tables * 16L; for ( nn = 0; nn < woff.num_tables; nn++ ) { WOFF_Table table = indices[nn]; if ( table->Offset != woff_offset || table->Offset + table->CompLength > woff.length || sfnt_offset + table->OrigLength > woff.totalSfntSize || table->CompLength > table->OrigLength ) { error = FT_THROW( Invalid_Table ); goto Exit; } table->OrigOffset = sfnt_offset; /* The offsets must be multiples of 4. */ woff_offset += ( table->CompLength + 3 ) & ~3; sfnt_offset += ( table->OrigLength + 3 ) & ~3; } /* * Final checks! * * We don't decode and check the metadata block. * We don't check table checksums either. * But other than those, I think we implement all * `MUST' checks from the spec. */ if ( woff.metaOffset ) { if ( woff.metaOffset != woff_offset || woff.metaOffset + woff.metaLength > woff.length ) { error = FT_THROW( Invalid_Table ); goto Exit; } /* We have padding only ... */ woff_offset += woff.metaLength; } if ( woff.privOffset ) { /* ... if it isn't the last block. */ woff_offset = ( woff_offset + 3 ) & ~3; if ( woff.privOffset != woff_offset || woff.privOffset + woff.privLength > woff.length ) { error = FT_THROW( Invalid_Table ); goto Exit; } /* No padding for the last block. */ woff_offset += woff.privLength; } if ( sfnt_offset != woff.totalSfntSize || woff_offset != woff.length ) { error = FT_THROW( Invalid_Table ); goto Exit; } /* Write the tables. */ for ( nn = 0; nn < woff.num_tables; nn++ ) { WOFF_Table table = tables + nn; /* Write SFNT table entry. */ WRITE_ULONG( sfnt_header, table->Tag ); WRITE_ULONG( sfnt_header, table->CheckSum ); WRITE_ULONG( sfnt_header, table->OrigOffset ); WRITE_ULONG( sfnt_header, table->OrigLength ); /* Write table data. */ if ( FT_STREAM_SEEK( table->Offset ) || FT_FRAME_ENTER( table->CompLength ) ) goto Exit; if ( table->CompLength == table->OrigLength ) { /* Uncompressed data; just copy. */ ft_memcpy( sfnt + table->OrigOffset, stream->cursor, table->OrigLength ); } else FT_ERROR(( "BxAddOn_TTF", false )); FT_FRAME_EXIT(); /* We don't check whether the padding bytes in the WOFF file are */ /* actually '\0'. For the output, however, we do set them properly. */ sfnt_offset = table->OrigOffset + table->OrigLength; while ( sfnt_offset & 3 ) { sfnt[sfnt_offset] = '\0'; sfnt_offset++; } } /* Ok! Finally ready. Swap out stream and return. */ FT_Stream_OpenMemory( sfnt_stream, sfnt, woff.totalSfntSize ); sfnt_stream->memory = stream->memory; sfnt_stream->close = sfnt_stream_close; FT_Stream_Free( face->root.stream, ( face->root.face_flags & FT_FACE_FLAG_EXTERNAL_STREAM ) != 0 ); face->root.stream = sfnt_stream; face->root.face_flags &= ~FT_FACE_FLAG_EXTERNAL_STREAM; Exit: FT_FREE( tables ); FT_FREE( indices ); if ( error ) { FT_FREE( sfnt ); FT_Stream_Close( sfnt_stream ); FT_FREE( sfnt_stream ); } return error; } static FT_Error sfnt_open_font( FT_Stream stream, TT_Face face ) { FT_Memory memory = stream->memory; FT_Error error; FT_ULong tag, offset; static const FT_Frame_Field ttc_header_fields[] = { #undef FT_STRUCTURE #define FT_STRUCTURE TTC_HeaderRec FT_FRAME_START( 8 ), FT_FRAME_LONG( version ), FT_FRAME_LONG( count ), /* this is ULong in the specs */ FT_FRAME_END }; face->ttc_header.tag = 0; face->ttc_header.version = 0; face->ttc_header.count = 0; retry: offset = FT_STREAM_POS(); if ( FT_READ_ULONG( tag ) ) return error; if ( tag == TTAG_wOFF ) { FT_TRACE2(( "sfnt_open_font: file is a WOFF; synthesizing SFNT\n" )); if ( FT_STREAM_SEEK( offset ) ) return error; error = woff_open_font( stream, face ); if ( error ) return error; /* Swap out stream and retry! */ stream = face->root.stream; goto retry; } if ( tag != 0x00010000UL && tag != TTAG_ttcf && tag != TTAG_OTTO && tag != TTAG_true && tag != TTAG_typ1 && tag != 0x00020000UL ) { FT_TRACE2(( " not a font using the SFNT container format\n" )); return FT_THROW( Unknown_File_Format ); } face->ttc_header.tag = TTAG_ttcf; if ( tag == TTAG_ttcf ) { FT_Int n; FT_TRACE3(( "sfnt_open_font: file is a collection\n" )); if ( FT_STREAM_READ_FIELDS( ttc_header_fields, &face->ttc_header ) ) return error; if ( face->ttc_header.count == 0 ) return FT_THROW( Invalid_Table ); /* a rough size estimate: let's conservatively assume that there */ /* is just a single table info in each subfont header (12 + 16*1 = */ /* 28 bytes), thus we have (at least) `12 + 4*count' bytes for the */ /* size of the TTC header plus `28*count' bytes for all subfont */ /* headers */ if ( (FT_ULong)face->ttc_header.count > stream->size / ( 28 + 4 ) ) return FT_THROW( Array_Too_Large ); /* now read the offsets of each font in the file */ if ( FT_NEW_ARRAY( face->ttc_header.offsets, face->ttc_header.count ) ) return error; if ( FT_FRAME_ENTER( face->ttc_header.count * 4L ) ) return error; for ( n = 0; n < face->ttc_header.count; n++ ) face->ttc_header.offsets[n] = FT_GET_ULONG(); FT_FRAME_EXIT(); } else { FT_TRACE3(( "sfnt_open_font: synthesize TTC\n" )); face->ttc_header.version = 1 << 16; face->ttc_header.count = 1; if ( FT_NEW( face->ttc_header.offsets ) ) return error; face->ttc_header.offsets[0] = offset; } return error; } FT_LOCAL_DEF( TT_Table ) tt_face_lookup_table( TT_Face face, FT_ULong tag ) { TT_Table entry; TT_Table limit; #ifdef FT_DEBUG_LEVEL_TRACE FT_Bool zero_length = FALSE; #endif FT_TRACE4(( "tt_face_lookup_table: %08p, `%c%c%c%c' -- ", face, (FT_Char)( tag >> 24 ), (FT_Char)( tag >> 16 ), (FT_Char)( tag >> 8 ), (FT_Char)( tag ) )); entry = face->dir_tables; limit = entry + face->num_tables; for ( ; entry < limit; entry++ ) { /* For compatibility with Windows, we consider */ /* zero-length tables the same as missing tables. */ if ( entry->Tag == tag ) { if ( entry->Length != 0 ) { FT_TRACE4(( "found table.\n" )); return entry; } #ifdef FT_DEBUG_LEVEL_TRACE zero_length = TRUE; #endif } } #ifdef FT_DEBUG_LEVEL_TRACE if ( zero_length ) FT_TRACE4(( "ignoring empty table\n" )); else FT_TRACE4(( "could not find table\n" )); #endif return NULL; } #define TT_MAC_LANGID_ENGLISH 0 #define TT_MAC_LANGID_FRENCH 1 #define TT_MAC_LANGID_GERMAN 2 #define TT_MAC_LANGID_ITALIAN 3 #define TT_MAC_LANGID_DUTCH 4 #define TT_MAC_LANGID_SWEDISH 5 #define TT_MAC_LANGID_SPANISH 6 #define TT_MAC_LANGID_DANISH 7 #define TT_MAC_LANGID_PORTUGUESE 8 #define TT_MAC_LANGID_NORWEGIAN 9 #define TT_MAC_LANGID_HEBREW 10 #define TT_MAC_LANGID_JAPANESE 11 #define TT_MAC_LANGID_ARABIC 12 #define TT_MAC_LANGID_FINNISH 13 #define TT_MAC_LANGID_GREEK 14 #define TT_MAC_LANGID_ICELANDIC 15 #define TT_MAC_LANGID_MALTESE 16 #define TT_MAC_LANGID_TURKISH 17 #define TT_MAC_LANGID_CROATIAN 18 #define TT_MAC_LANGID_CHINESE_TRADITIONAL 19 #define TT_MAC_LANGID_URDU 20 #define TT_MAC_LANGID_HINDI 21 #define TT_MAC_LANGID_THAI 22 #define TT_MAC_LANGID_KOREAN 23 #define TT_MAC_LANGID_LITHUANIAN 24 #define TT_MAC_LANGID_POLISH 25 #define TT_MAC_LANGID_HUNGARIAN 26 #define TT_MAC_LANGID_ESTONIAN 27 #define TT_MAC_LANGID_LETTISH 28 #define TT_MAC_LANGID_SAAMISK 29 #define TT_MAC_LANGID_FAEROESE 30 #define TT_MAC_LANGID_FARSI 31 #define TT_MAC_LANGID_RUSSIAN 32 #define TT_MAC_LANGID_CHINESE_SIMPLIFIED 33 #define TT_MAC_LANGID_FLEMISH 34 #define TT_MAC_LANGID_IRISH 35 #define TT_MAC_LANGID_ALBANIAN 36 #define TT_MAC_LANGID_ROMANIAN 37 #define TT_MAC_LANGID_CZECH 38 #define TT_MAC_LANGID_SLOVAK 39 #define TT_MAC_LANGID_SLOVENIAN 40 #define TT_MAC_LANGID_YIDDISH 41 #define TT_MAC_LANGID_SERBIAN 42 #define TT_MAC_LANGID_MACEDONIAN 43 #define TT_MAC_LANGID_BULGARIAN 44 #define TT_MAC_LANGID_UKRAINIAN 45 #define TT_MAC_LANGID_BYELORUSSIAN 46 #define TT_MAC_LANGID_UZBEK 47 #define TT_MAC_LANGID_KAZAKH 48 #define TT_MAC_LANGID_AZERBAIJANI 49 #define TT_MAC_LANGID_AZERBAIJANI_CYRILLIC_SCRIPT 49 #define TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT 50 #define TT_MAC_LANGID_ARMENIAN 51 #define TT_MAC_LANGID_GEORGIAN 52 #define TT_MAC_LANGID_MOLDAVIAN 53 #define TT_MAC_LANGID_KIRGHIZ 54 #define TT_MAC_LANGID_TAJIKI 55 #define TT_MAC_LANGID_TURKMEN 56 #define TT_MAC_LANGID_MONGOLIAN 57 #define TT_MAC_LANGID_MONGOLIAN_MONGOLIAN_SCRIPT 57 #define TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT 58 #define TT_MAC_LANGID_PASHTO 59 #define TT_MAC_LANGID_KURDISH 60 #define TT_MAC_LANGID_KASHMIRI 61 #define TT_MAC_LANGID_SINDHI 62 #define TT_MAC_LANGID_TIBETAN 63 #define TT_MAC_LANGID_NEPALI 64 #define TT_MAC_LANGID_SANSKRIT 65 #define TT_MAC_LANGID_MARATHI 66 #define TT_MAC_LANGID_BENGALI 67 #define TT_MAC_LANGID_ASSAMESE 68 #define TT_MAC_LANGID_GUJARATI 69 #define TT_MAC_LANGID_PUNJABI 70 #define TT_MAC_LANGID_ORIYA 71 #define TT_MAC_LANGID_MALAYALAM 72 #define TT_MAC_LANGID_KANNADA 73 #define TT_MAC_LANGID_TAMIL 74 #define TT_MAC_LANGID_TELUGU 75 #define TT_MAC_LANGID_SINHALESE 76 #define TT_MAC_LANGID_BURMESE 77 #define TT_MAC_LANGID_KHMER 78 #define TT_MAC_LANGID_LAO 79 #define TT_MAC_LANGID_VIETNAMESE 80 #define TT_MAC_LANGID_INDONESIAN 81 #define TT_MAC_LANGID_TAGALOG 82 #define TT_MAC_LANGID_MALAY_ROMAN_SCRIPT 83 #define TT_MAC_LANGID_MALAY_ARABIC_SCRIPT 84 #define TT_MAC_LANGID_AMHARIC 85 #define TT_MAC_LANGID_TIGRINYA 86 #define TT_MAC_LANGID_GALLA 87 #define TT_MAC_LANGID_SOMALI 88 #define TT_MAC_LANGID_SWAHILI 89 #define TT_MAC_LANGID_RUANDA 90 #define TT_MAC_LANGID_RUNDI 91 #define TT_MAC_LANGID_CHEWA 92 #define TT_MAC_LANGID_MALAGASY 93 #define TT_MAC_LANGID_ESPERANTO 94 #define TT_MAC_LANGID_WELSH 128 #define TT_MAC_LANGID_BASQUE 129 #define TT_MAC_LANGID_CATALAN 130 #define TT_MAC_LANGID_LATIN 131 #define TT_MAC_LANGID_QUECHUA 132 #define TT_MAC_LANGID_GUARANI 133 #define TT_MAC_LANGID_AYMARA 134 #define TT_MAC_LANGID_TATAR 135 #define TT_MAC_LANGID_UIGHUR 136 #define TT_MAC_LANGID_DZONGKHA 137 #define TT_MAC_LANGID_JAVANESE 138 #define TT_MAC_LANGID_SUNDANESE 139 #if 0 /* these seem to be errors that have been dropped */ #define TT_MAC_LANGID_SCOTTISH_GAELIC 140 #define TT_MAC_LANGID_IRISH_GAELIC 141 #endif /* The following codes are new as of 2000-03-10 */ #define TT_MAC_LANGID_GALICIAN 140 #define TT_MAC_LANGID_AFRIKAANS 141 #define TT_MAC_LANGID_BRETON 142 #define TT_MAC_LANGID_INUKTITUT 143 #define TT_MAC_LANGID_SCOTTISH_GAELIC 144 #define TT_MAC_LANGID_MANX_GAELIC 145 #define TT_MAC_LANGID_IRISH_GAELIC 146 #define TT_MAC_LANGID_TONGAN 147 #define TT_MAC_LANGID_GREEK_POLYTONIC 148 #define TT_MAC_LANGID_GREELANDIC 149 #define TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT 150 #define TT_MAC_ID_ROMAN 0 #define TT_MAC_ID_JAPANESE 1 #define TT_MAC_ID_TRADITIONAL_CHINESE 2 #define TT_MAC_ID_KOREAN 3 #define TT_MAC_ID_ARABIC 4 #define TT_MAC_ID_HEBREW 5 #define TT_MAC_ID_GREEK 6 #define TT_MAC_ID_RUSSIAN 7 #define TT_MAC_ID_RSYMBOL 8 #define TT_MAC_ID_DEVANAGARI 9 #define TT_MAC_ID_GURMUKHI 10 #define TT_MAC_ID_GUJARATI 11 #define TT_MAC_ID_ORIYA 12 #define TT_MAC_ID_BENGALI 13 #define TT_MAC_ID_TAMIL 14 #define TT_MAC_ID_TELUGU 15 #define TT_MAC_ID_KANNADA 16 #define TT_MAC_ID_MALAYALAM 17 #define TT_MAC_ID_SINHALESE 18 #define TT_MAC_ID_BURMESE 19 #define TT_MAC_ID_KHMER 20 #define TT_MAC_ID_THAI 21 #define TT_MAC_ID_LAOTIAN 22 #define TT_MAC_ID_GEORGIAN 23 #define TT_MAC_ID_ARMENIAN 24 #define TT_MAC_ID_MALDIVIAN 25 #define TT_MAC_ID_SIMPLIFIED_CHINESE 25 #define TT_MAC_ID_TIBETAN 26 #define TT_MAC_ID_MONGOLIAN 27 #define TT_MAC_ID_GEEZ 28 #define TT_MAC_ID_SLAVIC 29 #define TT_MAC_ID_VIETNAMESE 30 #define TT_MAC_ID_SINDHI 31 #define TT_MAC_ID_UNINTERP 32 #define TT_PEEK_SHORT FT_PEEK_SHORT #define TT_PEEK_USHORT FT_PEEK_USHORT #define TT_PEEK_UINT24 FT_PEEK_UOFF3 #define TT_PEEK_LONG FT_PEEK_LONG #define TT_PEEK_ULONG FT_PEEK_ULONG #define TT_NEXT_SHORT FT_NEXT_SHORT #define TT_NEXT_USHORT FT_NEXT_USHORT #define TT_NEXT_UINT24 FT_NEXT_UOFF3 #define TT_NEXT_LONG FT_NEXT_LONG #define TT_NEXT_ULONG FT_NEXT_ULONG typedef FT_String* (*TT_NameEntry_ConvertFunc)( TT_NameEntry entry, FT_Memory memory ); static FT_Error tt_face_get_name( TT_Face face, FT_UShort nameid, FT_String** name ) { FT_Memory memory = face->root.memory; FT_Error error = FT_Err_Ok; FT_String* result = NULL; FT_UShort n; TT_NameEntryRec* rec; FT_Int found_apple = -1; FT_Int found_apple_roman = -1; FT_Int found_apple_english = -1; FT_Int found_win = -1; FT_Int found_unicode = -1; FT_Bool is_english = 0; TT_NameEntry_ConvertFunc convert; FT_ASSERT( name ); rec = face->name_table.names; for ( n = 0; n < face->num_names; n++, rec++ ) { /* According to the OpenType 1.3 specification, only Microsoft or */ /* Apple platform IDs might be used in the `name' table. The */ /* `Unicode' platform is reserved for the `cmap' table, and the */ /* `ISO' one is deprecated. */ /* */ /* However, the Apple TrueType specification doesn't say the same */ /* thing and goes to suggest that all Unicode `name' table entries */ /* should be coded in UTF-16 (in big-endian format I suppose). */ /* */ if ( rec->nameID == nameid && rec->stringLength > 0 ) { switch ( rec->platformID ) { case TT_PLATFORM_APPLE_UNICODE: case TT_PLATFORM_ISO: /* there is `languageID' to check there. We should use this */ /* field only as a last solution when nothing else is */ /* available. */ /* */ found_unicode = n; break; case TT_PLATFORM_MACINTOSH: /* This is a bit special because some fonts will use either */ /* an English language id, or a Roman encoding id, to indicate */ /* the English version of its font name. */ /* */ if ( rec->languageID == TT_MAC_LANGID_ENGLISH ) found_apple_english = n; else if ( rec->encodingID == TT_MAC_ID_ROMAN ) found_apple_roman = n; break; case TT_PLATFORM_MICROSOFT: /* we only take a non-English name when there is nothing */ /* else available in the font */ /* */ if ( found_win == -1 || ( rec->languageID & 0x3FF ) == 0x009 ) { switch ( rec->encodingID ) { case TT_MS_ID_SYMBOL_CS: case TT_MS_ID_UNICODE_CS: case TT_MS_ID_UCS_4: is_english = FT_BOOL( ( rec->languageID & 0x3FF ) == 0x009 ); found_win = n; break; default: ; } } break; default: ; } } } found_apple = found_apple_roman; if ( found_apple_english >= 0 ) found_apple = found_apple_english; /* some fonts contain invalid Unicode or Macintosh formatted entries; */ /* we will thus favor names encoded in Windows formats if available */ /* (provided it is an English name) */ /* */ convert = NULL; if ( found_win >= 0 && !( found_apple >= 0 && !is_english ) ) { rec = face->name_table.names + found_win; switch ( rec->encodingID ) { /* all Unicode strings are encoded using UTF-16BE */ case TT_MS_ID_UNICODE_CS: case TT_MS_ID_SYMBOL_CS: convert = tt_name_entry_ascii_from_utf16; break; case TT_MS_ID_UCS_4: /* Apparently, if this value is found in a name table entry, it is */ /* documented as `full Unicode repertoire'. Experience with the */ /* MsGothic font shipped with Windows Vista shows that this really */ /* means UTF-16 encoded names (UCS-4 values are only used within */ /* charmaps). */ convert = tt_name_entry_ascii_from_utf16; break; default: ; } } else if ( found_apple >= 0 ) { rec = face->name_table.names + found_apple; convert = tt_name_entry_ascii_from_other; } else if ( found_unicode >= 0 ) { rec = face->name_table.names + found_unicode; convert = tt_name_entry_ascii_from_utf16; } if ( rec && convert ) { if ( rec->string == NULL ) { FT_Stream stream = face->name_table.stream; if ( FT_QNEW_ARRAY ( rec->string, rec->stringLength ) || FT_STREAM_SEEK( rec->stringOffset ) || FT_STREAM_READ( rec->string, rec->stringLength ) ) { FT_FREE( rec->string ); rec->stringLength = 0; result = NULL; goto Exit; } } result = convert( rec, memory ); } Exit: *name = result; return error; } FT_LOCAL_DEF( FT_Error ) tt_face_build_cmaps( TT_Face face ) { FT_Byte* table = face->cmap_table; FT_Byte* limit = table + face->cmap_size; FT_UInt volatile num_cmaps; FT_Byte* volatile p = table; FT_Library library = FT_FACE_LIBRARY( face ); FT_UNUSED( library ); if ( !p || p + 4 > limit ) return FT_THROW( Invalid_Table ); /* only recognize format 0 */ if ( TT_NEXT_USHORT( p ) != 0 ) { p -= 2; FT_ERROR(( "tt_face_build_cmaps:" " unsupported `cmap' table format = %d\n", TT_PEEK_USHORT( p ) )); return FT_THROW( Invalid_Table ); } num_cmaps = TT_NEXT_USHORT( p ); #ifdef FT_MAX_CHARMAP_CACHEABLE if ( num_cmaps > FT_MAX_CHARMAP_CACHEABLE ) FT_ERROR(( "tt_face_build_cmaps: too many cmap subtables (%d)\n" " subtable #%d and higher are loaded" " but cannot be searched\n", num_cmaps, FT_MAX_CHARMAP_CACHEABLE + 1 )); #endif for ( ; num_cmaps > 0 && p + 8 <= limit; num_cmaps-- ) { FT_CharMapRec charmap; FT_UInt32 offset; charmap.platform_id = TT_NEXT_USHORT( p ); charmap.encoding_id = TT_NEXT_USHORT( p ); charmap.face = FT_FACE( face ); charmap.encoding = FT_ENCODING_NONE; /* will be filled later */ offset = TT_NEXT_ULONG( p ); if ( offset && offset <= face->cmap_size - 2 ) { FT_Byte* volatile cmap = table + offset; volatile FT_UInt format = TT_PEEK_USHORT( cmap ); const TT_CMap_Class* volatile pclazz = TT_CMAP_CLASSES_GET; TT_CMap_Class volatile clazz; for ( ; *pclazz; pclazz++ ) { clazz = *pclazz; if ( clazz->format == format ) { volatile TT_ValidatorRec valid; volatile FT_Error error = FT_Err_Ok; ft_validator_init( FT_VALIDATOR( &valid ), cmap, limit, FT_VALIDATE_DEFAULT ); valid.num_glyphs = (FT_UInt)face->max_profile.numGlyphs; if ( ft_setjmp( FT_VALIDATOR( &valid )->jump_buffer) == 0 ) { /* validate this cmap sub-table */ error = clazz->validate( cmap, FT_VALIDATOR( &valid ) ); } if ( valid.validator.error == 0 ) { FT_CMap ttcmap; /* It might make sense to store the single variation */ /* selector cmap somewhere special. But it would have to be */ /* in the public FT_FaceRec, and we can't change that. */ if ( !FT_CMap_New( (FT_CMap_Class)clazz, cmap, &charmap, &ttcmap ) ) { /* it is simpler to directly set `flags' than adding */ /* a parameter to FT_CMap_New */ ((TT_CMap)ttcmap)->flags = (FT_Int)error; } } else { FT_TRACE0(( "tt_face_build_cmaps:" " broken cmap sub-table ignored\n" )); } break; } } if ( *pclazz == NULL ) { FT_TRACE0(( "tt_face_build_cmaps:" " unsupported cmap sub-table ignored\n" )); } } } return FT_Err_Ok; } static FT_Encoding sfnt_find_encoding( int platform_id, int encoding_id ) { typedef struct TEncoding_ { int platform_id; int encoding_id; FT_Encoding encoding; } TEncoding; static const TEncoding tt_encodings[] = { { TT_PLATFORM_ISO, -1, FT_ENCODING_UNICODE }, { TT_PLATFORM_APPLE_UNICODE, -1, FT_ENCODING_UNICODE }, { TT_PLATFORM_MACINTOSH, TT_MAC_ID_ROMAN, FT_ENCODING_APPLE_ROMAN }, { TT_PLATFORM_MICROSOFT, TT_MS_ID_SYMBOL_CS, FT_ENCODING_MS_SYMBOL }, { TT_PLATFORM_MICROSOFT, TT_MS_ID_UCS_4, FT_ENCODING_UNICODE }, { TT_PLATFORM_MICROSOFT, TT_MS_ID_UNICODE_CS, FT_ENCODING_UNICODE }, { TT_PLATFORM_MICROSOFT, TT_MS_ID_SJIS, FT_ENCODING_SJIS }, { TT_PLATFORM_MICROSOFT, TT_MS_ID_GB2312, FT_ENCODING_GB2312 }, { TT_PLATFORM_MICROSOFT, TT_MS_ID_BIG_5, FT_ENCODING_BIG5 }, { TT_PLATFORM_MICROSOFT, TT_MS_ID_WANSUNG, FT_ENCODING_WANSUNG }, { TT_PLATFORM_MICROSOFT, TT_MS_ID_JOHAB, FT_ENCODING_JOHAB } }; const TEncoding *cur, *limit; cur = tt_encodings; limit = cur + sizeof ( tt_encodings ) / sizeof ( tt_encodings[0] ); for ( ; cur < limit; cur++ ) { if ( cur->platform_id == platform_id ) { if ( cur->encoding_id == encoding_id || cur->encoding_id == -1 ) return cur->encoding; } } return FT_ENCODING_NONE; } FT_LOCAL_DEF( void ) tt_face_done_kern( TT_Face face ) { FT_Stream stream = face->root.stream; FT_FRAME_RELEASE( face->kern_table ); face->kern_table_size = 0; face->num_kern_tables = 0; face->kern_avail_bits = 0; face->kern_order_bits = 0; } #if defined TT_CONFIG_OPTION_POSTSCRIPT_NAMES && defined TT_CONFIG_OPTION_BDF FT_DEFINE_SERVICEDESCREC5( sfnt_services, FT_SERVICE_ID_SFNT_TABLE, &SFNT_SERVICE_SFNT_TABLE_GET, FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &SFNT_SERVICE_PS_NAME_GET, FT_SERVICE_ID_GLYPH_DICT, &SFNT_SERVICE_GLYPH_DICT_GET, FT_SERVICE_ID_BDF, &SFNT_SERVICE_BDF_GET, FT_SERVICE_ID_TT_CMAP, &TT_SERVICE_CMAP_INFO_GET ) #elif defined TT_CONFIG_OPTION_POSTSCRIPT_NAMES FT_DEFINE_SERVICEDESCREC4( sfnt_services, FT_SERVICE_ID_SFNT_TABLE, &SFNT_SERVICE_SFNT_TABLE_GET, FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &SFNT_SERVICE_PS_NAME_GET, FT_SERVICE_ID_GLYPH_DICT, &SFNT_SERVICE_GLYPH_DICT_GET, FT_SERVICE_ID_TT_CMAP, &TT_SERVICE_CMAP_INFO_GET ) #elif defined TT_CONFIG_OPTION_BDF FT_DEFINE_SERVICEDESCREC4( sfnt_services, FT_SERVICE_ID_SFNT_TABLE, &SFNT_SERVICE_SFNT_TABLE_GET, FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &SFNT_SERVICE_PS_NAME_GET, FT_SERVICE_ID_BDF, &SFNT_SERVICE_BDF_GET, FT_SERVICE_ID_TT_CMAP, &TT_SERVICE_CMAP_INFO_GET ) #else FT_DEFINE_SERVICEDESCREC3( sfnt_services, FT_SERVICE_ID_SFNT_TABLE, &SFNT_SERVICE_SFNT_TABLE_GET, FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &SFNT_SERVICE_PS_NAME_GET, FT_SERVICE_ID_TT_CMAP, &TT_SERVICE_CMAP_INFO_GET ) #endif static FT_Error tt_face_load_generic_header( TT_Face face, FT_Stream stream, FT_ULong tag ) { FT_Error error; TT_Header* header; static const FT_Frame_Field header_fields[] = { #undef FT_STRUCTURE #define FT_STRUCTURE TT_Header FT_FRAME_START( 54 ), FT_FRAME_ULONG ( Table_Version ), FT_FRAME_ULONG ( Font_Revision ), FT_FRAME_LONG ( CheckSum_Adjust ), FT_FRAME_LONG ( Magic_Number ), FT_FRAME_USHORT( Flags ), FT_FRAME_USHORT( Units_Per_EM ), FT_FRAME_LONG ( Created[0] ), FT_FRAME_LONG ( Created[1] ), FT_FRAME_LONG ( Modified[0] ), FT_FRAME_LONG ( Modified[1] ), FT_FRAME_SHORT ( xMin ), FT_FRAME_SHORT ( yMin ), FT_FRAME_SHORT ( xMax ), FT_FRAME_SHORT ( yMax ), FT_FRAME_USHORT( Mac_Style ), FT_FRAME_USHORT( Lowest_Rec_PPEM ), FT_FRAME_SHORT ( Font_Direction ), FT_FRAME_SHORT ( Index_To_Loc_Format ), FT_FRAME_SHORT ( Glyph_Data_Format ), FT_FRAME_END }; error = face->goto_table( face, tag, stream, 0 ); if ( error ) goto Exit; header = &face->header; if ( FT_STREAM_READ_FIELDS( header_fields, header ) ) goto Exit; FT_TRACE3(( "Units per EM: %4u\n", header->Units_Per_EM )); FT_TRACE3(( "IndexToLoc: %4d\n", header->Index_To_Loc_Format )); Exit: return error; } FT_LOCAL_DEF( FT_Int ) tt_face_get_kerning( TT_Face face, FT_UInt left_glyph, FT_UInt right_glyph ) { FT_Int result = 0; FT_UInt count, mask; FT_Byte* p = face->kern_table; FT_Byte* p_limit = p + face->kern_table_size; p += 4; mask = 0x0001; for ( count = face->num_kern_tables; count > 0 && p + 6 <= p_limit; count--, mask <<= 1 ) { FT_Byte* base = p; FT_Byte* next; FT_UInt version = FT_NEXT_USHORT( p ); FT_UInt length = FT_NEXT_USHORT( p ); FT_UInt coverage = FT_NEXT_USHORT( p ); FT_UInt num_pairs; FT_Int value = 0; FT_UNUSED( version ); next = base + length; if ( next > p_limit ) /* handle broken table */ next = p_limit; if ( ( face->kern_avail_bits & mask ) == 0 ) goto NextTable; if ( p + 8 > next ) goto NextTable; num_pairs = FT_NEXT_USHORT( p ); p += 6; if ( ( next - p ) < 6 * (int)num_pairs ) /* handle broken count */ num_pairs = (FT_UInt)( ( next - p ) / 6 ); switch ( coverage >> 8 ) { case 0: { FT_ULong key0 = TT_KERN_INDEX( left_glyph, right_glyph ); if ( face->kern_order_bits & mask ) /* binary search */ { FT_UInt min = 0; FT_UInt max = num_pairs; while ( min < max ) { FT_UInt mid = ( min + max ) >> 1; FT_Byte* q = p + 6 * mid; FT_ULong key; key = FT_NEXT_ULONG( q ); if ( key == key0 ) { value = FT_PEEK_SHORT( q ); goto Found; } if ( key < key0 ) min = mid + 1; else max = mid; } } else /* linear search */ { FT_UInt count2; for ( count2 = num_pairs; count2 > 0; count2-- ) { FT_ULong key = FT_NEXT_ULONG( p ); if ( key == key0 ) { value = FT_PEEK_SHORT( p ); goto Found; } p += 2; } } } break; /* * We don't support format 2 because we haven't seen a single font * using it in real life... */ default: ; } goto NextTable; Found: if ( coverage & 8 ) /* override or add */ result = value; else result += value; NextTable: p = next; } return result; } FT_LOCAL_DEF( FT_Error ) tt_face_load_font_dir( TT_Face face, FT_Stream stream ) { SFNT_HeaderRec sfnt; FT_Error error; FT_Memory memory = stream->memory; TT_TableRec* entry; FT_Int nn; static const FT_Frame_Field offset_table_fields[] = { #undef FT_STRUCTURE #define FT_STRUCTURE SFNT_HeaderRec FT_FRAME_START( 8 ), FT_FRAME_USHORT( num_tables ), FT_FRAME_USHORT( search_range ), FT_FRAME_USHORT( entry_selector ), FT_FRAME_USHORT( range_shift ), FT_FRAME_END }; FT_TRACE2(( "tt_face_load_font_dir: %08p\n", face )); /* read the offset table */ sfnt.offset = FT_STREAM_POS(); if ( FT_READ_ULONG( sfnt.format_tag ) || FT_STREAM_READ_FIELDS( offset_table_fields, &sfnt ) ) goto Exit; /* many fonts don't have these fields set correctly */ #if 0 if ( sfnt.search_range != 1 << ( sfnt.entry_selector + 4 ) || sfnt.search_range + sfnt.range_shift != sfnt.num_tables << 4 ) return FT_THROW( Unknown_File_Format ); #endif /* load the table directory */ FT_TRACE2(( "-- Number of tables: %10u\n", sfnt.num_tables )); FT_TRACE2(( "-- Format version: 0x%08lx\n", sfnt.format_tag )); if ( sfnt.format_tag != TTAG_OTTO ) { /* check first */ error = check_table_dir( &sfnt, stream ); if ( error ) { FT_TRACE2(( "tt_face_load_font_dir:" " invalid table directory for TrueType\n" )); goto Exit; } } face->num_tables = sfnt.num_tables; face->format_tag = sfnt.format_tag; if ( FT_QNEW_ARRAY( face->dir_tables, face->num_tables ) ) goto Exit; if ( FT_STREAM_SEEK( sfnt.offset + 12 ) || FT_FRAME_ENTER( face->num_tables * 16L ) ) goto Exit; entry = face->dir_tables; FT_TRACE2(( "\n" " tag offset length checksum\n" " ----------------------------------\n" )); for ( nn = 0; nn < sfnt.num_tables; nn++ ) { entry->Tag = FT_GET_TAG4(); entry->CheckSum = FT_GET_ULONG(); entry->Offset = FT_GET_ULONG(); entry->Length = FT_GET_ULONG(); /* ignore invalid tables */ if ( entry->Offset + entry->Length > stream->size ) continue; else { FT_TRACE2(( " %c%c%c%c %08lx %08lx %08lx\n", (FT_Char)( entry->Tag >> 24 ), (FT_Char)( entry->Tag >> 16 ), (FT_Char)( entry->Tag >> 8 ), (FT_Char)( entry->Tag ), entry->Offset, entry->Length, entry->CheckSum )); entry++; } } FT_FRAME_EXIT(); FT_TRACE2(( "table directory loaded\n\n" )); Exit: return error; } FT_LOCAL_DEF( FT_Error ) tt_face_load_hmtx( TT_Face face, FT_Stream stream, FT_Bool vertical ) { FT_Error error; FT_ULong tag, table_size; FT_ULong* ptable_offset; FT_ULong* ptable_size; if ( vertical ) { tag = TTAG_vmtx; ptable_offset = &face->vert_metrics_offset; ptable_size = &face->vert_metrics_size; } else { tag = TTAG_hmtx; ptable_offset = &face->horz_metrics_offset; ptable_size = &face->horz_metrics_size; } error = face->goto_table( face, tag, stream, &table_size ); if ( error ) goto Fail; *ptable_size = table_size; *ptable_offset = FT_STREAM_POS(); Fail: return error; } FT_LOCAL_DEF( FT_Error ) tt_face_get_metrics( TT_Face face, FT_Bool vertical, FT_UInt gindex, FT_Short *abearing, FT_UShort *aadvance ) { FT_Error error; FT_Stream stream = face->root.stream; TT_HoriHeader* header; FT_ULong table_pos, table_size, table_end; FT_UShort k; if ( vertical ) { void* v = &face->vertical; header = (TT_HoriHeader*)v; table_pos = face->vert_metrics_offset; table_size = face->vert_metrics_size; } else { header = &face->horizontal; table_pos = face->horz_metrics_offset; table_size = face->horz_metrics_size; } table_end = table_pos + table_size; k = header->number_Of_HMetrics; if ( k > 0 ) { if ( gindex < (FT_UInt)k ) { table_pos += 4 * gindex; if ( table_pos + 4 > table_end ) goto NoData; if ( FT_STREAM_SEEK( table_pos ) || FT_READ_USHORT( *aadvance ) || FT_READ_SHORT( *abearing ) ) goto NoData; } else { table_pos += 4 * ( k - 1 ); if ( table_pos + 4 > table_end ) goto NoData; if ( FT_STREAM_SEEK( table_pos ) || FT_READ_USHORT( *aadvance ) ) goto NoData; table_pos += 4 + 2 * ( gindex - k ); if ( table_pos + 2 > table_end ) *abearing = 0; else { if ( !FT_STREAM_SEEK( table_pos ) ) (void)FT_READ_SHORT( *abearing ); } } } else { NoData: *abearing = 0; *aadvance = 0; } return FT_Err_Ok; } FT_LOCAL_DEF( FT_Error ) tt_face_goto_table( TT_Face face, FT_ULong tag, FT_Stream stream, FT_ULong* length ) { TT_Table table; FT_Error error; table = tt_face_lookup_table( face, tag ); if ( table ) { if ( length ) *length = table->Length; if ( FT_STREAM_SEEK( table->Offset ) ) goto Exit; } else error = FT_THROW( Table_Missing ); Exit: return error; } FT_LOCAL_DEF( FT_Error ) sfnt_init_face( FT_Stream stream, TT_Face face, FT_Int face_index, FT_Int num_params, FT_Parameter* params ) { FT_Error error; FT_Library library = face->root.driver->root.library; SFNT_Service sfnt; /* for now, parameters are unused */ FT_UNUSED( num_params ); FT_UNUSED( params ); sfnt = (SFNT_Service)face->sfnt; if ( !sfnt ) { sfnt = (SFNT_Service)FT_Get_Module_Interface( library, "sfnt" ); if ( !sfnt ) { FT_ERROR(( "sfnt_init_face: cannot access `sfnt' module\n" )); return FT_THROW( Missing_Module ); } face->sfnt = sfnt; face->goto_table = sfnt->goto_table; } FT_FACE_FIND_GLOBAL_SERVICE( face, face->psnames, POSTSCRIPT_CMAPS ); FT_TRACE2(( "SFNT driver\n" )); error = sfnt_open_font( stream, face ); if ( error ) return error; /* Stream may have changed in sfnt_open_font. */ stream = face->root.stream; FT_TRACE2(( "sfnt_init_face: %08p, %ld\n", face, face_index )); if ( face_index < 0 ) face_index = 0; if ( face_index >= face->ttc_header.count ) return FT_THROW( Invalid_Argument ); if ( FT_STREAM_SEEK( face->ttc_header.offsets[face_index] ) ) return error; /* check that we have a valid TrueType file */ error = sfnt->load_font_dir( face, stream ); if ( error ) return error; face->root.num_faces = face->ttc_header.count; face->root.face_index = face_index; return error; } FT_LOCAL_DEF( FT_Error ) sfnt_load_face( FT_Stream stream, TT_Face face, FT_Int face_index, FT_Int num_params, FT_Parameter* params ) { FT_Error error; #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES FT_Error psnames_error; #endif FT_Bool has_outline; FT_Bool is_apple_sbit; FT_Bool is_apple_sbix; FT_Bool ignore_preferred_family = FALSE; FT_Bool ignore_preferred_subfamily = FALSE; SFNT_Service sfnt = (SFNT_Service)face->sfnt; FT_UNUSED( face_index ); /* Check parameters */ { FT_Int i; for ( i = 0; i < num_params; i++ ) { if ( params[i].tag == FT_PARAM_TAG_IGNORE_PREFERRED_FAMILY ) ignore_preferred_family = TRUE; else if ( params[i].tag == FT_PARAM_TAG_IGNORE_PREFERRED_SUBFAMILY ) ignore_preferred_subfamily = TRUE; } } /* Load tables */ /* We now support two SFNT-based bitmapped font formats. They */ /* are recognized easily as they do not include a `glyf' */ /* table. */ /* */ /* The first format comes from Apple, and uses a table named */ /* `bhed' instead of `head' to store the font header (using */ /* the same format). It also doesn't include horizontal and */ /* vertical metrics tables (i.e. `hhea' and `vhea' tables are */ /* missing). */ /* */ /* The other format comes from Microsoft, and is used with */ /* WinCE/PocketPC. It looks like a standard TTF, except that */ /* it doesn't contain outlines. */ /* */ FT_TRACE2(( "sfnt_load_face: %08p\n\n", face )); /* do we have outlines in there? */ #ifdef FT_CONFIG_OPTION_INCREMENTAL has_outline = FT_BOOL( face->root.internal->incremental_interface != 0 || tt_face_lookup_table( face, TTAG_glyf ) != 0 || tt_face_lookup_table( face, TTAG_CFF ) != 0 ); #else has_outline = FT_BOOL( tt_face_lookup_table( face, TTAG_glyf ) != 0 || tt_face_lookup_table( face, TTAG_CFF ) != 0 ); #endif is_apple_sbit = 0; is_apple_sbix = !face->goto_table( face, TTAG_sbix, stream, 0 ); /* Apple 'sbix' color bitmaps are rendered scaled and then the 'glyf' * outline rendered on top. We don't support that yet, so just ignore * the 'glyf' outline and advertise it as a bitmap-only font. */ if ( is_apple_sbix ) has_outline = FALSE; /* if this font doesn't contain outlines, we try to load */ /* a `bhed' table */ if ( !has_outline && sfnt->load_bhed ) { LOAD_( bhed ); is_apple_sbit = FT_BOOL( !error ); } /* load the font header (`head' table) if this isn't an Apple */ /* sbit font file */ if ( !is_apple_sbit || is_apple_sbix ) { LOAD_( head ); if ( error ) goto Exit; } if ( face->header.Units_Per_EM == 0 ) { error = FT_THROW( Invalid_Table ); goto Exit; } /* the following tables are often not present in embedded TrueType */ /* fonts within PDF documents, so don't check for them. */ LOAD_( maxp ); LOAD_( cmap ); /* the following tables are optional in PCL fonts -- */ /* don't check for errors */ LOAD_( name ); LOAD_( post ); #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES psnames_error = error; #endif /* do not load the metrics headers and tables if this is an Apple */ /* sbit font file */ if ( !is_apple_sbit ) { /* load the `hhea' and `hmtx' tables */ LOADM_( hhea, 0 ); if ( !error ) { LOADM_( hmtx, 0 ); if ( FT_ERR_EQ( error, Table_Missing ) ) { error = FT_THROW( Hmtx_Table_Missing ); #ifdef FT_CONFIG_OPTION_INCREMENTAL /* If this is an incrementally loaded font and there are */ /* overriding metrics, tolerate a missing `hmtx' table. */ if ( face->root.internal->incremental_interface && face->root.internal->incremental_interface->funcs-> get_glyph_metrics ) { face->horizontal.number_Of_HMetrics = 0; error = FT_Err_Ok; } #endif } } else if ( FT_ERR_EQ( error, Table_Missing ) ) { /* No `hhea' table necessary for SFNT Mac fonts. */ if ( face->format_tag == TTAG_true ) { FT_TRACE2(( "This is an SFNT Mac font.\n" )); has_outline = 0; error = FT_Err_Ok; } else { error = FT_THROW( Horiz_Header_Missing ); #ifdef FT_CONFIG_OPTION_INCREMENTAL /* If this is an incrementally loaded font and there are */ /* overriding metrics, tolerate a missing `hhea' table. */ if ( face->root.internal->incremental_interface && face->root.internal->incremental_interface->funcs-> get_glyph_metrics ) { face->horizontal.number_Of_HMetrics = 0; error = FT_Err_Ok; } #endif } } if ( error ) goto Exit; /* try to load the `vhea' and `vmtx' tables */ LOADM_( hhea, 1 ); if ( !error ) { LOADM_( hmtx, 1 ); if ( !error ) face->vertical_info = 1; } if ( error && FT_ERR_NEQ( error, Table_Missing ) ) goto Exit; LOAD_( os2 ); if ( error ) { /* we treat the table as missing if there are any errors */ face->os2.version = 0xFFFFU; } } /* the optional tables */ /* embedded bitmap support */ if ( sfnt->load_eblc ) { LOAD_( eblc ); if ( error ) { /* a font which contains neither bitmaps nor outlines is */ /* still valid (although rather useless in most cases); */ /* however, you can find such stripped fonts in PDFs */ if ( FT_ERR_EQ( error, Table_Missing ) ) error = FT_Err_Ok; else goto Exit; } } LOAD_( pclt ); if ( error ) { if ( FT_ERR_NEQ( error, Table_Missing ) ) goto Exit; face->pclt.Version = 0; } /* consider the kerning and gasp tables as optional */ LOAD_( gasp ); LOAD_( kern ); face->root.num_glyphs = face->max_profile.numGlyphs; /* Bit 8 of the `fsSelection' field in the `OS/2' table denotes */ /* a WWS-only font face. `WWS' stands for `weight', width', and */ /* `slope', a term used by Microsoft's Windows Presentation */ /* Foundation (WPF). This flag has been introduced in version */ /* 1.5 of the OpenType specification (May 2008). */ face->root.family_name = NULL; face->root.style_name = NULL; if ( face->os2.version != 0xFFFFU && face->os2.fsSelection & 256 ) { if ( !ignore_preferred_family ) GET_NAME( PREFERRED_FAMILY, &face->root.family_name ); if ( !face->root.family_name ) GET_NAME( FONT_FAMILY, &face->root.family_name ); if ( !ignore_preferred_subfamily ) GET_NAME( PREFERRED_SUBFAMILY, &face->root.style_name ); if ( !face->root.style_name ) GET_NAME( FONT_SUBFAMILY, &face->root.style_name ); } else { GET_NAME( WWS_FAMILY, &face->root.family_name ); if ( !face->root.family_name && !ignore_preferred_family ) GET_NAME( PREFERRED_FAMILY, &face->root.family_name ); if ( !face->root.family_name ) GET_NAME( FONT_FAMILY, &face->root.family_name ); GET_NAME( WWS_SUBFAMILY, &face->root.style_name ); if ( !face->root.style_name && !ignore_preferred_subfamily ) GET_NAME( PREFERRED_SUBFAMILY, &face->root.style_name ); if ( !face->root.style_name ) GET_NAME( FONT_SUBFAMILY, &face->root.style_name ); } /* now set up root fields */ { FT_Face root = &face->root; FT_Long flags = root->face_flags; /*********************************************************************/ /* */ /* Compute face flags. */ /* */ if ( face->sbit_table_type == TT_SBIT_TABLE_TYPE_CBLC || face->sbit_table_type == TT_SBIT_TABLE_TYPE_SBIX ) flags |= FT_FACE_FLAG_COLOR; /* color glyphs */ if ( has_outline == TRUE ) flags |= FT_FACE_FLAG_SCALABLE; /* scalable outlines */ /* The sfnt driver only supports bitmap fonts natively, thus we */ /* don't set FT_FACE_FLAG_HINTER. */ flags |= FT_FACE_FLAG_SFNT | /* SFNT file format */ FT_FACE_FLAG_HORIZONTAL; /* horizontal data */ #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES if ( !psnames_error && face->postscript.FormatType != 0x00030000L ) flags |= FT_FACE_FLAG_GLYPH_NAMES; #endif /* fixed width font? */ if ( face->postscript.isFixedPitch ) flags |= FT_FACE_FLAG_FIXED_WIDTH; /* vertical information? */ if ( face->vertical_info ) flags |= FT_FACE_FLAG_VERTICAL; /* kerning available ? */ if ( TT_FACE_HAS_KERNING( face ) ) flags |= FT_FACE_FLAG_KERNING; #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT /* Don't bother to load the tables unless somebody asks for them. */ /* No need to do work which will (probably) not be used. */ if ( tt_face_lookup_table( face, TTAG_glyf ) != 0 && tt_face_lookup_table( face, TTAG_fvar ) != 0 && tt_face_lookup_table( face, TTAG_gvar ) != 0 ) flags |= FT_FACE_FLAG_MULTIPLE_MASTERS; #endif root->face_flags = flags; /*********************************************************************/ /* */ /* Compute style flags. */ /* */ flags = 0; if ( has_outline == TRUE && face->os2.version != 0xFFFFU ) { /* We have an OS/2 table; use the `fsSelection' field. Bit 9 */ /* indicates an oblique font face. This flag has been */ /* introduced in version 1.5 of the OpenType specification. */ if ( face->os2.fsSelection & 512 ) /* bit 9 */ flags |= FT_STYLE_FLAG_ITALIC; else if ( face->os2.fsSelection & 1 ) /* bit 0 */ flags |= FT_STYLE_FLAG_ITALIC; if ( face->os2.fsSelection & 32 ) /* bit 5 */ flags |= FT_STYLE_FLAG_BOLD; } else { /* this is an old Mac font, use the header field */ if ( face->header.Mac_Style & 1 ) flags |= FT_STYLE_FLAG_BOLD; if ( face->header.Mac_Style & 2 ) flags |= FT_STYLE_FLAG_ITALIC; } root->style_flags = flags; /*********************************************************************/ /* */ /* Polish the charmaps. */ /* */ /* Try to set the charmap encoding according to the platform & */ /* encoding ID of each charmap. */ /* */ tt_face_build_cmaps( face ); /* ignore errors */ /* set the encoding fields */ { FT_Int m; for ( m = 0; m < root->num_charmaps; m++ ) { FT_CharMap charmap = root->charmaps[m]; charmap->encoding = sfnt_find_encoding( charmap->platform_id, charmap->encoding_id ); #if 0 if ( root->charmap == NULL && charmap->encoding == FT_ENCODING_UNICODE ) { /* set 'root->charmap' to the first Unicode encoding we find */ root->charmap = charmap; } #endif } } #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS /* * Now allocate the root array of FT_Bitmap_Size records and * populate them. Unfortunately, it isn't possible to indicate bit * depths in the FT_Bitmap_Size record. This is a design error. */ { FT_UInt i, count; count = face->sbit_num_strikes; if ( count > 0 ) { FT_Memory memory = face->root.stream->memory; FT_UShort em_size = face->header.Units_Per_EM; FT_Short avgwidth = face->os2.xAvgCharWidth; FT_Size_Metrics metrics; if ( em_size == 0 || face->os2.version == 0xFFFFU ) { avgwidth = 1; em_size = 1; } if ( FT_NEW_ARRAY( root->available_sizes, count ) ) goto Exit; for ( i = 0; i < count; i++ ) { FT_Bitmap_Size* bsize = root->available_sizes + i; error = sfnt->load_strike_metrics( face, i, &metrics ); if ( error ) goto Exit; bsize->height = (FT_Short)( metrics.height >> 6 ); bsize->width = (FT_Short)( ( avgwidth * metrics.x_ppem + em_size / 2 ) / em_size ); bsize->x_ppem = metrics.x_ppem << 6; bsize->y_ppem = metrics.y_ppem << 6; /* assume 72dpi */ bsize->size = metrics.y_ppem << 6; } root->face_flags |= FT_FACE_FLAG_FIXED_SIZES; root->num_fixed_sizes = (FT_Int)count; } } #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ /* a font with no bitmaps and no outlines is scalable; */ /* it has only empty glyphs then */ if ( !FT_HAS_FIXED_SIZES( root ) && !FT_IS_SCALABLE( root ) ) root->face_flags |= FT_FACE_FLAG_SCALABLE; /*********************************************************************/ /* */ /* Set up metrics. */ /* */ if ( FT_IS_SCALABLE( root ) ) { /* XXX What about if outline header is missing */ /* (e.g. sfnt wrapped bitmap)? */ root->bbox.xMin = face->header.xMin; root->bbox.yMin = face->header.yMin; root->bbox.xMax = face->header.xMax; root->bbox.yMax = face->header.yMax; root->units_per_EM = face->header.Units_Per_EM; /* XXX: Computing the ascender/descender/height is very different */ /* from what the specification tells you. Apparently, we */ /* must be careful because */ /* */ /* - not all fonts have an OS/2 table; in this case, we take */ /* the values in the horizontal header. However, these */ /* values very often are not reliable. */ /* */ /* - otherwise, the correct typographic values are in the */ /* sTypoAscender, sTypoDescender & sTypoLineGap fields. */ /* */ /* However, certain fonts have these fields set to 0. */ /* Rather, they have usWinAscent & usWinDescent correctly */ /* set (but with different values). */ /* */ /* As an example, Arial Narrow is implemented through four */ /* files ARIALN.TTF, ARIALNI.TTF, ARIALNB.TTF & ARIALNBI.TTF */ /* */ /* Strangely, all fonts have the same values in their */ /* sTypoXXX fields, except ARIALNB which sets them to 0. */ /* */ /* On the other hand, they all have different */ /* usWinAscent/Descent values -- as a conclusion, the OS/2 */ /* table cannot be used to compute the text height reliably! */ /* */ /* The ascender and descender are taken from the `hhea' table. */ /* If zero, they are taken from the `OS/2' table. */ root->ascender = face->horizontal.Ascender; root->descender = face->horizontal.Descender; root->height = (FT_Short)( root->ascender - root->descender + face->horizontal.Line_Gap ); if ( !( root->ascender || root->descender ) ) { if ( face->os2.version != 0xFFFFU ) { if ( face->os2.sTypoAscender || face->os2.sTypoDescender ) { root->ascender = face->os2.sTypoAscender; root->descender = face->os2.sTypoDescender; root->height = (FT_Short)( root->ascender - root->descender + face->os2.sTypoLineGap ); } else { root->ascender = (FT_Short)face->os2.usWinAscent; root->descender = -(FT_Short)face->os2.usWinDescent; root->height = (FT_UShort)( root->ascender - root->descender ); } } } root->max_advance_width = face->horizontal.advance_Width_Max; root->max_advance_height = (FT_Short)( face->vertical_info ? face->vertical.advance_Height_Max : root->height ); /* See http://www.microsoft.com/OpenType/OTSpec/post.htm -- */ /* Adjust underline position from top edge to centre of */ /* stroke to convert TrueType meaning to FreeType meaning. */ root->underline_position = face->postscript.underlinePosition - face->postscript.underlineThickness / 2; root->underline_thickness = face->postscript.underlineThickness; } } Exit: FT_TRACE2(( "sfnt_load_face: done\n" )); return error; } FT_LOCAL_DEF( void ) sfnt_done_face( TT_Face face ) { FT_Memory memory; SFNT_Service sfnt; if ( !face ) return; memory = face->root.memory; sfnt = (SFNT_Service)face->sfnt; if ( sfnt ) { /* destroy the postscript names table if it is loaded */ if ( sfnt->free_psnames ) sfnt->free_psnames( face ); /* destroy the embedded bitmaps table if it is loaded */ if ( sfnt->free_eblc ) sfnt->free_eblc( face ); } #ifdef TT_CONFIG_OPTION_BDF /* freeing the embedded BDF properties */ tt_face_free_bdf_props( face ); #endif /* freeing the kerning table */ tt_face_done_kern( face ); /* freeing the collection table */ FT_FREE( face->ttc_header.offsets ); face->ttc_header.count = 0; /* freeing table directory */ FT_FREE( face->dir_tables ); face->num_tables = 0; { FT_Stream stream = FT_FACE_STREAM( face ); /* simply release the 'cmap' table frame */ FT_FRAME_RELEASE( face->cmap_table ); face->cmap_size = 0; } /* freeing the horizontal metrics */ { FT_Stream stream = FT_FACE_STREAM( face ); FT_FRAME_RELEASE( face->horz_metrics ); FT_FRAME_RELEASE( face->vert_metrics ); face->horz_metrics_size = 0; face->vert_metrics_size = 0; } /* freeing the vertical ones, if any */ if ( face->vertical_info ) { FT_FREE( face->vertical.long_metrics ); FT_FREE( face->vertical.short_metrics ); face->vertical_info = 0; } /* freeing the gasp table */ FT_FREE( face->gasp.gaspRanges ); face->gasp.numRanges = 0; /* freeing the name table */ if ( sfnt ) sfnt->free_name( face ); /* freeing family and style name */ FT_FREE( face->root.family_name ); FT_FREE( face->root.style_name ); /* freeing sbit size table */ FT_FREE( face->root.available_sizes ); face->root.num_fixed_sizes = 0; FT_FREE( face->postscript_name ); face->sfnt = 0; } FT_CALLBACK_DEF( FT_Module_Interface ) sfnt_get_interface( FT_Module module, const char* module_interface ) { /* SFNT_SERVICES_GET derefers `library' in PIC mode */ #ifdef FT_CONFIG_OPTION_PIC FT_Library library; if ( !module ) return NULL; library = module->library; if ( !library ) return NULL; #else FT_UNUSED( module ); #endif return ft_service_list_lookup( SFNT_SERVICES_GET, module_interface ); } FT_LOCAL_DEF( FT_Error ) tt_face_load_any( TT_Face face, FT_ULong tag, FT_Long offset, FT_Byte* buffer, FT_ULong* length ) { FT_Error error; FT_Stream stream; TT_Table table; FT_ULong size; if ( tag != 0 ) { /* look for tag in font directory */ table = tt_face_lookup_table( face, tag ); if ( !table ) { error = FT_THROW( Table_Missing ); goto Exit; } offset += table->Offset; size = table->Length; } else /* tag == 0 -- the user wants to access the font file directly */ size = face->root.stream->size; if ( length && *length == 0 ) { *length = size; return FT_Err_Ok; } if ( length ) size = *length; stream = face->root.stream; /* the `if' is syntactic sugar for picky compilers */ if ( FT_STREAM_READ_AT( offset, buffer, size ) ) goto Exit; Exit: return error; } FT_LOCAL_DEF( FT_Error ) tt_face_load_head( TT_Face face, FT_Stream stream ) { return tt_face_load_generic_header( face, stream, TTAG_head ); } FT_LOCAL_DEF( FT_Error ) tt_face_load_hhea( TT_Face face, FT_Stream stream, FT_Bool vertical ) { FT_Error error; TT_HoriHeader* header; static const FT_Frame_Field metrics_header_fields[] = { #undef FT_STRUCTURE #define FT_STRUCTURE TT_HoriHeader FT_FRAME_START( 36 ), FT_FRAME_ULONG ( Version ), FT_FRAME_SHORT ( Ascender ), FT_FRAME_SHORT ( Descender ), FT_FRAME_SHORT ( Line_Gap ), FT_FRAME_USHORT( advance_Width_Max ), FT_FRAME_SHORT ( min_Left_Side_Bearing ), FT_FRAME_SHORT ( min_Right_Side_Bearing ), FT_FRAME_SHORT ( xMax_Extent ), FT_FRAME_SHORT ( caret_Slope_Rise ), FT_FRAME_SHORT ( caret_Slope_Run ), FT_FRAME_SHORT ( caret_Offset ), FT_FRAME_SHORT ( Reserved[0] ), FT_FRAME_SHORT ( Reserved[1] ), FT_FRAME_SHORT ( Reserved[2] ), FT_FRAME_SHORT ( Reserved[3] ), FT_FRAME_SHORT ( metric_Data_Format ), FT_FRAME_USHORT( number_Of_HMetrics ), FT_FRAME_END }; if ( vertical ) { void *v = &face->vertical; error = face->goto_table( face, TTAG_vhea, stream, 0 ); if ( error ) goto Fail; header = (TT_HoriHeader*)v; } else { error = face->goto_table( face, TTAG_hhea, stream, 0 ); if ( error ) goto Fail; header = &face->horizontal; } if ( FT_STREAM_READ_FIELDS( metrics_header_fields, header ) ) goto Fail; FT_TRACE3(( "Ascender: %5d\n", header->Ascender )); FT_TRACE3(( "Descender: %5d\n", header->Descender )); FT_TRACE3(( "number_Of_Metrics: %5u\n", header->number_Of_HMetrics )); header->long_metrics = NULL; header->short_metrics = NULL; Fail: return error; } FT_LOCAL_DEF( FT_Error ) tt_face_load_cmap( TT_Face face, FT_Stream stream ) { FT_Error error; error = face->goto_table( face, TTAG_cmap, stream, &face->cmap_size ); if ( error ) goto Exit; if ( FT_FRAME_EXTRACT( face->cmap_size, face->cmap_table ) ) face->cmap_size = 0; Exit: return error; } FT_LOCAL_DEF( FT_Error ) tt_face_load_maxp( TT_Face face, FT_Stream stream ) { FT_Error error; TT_MaxProfile* maxProfile = &face->max_profile; static const FT_Frame_Field maxp_fields[] = { #undef FT_STRUCTURE #define FT_STRUCTURE TT_MaxProfile FT_FRAME_START( 6 ), FT_FRAME_LONG ( version ), FT_FRAME_USHORT( numGlyphs ), FT_FRAME_END }; static const FT_Frame_Field maxp_fields_extra[] = { FT_FRAME_START( 26 ), FT_FRAME_USHORT( maxPoints ), FT_FRAME_USHORT( maxContours ), FT_FRAME_USHORT( maxCompositePoints ), FT_FRAME_USHORT( maxCompositeContours ), FT_FRAME_USHORT( maxZones ), FT_FRAME_USHORT( maxTwilightPoints ), FT_FRAME_USHORT( maxStorage ), FT_FRAME_USHORT( maxFunctionDefs ), FT_FRAME_USHORT( maxInstructionDefs ), FT_FRAME_USHORT( maxStackElements ), FT_FRAME_USHORT( maxSizeOfInstructions ), FT_FRAME_USHORT( maxComponentElements ), FT_FRAME_USHORT( maxComponentDepth ), FT_FRAME_END }; error = face->goto_table( face, TTAG_maxp, stream, 0 ); if ( error ) goto Exit; if ( FT_STREAM_READ_FIELDS( maxp_fields, maxProfile ) ) goto Exit; maxProfile->maxPoints = 0; maxProfile->maxContours = 0; maxProfile->maxCompositePoints = 0; maxProfile->maxCompositeContours = 0; maxProfile->maxZones = 0; maxProfile->maxTwilightPoints = 0; maxProfile->maxStorage = 0; maxProfile->maxFunctionDefs = 0; maxProfile->maxInstructionDefs = 0; maxProfile->maxStackElements = 0; maxProfile->maxSizeOfInstructions = 0; maxProfile->maxComponentElements = 0; maxProfile->maxComponentDepth = 0; if ( maxProfile->version >= 0x10000L ) { if ( FT_STREAM_READ_FIELDS( maxp_fields_extra, maxProfile ) ) goto Exit; /* XXX: an adjustment that is necessary to load certain */ /* broken fonts like `Keystrokes MT' :-( */ /* */ /* We allocate 64 function entries by default when */ /* the maxFunctionDefs value is smaller. */ if ( maxProfile->maxFunctionDefs < 64 ) maxProfile->maxFunctionDefs = 64; /* we add 4 phantom points later */ if ( maxProfile->maxTwilightPoints > ( 0xFFFFU - 4 ) ) { FT_TRACE0(( "tt_face_load_maxp:" " too much twilight points in `maxp' table;\n" " " " some glyphs might be rendered incorrectly\n" )); maxProfile->maxTwilightPoints = 0xFFFFU - 4; } /* we arbitrarily limit recursion to avoid stack exhaustion */ if ( maxProfile->maxComponentDepth > 100 ) { FT_TRACE0(( "tt_face_load_maxp:" " abnormally large component depth (%d) set to 100\n", maxProfile->maxComponentDepth )); maxProfile->maxComponentDepth = 100; } } FT_TRACE3(( "numGlyphs: %u\n", maxProfile->numGlyphs )); Exit: return error; } FT_LOCAL_DEF( FT_Error ) tt_face_load_os2( TT_Face face, FT_Stream stream ) { FT_Error error; TT_OS2* os2; static const FT_Frame_Field os2_fields[] = { #undef FT_STRUCTURE #define FT_STRUCTURE TT_OS2 FT_FRAME_START( 78 ), FT_FRAME_USHORT( version ), FT_FRAME_SHORT ( xAvgCharWidth ), FT_FRAME_USHORT( usWeightClass ), FT_FRAME_USHORT( usWidthClass ), FT_FRAME_SHORT ( fsType ), FT_FRAME_SHORT ( ySubscriptXSize ), FT_FRAME_SHORT ( ySubscriptYSize ), FT_FRAME_SHORT ( ySubscriptXOffset ), FT_FRAME_SHORT ( ySubscriptYOffset ), FT_FRAME_SHORT ( ySuperscriptXSize ), FT_FRAME_SHORT ( ySuperscriptYSize ), FT_FRAME_SHORT ( ySuperscriptXOffset ), FT_FRAME_SHORT ( ySuperscriptYOffset ), FT_FRAME_SHORT ( yStrikeoutSize ), FT_FRAME_SHORT ( yStrikeoutPosition ), FT_FRAME_SHORT ( sFamilyClass ), FT_FRAME_BYTE ( panose[0] ), FT_FRAME_BYTE ( panose[1] ), FT_FRAME_BYTE ( panose[2] ), FT_FRAME_BYTE ( panose[3] ), FT_FRAME_BYTE ( panose[4] ), FT_FRAME_BYTE ( panose[5] ), FT_FRAME_BYTE ( panose[6] ), FT_FRAME_BYTE ( panose[7] ), FT_FRAME_BYTE ( panose[8] ), FT_FRAME_BYTE ( panose[9] ), FT_FRAME_ULONG ( ulUnicodeRange1 ), FT_FRAME_ULONG ( ulUnicodeRange2 ), FT_FRAME_ULONG ( ulUnicodeRange3 ), FT_FRAME_ULONG ( ulUnicodeRange4 ), FT_FRAME_BYTE ( achVendID[0] ), FT_FRAME_BYTE ( achVendID[1] ), FT_FRAME_BYTE ( achVendID[2] ), FT_FRAME_BYTE ( achVendID[3] ), FT_FRAME_USHORT( fsSelection ), FT_FRAME_USHORT( usFirstCharIndex ), FT_FRAME_USHORT( usLastCharIndex ), FT_FRAME_SHORT ( sTypoAscender ), FT_FRAME_SHORT ( sTypoDescender ), FT_FRAME_SHORT ( sTypoLineGap ), FT_FRAME_USHORT( usWinAscent ), FT_FRAME_USHORT( usWinDescent ), FT_FRAME_END }; /* `OS/2' version 1 and newer */ static const FT_Frame_Field os2_fields_extra1[] = { FT_FRAME_START( 8 ), FT_FRAME_ULONG( ulCodePageRange1 ), FT_FRAME_ULONG( ulCodePageRange2 ), FT_FRAME_END }; /* `OS/2' version 2 and newer */ static const FT_Frame_Field os2_fields_extra2[] = { FT_FRAME_START( 10 ), FT_FRAME_SHORT ( sxHeight ), FT_FRAME_SHORT ( sCapHeight ), FT_FRAME_USHORT( usDefaultChar ), FT_FRAME_USHORT( usBreakChar ), FT_FRAME_USHORT( usMaxContext ), FT_FRAME_END }; /* `OS/2' version 5 and newer */ static const FT_Frame_Field os2_fields_extra5[] = { FT_FRAME_START( 4 ), FT_FRAME_USHORT( usLowerOpticalPointSize ), FT_FRAME_USHORT( usUpperOpticalPointSize ), FT_FRAME_END }; /* We now support old Mac fonts where the OS/2 table doesn't */ /* exist. Simply put, we set the `version' field to 0xFFFF */ /* and test this value each time we need to access the table. */ error = face->goto_table( face, TTAG_OS2, stream, 0 ); if ( error ) goto Exit; os2 = &face->os2; if ( FT_STREAM_READ_FIELDS( os2_fields, os2 ) ) goto Exit; os2->ulCodePageRange1 = 0; os2->ulCodePageRange2 = 0; os2->sxHeight = 0; os2->sCapHeight = 0; os2->usDefaultChar = 0; os2->usBreakChar = 0; os2->usMaxContext = 0; os2->usLowerOpticalPointSize = 0; os2->usUpperOpticalPointSize = 0xFFFF; if ( os2->version >= 0x0001 ) { /* only version 1 tables */ if ( FT_STREAM_READ_FIELDS( os2_fields_extra1, os2 ) ) goto Exit; if ( os2->version >= 0x0002 ) { /* only version 2 tables */ if ( FT_STREAM_READ_FIELDS( os2_fields_extra2, os2 ) ) goto Exit; if ( os2->version >= 0x0005 ) { /* only version 5 tables */ if ( FT_STREAM_READ_FIELDS( os2_fields_extra5, os2 ) ) goto Exit; } } } FT_TRACE3(( "sTypoAscender: %4d\n", os2->sTypoAscender )); FT_TRACE3(( "sTypoDescender: %4d\n", os2->sTypoDescender )); FT_TRACE3(( "usWinAscent: %4u\n", os2->usWinAscent )); FT_TRACE3(( "usWinDescent: %4u\n", os2->usWinDescent )); FT_TRACE3(( "fsSelection: 0x%2x\n", os2->fsSelection )); Exit: return error; } FT_LOCAL_DEF( FT_Error ) tt_face_load_post( TT_Face face, FT_Stream stream ) { FT_Error error; TT_Postscript* post = &face->postscript; static const FT_Frame_Field post_fields[] = { #undef FT_STRUCTURE #define FT_STRUCTURE TT_Postscript FT_FRAME_START( 32 ), FT_FRAME_ULONG( FormatType ), FT_FRAME_ULONG( italicAngle ), FT_FRAME_SHORT( underlinePosition ), FT_FRAME_SHORT( underlineThickness ), FT_FRAME_ULONG( isFixedPitch ), FT_FRAME_ULONG( minMemType42 ), FT_FRAME_ULONG( maxMemType42 ), FT_FRAME_ULONG( minMemType1 ), FT_FRAME_ULONG( maxMemType1 ), FT_FRAME_END }; error = face->goto_table( face, TTAG_post, stream, 0 ); if ( error ) return error; if ( FT_STREAM_READ_FIELDS( post_fields, post ) ) return error; /* we don't load the glyph names, we do that in another */ /* module (ttpost). */ FT_TRACE3(( "FormatType: 0x%x\n", post->FormatType )); FT_TRACE3(( "isFixedPitch: %s\n", post->isFixedPitch ? " yes" : " no" )); return FT_Err_Ok; } FT_LOCAL_DEF( FT_Error ) tt_face_load_name( TT_Face face, FT_Stream stream ) { FT_Error error; FT_Memory memory = stream->memory; FT_ULong table_pos, table_len; FT_ULong storage_start, storage_limit; FT_UInt count; TT_NameTable table; static const FT_Frame_Field name_table_fields[] = { #undef FT_STRUCTURE #define FT_STRUCTURE TT_NameTableRec FT_FRAME_START( 6 ), FT_FRAME_USHORT( format ), FT_FRAME_USHORT( numNameRecords ), FT_FRAME_USHORT( storageOffset ), FT_FRAME_END }; static const FT_Frame_Field name_record_fields[] = { #undef FT_STRUCTURE #define FT_STRUCTURE TT_NameEntryRec /* no FT_FRAME_START */ FT_FRAME_USHORT( platformID ), FT_FRAME_USHORT( encodingID ), FT_FRAME_USHORT( languageID ), FT_FRAME_USHORT( nameID ), FT_FRAME_USHORT( stringLength ), FT_FRAME_USHORT( stringOffset ), FT_FRAME_END }; table = &face->name_table; table->stream = stream; error = face->goto_table( face, TTAG_name, stream, &table_len ); if ( error ) goto Exit; table_pos = FT_STREAM_POS(); if ( FT_STREAM_READ_FIELDS( name_table_fields, table ) ) goto Exit; /* Some popular Asian fonts have an invalid `storageOffset' value */ /* (it should be at least "6 + 12*num_names"). However, the string */ /* offsets, computed as "storageOffset + entry->stringOffset", are */ /* valid pointers within the name table... */ /* */ /* We thus can't check `storageOffset' right now. */ /* */ storage_start = table_pos + 6 + 12*table->numNameRecords; storage_limit = table_pos + table_len; if ( storage_start > storage_limit ) { FT_ERROR(( "tt_face_load_name: invalid `name' table\n" )); error = FT_THROW( Name_Table_Missing ); goto Exit; } /* Allocate the array of name records. */ count = table->numNameRecords; table->numNameRecords = 0; if ( FT_NEW_ARRAY( table->names, count ) || FT_FRAME_ENTER( count * 12 ) ) goto Exit; /* Load the name records and determine how much storage is needed */ /* to hold the strings themselves. */ { TT_NameEntryRec* entry = table->names; for ( ; count > 0; count-- ) { if ( FT_STREAM_READ_FIELDS( name_record_fields, entry ) ) continue; /* check that the name is not empty */ if ( entry->stringLength == 0 ) continue; /* check that the name string is within the table */ entry->stringOffset += table_pos + table->storageOffset; if ( entry->stringOffset < storage_start || entry->stringOffset + entry->stringLength > storage_limit ) { /* invalid entry - ignore it */ entry->stringOffset = 0; entry->stringLength = 0; continue; } entry++; } table->numNameRecords = (FT_UInt)( entry - table->names ); } FT_FRAME_EXIT(); /* everything went well, update face->num_names */ face->num_names = (FT_UShort) table->numNameRecords; Exit: return error; } FT_LOCAL_DEF( void ) tt_face_free_name( TT_Face face ) { FT_Memory memory = face->root.driver->root.memory; TT_NameTable table = &face->name_table; TT_NameEntry entry = table->names; FT_UInt count = table->numNameRecords; if ( table->names ) { for ( ; count > 0; count--, entry++ ) { FT_FREE( entry->string ); entry->stringLength = 0; } /* free strings table */ FT_FREE( table->names ); } table->numNameRecords = 0; table->format = 0; table->storageOffset = 0; } FT_LOCAL_DEF( FT_Error ) tt_face_load_kern( TT_Face face, FT_Stream stream ) { FT_Error error; FT_ULong table_size; FT_Byte* p; FT_Byte* p_limit; FT_UInt nn, num_tables; FT_UInt32 avail = 0, ordered = 0; /* the kern table is optional; exit silently if it is missing */ error = face->goto_table( face, TTAG_kern, stream, &table_size ); if ( error ) goto Exit; if ( table_size < 4 ) /* the case of a malformed table */ { FT_ERROR(( "tt_face_load_kern:" " kerning table is too small - ignored\n" )); error = FT_THROW( Table_Missing ); goto Exit; } if ( FT_FRAME_EXTRACT( table_size, face->kern_table ) ) { FT_ERROR(( "tt_face_load_kern:" " could not extract kerning table\n" )); goto Exit; } face->kern_table_size = table_size; p = face->kern_table; p_limit = p + table_size; p += 2; /* skip version */ num_tables = FT_NEXT_USHORT( p ); if ( num_tables > 32 ) /* we only support up to 32 sub-tables */ num_tables = 32; for ( nn = 0; nn < num_tables; nn++ ) { FT_UInt num_pairs, length, coverage; FT_Byte* p_next; FT_UInt32 mask = (FT_UInt32)1UL << nn; if ( p + 6 > p_limit ) break; p_next = p; p += 2; /* skip version */ length = FT_NEXT_USHORT( p ); coverage = FT_NEXT_USHORT( p ); if ( length <= 6 ) break; p_next += length; if ( p_next > p_limit ) /* handle broken table */ p_next = p_limit; /* only use horizontal kerning tables */ if ( ( coverage & ~8 ) != 0x0001 || p + 8 > p_limit ) goto NextTable; num_pairs = FT_NEXT_USHORT( p ); p += 6; if ( ( p_next - p ) < 6 * (int)num_pairs ) /* handle broken count */ num_pairs = (FT_UInt)( ( p_next - p ) / 6 ); avail |= mask; /* * Now check whether the pairs in this table are ordered. * We then can use binary search. */ if ( num_pairs > 0 ) { FT_ULong count; FT_ULong old_pair; old_pair = FT_NEXT_ULONG( p ); p += 2; for ( count = num_pairs - 1; count > 0; count-- ) { FT_UInt32 cur_pair; cur_pair = FT_NEXT_ULONG( p ); if ( cur_pair <= old_pair ) break; p += 2; old_pair = cur_pair; } if ( count == 0 ) ordered |= mask; } NextTable: p = p_next; } face->num_kern_tables = nn; face->kern_avail_bits = avail; face->kern_order_bits = ordered; Exit: return error; } FT_LOCAL_DEF( FT_Error ) tt_face_load_gasp( TT_Face face, FT_Stream stream ) { FT_Error error; FT_Memory memory = stream->memory; FT_UInt j,num_ranges; TT_GaspRange gaspranges = NULL; /* the gasp table is optional */ error = face->goto_table( face, TTAG_gasp, stream, 0 ); if ( error ) goto Exit; if ( FT_FRAME_ENTER( 4L ) ) goto Exit; face->gasp.version = FT_GET_USHORT(); face->gasp.numRanges = FT_GET_USHORT(); FT_FRAME_EXIT(); /* only support versions 0 and 1 of the table */ if ( face->gasp.version >= 2 ) { face->gasp.numRanges = 0; error = FT_THROW( Invalid_Table ); goto Exit; } num_ranges = face->gasp.numRanges; FT_TRACE3(( "numRanges: %u\n", num_ranges )); if ( FT_QNEW_ARRAY( face->gasp.gaspRanges, num_ranges ) || FT_FRAME_ENTER( num_ranges * 4L ) ) goto Exit; gaspranges = face->gasp.gaspRanges; for ( j = 0; j < num_ranges; j++ ) { gaspranges[j].maxPPEM = FT_GET_USHORT(); gaspranges[j].gaspFlag = FT_GET_USHORT(); FT_TRACE3(( "gaspRange %d: rangeMaxPPEM %5d, rangeGaspBehavior 0x%x\n", j, gaspranges[j].maxPPEM, gaspranges[j].gaspFlag )); } FT_FRAME_EXIT(); Exit: return error; } FT_LOCAL_DEF( FT_Error ) tt_face_load_pclt( TT_Face face, FT_Stream stream ) { static const FT_Frame_Field pclt_fields[] = { #undef FT_STRUCTURE #define FT_STRUCTURE TT_PCLT FT_FRAME_START( 54 ), FT_FRAME_ULONG ( Version ), FT_FRAME_ULONG ( FontNumber ), FT_FRAME_USHORT( Pitch ), FT_FRAME_USHORT( xHeight ), FT_FRAME_USHORT( Style ), FT_FRAME_USHORT( TypeFamily ), FT_FRAME_USHORT( CapHeight ), FT_FRAME_USHORT( SymbolSet ), FT_FRAME_BYTES ( TypeFace, 16 ), FT_FRAME_BYTES ( CharacterComplement, 8 ), FT_FRAME_BYTES ( FileName, 6 ), FT_FRAME_CHAR ( StrokeWeight ), FT_FRAME_CHAR ( WidthType ), FT_FRAME_BYTE ( SerifStyle ), FT_FRAME_BYTE ( Reserved ), FT_FRAME_END }; FT_Error error; TT_PCLT* pclt = &face->pclt; /* optional table */ error = face->goto_table( face, TTAG_PCLT, stream, 0 ); if ( error ) goto Exit; if ( FT_STREAM_READ_FIELDS( pclt_fields, pclt ) ) goto Exit; Exit: return error; } #define AF_UNIRANGE_REC( a, b ) { (FT_UInt32)(a), (FT_UInt32)(b) } const AF_Script_UniRangeRec af_cyrl_uniranges[] = { AF_UNIRANGE_REC( 0x0400UL, 0x04FFUL ), /* Cyrillic */ AF_UNIRANGE_REC( 0x0500UL, 0x052FUL ), /* Cyrillic Supplement */ AF_UNIRANGE_REC( 0x2DE0UL, 0x2DFFUL ), /* Cyrillic Extended-A */ AF_UNIRANGE_REC( 0xA640UL, 0xA69FUL ), /* Cyrillic Extended-B */ AF_UNIRANGE_REC( 0UL, 0UL ) }; const AF_Script_UniRangeRec af_grek_uniranges[] = { AF_UNIRANGE_REC( 0x0370UL, 0x03FFUL ), /* Greek and Coptic */ AF_UNIRANGE_REC( 0x1F00UL, 0x1FFFUL ), /* Greek Extended */ AF_UNIRANGE_REC( 0UL, 0UL ) }; const AF_Script_UniRangeRec af_hebr_uniranges[] = { AF_UNIRANGE_REC( 0x0590UL, 0x05FFUL ), /* Hebrew */ AF_UNIRANGE_REC( 0xFB1DUL, 0xFB4FUL ), /* Alphab. Present. Forms (Hebrew) */ AF_UNIRANGE_REC( 0UL, 0UL ) }; const AF_Script_UniRangeRec af_latn_uniranges[] = { AF_UNIRANGE_REC( 0x0020UL, 0x007FUL ), /* Basic Latin (no control chars) */ AF_UNIRANGE_REC( 0x00A0UL, 0x00FFUL ), /* Latin-1 Supplement (no control chars) */ AF_UNIRANGE_REC( 0x0100UL, 0x017FUL ), /* Latin Extended-A */ AF_UNIRANGE_REC( 0x0180UL, 0x024FUL ), /* Latin Extended-B */ AF_UNIRANGE_REC( 0x0250UL, 0x02AFUL ), /* IPA Extensions */ AF_UNIRANGE_REC( 0x02B0UL, 0x02FFUL ), /* Spacing Modifier Letters */ AF_UNIRANGE_REC( 0x0300UL, 0x036FUL ), /* Combining Diacritical Marks */ AF_UNIRANGE_REC( 0x1D00UL, 0x1D7FUL ), /* Phonetic Extensions */ AF_UNIRANGE_REC( 0x1D80UL, 0x1DBFUL ), /* Phonetic Extensions Supplement */ AF_UNIRANGE_REC( 0x1DC0UL, 0x1DFFUL ), /* Combining Diacritical Marks Supplement */ AF_UNIRANGE_REC( 0x1E00UL, 0x1EFFUL ), /* Latin Extended Additional */ AF_UNIRANGE_REC( 0x2000UL, 0x206FUL ), /* General Punctuation */ AF_UNIRANGE_REC( 0x2070UL, 0x209FUL ), /* Superscripts and Subscripts */ AF_UNIRANGE_REC( 0x20A0UL, 0x20CFUL ), /* Currency Symbols */ AF_UNIRANGE_REC( 0x2150UL, 0x218FUL ), /* Number Forms */ AF_UNIRANGE_REC( 0x2460UL, 0x24FFUL ), /* Enclosed Alphanumerics */ AF_UNIRANGE_REC( 0x2C60UL, 0x2C7FUL ), /* Latin Extended-C */ AF_UNIRANGE_REC( 0x2E00UL, 0x2E7FUL ), /* Supplemental Punctuation */ AF_UNIRANGE_REC( 0xA720UL, 0xA7FFUL ), /* Latin Extended-D */ AF_UNIRANGE_REC( 0xFB00UL, 0xFB06UL ), /* Alphab. Present. Forms (Latin Ligs) */ AF_UNIRANGE_REC( 0x1D400UL, 0x1D7FFUL ), /* Mathematical Alphanumeric Symbols */ AF_UNIRANGE_REC( 0x1F100UL, 0x1F1FFUL ), /* Enclosed Alphanumeric Supplement */ AF_UNIRANGE_REC( 0UL, 0UL ) }; const AF_Script_UniRangeRec af_none_uniranges[] = { AF_UNIRANGE_REC( 0UL, 0UL ) }; #ifdef AF_CONFIG_OPTION_INDIC const AF_Script_UniRangeRec af_beng_uniranges[] = { AF_UNIRANGE_REC( 0x0980UL, 0x09FFUL ), /* Bengali */ AF_UNIRANGE_REC( 0UL, 0UL ) }; const AF_Script_UniRangeRec af_deva_uniranges[] = { AF_UNIRANGE_REC( 0x0900UL, 0x097FUL ), /* Devanagari */ AF_UNIRANGE_REC( 0UL, 0UL ) }; const AF_Script_UniRangeRec af_gujr_uniranges[] = { AF_UNIRANGE_REC( 0x0A80UL, 0x0AFFUL ), /* Gujarati */ AF_UNIRANGE_REC( 0UL, 0UL ) }; const AF_Script_UniRangeRec af_guru_uniranges[] = { AF_UNIRANGE_REC( 0x0A00UL, 0x0A7FUL ), /* Gurmukhi */ AF_UNIRANGE_REC( 0UL, 0UL ) }; const AF_Script_UniRangeRec af_knda_uniranges[] = { AF_UNIRANGE_REC( 0x0C80UL, 0x0CFFUL ), /* Kannada */ AF_UNIRANGE_REC( 0UL, 0UL ) }; const AF_Script_UniRangeRec af_limb_uniranges[] = { AF_UNIRANGE_REC( 0x1900UL, 0x194FUL ), /* Limbu */ AF_UNIRANGE_REC( 0UL, 0UL ) }; const AF_Script_UniRangeRec af_mlym_uniranges[] = { AF_UNIRANGE_REC( 0x0D00UL, 0x0D7FUL ), /* Malayalam */ AF_UNIRANGE_REC( 0UL, 0UL ) }; const AF_Script_UniRangeRec af_orya_uniranges[] = { AF_UNIRANGE_REC( 0x0B00UL, 0x0B7FUL ), /* Oriya */ AF_UNIRANGE_REC( 0UL, 0UL ) }; const AF_Script_UniRangeRec af_sinh_uniranges[] = { AF_UNIRANGE_REC( 0x0D80UL, 0x0DFFUL ), /* Sinhala */ AF_UNIRANGE_REC( 0UL, 0UL ) }; const AF_Script_UniRangeRec af_sund_uniranges[] = { AF_UNIRANGE_REC( 0x1B80UL, 0x1BBFUL ), /* Sundanese */ AF_UNIRANGE_REC( 0UL, 0UL ) }; const AF_Script_UniRangeRec af_sylo_uniranges[] = { AF_UNIRANGE_REC( 0xA800UL, 0xA82FUL ), /* Syloti Nagri */ AF_UNIRANGE_REC( 0UL, 0UL ) }; const AF_Script_UniRangeRec af_taml_uniranges[] = { AF_UNIRANGE_REC( 0x0B80UL, 0x0BFFUL ), /* Tamil */ AF_UNIRANGE_REC( 0UL, 0UL ) }; const AF_Script_UniRangeRec af_telu_uniranges[] = { AF_UNIRANGE_REC( 0x0C00UL, 0x0C7FUL ), /* Telugu */ AF_UNIRANGE_REC( 0UL, 0UL ) }; const AF_Script_UniRangeRec af_tibt_uniranges[] = { AF_UNIRANGE_REC( 0x0F00UL, 0x0FFFUL ), /* Tibetan */ AF_UNIRANGE_REC( 0UL, 0UL ) }; #endif /* !AF_CONFIG_OPTION_INDIC */ #ifdef AF_CONFIG_OPTION_CJK /* this corresponds to Unicode 6.0 */ const AF_Script_UniRangeRec af_hani_uniranges[] = { AF_UNIRANGE_REC( 0x1100UL, 0x11FFUL ), /* Hangul Jamo */ AF_UNIRANGE_REC( 0x2E80UL, 0x2EFFUL ), /* CJK Radicals Supplement */ AF_UNIRANGE_REC( 0x2F00UL, 0x2FDFUL ), /* Kangxi Radicals */ AF_UNIRANGE_REC( 0x2FF0UL, 0x2FFFUL ), /* Ideographic Description Characters */ AF_UNIRANGE_REC( 0x3000UL, 0x303FUL ), /* CJK Symbols and Punctuation */ AF_UNIRANGE_REC( 0x3040UL, 0x309FUL ), /* Hiragana */ AF_UNIRANGE_REC( 0x30A0UL, 0x30FFUL ), /* Katakana */ AF_UNIRANGE_REC( 0x3100UL, 0x312FUL ), /* Bopomofo */ AF_UNIRANGE_REC( 0x3130UL, 0x318FUL ), /* Hangul Compatibility Jamo */ AF_UNIRANGE_REC( 0x3190UL, 0x319FUL ), /* Kanbun */ AF_UNIRANGE_REC( 0x31A0UL, 0x31BFUL ), /* Bopomofo Extended */ AF_UNIRANGE_REC( 0x31C0UL, 0x31EFUL ), /* CJK Strokes */ AF_UNIRANGE_REC( 0x31F0UL, 0x31FFUL ), /* Katakana Phonetic Extensions */ AF_UNIRANGE_REC( 0x3200UL, 0x32FFUL ), /* Enclosed CJK Letters and Months */ AF_UNIRANGE_REC( 0x3300UL, 0x33FFUL ), /* CJK Compatibility */ AF_UNIRANGE_REC( 0x3400UL, 0x4DBFUL ), /* CJK Unified Ideographs Extension A */ AF_UNIRANGE_REC( 0x4DC0UL, 0x4DFFUL ), /* Yijing Hexagram Symbols */ AF_UNIRANGE_REC( 0x4E00UL, 0x9FFFUL ), /* CJK Unified Ideographs */ AF_UNIRANGE_REC( 0xA960UL, 0xA97FUL ), /* Hangul Jamo Extended-A */ AF_UNIRANGE_REC( 0xAC00UL, 0xD7AFUL ), /* Hangul Syllables */ AF_UNIRANGE_REC( 0xD7B0UL, 0xD7FFUL ), /* Hangul Jamo Extended-B */ AF_UNIRANGE_REC( 0xF900UL, 0xFAFFUL ), /* CJK Compatibility Ideographs */ AF_UNIRANGE_REC( 0xFE10UL, 0xFE1FUL ), /* Vertical forms */ AF_UNIRANGE_REC( 0xFE30UL, 0xFE4FUL ), /* CJK Compatibility Forms */ AF_UNIRANGE_REC( 0xFF00UL, 0xFFEFUL ), /* Halfwidth and Fullwidth Forms */ AF_UNIRANGE_REC( 0x1B000UL, 0x1B0FFUL ), /* Kana Supplement */ AF_UNIRANGE_REC( 0x1D300UL, 0x1D35FUL ), /* Tai Xuan Hing Symbols */ AF_UNIRANGE_REC( 0x1F200UL, 0x1F2FFUL ), /* Enclosed Ideographic Supplement */ AF_UNIRANGE_REC( 0x20000UL, 0x2A6DFUL ), /* CJK Unified Ideographs Extension B */ AF_UNIRANGE_REC( 0x2A700UL, 0x2B73FUL ), /* CJK Unified Ideographs Extension C */ AF_UNIRANGE_REC( 0x2B740UL, 0x2B81FUL ), /* CJK Unified Ideographs Extension D */ AF_UNIRANGE_REC( 0x2F800UL, 0x2FA1FUL ), /* CJK Compatibility Ideographs Supplement */ AF_UNIRANGE_REC( 0UL, 0UL ) }; #endif /* !AF_CONFIG_OPTION_CJK */ // ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ FT_DEFINE_SFNT_INTERFACE( sfnt_interface, tt_face_goto_table, sfnt_init_face, sfnt_load_face, sfnt_done_face, sfnt_get_interface, tt_face_load_any, tt_face_load_head, tt_face_load_hhea, tt_face_load_cmap, tt_face_load_maxp, tt_face_load_os2, tt_face_load_post, tt_face_load_name, tt_face_free_name, tt_face_load_kern, tt_face_load_gasp, tt_face_load_pclt, /* see `ttload.h' */ PUT_EMBEDDED_BITMAPS( tt_face_load_bhed ), PUT_EMBEDDED_BITMAPS( tt_face_load_sbit_image ), /* see `ttpost.h' */ PUT_PS_NAMES( tt_face_get_ps_name ), PUT_PS_NAMES( tt_face_free_ps_names ), /* since version 2.1.8 */ tt_face_get_kerning, /* since version 2.2 */ tt_face_load_font_dir, tt_face_load_hmtx, /* see `ttsbit.h' and `sfnt.h' */ PUT_EMBEDDED_BITMAPS( tt_face_load_sbit ), PUT_EMBEDDED_BITMAPS( tt_face_free_sbit ), PUT_EMBEDDED_BITMAPS( tt_face_set_sbit_strike ), PUT_EMBEDDED_BITMAPS( tt_face_load_strike_metrics ), tt_face_get_metrics ) FT_DEFINE_MODULE( sfnt_module_class, 0, /* not a font driver or renderer */ sizeof ( FT_ModuleRec ), "sfnt", /* driver name */ 0x10000L, /* driver version 1.0 */ 0x20000L, /* driver requires FreeType 2.0 or higher */ (const void*)&SFNT_INTERFACE_GET, /* module specific interface */ (FT_Module_Constructor)0, (FT_Module_Destructor) 0, (FT_Module_Requester) sfnt_get_interface ) // ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ #define VARIANT_BIT 0x80000000UL #define BASE_GLYPH( code ) ( (FT_UInt32)( (code) & ~VARIANT_BIT ) ) static const char ft_standard_glyph_names[3696] = { '.','n','u','l','l', 0, 'n','o','n','m','a','r','k','i','n','g','r','e','t','u','r','n', 0, 'n','o','t','e','q','u','a','l', 0, 'i','n','f','i','n','i','t','y', 0, 'l','e','s','s','e','q','u','a','l', 0, 'g','r','e','a','t','e','r','e','q','u','a','l', 0, 'p','a','r','t','i','a','l','d','i','f','f', 0, 's','u','m','m','a','t','i','o','n', 0, 'p','r','o','d','u','c','t', 0, 'p','i', 0, 'i','n','t','e','g','r','a','l', 0, 'O','m','e','g','a', 0, 'r','a','d','i','c','a','l', 0, 'a','p','p','r','o','x','e','q','u','a','l', 0, 'D','e','l','t','a', 0, 'n','o','n','b','r','e','a','k','i','n','g','s','p','a','c','e', 0, 'l','o','z','e','n','g','e', 0, 'a','p','p','l','e', 0, 'f','r','a','n','c', 0, 'G','b','r','e','v','e', 0, 'g','b','r','e','v','e', 0, 'I','d','o','t','a','c','c','e','n','t', 0, 'S','c','e','d','i','l','l','a', 0, 's','c','e','d','i','l','l','a', 0, 'C','a','c','u','t','e', 0, 'c','a','c','u','t','e', 0, 'C','c','a','r','o','n', 0, 'c','c','a','r','o','n', 0, 'd','c','r','o','a','t', 0, '.','n','o','t','d','e','f', 0, 's','p','a','c','e', 0, 'e','x','c','l','a','m', 0, 'q','u','o','t','e','d','b','l', 0, 'n','u','m','b','e','r','s','i','g','n', 0, 'd','o','l','l','a','r', 0, 'p','e','r','c','e','n','t', 0, 'a','m','p','e','r','s','a','n','d', 0, 'q','u','o','t','e','r','i','g','h','t', 0, 'p','a','r','e','n','l','e','f','t', 0, 'p','a','r','e','n','r','i','g','h','t', 0, 'a','s','t','e','r','i','s','k', 0, 'p','l','u','s', 0, 'c','o','m','m','a', 0, 'h','y','p','h','e','n', 0, 'p','e','r','i','o','d', 0, 's','l','a','s','h', 0, 'z','e','r','o', 0, 'o','n','e', 0, 't','w','o', 0, 't','h','r','e','e', 0, 'f','o','u','r', 0, 'f','i','v','e', 0, 's','i','x', 0, 's','e','v','e','n', 0, 'e','i','g','h','t', 0, 'n','i','n','e', 0, 'c','o','l','o','n', 0, 's','e','m','i','c','o','l','o','n', 0, 'l','e','s','s', 0, 'e','q','u','a','l', 0, 'g','r','e','a','t','e','r', 0, 'q','u','e','s','t','i','o','n', 0, 'a','t', 0, 'A', 0, 'B', 0, 'C', 0, 'D', 0, 'E', 0, 'F', 0, 'G', 0, 'H', 0, 'I', 0, 'J', 0, 'K', 0, 'L', 0, 'M', 0, 'N', 0, 'O', 0, 'P', 0, 'Q', 0, 'R', 0, 'S', 0, 'T', 0, 'U', 0, 'V', 0, 'W', 0, 'X', 0, 'Y', 0, 'Z', 0, 'b','r','a','c','k','e','t','l','e','f','t', 0, 'b','a','c','k','s','l','a','s','h', 0, 'b','r','a','c','k','e','t','r','i','g','h','t', 0, 'a','s','c','i','i','c','i','r','c','u','m', 0, 'u','n','d','e','r','s','c','o','r','e', 0, 'q','u','o','t','e','l','e','f','t', 0, 'a', 0, 'b', 0, 'c', 0, 'd', 0, 'e', 0, 'f', 0, 'g', 0, 'h', 0, 'i', 0, 'j', 0, 'k', 0, 'l', 0, 'm', 0, 'n', 0, 'o', 0, 'p', 0, 'q', 0, 'r', 0, 's', 0, 't', 0, 'u', 0, 'v', 0, 'w', 0, 'x', 0, 'y', 0, 'z', 0, 'b','r','a','c','e','l','e','f','t', 0, 'b','a','r', 0, 'b','r','a','c','e','r','i','g','h','t', 0, 'a','s','c','i','i','t','i','l','d','e', 0, 'e','x','c','l','a','m','d','o','w','n', 0, 'c','e','n','t', 0, 's','t','e','r','l','i','n','g', 0, 'f','r','a','c','t','i','o','n', 0, 'y','e','n', 0, 'f','l','o','r','i','n', 0, 's','e','c','t','i','o','n', 0, 'c','u','r','r','e','n','c','y', 0, 'q','u','o','t','e','s','i','n','g','l','e', 0, 'q','u','o','t','e','d','b','l','l','e','f','t', 0, 'g','u','i','l','l','e','m','o','t','l','e','f','t', 0, 'g','u','i','l','s','i','n','g','l','l','e','f','t', 0, 'g','u','i','l','s','i','n','g','l','r','i','g','h','t', 0, 'f','i', 0, 'f','l', 0, 'e','n','d','a','s','h', 0, 'd','a','g','g','e','r', 0, 'd','a','g','g','e','r','d','b','l', 0, 'p','e','r','i','o','d','c','e','n','t','e','r','e','d', 0, 'p','a','r','a','g','r','a','p','h', 0, 'b','u','l','l','e','t', 0, 'q','u','o','t','e','s','i','n','g','l','b','a','s','e', 0, 'q','u','o','t','e','d','b','l','b','a','s','e', 0, 'q','u','o','t','e','d','b','l','r','i','g','h','t', 0, 'g','u','i','l','l','e','m','o','t','r','i','g','h','t', 0, 'e','l','l','i','p','s','i','s', 0, 'p','e','r','t','h','o','u','s','a','n','d', 0, 'q','u','e','s','t','i','o','n','d','o','w','n', 0, 'g','r','a','v','e', 0, 'a','c','u','t','e', 0, 'c','i','r','c','u','m','f','l','e','x', 0, 't','i','l','d','e', 0, 'm','a','c','r','o','n', 0, 'b','r','e','v','e', 0, 'd','o','t','a','c','c','e','n','t', 0, 'd','i','e','r','e','s','i','s', 0, 'r','i','n','g', 0, 'c','e','d','i','l','l','a', 0, 'h','u','n','g','a','r','u','m','l','a','u','t', 0, 'o','g','o','n','e','k', 0, 'c','a','r','o','n', 0, 'e','m','d','a','s','h', 0, 'A','E', 0, 'o','r','d','f','e','m','i','n','i','n','e', 0, 'L','s','l','a','s','h', 0, 'O','s','l','a','s','h', 0, 'O','E', 0, 'o','r','d','m','a','s','c','u','l','i','n','e', 0, 'a','e', 0, 'd','o','t','l','e','s','s','i', 0, 'l','s','l','a','s','h', 0, 'o','s','l','a','s','h', 0, 'o','e', 0, 'g','e','r','m','a','n','d','b','l','s', 0, 'o','n','e','s','u','p','e','r','i','o','r', 0, 'l','o','g','i','c','a','l','n','o','t', 0, 'm','u', 0, 't','r','a','d','e','m','a','r','k', 0, 'E','t','h', 0, 'o','n','e','h','a','l','f', 0, 'p','l','u','s','m','i','n','u','s', 0, 'T','h','o','r','n', 0, 'o','n','e','q','u','a','r','t','e','r', 0, 'd','i','v','i','d','e', 0, 'b','r','o','k','e','n','b','a','r', 0, 'd','e','g','r','e','e', 0, 't','h','o','r','n', 0, 't','h','r','e','e','q','u','a','r','t','e','r','s', 0, 't','w','o','s','u','p','e','r','i','o','r', 0, 'r','e','g','i','s','t','e','r','e','d', 0, 'm','i','n','u','s', 0, 'e','t','h', 0, 'm','u','l','t','i','p','l','y', 0, 't','h','r','e','e','s','u','p','e','r','i','o','r', 0, 'c','o','p','y','r','i','g','h','t', 0, 'A','a','c','u','t','e', 0, 'A','c','i','r','c','u','m','f','l','e','x', 0, 'A','d','i','e','r','e','s','i','s', 0, 'A','g','r','a','v','e', 0, 'A','r','i','n','g', 0, 'A','t','i','l','d','e', 0, 'C','c','e','d','i','l','l','a', 0, 'E','a','c','u','t','e', 0, 'E','c','i','r','c','u','m','f','l','e','x', 0, 'E','d','i','e','r','e','s','i','s', 0, 'E','g','r','a','v','e', 0, 'I','a','c','u','t','e', 0, 'I','c','i','r','c','u','m','f','l','e','x', 0, 'I','d','i','e','r','e','s','i','s', 0, 'I','g','r','a','v','e', 0, 'N','t','i','l','d','e', 0, 'O','a','c','u','t','e', 0, 'O','c','i','r','c','u','m','f','l','e','x', 0, 'O','d','i','e','r','e','s','i','s', 0, 'O','g','r','a','v','e', 0, 'O','t','i','l','d','e', 0, 'S','c','a','r','o','n', 0, 'U','a','c','u','t','e', 0, 'U','c','i','r','c','u','m','f','l','e','x', 0, 'U','d','i','e','r','e','s','i','s', 0, 'U','g','r','a','v','e', 0, 'Y','a','c','u','t','e', 0, 'Y','d','i','e','r','e','s','i','s', 0, 'Z','c','a','r','o','n', 0, 'a','a','c','u','t','e', 0, 'a','c','i','r','c','u','m','f','l','e','x', 0, 'a','d','i','e','r','e','s','i','s', 0, 'a','g','r','a','v','e', 0, 'a','r','i','n','g', 0, 'a','t','i','l','d','e', 0, 'c','c','e','d','i','l','l','a', 0, 'e','a','c','u','t','e', 0, 'e','c','i','r','c','u','m','f','l','e','x', 0, 'e','d','i','e','r','e','s','i','s', 0, 'e','g','r','a','v','e', 0, 'i','a','c','u','t','e', 0, 'i','c','i','r','c','u','m','f','l','e','x', 0, 'i','d','i','e','r','e','s','i','s', 0, 'i','g','r','a','v','e', 0, 'n','t','i','l','d','e', 0, 'o','a','c','u','t','e', 0, 'o','c','i','r','c','u','m','f','l','e','x', 0, 'o','d','i','e','r','e','s','i','s', 0, 'o','g','r','a','v','e', 0, 'o','t','i','l','d','e', 0, 's','c','a','r','o','n', 0, 'u','a','c','u','t','e', 0, 'u','c','i','r','c','u','m','f','l','e','x', 0, 'u','d','i','e','r','e','s','i','s', 0, 'u','g','r','a','v','e', 0, 'y','a','c','u','t','e', 0, 'y','d','i','e','r','e','s','i','s', 0, 'z','c','a','r','o','n', 0, 'e','x','c','l','a','m','s','m','a','l','l', 0, 'H','u','n','g','a','r','u','m','l','a','u','t','s','m','a','l','l', 0, 'd','o','l','l','a','r','o','l','d','s','t','y','l','e', 0, 'd','o','l','l','a','r','s','u','p','e','r','i','o','r', 0, 'a','m','p','e','r','s','a','n','d','s','m','a','l','l', 0, 'A','c','u','t','e','s','m','a','l','l', 0, 'p','a','r','e','n','l','e','f','t','s','u','p','e','r','i','o','r', 0, 'p','a','r','e','n','r','i','g','h','t','s','u','p','e','r','i','o','r', 0, 't','w','o','d','o','t','e','n','l','e','a','d','e','r', 0, 'o','n','e','d','o','t','e','n','l','e','a','d','e','r', 0, 'z','e','r','o','o','l','d','s','t','y','l','e', 0, 'o','n','e','o','l','d','s','t','y','l','e', 0, 't','w','o','o','l','d','s','t','y','l','e', 0, 't','h','r','e','e','o','l','d','s','t','y','l','e', 0, 'f','o','u','r','o','l','d','s','t','y','l','e', 0, 'f','i','v','e','o','l','d','s','t','y','l','e', 0, 's','i','x','o','l','d','s','t','y','l','e', 0, 's','e','v','e','n','o','l','d','s','t','y','l','e', 0, 'e','i','g','h','t','o','l','d','s','t','y','l','e', 0, 'n','i','n','e','o','l','d','s','t','y','l','e', 0, 'c','o','m','m','a','s','u','p','e','r','i','o','r', 0, 't','h','r','e','e','q','u','a','r','t','e','r','s','e','m','d','a','s','h', 0, 'p','e','r','i','o','d','s','u','p','e','r','i','o','r', 0, 'q','u','e','s','t','i','o','n','s','m','a','l','l', 0, 'a','s','u','p','e','r','i','o','r', 0, 'b','s','u','p','e','r','i','o','r', 0, 'c','e','n','t','s','u','p','e','r','i','o','r', 0, 'd','s','u','p','e','r','i','o','r', 0, 'e','s','u','p','e','r','i','o','r', 0, 'i','s','u','p','e','r','i','o','r', 0, 'l','s','u','p','e','r','i','o','r', 0, 'm','s','u','p','e','r','i','o','r', 0, 'n','s','u','p','e','r','i','o','r', 0, 'o','s','u','p','e','r','i','o','r', 0, 'r','s','u','p','e','r','i','o','r', 0, 's','s','u','p','e','r','i','o','r', 0, 't','s','u','p','e','r','i','o','r', 0, 'f','f', 0, 'f','f','i', 0, 'f','f','l', 0, 'p','a','r','e','n','l','e','f','t','i','n','f','e','r','i','o','r', 0, 'p','a','r','e','n','r','i','g','h','t','i','n','f','e','r','i','o','r', 0, 'C','i','r','c','u','m','f','l','e','x','s','m','a','l','l', 0, 'h','y','p','h','e','n','s','u','p','e','r','i','o','r', 0, 'G','r','a','v','e','s','m','a','l','l', 0, 'A','s','m','a','l','l', 0, 'B','s','m','a','l','l', 0, 'C','s','m','a','l','l', 0, 'D','s','m','a','l','l', 0, 'E','s','m','a','l','l', 0, 'F','s','m','a','l','l', 0, 'G','s','m','a','l','l', 0, 'H','s','m','a','l','l', 0, 'I','s','m','a','l','l', 0, 'J','s','m','a','l','l', 0, 'K','s','m','a','l','l', 0, 'L','s','m','a','l','l', 0, 'M','s','m','a','l','l', 0, 'N','s','m','a','l','l', 0, 'O','s','m','a','l','l', 0, 'P','s','m','a','l','l', 0, 'Q','s','m','a','l','l', 0, 'R','s','m','a','l','l', 0, 'S','s','m','a','l','l', 0, 'T','s','m','a','l','l', 0, 'U','s','m','a','l','l', 0, 'V','s','m','a','l','l', 0, 'W','s','m','a','l','l', 0, 'X','s','m','a','l','l', 0, 'Y','s','m','a','l','l', 0, 'Z','s','m','a','l','l', 0, 'c','o','l','o','n','m','o','n','e','t','a','r','y', 0, 'o','n','e','f','i','t','t','e','d', 0, 'r','u','p','i','a','h', 0, 'T','i','l','d','e','s','m','a','l','l', 0, 'e','x','c','l','a','m','d','o','w','n','s','m','a','l','l', 0, 'c','e','n','t','o','l','d','s','t','y','l','e', 0, 'L','s','l','a','s','h','s','m','a','l','l', 0, 'S','c','a','r','o','n','s','m','a','l','l', 0, 'Z','c','a','r','o','n','s','m','a','l','l', 0, 'D','i','e','r','e','s','i','s','s','m','a','l','l', 0, 'B','r','e','v','e','s','m','a','l','l', 0, 'C','a','r','o','n','s','m','a','l','l', 0, 'D','o','t','a','c','c','e','n','t','s','m','a','l','l', 0, 'M','a','c','r','o','n','s','m','a','l','l', 0, 'f','i','g','u','r','e','d','a','s','h', 0, 'h','y','p','h','e','n','i','n','f','e','r','i','o','r', 0, 'O','g','o','n','e','k','s','m','a','l','l', 0, 'R','i','n','g','s','m','a','l','l', 0, 'C','e','d','i','l','l','a','s','m','a','l','l', 0, 'q','u','e','s','t','i','o','n','d','o','w','n','s','m','a','l','l', 0, 'o','n','e','e','i','g','h','t','h', 0, 't','h','r','e','e','e','i','g','h','t','h','s', 0, 'f','i','v','e','e','i','g','h','t','h','s', 0, 's','e','v','e','n','e','i','g','h','t','h','s', 0, 'o','n','e','t','h','i','r','d', 0, 't','w','o','t','h','i','r','d','s', 0, 'z','e','r','o','s','u','p','e','r','i','o','r', 0, 'f','o','u','r','s','u','p','e','r','i','o','r', 0, 'f','i','v','e','s','u','p','e','r','i','o','r', 0, 's','i','x','s','u','p','e','r','i','o','r', 0, 's','e','v','e','n','s','u','p','e','r','i','o','r', 0, 'e','i','g','h','t','s','u','p','e','r','i','o','r', 0, 'n','i','n','e','s','u','p','e','r','i','o','r', 0, 'z','e','r','o','i','n','f','e','r','i','o','r', 0, 'o','n','e','i','n','f','e','r','i','o','r', 0, 't','w','o','i','n','f','e','r','i','o','r', 0, 't','h','r','e','e','i','n','f','e','r','i','o','r', 0, 'f','o','u','r','i','n','f','e','r','i','o','r', 0, 'f','i','v','e','i','n','f','e','r','i','o','r', 0, 's','i','x','i','n','f','e','r','i','o','r', 0, 's','e','v','e','n','i','n','f','e','r','i','o','r', 0, 'e','i','g','h','t','i','n','f','e','r','i','o','r', 0, 'n','i','n','e','i','n','f','e','r','i','o','r', 0, 'c','e','n','t','i','n','f','e','r','i','o','r', 0, 'd','o','l','l','a','r','i','n','f','e','r','i','o','r', 0, 'p','e','r','i','o','d','i','n','f','e','r','i','o','r', 0, 'c','o','m','m','a','i','n','f','e','r','i','o','r', 0, 'A','g','r','a','v','e','s','m','a','l','l', 0, 'A','a','c','u','t','e','s','m','a','l','l', 0, 'A','c','i','r','c','u','m','f','l','e','x','s','m','a','l','l', 0, 'A','t','i','l','d','e','s','m','a','l','l', 0, 'A','d','i','e','r','e','s','i','s','s','m','a','l','l', 0, 'A','r','i','n','g','s','m','a','l','l', 0, 'A','E','s','m','a','l','l', 0, 'C','c','e','d','i','l','l','a','s','m','a','l','l', 0, 'E','g','r','a','v','e','s','m','a','l','l', 0, 'E','a','c','u','t','e','s','m','a','l','l', 0, 'E','c','i','r','c','u','m','f','l','e','x','s','m','a','l','l', 0, 'E','d','i','e','r','e','s','i','s','s','m','a','l','l', 0, 'I','g','r','a','v','e','s','m','a','l','l', 0, 'I','a','c','u','t','e','s','m','a','l','l', 0, 'I','c','i','r','c','u','m','f','l','e','x','s','m','a','l','l', 0, 'I','d','i','e','r','e','s','i','s','s','m','a','l','l', 0, 'E','t','h','s','m','a','l','l', 0, 'N','t','i','l','d','e','s','m','a','l','l', 0, 'O','g','r','a','v','e','s','m','a','l','l', 0, 'O','a','c','u','t','e','s','m','a','l','l', 0, 'O','c','i','r','c','u','m','f','l','e','x','s','m','a','l','l', 0, 'O','t','i','l','d','e','s','m','a','l','l', 0, 'O','d','i','e','r','e','s','i','s','s','m','a','l','l', 0, 'O','E','s','m','a','l','l', 0, 'O','s','l','a','s','h','s','m','a','l','l', 0, 'U','g','r','a','v','e','s','m','a','l','l', 0, 'U','a','c','u','t','e','s','m','a','l','l', 0, 'U','c','i','r','c','u','m','f','l','e','x','s','m','a','l','l', 0, 'U','d','i','e','r','e','s','i','s','s','m','a','l','l', 0, 'Y','a','c','u','t','e','s','m','a','l','l', 0, 'T','h','o','r','n','s','m','a','l','l', 0, 'Y','d','i','e','r','e','s','i','s','s','m','a','l','l', 0, '0','0','1','.','0','0','0', 0, '0','0','1','.','0','0','1', 0, '0','0','1','.','0','0','2', 0, '0','0','1','.','0','0','3', 0, 'B','l','a','c','k', 0, 'B','o','l','d', 0, 'B','o','o','k', 0, 'L','i','g','h','t', 0, 'M','e','d','i','u','m', 0, 'R','e','g','u','l','a','r', 0, 'R','o','m','a','n', 0, 'S','e','m','i','b','o','l','d', 0, }; #define FT_NUM_MAC_NAMES 258 /* Values are offsets into the `ft_standard_glyph_names' table */ static const short ft_mac_names[FT_NUM_MAC_NAMES] = { 253, 0, 6, 261, 267, 274, 283, 294, 301, 309, 758, 330, 340, 351, 360, 365, 371, 378, 385, 391, 396, 400, 404, 410, 415, 420, 424, 430, 436, 441, 447, 457, 462, 468, 476, 485, 488, 490, 492, 494, 496, 498, 500, 502, 504, 506, 508, 510, 512, 514, 516, 518, 520, 522, 524, 526, 528, 530, 532, 534, 536, 538, 540, 552, 562, 575, 587, 979, 608, 610, 612, 614, 616, 618, 620, 622, 624, 626, 628, 630, 632, 634, 636, 638, 640, 642, 644, 646, 648, 650, 652, 654, 656, 658, 660, 670, 674, 685, 1375,1392,1405,1414,1486,1512,1562,1603,1632,1610,1622,1645,1639,1652, 1661,1690,1668,1680,1697,1726,1704,1716,1733,1740,1769,1747,1759,1776, 1790,1819,1797,1809, 839,1263, 707, 712, 741, 881, 871,1160,1302,1346, 1197, 985,1031, 23,1086,1108, 32,1219, 41, 51, 730,1194, 64, 76, 86, 94, 97,1089,1118, 106,1131,1150, 966, 696,1183, 112, 734, 120, 132, 783, 930, 945, 138,1385,1398,1529,1115,1157, 832,1079, 770, 916, 598, 319,1246, 155,1833,1586, 721, 749, 797, 811, 826, 829, 846, 856, 888, 903, 954,1363,1421,1356,1433,1443,1450,1457,1469,1479,1493,1500, 163,1522,1543,1550,1572,1134, 991,1002,1008,1015,1021,1040,1045,1053, 1066,1073,1101,1143,1536,1783,1596,1843,1253,1207,1319,1579,1826,1229, 1270,1313,1323,1171,1290,1332,1211,1235,1276, 169, 175, 182, 189, 200, 209, 218, 225, 232, 239, 246 }; #define FT_NUM_SID_NAMES 391 /* Values are offsets into the `ft_standard_glyph_names' table */ static const short ft_sid_names[FT_NUM_SID_NAMES] = { 253, 261, 267, 274, 283, 294, 301, 309, 319, 330, 340, 351, 360, 365, 371, 378, 385, 391, 396, 400, 404, 410, 415, 420, 424, 430, 436, 441, 447, 457, 462, 468, 476, 485, 488, 490, 492, 494, 496, 498, 500, 502, 504, 506, 508, 510, 512, 514, 516, 518, 520, 522, 524, 526, 528, 530, 532, 534, 536, 538, 540, 552, 562, 575, 587, 598, 608, 610, 612, 614, 616, 618, 620, 622, 624, 626, 628, 630, 632, 634, 636, 638, 640, 642, 644, 646, 648, 650, 652, 654, 656, 658, 660, 670, 674, 685, 696, 707, 712, 721, 730, 734, 741, 749, 758, 770, 783, 797, 811, 826, 829, 832, 839, 846, 856, 871, 881, 888, 903, 916, 930, 945, 954, 966, 979, 985, 991,1002,1008,1015,1021,1031,1040,1045,1053,1066,1073,1079,1086,1089, 1101,1108,1115,1118,1131,1134,1143,1150,1157,1160,1171,1183,1194,1197, 1207,1211,1219,1229,1235,1246,1253,1263,1270,1276,1290,1302,1313,1319, 1323,1332,1346,1356,1363,1375,1385,1392,1398,1405,1414,1421,1433,1443, 1450,1457,1469,1479,1486,1493,1500,1512,1522,1529,1536,1543,1550,1562, 1572,1579,1586,1596,1603,1610,1622,1632,1639,1645,1652,1661,1668,1680, 1690,1697,1704,1716,1726,1733,1740,1747,1759,1769,1776,1783,1790,1797, 1809,1819,1826,1833,1843,1850,1862,1880,1895,1910,1925,1936,1954,1973, 1988,2003,2016,2028,2040,2054,2067,2080,2092,2106,2120,2133,2147,2167, 2182,2196,2206,2216,2229,2239,2249,2259,2269,2279,2289,2299,2309,2319, 2329,2332,2336,2340,2358,2377,2393,2408,2419,2426,2433,2440,2447,2454, 2461,2468,2475,2482,2489,2496,2503,2510,2517,2524,2531,2538,2545,2552, 2559,2566,2573,2580,2587,2594,2601,2615,2625,2632,2643,2659,2672,2684, 2696,2708,2722,2733,2744,2759,2771,2782,2797,2809,2819,2832,2850,2860, 2873,2885,2898,2907,2917,2930,2943,2956,2968,2982,2996,3009,3022,3034, 3046,3060,3073,3086,3098,3112,3126,3139,3152,3167,3182,3196,3208,3220, 3237,3249,3264,3275,3283,3297,3309,3321,3338,3353,3365,3377,3394,3409, 3418,3430,3442,3454,3471,3483,3498,3506,3518,3530,3542,3559,3574,3586, 3597,3612,3620,3628,3636,3644,3650,3655,3660,3666,3673,3681,3687 }; /* the following are indices into the SID name table */ static const unsigned short t1_standard_encoding[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110, 0,111,112,113,114, 0,115,116,117,118,119,120,121,122, 0,123, 0,124,125,126,127,128,129,130,131, 0,132,133, 0,134,135,136, 137, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,138, 0,139, 0, 0, 0, 0,140,141,142,143, 0, 0, 0, 0, 0,144, 0, 0, 0,145, 0, 0,146,147,148,149, 0, 0, 0, 0 }; /* the following are indices into the SID name table */ static const unsigned short t1_expert_encoding[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,229,230, 0,231,232,233,234,235,236,237,238, 13, 14, 15, 99, 239,240,241,242,243,244,245,246,247,248, 27, 28,249,250,251,252, 0,253,254,255,256,257, 0, 0, 0,258, 0, 0,259,260,261,262, 0, 0,263,264,265, 0,266,109,110,267,268,269, 0,270,271,272, 273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288, 289,290,291,292,293,294,295,296,297,298,299,300,301,302,303, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,304,305,306, 0, 0,307,308,309,310,311, 0,312, 0, 0,313, 0, 0,314,315, 0, 0,316,317,318, 0, 0, 0,158,155,163,319, 320,321,322,323,324,325, 0, 0,326,150,164,169,327,328,329,330, 331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346, 347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362, 363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378 }; /* * This table is a compressed version of the Adobe Glyph List (AGL), * optimized for efficient searching. It has been generated by the * `glnames.py' python script located in the `src/tools' directory. * * The lookup function to get the Unicode value for a given string * is defined below the table. */ static const unsigned char ft_adobe_glyph_list[55997L] = { 0, 52, 0,106, 2,167, 3, 63, 4,220, 6,125, 9,143, 10, 23, 11,137, 12,199, 14,246, 15, 87, 16,233, 17,219, 18,104, 19, 88, 22,110, 23, 32, 23, 71, 24, 77, 27,156, 29, 73, 31,247, 32,107, 32,222, 33, 55, 34,154, 35,218, 58, 10, 64,122, 72,188, 80,109, 88,104, 93, 61, 98,168,106, 91,114,111,115,237,122,180,127,255, 135,164,143,132,149,213,158,108,161,115,168,175,183,147,197,199, 202, 25,204,166,208,209,209, 81,215, 26, 65,143, 0, 65, 0,140, 0,175, 0,193, 1, 15, 1,147, 1,233, 1,251, 2, 7, 2, 40, 2, 57, 2, 82, 2, 91, 2,128, 2,136, 2,154, 69,131, 0,198, 0,150, 0,158, 0,167,225,227,245,244,101,128, 1,252,237,225, 227,242,239,110,128, 1,226,243,237,225,236,108,128,247,230,225, 227,245,244,101,129, 0,193, 0,185,243,237,225,236,108,128,247, 225,226,242,229,246,101,134, 1, 2, 0,213, 0,221, 0,232, 0, 243, 0,251, 1, 7,225,227,245,244,101,128, 30,174,227,249,242, 233,236,236,233, 99,128, 4,208,228,239,244,226,229,236,239,119, 128, 30,182,231,242,225,246,101,128, 30,176,232,239,239,235,225, 226,239,246,101,128, 30,178,244,233,236,228,101,128, 30,180, 99, 4, 1, 25, 1, 32, 1,121, 1,137,225,242,239,110,128, 1,205, 233,242, 99, 2, 1, 40, 1, 45,236,101,128, 36,182,245,237,230, 236,229,120,134, 0,194, 1, 66, 1, 74, 1, 85, 1, 93, 1,105, 1,113,225,227,245,244,101,128, 30,164,228,239,244,226,229,236, 239,119,128, 30,172,231,242,225,246,101,128, 30,166,232,239,239, 235,225,226,239,246,101,128, 30,168,243,237,225,236,108,128,247, 226,244,233,236,228,101,128, 30,170,245,244,101,129,246,201, 1, 129,243,237,225,236,108,128,247,180,249,242,233,236,236,233, 99, 128, 4, 16,100, 3, 1,155, 1,165, 1,209,226,236,231,242,225, 246,101,128, 2, 0,233,229,242,229,243,233,115,131, 0,196, 1, 181, 1,192, 1,201,227,249,242,233,236,236,233, 99,128, 4,210, 237,225,227,242,239,110,128, 1,222,243,237,225,236,108,128,247, 228,239,116, 2, 1,216, 1,224,226,229,236,239,119,128, 30,160, 237,225,227,242,239,110,128, 1,224,231,242,225,246,101,129, 0, 192, 1,243,243,237,225,236,108,128,247,224,232,239,239,235,225, 226,239,246,101,128, 30,162,105, 2, 2, 13, 2, 25,229,227,249, 242,233,236,236,233, 99,128, 4,212,238,246,229,242,244,229,228, 226,242,229,246,101,128, 2, 2,236,240,232, 97,129, 3,145, 2, 49,244,239,238,239,115,128, 3,134,109, 2, 2, 63, 2, 71,225, 227,242,239,110,128, 1, 0,239,238,239,243,240,225,227,101,128, 255, 33,239,231,239,238,229,107,128, 1, 4,242,233,238,103,131, 0,197, 2,104, 2,112, 2,120,225,227,245,244,101,128, 1,250, 226,229,236,239,119,128, 30, 0,243,237,225,236,108,128,247,229, 243,237,225,236,108,128,247, 97,244,233,236,228,101,129, 0,195, 2,146,243,237,225,236,108,128,247,227,249,226,225,242,237,229, 238,233,225,110,128, 5, 49, 66,137, 0, 66, 2,189, 2,198, 2, 223, 3, 3, 3, 10, 3, 22, 3, 34, 3, 46, 3, 54,227,233,242, 227,236,101,128, 36,183,228,239,116, 2, 2,206, 2,215,225,227, 227,229,238,116,128, 30, 2,226,229,236,239,119,128, 30, 4,101, 3, 2,231, 2,242, 2,254,227,249,242,233,236,236,233, 99,128, 4, 17,238,225,242,237,229,238,233,225,110,128, 5, 50,244, 97, 128, 3,146,232,239,239,107,128, 1,129,236,233,238,229,226,229, 236,239,119,128, 30, 6,237,239,238,239,243,240,225,227,101,128, 255, 34,242,229,246,229,243,237,225,236,108,128,246,244,243,237, 225,236,108,128,247, 98,244,239,240,226,225,114,128, 1,130, 67, 137, 0, 67, 3, 85, 3,127, 3,193, 3,210, 3,224, 4,171, 4, 188, 4,200, 4,212, 97, 3, 3, 93, 3,104, 3,111,225,242,237, 229,238,233,225,110,128, 5, 62,227,245,244,101,128, 1, 6,242, 239,110,129,246,202, 3,119,243,237,225,236,108,128,246,245, 99, 3, 3,135, 3,142, 3,171,225,242,239,110,128, 1, 12,229,228, 233,236,236, 97,130, 0,199, 3,155, 3,163,225,227,245,244,101, 128, 30, 8,243,237,225,236,108,128,247,231,233,242, 99, 2, 3, 179, 3,184,236,101,128, 36,184,245,237,230,236,229,120,128, 1, 8,228,239,116,129, 1, 10, 3,201,225,227,227,229,238,116,128, 1, 10,229,228,233,236,236,225,243,237,225,236,108,128,247,184, 104, 4, 3,234, 3,246, 4,161, 4,165,225,225,242,237,229,238, 233,225,110,128, 5, 73,101, 6, 4, 4, 4, 24, 4, 35, 4,103, 4,115, 4,136,225,226,235,232,225,243,233,225,238,227,249,242, 233,236,236,233, 99,128, 4,188,227,249,242,233,236,236,233, 99, 128, 4, 39,100, 2, 4, 41, 4, 85,229,243,227,229,238,228,229, 114, 2, 4, 54, 4, 74,225,226,235,232,225,243,233,225,238,227, 249,242,233,236,236,233, 99,128, 4,190,227,249,242,233,236,236, 233, 99,128, 4,182,233,229,242,229,243,233,243,227,249,242,233, 236,236,233, 99,128, 4,244,232,225,242,237,229,238,233,225,110, 128, 5, 67,235,232,225,235,225,243,243,233,225,238,227,249,242, 233,236,236,233, 99,128, 4,203,246,229,242,244,233,227,225,236, 243,244,242,239,235,229,227,249,242,233,236,236,233, 99,128, 4, 184,105,128, 3,167,239,239,107,128, 1,135,233,242,227,245,237, 230,236,229,248,243,237,225,236,108,128,246,246,237,239,238,239, 243,240,225,227,101,128,255, 35,239,225,242,237,229,238,233,225, 110,128, 5, 81,243,237,225,236,108,128,247, 99, 68,142, 0, 68, 4,252, 5, 10, 5, 36, 5, 96, 5,121, 5,166, 5,173, 5,231, 5,244, 6, 0, 6, 12, 6, 28, 6, 48, 6, 57, 90,129, 1,241, 5, 2,227,225,242,239,110,128, 1,196, 97, 2, 5, 16, 5, 27, 225,242,237,229,238,233,225,110,128, 5, 52,230,242,233,227,225, 110,128, 1,137, 99, 4, 5, 46, 5, 53, 5, 62, 5, 89,225,242, 239,110,128, 1, 14,229,228,233,236,236, 97,128, 30, 16,233,242, 99, 2, 5, 70, 5, 75,236,101,128, 36,185,245,237,230,236,229, 248,226,229,236,239,119,128, 30, 18,242,239,225,116,128, 1, 16, 228,239,116, 2, 5,104, 5,113,225,227,227,229,238,116,128, 30, 10,226,229,236,239,119,128, 30, 12,101, 3, 5,129, 5,140, 5, 150,227,249,242,233,236,236,233, 99,128, 4, 20,233,227,239,240, 244,233, 99,128, 3,238,236,244, 97,129, 34, 6, 5,158,231,242, 229,229,107,128, 3,148,232,239,239,107,128, 1,138,105, 2, 5, 179, 5,218,229,242,229,243,233,115,131,246,203, 5,194, 5,202, 5,210,193,227,245,244,101,128,246,204,199,242,225,246,101,128, 246,205,243,237,225,236,108,128,247,168,231,225,237,237,225,231, 242,229,229,107,128, 3,220,234,229,227,249,242,233,236,236,233, 99,128, 4, 2,236,233,238,229,226,229,236,239,119,128, 30, 14, 237,239,238,239,243,240,225,227,101,128,255, 36,239,244,225,227, 227,229,238,244,243,237,225,236,108,128,246,247,115, 2, 6, 34, 6, 41,236,225,243,104,128, 1, 16,237,225,236,108,128,247,100, 244,239,240,226,225,114,128, 1,139,122,131, 1,242, 6, 67, 6, 75, 6,112,227,225,242,239,110,128, 1,197,101, 2, 6, 81, 6, 101,225,226,235,232,225,243,233,225,238,227,249,242,233,236,236, 233, 99,128, 4,224,227,249,242,233,236,236,233, 99,128, 4, 5, 232,229,227,249,242,233,236,236,233, 99,128, 4, 15, 69,146, 0, 69, 6,165, 6,183, 6,191, 7, 89, 7,153, 7,165, 7,183, 7, 211, 8, 7, 8, 36, 8, 94, 8,169, 8,189, 8,208, 8,248, 9, 44, 9,109, 9,115,225,227,245,244,101,129, 0,201, 6,175,243, 237,225,236,108,128,247,233,226,242,229,246,101,128, 1, 20, 99, 5, 6,203, 6,210, 6,224, 6,236, 7, 79,225,242,239,110,128, 1, 26,229,228,233,236,236,225,226,242,229,246,101,128, 30, 28, 232,225,242,237,229,238,233,225,110,128, 5, 53,233,242, 99, 2, 6,244, 6,249,236,101,128, 36,186,245,237,230,236,229,120,135, 0,202, 7, 16, 7, 24, 7, 32, 7, 43, 7, 51, 7, 63, 7, 71, 225,227,245,244,101,128, 30,190,226,229,236,239,119,128, 30, 24, 228,239,244,226,229,236,239,119,128, 30,198,231,242,225,246,101, 128, 30,192,232,239,239,235,225,226,239,246,101,128, 30,194,243, 237,225,236,108,128,247,234,244,233,236,228,101,128, 30,196,249, 242,233,236,236,233, 99,128, 4, 4,100, 3, 7, 97, 7,107, 7, 127,226,236,231,242,225,246,101,128, 2, 4,233,229,242,229,243, 233,115,129, 0,203, 7,119,243,237,225,236,108,128,247,235,239, 116,130, 1, 22, 7,136, 7,145,225,227,227,229,238,116,128, 1, 22,226,229,236,239,119,128, 30,184,230,227,249,242,233,236,236, 233, 99,128, 4, 36,231,242,225,246,101,129, 0,200, 7,175,243, 237,225,236,108,128,247,232,104, 2, 7,189, 7,200,225,242,237, 229,238,233,225,110,128, 5, 55,239,239,235,225,226,239,246,101, 128, 30,186,105, 3, 7,219, 7,230, 7,245,231,232,244,242,239, 237,225,110,128, 33,103,238,246,229,242,244,229,228,226,242,229, 246,101,128, 2, 6,239,244,233,230,233,229,228,227,249,242,233, 236,236,233, 99,128, 4,100,108, 2, 8, 13, 8, 24,227,249,242, 233,236,236,233, 99,128, 4, 27,229,246,229,238,242,239,237,225, 110,128, 33,106,109, 3, 8, 44, 8, 72, 8, 83,225,227,242,239, 110,130, 1, 18, 8, 56, 8, 64,225,227,245,244,101,128, 30, 22, 231,242,225,246,101,128, 30, 20,227,249,242,233,236,236,233, 99, 128, 4, 28,239,238,239,243,240,225,227,101,128,255, 37,110, 4, 8,104, 8,115, 8,135, 8,154,227,249,242,233,236,236,233, 99, 128, 4, 29,228,229,243,227,229,238,228,229,242,227,249,242,233, 236,236,233, 99,128, 4,162,103,129, 1, 74, 8,141,232,229,227, 249,242,233,236,236,233, 99,128, 4,164,232,239,239,235,227,249, 242,233,236,236,233, 99,128, 4,199,111, 2, 8,175, 8,183,231, 239,238,229,107,128, 1, 24,240,229,110,128, 1,144,240,243,233, 236,239,110,129, 3,149, 8,200,244,239,238,239,115,128, 3,136, 114, 2, 8,214, 8,225,227,249,242,233,236,236,233, 99,128, 4, 32,229,246,229,242,243,229,100,129, 1,142, 8,237,227,249,242, 233,236,236,233, 99,128, 4, 45,115, 4, 9, 2, 9, 13, 9, 33, 9, 37,227,249,242,233,236,236,233, 99,128, 4, 33,228,229,243, 227,229,238,228,229,242,227,249,242,233,236,236,233, 99,128, 4, 170,104,128, 1,169,237,225,236,108,128,247,101,116, 3, 9, 52, 9, 78, 9, 92, 97,130, 3,151, 9, 60, 9, 70,242,237,229,238, 233,225,110,128, 5, 56,244,239,238,239,115,128, 3,137,104,129, 0,208, 9, 84,243,237,225,236,108,128,247,240,233,236,228,101, 129, 30,188, 9,101,226,229,236,239,119,128, 30, 26,245,242,111, 128, 32,172,250,104,130, 1,183, 9,124, 9,132,227,225,242,239, 110,128, 1,238,242,229,246,229,242,243,229,100,128, 1,184, 70, 136, 0, 70, 9,163, 9,172, 9,184, 9,212, 9,219, 9,248, 10, 4, 10, 15,227,233,242,227,236,101,128, 36,187,228,239,244,225, 227,227,229,238,116,128, 30, 30,101, 2, 9,190, 9,202,232,225, 242,237,229,238,233,225,110,128, 5, 86,233,227,239,240,244,233, 99,128, 3,228,232,239,239,107,128, 1,145,105, 2, 9,225, 9, 238,244,225,227,249,242,233,236,236,233, 99,128, 4,114,246,229, 242,239,237,225,110,128, 33,100,237,239,238,239,243,240,225,227, 101,128,255, 38,239,245,242,242,239,237,225,110,128, 33, 99,243, 237,225,236,108,128,247,102, 71,140, 0, 71, 10, 51, 10, 61, 10, 107, 10,115, 10,176, 10,193, 10,205, 11, 39, 11, 52, 11, 65, 11, 90, 11,107,194,243,241,245,225,242,101,128, 51,135, 97, 3, 10, 69, 10, 76, 10, 94,227,245,244,101,128, 1,244,237,237, 97,129, 3,147, 10, 84,225,230,242,233,227,225,110,128, 1,148,238,231, 233,225,227,239,240,244,233, 99,128, 3,234,226,242,229,246,101, 128, 1, 30, 99, 4, 10,125, 10,132, 10,141, 10,163,225,242,239, 110,128, 1,230,229,228,233,236,236, 97,128, 1, 34,233,242, 99, 2, 10,149, 10,154,236,101,128, 36,188,245,237,230,236,229,120, 128, 1, 28,239,237,237,225,225,227,227,229,238,116,128, 1, 34, 228,239,116,129, 1, 32, 10,184,225,227,227,229,238,116,128, 1, 32,229,227,249,242,233,236,236,233, 99,128, 4, 19,104, 3, 10, 213, 10,226, 11, 33,225,228,225,242,237,229,238,233,225,110,128, 5, 66,101, 3, 10,234, 10,255, 11, 16,237,233,228,228,236,229, 232,239,239,235,227,249,242,233,236,236,233, 99,128, 4,148,243, 244,242,239,235,229,227,249,242,233,236,236,233, 99,128, 4,146, 245,240,244,245,242,238,227,249,242,233,236,236,233, 99,128, 4, 144,239,239,107,128, 1,147,233,237,225,242,237,229,238,233,225, 110,128, 5, 51,234,229,227,249,242,233,236,236,233, 99,128, 4, 3,109, 2, 11, 71, 11, 79,225,227,242,239,110,128, 30, 32,239, 238,239,243,240,225,227,101,128,255, 39,242,225,246,101,129,246, 206, 11, 99,243,237,225,236,108,128,247, 96,115, 2, 11,113, 11, 129,237,225,236,108,129,247,103, 11,122,232,239,239,107,128, 2, 155,244,242,239,235,101,128, 1,228, 72,140, 0, 72, 11,165, 11, 190, 11,198, 11,208, 12, 17, 12, 40, 12, 77, 12,117, 12,129, 12, 157, 12,165, 12,189,177,184, 53, 3, 11,175, 11,180, 11,185,179, 51,128, 37,207,180, 51,128, 37,170,181, 49,128, 37,171,178,178, 176,183, 51,128, 37,161,208,243,241,245,225,242,101,128, 51,203, 97, 3, 11,216, 11,236, 12, 0,225,226,235,232,225,243,233,225, 238,227,249,242,233,236,236,233, 99,128, 4,168,228,229,243,227, 229,238,228,229,242,227,249,242,233,236,236,233, 99,128, 4,178, 242,228,243,233,231,238,227,249,242,233,236,236,233, 99,128, 4, 42, 98, 2, 12, 23, 12, 28,225,114,128, 1, 38,242,229,246,229, 226,229,236,239,119,128, 30, 42, 99, 2, 12, 46, 12, 55,229,228, 233,236,236, 97,128, 30, 40,233,242, 99, 2, 12, 63, 12, 68,236, 101,128, 36,189,245,237,230,236,229,120,128, 1, 36,100, 2, 12, 83, 12, 93,233,229,242,229,243,233,115,128, 30, 38,239,116, 2, 12,100, 12,109,225,227,227,229,238,116,128, 30, 34,226,229,236, 239,119,128, 30, 36,237,239,238,239,243,240,225,227,101,128,255, 40,111, 2, 12,135, 12,146,225,242,237,229,238,233,225,110,128, 5, 64,242,233,227,239,240,244,233, 99,128, 3,232,243,237,225, 236,108,128,247,104,245,238,231,225,242,245,237,236,225,245,116, 129,246,207, 12,181,243,237,225,236,108,128,246,248,250,243,241, 245,225,242,101,128, 51,144, 73,146, 0, 73, 12,239, 12,251, 12, 255, 13, 11, 13, 29, 13, 37, 13, 94, 13,181, 13,214, 13,224, 13, 242, 13,254, 14, 48, 14, 86, 14, 99, 14,166, 14,187, 14,205,193, 227,249,242,233,236,236,233, 99,128, 4, 47, 74,128, 1, 50,213, 227,249,242,233,236,236,233, 99,128, 4, 46,225,227,245,244,101, 129, 0,205, 13, 21,243,237,225,236,108,128,247,237,226,242,229, 246,101,128, 1, 44, 99, 3, 13, 45, 13, 52, 13, 84,225,242,239, 110,128, 1,207,233,242, 99, 2, 13, 60, 13, 65,236,101,128, 36, 190,245,237,230,236,229,120,129, 0,206, 13, 76,243,237,225,236, 108,128,247,238,249,242,233,236,236,233, 99,128, 4, 6,100, 3, 13,102, 13,112, 13,155,226,236,231,242,225,246,101,128, 2, 8, 233,229,242,229,243,233,115,131, 0,207, 13,128, 13,136, 13,147, 225,227,245,244,101,128, 30, 46,227,249,242,233,236,236,233, 99, 128, 4,228,243,237,225,236,108,128,247,239,239,116,130, 1, 48, 13,164, 13,173,225,227,227,229,238,116,128, 1, 48,226,229,236, 239,119,128, 30,202,101, 2, 13,187, 13,203,226,242,229,246,229, 227,249,242,233,236,236,233, 99,128, 4,214,227,249,242,233,236, 236,233, 99,128, 4, 21,230,242,225,235,244,245,114,128, 33, 17, 231,242,225,246,101,129, 0,204, 13,234,243,237,225,236,108,128, 247,236,232,239,239,235,225,226,239,246,101,128, 30,200,105, 3, 14, 6, 14, 17, 14, 32,227,249,242,233,236,236,233, 99,128, 4, 24,238,246,229,242,244,229,228,226,242,229,246,101,128, 2, 10, 243,232,239,242,244,227,249,242,233,236,236,233, 99,128, 4, 25, 109, 2, 14, 54, 14, 75,225,227,242,239,110,129, 1, 42, 14, 64, 227,249,242,233,236,236,233, 99,128, 4,226,239,238,239,243,240, 225,227,101,128,255, 41,238,233,225,242,237,229,238,233,225,110, 128, 5, 59,111, 3, 14,107, 14,118, 14,126,227,249,242,233,236, 236,233, 99,128, 4, 1,231,239,238,229,107,128, 1, 46,244, 97, 131, 3,153, 14,137, 14,147, 14,158,225,230,242,233,227,225,110, 128, 1,150,228,233,229,242,229,243,233,115,128, 3,170,244,239, 238,239,115,128, 3,138,115, 2, 14,172, 14,179,237,225,236,108, 128,247,105,244,242,239,235,101,128, 1,151,244,233,236,228,101, 129, 1, 40, 14,197,226,229,236,239,119,128, 30, 44,250,232,233, 244,243, 97, 2, 14,216, 14,227,227,249,242,233,236,236,233, 99, 128, 4,116,228,226,236,231,242,225,246,229,227,249,242,233,236, 236,233, 99,128, 4,118, 74,134, 0, 74, 15, 6, 15, 18, 15, 41, 15, 53, 15, 67, 15, 79,225,225,242,237,229,238,233,225,110,128, 5, 65,227,233,242, 99, 2, 15, 27, 15, 32,236,101,128, 36,191, 245,237,230,236,229,120,128, 1, 52,229,227,249,242,233,236,236, 233, 99,128, 4, 8,232,229,232,225,242,237,229,238,233,225,110, 128, 5, 75,237,239,238,239,243,240,225,227,101,128,255, 42,243, 237,225,236,108,128,247,106, 75,140, 0, 75, 15,115, 15,125, 15, 135, 16, 18, 16, 65, 16, 76, 16,106, 16,143, 16,156, 16,168, 16, 180, 16,208,194,243,241,245,225,242,101,128, 51,133,203,243,241, 245,225,242,101,128, 51,205, 97, 7, 15,151, 15,169, 15,191, 15, 211, 15,226, 15,232, 15,249,226,225,243,232,235,233,242,227,249, 242,233,236,236,233, 99,128, 4,160, 99, 2, 15,175, 15,181,245, 244,101,128, 30, 48,249,242,233,236,236,233, 99,128, 4, 26,228, 229,243,227,229,238,228,229,242,227,249,242,233,236,236,233, 99, 128, 4,154,232,239,239,235,227,249,242,233,236,236,233, 99,128, 4,195,240,240, 97,128, 3,154,243,244,242,239,235,229,227,249, 242,233,236,236,233, 99,128, 4,158,246,229,242,244,233,227,225, 236,243,244,242,239,235,229,227,249,242,233,236,236,233, 99,128, 4,156, 99, 4, 16, 28, 16, 35, 16, 44, 16, 52,225,242,239,110, 128, 1,232,229,228,233,236,236, 97,128, 1, 54,233,242,227,236, 101,128, 36,192,239,237,237,225,225,227,227,229,238,116,128, 1, 54,228,239,244,226,229,236,239,119,128, 30, 50,101, 2, 16, 82, 16, 94,232,225,242,237,229,238,233,225,110,128, 5, 84,238,225, 242,237,229,238,233,225,110,128, 5, 63,104, 3, 16,114, 16,126, 16,137,225,227,249,242,233,236,236,233, 99,128, 4, 37,229,233, 227,239,240,244,233, 99,128, 3,230,239,239,107,128, 1,152,234, 229,227,249,242,233,236,236,233, 99,128, 4, 12,236,233,238,229, 226,229,236,239,119,128, 30, 52,237,239,238,239,243,240,225,227, 101,128,255, 43,239,240,240, 97, 2, 16,189, 16,200,227,249,242, 233,236,236,233, 99,128, 4,128,231,242,229,229,107,128, 3,222, 115, 2, 16,214, 16,226,233,227,249,242,233,236,236,233, 99,128, 4,110,237,225,236,108,128,247,107, 76,138, 0, 76, 17, 1, 17, 5, 17, 9, 17, 29, 17, 95, 17,133, 17,147, 17,165, 17,177, 17, 189, 74,128, 1,199, 76,128,246,191, 97, 2, 17, 15, 17, 22,227, 245,244,101,128, 1, 57,237,226,228, 97,128, 3,155, 99, 4, 17, 39, 17, 46, 17, 55, 17, 82,225,242,239,110,128, 1, 61,229,228, 233,236,236, 97,128, 1, 59,233,242, 99, 2, 17, 63, 17, 68,236, 101,128, 36,193,245,237,230,236,229,248,226,229,236,239,119,128, 30, 60,239,237,237,225,225,227,227,229,238,116,128, 1, 59,228, 239,116,130, 1, 63, 17,105, 17,114,225,227,227,229,238,116,128, 1, 63,226,229,236,239,119,129, 30, 54, 17,124,237,225,227,242, 239,110,128, 30, 56,233,247,238,225,242,237,229,238,233,225,110, 128, 5, 60,106,129, 1,200, 17,153,229,227,249,242,233,236,236, 233, 99,128, 4, 9,236,233,238,229,226,229,236,239,119,128, 30, 58,237,239,238,239,243,240,225,227,101,128,255, 44,115, 2, 17, 195, 17,212,236,225,243,104,129, 1, 65, 17,204,243,237,225,236, 108,128,246,249,237,225,236,108,128,247,108, 77,137, 0, 77, 17, 241, 17,251, 18, 24, 18, 33, 18, 58, 18, 71, 18, 83, 18, 91, 18, 100,194,243,241,245,225,242,101,128, 51,134,225, 99, 2, 18, 2, 18, 18,242,239,110,129,246,208, 18, 10,243,237,225,236,108,128, 247,175,245,244,101,128, 30, 62,227,233,242,227,236,101,128, 36, 194,228,239,116, 2, 18, 41, 18, 50,225,227,227,229,238,116,128, 30, 64,226,229,236,239,119,128, 30, 66,229,238,225,242,237,229, 238,233,225,110,128, 5, 68,237,239,238,239,243,240,225,227,101, 128,255, 45,243,237,225,236,108,128,247,109,244,245,242,238,229, 100,128, 1,156,117,128, 3,156, 78,141, 0, 78, 18,134, 18,138, 18,146, 18,212, 18,237, 18,248, 19, 3, 19, 21, 19, 33, 19, 45, 19, 58, 19, 66, 19, 84, 74,128, 1,202,225,227,245,244,101,128, 1, 67, 99, 4, 18,156, 18,163, 18,172, 18,199,225,242,239,110, 128, 1, 71,229,228,233,236,236, 97,128, 1, 69,233,242, 99, 2, 18,180, 18,185,236,101,128, 36,195,245,237,230,236,229,248,226, 229,236,239,119,128, 30, 74,239,237,237,225,225,227,227,229,238, 116,128, 1, 69,228,239,116, 2, 18,220, 18,229,225,227,227,229, 238,116,128, 30, 68,226,229,236,239,119,128, 30, 70,232,239,239, 235,236,229,230,116,128, 1,157,233,238,229,242,239,237,225,110, 128, 33,104,106,129, 1,203, 19, 9,229,227,249,242,233,236,236, 233, 99,128, 4, 10,236,233,238,229,226,229,236,239,119,128, 30, 72,237,239,238,239,243,240,225,227,101,128,255, 46,239,247,225, 242,237,229,238,233,225,110,128, 5, 70,243,237,225,236,108,128, 247,110,244,233,236,228,101,129, 0,209, 19, 76,243,237,225,236, 108,128,247,241,117,128, 3,157, 79,141, 0, 79, 19,118, 19,132, 19,150, 19,203, 20, 78, 20,152, 20,187, 21, 48, 21, 69, 21,213, 21,223, 21,254, 22, 53, 69,129, 1, 82, 19,124,243,237,225,236, 108,128,246,250,225,227,245,244,101,129, 0,211, 19,142,243,237, 225,236,108,128,247,243, 98, 2, 19,156, 19,196,225,242,242,229, 100, 2, 19,166, 19,177,227,249,242,233,236,236,233, 99,128, 4, 232,228,233,229,242,229,243,233,243,227,249,242,233,236,236,233, 99,128, 4,234,242,229,246,101,128, 1, 78, 99, 4, 19,213, 19, 220, 19,235, 20, 68,225,242,239,110,128, 1,209,229,238,244,229, 242,229,228,244,233,236,228,101,128, 1,159,233,242, 99, 2, 19, 243, 19,248,236,101,128, 36,196,245,237,230,236,229,120,134, 0, 212, 20, 13, 20, 21, 20, 32, 20, 40, 20, 52, 20, 60,225,227,245, 244,101,128, 30,208,228,239,244,226,229,236,239,119,128, 30,216, 231,242,225,246,101,128, 30,210,232,239,239,235,225,226,239,246, 101,128, 30,212,243,237,225,236,108,128,247,244,244,233,236,228, 101,128, 30,214,249,242,233,236,236,233, 99,128, 4, 30,100, 3, 20, 86, 20,109, 20,142,226,108, 2, 20, 93, 20,101,225,227,245, 244,101,128, 1, 80,231,242,225,246,101,128, 2, 12,233,229,242, 229,243,233,115,130, 0,214, 20,123, 20,134,227,249,242,233,236, 236,233, 99,128, 4,230,243,237,225,236,108,128,247,246,239,244, 226,229,236,239,119,128, 30,204,103, 2, 20,158, 20,170,239,238, 229,235,243,237,225,236,108,128,246,251,242,225,246,101,129, 0, 210, 20,179,243,237,225,236,108,128,247,242,104, 4, 20,197, 20, 208, 20,212, 21, 34,225,242,237,229,238,233,225,110,128, 5, 85, 109,128, 33, 38,111, 2, 20,218, 20,228,239,235,225,226,239,246, 101,128, 30,206,242,110,133, 1,160, 20,243, 20,251, 21, 6, 21, 14, 21, 26,225,227,245,244,101,128, 30,218,228,239,244,226,229, 236,239,119,128, 30,226,231,242,225,246,101,128, 30,220,232,239, 239,235,225,226,239,246,101,128, 30,222,244,233,236,228,101,128, 30,224,245,238,231,225,242,245,237,236,225,245,116,128, 1, 80, 105,129, 1,162, 21, 54,238,246,229,242,244,229,228,226,242,229, 246,101,128, 2, 14,109, 4, 21, 79, 21,107, 21,184, 21,202,225, 227,242,239,110,130, 1, 76, 21, 91, 21, 99,225,227,245,244,101, 128, 30, 82,231,242,225,246,101,128, 30, 80,229,231, 97,132, 33, 38, 21,121, 21,132, 21,140, 21,156,227,249,242,233,236,236,233, 99,128, 4, 96,231,242,229,229,107,128, 3,169,242,239,245,238, 228,227,249,242,233,236,236,233, 99,128, 4,122,116, 2, 21,162, 21,177,233,244,236,239,227,249,242,233,236,236,233, 99,128, 4, 124,239,238,239,115,128, 3,143,233,227,242,239,110,129, 3,159, 21,194,244,239,238,239,115,128, 3,140,239,238,239,243,240,225, 227,101,128,255, 47,238,229,242,239,237,225,110,128, 33, 96,111, 2, 21,229, 21,248,231,239,238,229,107,129, 1,234, 21,239,237, 225,227,242,239,110,128, 1,236,240,229,110,128, 1,134,115, 3, 22, 6, 22, 33, 22, 40,236,225,243,104,130, 0,216, 22, 17, 22, 25,225,227,245,244,101,128, 1,254,243,237,225,236,108,128,247, 248,237,225,236,108,128,247,111,244,242,239,235,229,225,227,245, 244,101,128, 1,254,116, 2, 22, 59, 22, 70,227,249,242,233,236, 236,233, 99,128, 4,126,233,236,228,101,131, 0,213, 22, 83, 22, 91, 22,102,225,227,245,244,101,128, 30, 76,228,233,229,242,229, 243,233,115,128, 30, 78,243,237,225,236,108,128,247,245, 80,136, 0, 80, 22,130, 22,138, 22,147, 22,159, 22,211, 22,227, 22,246, 23, 2,225,227,245,244,101,128, 30, 84,227,233,242,227,236,101, 128, 36,197,228,239,244,225,227,227,229,238,116,128, 30, 86,101, 3, 22,167, 22,178, 22,190,227,249,242,233,236,236,233, 99,128, 4, 31,232,225,242,237,229,238,233,225,110,128, 5, 74,237,233, 228,228,236,229,232,239,239,235,227,249,242,233,236,236,233, 99, 128, 4,166,104, 2, 22,217, 22,221,105,128, 3,166,239,239,107, 128, 1,164,105,129, 3,160, 22,233,247,242,225,242,237,229,238, 233,225,110,128, 5, 83,237,239,238,239,243,240,225,227,101,128, 255, 48,115, 2, 23, 8, 23, 25,105,129, 3,168, 23, 14,227,249, 242,233,236,236,233, 99,128, 4,112,237,225,236,108,128,247,112, 81,131, 0, 81, 23, 42, 23, 51, 23, 63,227,233,242,227,236,101, 128, 36,198,237,239,238,239,243,240,225,227,101,128,255, 49,243, 237,225,236,108,128,247,113, 82,138, 0, 82, 23, 95, 23,119, 23, 166, 23,217, 23,230, 23,240, 23,245, 24, 19, 24, 31, 24, 43, 97, 2, 23,101, 23,112,225,242,237,229,238,233,225,110,128, 5, 76, 227,245,244,101,128, 1, 84, 99, 4, 23,129, 23,136, 23,145, 23, 153,225,242,239,110,128, 1, 88,229,228,233,236,236, 97,128, 1, 86,233,242,227,236,101,128, 36,199,239,237,237,225,225,227,227, 229,238,116,128, 1, 86,100, 2, 23,172, 23,182,226,236,231,242, 225,246,101,128, 2, 16,239,116, 2, 23,189, 23,198,225,227,227, 229,238,116,128, 30, 88,226,229,236,239,119,129, 30, 90, 23,208, 237,225,227,242,239,110,128, 30, 92,229,232,225,242,237,229,238, 233,225,110,128, 5, 80,230,242,225,235,244,245,114,128, 33, 28, 232,111,128, 3,161,233,110, 2, 23,252, 24, 5,231,243,237,225, 236,108,128,246,252,246,229,242,244,229,228,226,242,229,246,101, 128, 2, 18,236,233,238,229,226,229,236,239,119,128, 30, 94,237, 239,238,239,243,240,225,227,101,128,255, 50,243,237,225,236,108, 129,247,114, 24, 53,233,238,246,229,242,244,229,100,129, 2,129, 24, 66,243,245,240,229,242,233,239,114,128, 2,182, 83,139, 0, 83, 24,103, 26, 17, 26, 55, 26,182, 26,221, 26,250, 27, 84, 27, 105, 27,117, 27,135, 27,143, 70, 6, 24,117, 24,209, 24,241, 25, 77, 25,119, 25,221, 48, 9, 24,137, 24,145, 24,153, 24,161, 24, 169, 24,177, 24,185, 24,193, 24,201,177,176,176,176, 48,128, 37, 12,178,176,176,176, 48,128, 37, 20,179,176,176,176, 48,128, 37, 16,180,176,176,176, 48,128, 37, 24,181,176,176,176, 48,128, 37, 60,182,176,176,176, 48,128, 37, 44,183,176,176,176, 48,128, 37, 52,184,176,176,176, 48,128, 37, 28,185,176,176,176, 48,128, 37, 36, 49, 3, 24,217, 24,225, 24,233,176,176,176,176, 48,128, 37, 0,177,176,176,176, 48,128, 37, 2,185,176,176,176, 48,128, 37, 97, 50, 9, 25, 5, 25, 13, 25, 21, 25, 29, 25, 37, 25, 45, 25, 53, 25, 61, 25, 69,176,176,176,176, 48,128, 37, 98,177,176,176, 176, 48,128, 37, 86,178,176,176,176, 48,128, 37, 85,179,176,176, 176, 48,128, 37, 99,180,176,176,176, 48,128, 37, 81,181,176,176, 176, 48,128, 37, 87,182,176,176,176, 48,128, 37, 93,183,176,176, 176, 48,128, 37, 92,184,176,176,176, 48,128, 37, 91, 51, 4, 25, 87, 25, 95, 25,103, 25,111,182,176,176,176, 48,128, 37, 94,183, 176,176,176, 48,128, 37, 95,184,176,176,176, 48,128, 37, 90,185, 176,176,176, 48,128, 37, 84, 52, 10, 25,141, 25,149, 25,157, 25, 165, 25,173, 25,181, 25,189, 25,197, 25,205, 25,213,176,176,176, 176, 48,128, 37,105,177,176,176,176, 48,128, 37,102,178,176,176, 176, 48,128, 37, 96,179,176,176,176, 48,128, 37, 80,180,176,176, 176, 48,128, 37,108,181,176,176,176, 48,128, 37,103,182,176,176, 176, 48,128, 37,104,183,176,176,176, 48,128, 37,100,184,176,176, 176, 48,128, 37,101,185,176,176,176, 48,128, 37, 89, 53, 5, 25, 233, 25,241, 25,249, 26, 1, 26, 9,176,176,176,176, 48,128, 37, 88,177,176,176,176, 48,128, 37, 82,178,176,176,176, 48,128, 37, 83,179,176,176,176, 48,128, 37,107,180,176,176,176, 48,128, 37, 106, 97, 2, 26, 23, 26, 44,227,245,244,101,129, 1, 90, 26, 32, 228,239,244,225,227,227,229,238,116,128, 30,100,237,240,233,231, 242,229,229,107,128, 3,224, 99, 5, 26, 67, 26, 98, 26,107, 26, 147, 26,169,225,242,239,110,130, 1, 96, 26, 78, 26, 90,228,239, 244,225,227,227,229,238,116,128, 30,102,243,237,225,236,108,128, 246,253,229,228,233,236,236, 97,128, 1, 94,232,247, 97,130, 1, 143, 26,117, 26,128,227,249,242,233,236,236,233, 99,128, 4,216, 228,233,229,242,229,243,233,243,227,249,242,233,236,236,233, 99, 128, 4,218,233,242, 99, 2, 26,155, 26,160,236,101,128, 36,200, 245,237,230,236,229,120,128, 1, 92,239,237,237,225,225,227,227, 229,238,116,128, 2, 24,228,239,116, 2, 26,190, 26,199,225,227, 227,229,238,116,128, 30, 96,226,229,236,239,119,129, 30, 98, 26, 209,228,239,244,225,227,227,229,238,116,128, 30,104,101, 2, 26, 227, 26,239,232,225,242,237,229,238,233,225,110,128, 5, 77,246, 229,238,242,239,237,225,110,128, 33,102,104, 5, 27, 6, 27, 34, 27, 48, 27, 59, 27, 72, 97, 2, 27, 12, 27, 23,225,242,237,229, 238,233,225,110,128, 5, 71,227,249,242,233,236,236,233, 99,128, 4, 40,227,232,225,227,249,242,233,236,236,233, 99,128, 4, 41, 229,233,227,239,240,244,233, 99,128, 3,226,232,225,227,249,242, 233,236,236,233, 99,128, 4,186,233,237,225,227,239,240,244,233, 99,128, 3,236,105, 2, 27, 90, 27, 96,231,237, 97,128, 3,163, 248,242,239,237,225,110,128, 33,101,237,239,238,239,243,240,225, 227,101,128,255, 51,239,230,244,243,233,231,238,227,249,242,233, 236,236,233, 99,128, 4, 44,243,237,225,236,108,128,247,115,244, 233,231,237,225,231,242,229,229,107,128, 3,218, 84,141, 0, 84, 27,186, 27,191, 27,197, 28, 7, 28, 32, 28, 96, 28,147, 28,177, 28,189, 28,201, 28,246, 29, 6, 29, 46,225,117,128, 3,164,226, 225,114,128, 1,102, 99, 4, 27,207, 27,214, 27,223, 27,250,225, 242,239,110,128, 1,100,229,228,233,236,236, 97,128, 1, 98,233, 242, 99, 2, 27,231, 27,236,236,101,128, 36,201,245,237,230,236, 229,248,226,229,236,239,119,128, 30,112,239,237,237,225,225,227, 227,229,238,116,128, 1, 98,228,239,116, 2, 28, 15, 28, 24,225, 227,227,229,238,116,128, 30,106,226,229,236,239,119,128, 30,108, 101, 4, 28, 42, 28, 53, 28, 73, 28, 82,227,249,242,233,236,236, 233, 99,128, 4, 34,228,229,243,227,229,238,228,229,242,227,249, 242,233,236,236,233, 99,128, 4,172,238,242,239,237,225,110,128, 33,105,244,243,229,227,249,242,233,236,236,233, 99,128, 4,180, 104, 3, 28,104, 28,110, 28,136,229,244, 97,128, 3,152,111, 2, 28,116, 28,121,239,107,128, 1,172,242,110,129, 0,222, 28,128, 243,237,225,236,108,128,247,254,242,229,229,242,239,237,225,110, 128, 33, 98,105, 2, 28,153, 28,164,236,228,229,243,237,225,236, 108,128,246,254,247,238,225,242,237,229,238,233,225,110,128, 5, 79,236,233,238,229,226,229,236,239,119,128, 30,110,237,239,238, 239,243,240,225,227,101,128,255, 52,111, 2, 28,207, 28,218,225, 242,237,229,238,233,225,110,128, 5, 57,238,101, 3, 28,227, 28, 234, 28,240,230,233,246,101,128, 1,188,243,233,120,128, 1,132, 244,247,111,128, 1,167,242,229,244,242,239,230,236,229,248,232, 239,239,107,128, 1,174,115, 3, 29, 14, 29, 26, 29, 39,229,227, 249,242,233,236,236,233, 99,128, 4, 38,232,229,227,249,242,233, 236,236,233, 99,128, 4, 11,237,225,236,108,128,247,116,119, 2, 29, 52, 29, 64,229,236,246,229,242,239,237,225,110,128, 33,107, 239,242,239,237,225,110,128, 33, 97, 85,142, 0, 85, 29,105, 29, 123, 29,131, 29,198, 30, 69, 30, 87, 30,198, 30,214, 30,226, 31, 21, 31, 30, 31,142, 31,149, 31,219,225,227,245,244,101,129, 0, 218, 29,115,243,237,225,236,108,128,247,250,226,242,229,246,101, 128, 1,108, 99, 3, 29,139, 29,146, 29,188,225,242,239,110,128, 1,211,233,242, 99, 2, 29,154, 29,159,236,101,128, 36,202,245, 237,230,236,229,120,130, 0,219, 29,172, 29,180,226,229,236,239, 119,128, 30,118,243,237,225,236,108,128,247,251,249,242,233,236, 236,233, 99,128, 4, 35,100, 3, 29,206, 29,229, 30, 59,226,108, 2, 29,213, 29,221,225,227,245,244,101,128, 1,112,231,242,225, 246,101,128, 2, 20,233,229,242,229,243,233,115,134, 0,220, 29, 251, 30, 3, 30, 11, 30, 34, 30, 42, 30, 51,225,227,245,244,101, 128, 1,215,226,229,236,239,119,128, 30,114, 99, 2, 30, 17, 30, 24,225,242,239,110,128, 1,217,249,242,233,236,236,233, 99,128, 4,240,231,242,225,246,101,128, 1,219,237,225,227,242,239,110, 128, 1,213,243,237,225,236,108,128,247,252,239,244,226,229,236, 239,119,128, 30,228,231,242,225,246,101,129, 0,217, 30, 79,243, 237,225,236,108,128,247,249,104, 2, 30, 93, 30,171,111, 2, 30, 99, 30,109,239,235,225,226,239,246,101,128, 30,230,242,110,133, 1,175, 30,124, 30,132, 30,143, 30,151, 30,163,225,227,245,244, 101,128, 30,232,228,239,244,226,229,236,239,119,128, 30,240,231, 242,225,246,101,128, 30,234,232,239,239,235,225,226,239,246,101, 128, 30,236,244,233,236,228,101,128, 30,238,245,238,231,225,242, 245,237,236,225,245,116,129, 1,112, 30,187,227,249,242,233,236, 236,233, 99,128, 4,242,233,238,246,229,242,244,229,228,226,242, 229,246,101,128, 2, 22,235,227,249,242,233,236,236,233, 99,128, 4,120,109, 2, 30,232, 31, 10,225,227,242,239,110,130, 1,106, 30,244, 30,255,227,249,242,233,236,236,233, 99,128, 4,238,228, 233,229,242,229,243,233,115,128, 30,122,239,238,239,243,240,225, 227,101,128,255, 53,239,231,239,238,229,107,128, 1,114,240,243, 233,236,239,110,133, 3,165, 31, 49, 31, 53, 31, 90, 31,121, 31, 134, 49,128, 3,210, 97, 2, 31, 59, 31, 81,227,245,244,229,232, 239,239,235,243,249,237,226,239,236,231,242,229,229,107,128, 3, 211,230,242,233,227,225,110,128, 1,177,228,233,229,242,229,243, 233,115,129, 3,171, 31,103,232,239,239,235,243,249,237,226,239, 236,231,242,229,229,107,128, 3,212,232,239,239,235,243,249,237, 226,239,108,128, 3,210,244,239,238,239,115,128, 3,142,242,233, 238,103,128, 1,110,115, 3, 31,157, 31,172, 31,179,232,239,242, 244,227,249,242,233,236,236,233, 99,128, 4, 14,237,225,236,108, 128,247,117,244,242,225,233,231,232,116, 2, 31,191, 31,202,227, 249,242,233,236,236,233, 99,128, 4,174,243,244,242,239,235,229, 227,249,242,233,236,236,233, 99,128, 4,176,244,233,236,228,101, 130, 1,104, 31,231, 31,239,225,227,245,244,101,128, 30,120,226, 229,236,239,119,128, 30,116, 86,136, 0, 86, 32, 11, 32, 20, 32, 31, 32, 60, 32, 67, 32, 79, 32, 91, 32, 99,227,233,242,227,236, 101,128, 36,203,228,239,244,226,229,236,239,119,128, 30,126,101, 2, 32, 37, 32, 48,227,249,242,233,236,236,233, 99,128, 4, 18, 247,225,242,237,229,238,233,225,110,128, 5, 78,232,239,239,107, 128, 1,178,237,239,238,239,243,240,225,227,101,128,255, 54,239, 225,242,237,229,238,233,225,110,128, 5, 72,243,237,225,236,108, 128,247,118,244,233,236,228,101,128, 30,124, 87,134, 0, 87, 32, 123, 32,131, 32,154, 32,194, 32,202, 32,214,225,227,245,244,101, 128, 30,130,227,233,242, 99, 2, 32,140, 32,145,236,101,128, 36, 204,245,237,230,236,229,120,128, 1,116,100, 2, 32,160, 32,170, 233,229,242,229,243,233,115,128, 30,132,239,116, 2, 32,177, 32, 186,225,227,227,229,238,116,128, 30,134,226,229,236,239,119,128, 30,136,231,242,225,246,101,128, 30,128,237,239,238,239,243,240, 225,227,101,128,255, 55,243,237,225,236,108,128,247,119, 88,134, 0, 88, 32,238, 32,247, 33, 18, 33, 31, 33, 35, 33, 47,227,233, 242,227,236,101,128, 36,205,100, 2, 32,253, 33, 7,233,229,242, 229,243,233,115,128, 30,140,239,244,225,227,227,229,238,116,128, 30,138,229,232,225,242,237,229,238,233,225,110,128, 5, 61,105, 128, 3,158,237,239,238,239,243,240,225,227,101,128,255, 56,243, 237,225,236,108,128,247,120, 89,139, 0, 89, 33, 81, 33,116, 33, 139, 33,189, 33,228, 33,236, 33,253, 34, 40, 34, 52, 34, 60, 34, 68, 97, 2, 33, 87, 33,104,227,245,244,101,129, 0,221, 33, 96, 243,237,225,236,108,128,247,253,244,227,249,242,233,236,236,233, 99,128, 4, 98,227,233,242, 99, 2, 33,125, 33,130,236,101,128, 36,206,245,237,230,236,229,120,128, 1,118,100, 2, 33,145, 33, 165,233,229,242,229,243,233,115,129, 1,120, 33,157,243,237,225, 236,108,128,247,255,239,116, 2, 33,172, 33,181,225,227,227,229, 238,116,128, 30,142,226,229,236,239,119,128, 30,244,229,114, 2, 33,196, 33,208,233,227,249,242,233,236,236,233, 99,128, 4, 43, 245,228,233,229,242,229,243,233,243,227,249,242,233,236,236,233, 99,128, 4,248,231,242,225,246,101,128, 30,242,232,239,239,107, 129, 1,179, 33,245,225,226,239,246,101,128, 30,246,105, 3, 34, 5, 34, 16, 34, 27,225,242,237,229,238,233,225,110,128, 5, 69, 227,249,242,233,236,236,233, 99,128, 4, 7,247,238,225,242,237, 229,238,233,225,110,128, 5, 82,237,239,238,239,243,240,225,227, 101,128,255, 57,243,237,225,236,108,128,247,121,244,233,236,228, 101,128, 30,248,245,115, 2, 34, 75, 34,113,226,233,103, 2, 34, 83, 34, 94,227,249,242,233,236,236,233, 99,128, 4,106,233,239, 244,233,230,233,229,228,227,249,242,233,236,236,233, 99,128, 4, 108,236,233,244,244,236,101, 2, 34,124, 34,135,227,249,242,233, 236,236,233, 99,128, 4,102,233,239,244,233,230,233,229,228,227, 249,242,233,236,236,233, 99,128, 4,104, 90,136, 0, 90, 34,174, 34,198, 34,243, 35, 14, 35, 81, 35,173, 35,185, 35,197, 97, 2, 34,180, 34,191,225,242,237,229,238,233,225,110,128, 5, 54,227, 245,244,101,128, 1,121, 99, 2, 34,204, 34,221,225,242,239,110, 129, 1,125, 34,213,243,237,225,236,108,128,246,255,233,242, 99, 2, 34,229, 34,234,236,101,128, 36,207,245,237,230,236,229,120, 128, 30,144,228,239,116,130, 1,123, 34,253, 35, 6,225,227,227, 229,238,116,128, 1,123,226,229,236,239,119,128, 30,146,101, 3, 35, 22, 35, 33, 35, 76,227,249,242,233,236,236,233, 99,128, 4, 23,100, 2, 35, 39, 35, 58,229,243,227,229,238,228,229,242,227, 249,242,233,236,236,233, 99,128, 4,152,233,229,242,229,243,233, 243,227,249,242,233,236,236,233, 99,128, 4,222,244, 97,128, 3, 150,232,101, 4, 35, 92, 35,103, 35,119, 35,130,225,242,237,229, 238,233,225,110,128, 5, 58,226,242,229,246,229,227,249,242,233, 236,236,233, 99,128, 4,193,227,249,242,233,236,236,233, 99,128, 4, 22,100, 2, 35,136, 35,155,229,243,227,229,238,228,229,242, 227,249,242,233,236,236,233, 99,128, 4,150,233,229,242,229,243, 233,243,227,249,242,233,236,236,233, 99,128, 4,220,236,233,238, 229,226,229,236,239,119,128, 30,148,237,239,238,239,243,240,225, 227,101,128,255, 58,115, 2, 35,203, 35,210,237,225,236,108,128, 247,122,244,242,239,235,101,128, 1,181, 97,158, 0, 97, 36, 26, 38,154, 39, 4, 39, 68, 39,132, 39,196, 40, 4, 40, 68, 40,126, 40,190, 41, 70, 41,217, 42,137, 42,237, 43, 17, 49,192, 49,229, 50, 0, 50,225, 51, 7, 52, 96, 52,168, 53,123, 53,132, 54, 5, 56, 13, 57, 3, 57, 50, 57,201, 57,215, 49,138, 39, 1, 36, 50, 36,114, 36,154, 36,218, 37, 26, 37, 90, 37,154, 37,218, 38, 26, 38, 90, 48,138, 39, 33, 36, 74, 36, 78, 36, 82, 36, 86, 36, 90, 36, 94, 36, 98, 36,102, 36,106, 36,110, 48,128, 39, 94, 49,128, 39, 97, 50,128, 39, 98, 51,128, 39, 99, 52,128, 39,100, 53,128, 39, 16, 54,128, 39,101, 55,128, 39,102, 56,128, 39,103, 57,128, 38, 96, 49,134, 38, 27, 36,130, 36,134, 36,138, 36,142, 36,146, 36,150, 48,128, 38,101, 49,128, 38,102, 50,128, 38, 99, 55,128, 39, 9, 56,128, 39, 8, 57,128, 39, 7, 50,138, 38, 30, 36,178, 36,182, 36,186, 36,190, 36,194, 36,198, 36,202, 36,206, 36,210, 36,214, 48,128, 36, 96, 49,128, 36, 97, 50,128, 36, 98, 51,128, 36, 99, 52,128, 36,100, 53,128, 36,101, 54,128, 36,102, 55,128, 36,103, 56,128, 36,104, 57,128, 36,105, 51,138, 39, 12, 36,242, 36,246, 36,250, 36,254, 37, 2, 37, 6, 37, 10, 37, 14, 37, 18, 37, 22, 48,128, 39,118, 49,128, 39,119, 50,128, 39,120, 51,128, 39,121, 52,128, 39,122, 53,128, 39,123, 54,128, 39,124, 55,128, 39,125, 56,128, 39,126, 57,128, 39,127, 52,138, 39, 13, 37, 50, 37, 54, 37, 58, 37, 62, 37, 66, 37, 70, 37, 74, 37, 78, 37, 82, 37, 86, 48,128, 39,128, 49,128, 39,129, 50,128, 39,130, 51,128, 39,131, 52,128, 39,132, 53,128, 39,133, 54,128, 39,134, 55,128, 39,135, 56,128, 39,136, 57,128, 39,137, 53,138, 39, 14, 37,114, 37,118, 37,122, 37,126, 37,130, 37,134, 37,138, 37,142, 37,146, 37,150, 48,128, 39,138, 49,128, 39,139, 50,128, 39,140, 51,128, 39,141, 52,128, 39,142, 53,128, 39,143, 54,128, 39,144, 55,128, 39,145, 56,128, 39,146, 57,128, 39,147, 54,138, 39, 15, 37,178, 37,182, 37,186, 37,190, 37,194, 37,198, 37,202, 37,206, 37,210, 37,214, 48,128, 39,148, 49,128, 33,146, 50,128, 39,163, 51,128, 33,148, 52,128, 33,149, 53,128, 39,153, 54,128, 39,155, 55,128, 39,156, 56,128, 39,157, 57,128, 39,158, 55,138, 39, 17, 37,242, 37,246, 37,250, 37,254, 38, 2, 38, 6, 38, 10, 38, 14, 38, 18, 38, 22, 48,128, 39,159, 49,128, 39,160, 50,128, 39,161, 51,128, 39,162, 52,128, 39,164, 53,128, 39,165, 54,128, 39,166, 55,128, 39,167, 56,128, 39,168, 57,128, 39,169, 56,138, 39, 18, 38, 50, 38, 54, 38, 58, 38, 62, 38, 66, 38, 70, 38, 74, 38, 78, 38, 82, 38, 86, 48,128, 39,171, 49,128, 39,173, 50,128, 39,175, 51,128, 39,178, 52,128, 39,179, 53,128, 39,181, 54,128, 39,184, 55,128, 39,186, 56,128, 39,187, 57,128, 39,188, 57,138, 39, 19, 38,114, 38,118, 38,122, 38,126, 38,130, 38,134, 38,138, 38,142, 38,146, 38,150, 48,128, 39,189, 49,128, 39,190, 50,128, 39,154, 51,128, 39,170, 52,128, 39,182, 53,128, 39,185, 54,128, 39,152, 55,128, 39,180, 56,128, 39,183, 57,128, 39,172, 50,138, 39, 2, 38,178, 38,224, 38,228, 38,232, 38,236, 38,240, 38,244, 38,248, 38,252, 39, 0, 48,135, 39, 20, 38,196, 38,200, 38,204, 38,208, 38,212, 38,216, 38,220, 48,128, 39,174, 49,128, 39,177, 50,128, 39, 3, 51,128, 39, 80, 52,128, 39, 82, 53,128, 39,110, 54,128, 39,112, 49,128, 39, 21, 50,128, 39, 22, 51,128, 39, 23, 52,128, 39, 24, 53,128, 39, 25, 54,128, 39, 26, 55,128, 39, 27, 56,128, 39, 28, 57,128, 39, 34, 51,138, 39, 4, 39, 28, 39, 32, 39, 36, 39, 40, 39, 44, 39, 48, 39, 52, 39, 56, 39, 60, 39, 64, 48,128, 39, 35, 49,128, 39, 36, 50,128, 39, 37, 51,128, 39, 38, 52,128, 39, 39, 53,128, 38, 5, 54,128, 39, 41, 55,128, 39, 42, 56,128, 39, 43, 57,128, 39, 44, 52,138, 38, 14, 39, 92, 39, 96, 39,100, 39,104, 39,108, 39,112, 39,116, 39,120, 39,124, 39,128, 48,128, 39, 45, 49,128, 39, 46, 50,128, 39, 47, 51,128, 39, 48, 52,128, 39, 49, 53,128, 39, 50, 54,128, 39, 51, 55,128, 39, 52, 56,128, 39, 53, 57,128, 39, 54, 53,138, 39, 6, 39,156, 39,160, 39,164, 39,168, 39,172, 39,176, 39,180, 39,184, 39,188, 39,192, 48,128, 39, 55, 49,128, 39, 56, 50,128, 39, 57, 51,128, 39, 58, 52,128, 39, 59, 53,128, 39, 60, 54,128, 39, 61, 55,128, 39, 62, 56,128, 39, 63, 57,128, 39, 64, 54,138, 39, 29, 39,220, 39,224, 39,228, 39,232, 39,236, 39,240, 39,244, 39,248, 39,252, 40, 0, 48,128, 39, 65, 49,128, 39, 66, 50,128, 39, 67, 51,128, 39, 68, 52,128, 39, 69, 53,128, 39, 70, 54,128, 39, 71, 55,128, 39, 72, 56,128, 39, 73, 57,128, 39, 74, 55,138, 39, 30, 40, 28, 40, 32, 40, 36, 40, 40, 40, 44, 40, 48, 40, 52, 40, 56, 40, 60, 40, 64, 48,128, 39, 75, 49,128, 37,207, 50,128, 39, 77, 51,128, 37,160, 52,128, 39, 79, 53,128, 39, 81, 54,128, 37,178, 55,128, 37,188, 56,128, 37,198, 57,128, 39, 86, 56,137, 39, 31, 40, 90, 40, 94, 40, 98, 40,102, 40,106, 40,110, 40,114, 40,118, 40,122, 49,128, 37,215, 50,128, 39, 88, 51,128, 39, 89, 52,128, 39, 90, 53,128, 39,111, 54,128, 39,113, 55,128, 39,114, 56,128, 39,115, 57,128, 39,104, 57,138, 39, 32, 40,150, 40,154, 40,158, 40,162, 40,166, 40,170, 40,174, 40,178, 40,182, 40,186, 48,128, 39,105, 49,128, 39,108, 50,128, 39,109, 51,128, 39,106, 52,128, 39,107, 53,128, 39,116, 54,128, 39,117, 55,128, 39, 91, 56,128, 39, 92, 57,128, 39, 93, 97, 7, 40,206, 40,216, 40,223, 40,230, 40,255, 41, 15, 41, 26,226,229, 238,231,225,236,105,128, 9,134,227,245,244,101,128, 0,225,228, 229,246, 97,128, 9, 6,231,117, 2, 40,237, 40,246,234,225,242, 225,244,105,128, 10,134,242,237,245,235,232,105,128, 10, 6,237, 225,244,242,225,231,245,242,237,245,235,232,105,128, 10, 62,242, 245,243,241,245,225,242,101,128, 51, 3,246,239,247,229,236,243, 233,231,110, 3, 41, 42, 41, 52, 41, 59,226,229,238,231,225,236, 105,128, 9,190,228,229,246, 97,128, 9, 62,231,245,234,225,242, 225,244,105,128, 10,190, 98, 4, 41, 80, 41,121, 41,130, 41,140, 226,242,229,246,233,225,244,233,239,110, 2, 41, 95, 41,110,237, 225,242,235,225,242,237,229,238,233,225,110,128, 5, 95,243,233, 231,238,228,229,246, 97,128, 9,112,229,238,231,225,236,105,128, 9,133,239,240,239,237,239,230,111,128, 49, 26,242,229,246,101, 134, 1, 3, 41,159, 41,167, 41,178, 41,189, 41,197, 41,209,225, 227,245,244,101,128, 30,175,227,249,242,233,236,236,233, 99,128, 4,209,228,239,244,226,229,236,239,119,128, 30,183,231,242,225, 246,101,128, 30,177,232,239,239,235,225,226,239,246,101,128, 30, 179,244,233,236,228,101,128, 30,181, 99, 4, 41,227, 41,234, 42, 57, 42,127,225,242,239,110,128, 1,206,233,242, 99, 2, 41,242, 41,247,236,101,128, 36,208,245,237,230,236,229,120,133, 0,226, 42, 10, 42, 18, 42, 29, 42, 37, 42, 49,225,227,245,244,101,128, 30,165,228,239,244,226,229,236,239,119,128, 30,173,231,242,225, 246,101,128, 30,167,232,239,239,235,225,226,239,246,101,128, 30, 169,244,233,236,228,101,128, 30,171,245,244,101,133, 0,180, 42, 73, 42, 84, 42,101, 42,108, 42,117,226,229,236,239,247,227,237, 98,128, 3, 23, 99, 2, 42, 90, 42, 95,237, 98,128, 3, 1,239, 237, 98,128, 3, 1,228,229,246, 97,128, 9, 84,236,239,247,237, 239,100,128, 2,207,244,239,238,229,227,237, 98,128, 3, 65,249, 242,233,236,236,233, 99,128, 4, 48,100, 5, 42,149, 42,159, 42, 173, 42,179, 42,213,226,236,231,242,225,246,101,128, 2, 1,228, 225,235,231,245,242,237,245,235,232,105,128, 10,113,229,246, 97, 128, 9, 5,233,229,242,229,243,233,115,130, 0,228, 42,193, 42, 204,227,249,242,233,236,236,233, 99,128, 4,211,237,225,227,242, 239,110,128, 1,223,239,116, 2, 42,220, 42,228,226,229,236,239, 119,128, 30,161,237,225,227,242,239,110,128, 1,225,101,131, 0, 230, 42,247, 42,255, 43, 8,225,227,245,244,101,128, 1,253,235, 239,242,229,225,110,128, 49, 80,237,225,227,242,239,110,128, 1, 227,230,233,105, 6, 43, 33, 43, 53, 45,246, 45,252, 46, 11, 49, 111, 48, 2, 43, 39, 43, 46,176,178,176, 56,128, 32, 21,184,185, 180, 49,128, 32,164,177, 48, 3, 43, 62, 45, 86, 45,221, 48, 9, 43, 82, 43,102, 43,164, 43,226, 44, 32, 44, 94, 44,156, 44,218, 45, 24, 49, 3, 43, 90, 43, 94, 43, 98, 55,128, 4, 16, 56,128, 4, 17, 57,128, 4, 18, 50, 10, 43,124, 43,128, 43,132, 43,136, 43,140, 43,144, 43,148, 43,152, 43,156, 43,160, 48,128, 4, 19, 49,128, 4, 20, 50,128, 4, 21, 51,128, 4, 1, 52,128, 4, 22, 53,128, 4, 23, 54,128, 4, 24, 55,128, 4, 25, 56,128, 4, 26, 57,128, 4, 27, 51, 10, 43,186, 43,190, 43,194, 43,198, 43,202, 43,206, 43,210, 43,214, 43,218, 43,222, 48,128, 4, 28, 49,128, 4, 29, 50,128, 4, 30, 51,128, 4, 31, 52,128, 4, 32, 53,128, 4, 33, 54,128, 4, 34, 55,128, 4, 35, 56,128, 4, 36, 57,128, 4, 37, 52, 10, 43,248, 43,252, 44, 0, 44, 4, 44, 8, 44, 12, 44, 16, 44, 20, 44, 24, 44, 28, 48,128, 4, 38, 49,128, 4, 39, 50,128, 4, 40, 51,128, 4, 41, 52,128, 4, 42, 53,128, 4, 43, 54,128, 4, 44, 55,128, 4, 45, 56,128, 4, 46, 57,128, 4, 47, 53, 10, 44, 54, 44, 58, 44, 62, 44, 66, 44, 70, 44, 74, 44, 78, 44, 82, 44, 86, 44, 90, 48,128, 4,144, 49,128, 4, 2, 50,128, 4, 3, 51,128, 4, 4, 52,128, 4, 5, 53,128, 4, 6, 54,128, 4, 7, 55,128, 4, 8, 56,128, 4, 9, 57,128, 4, 10, 54, 10, 44,116, 44,120, 44,124, 44,128, 44,132, 44,136, 44,140, 44,144, 44,148, 44,152, 48,128, 4, 11, 49,128, 4, 12, 50,128, 4, 14, 51,128,246,196, 52,128,246,197, 53,128, 4, 48, 54,128, 4, 49, 55,128, 4, 50, 56,128, 4, 51, 57,128, 4, 52, 55, 10, 44,178, 44,182, 44,186, 44,190, 44,194, 44,198, 44,202, 44,206, 44,210, 44,214, 48,128, 4, 53, 49,128, 4, 81, 50,128, 4, 54, 51,128, 4, 55, 52,128, 4, 56, 53,128, 4, 57, 54,128, 4, 58, 55,128, 4, 59, 56,128, 4, 60, 57,128, 4, 61, 56, 10, 44,240, 44,244, 44,248, 44,252, 45, 0, 45, 4, 45, 8, 45, 12, 45, 16, 45, 20, 48,128, 4, 62, 49,128, 4, 63, 50,128, 4, 64, 51,128, 4, 65, 52,128, 4, 66, 53,128, 4, 67, 54,128, 4, 68, 55,128, 4, 69, 56,128, 4, 70, 57,128, 4, 71, 57, 10, 45, 46, 45, 50, 45, 54, 45, 58, 45, 62, 45, 66, 45, 70, 45, 74, 45, 78, 45, 82, 48,128, 4, 72, 49,128, 4, 73, 50,128, 4, 74, 51,128, 4, 75, 52,128, 4, 76, 53,128, 4, 77, 54,128, 4, 78, 55,128, 4, 79, 56,128, 4,145, 57,128, 4, 82, 49, 4, 45, 96, 45,158, 45,163, 45,189, 48, 10, 45,118, 45,122, 45,126, 45,130, 45,134, 45,138, 45,142, 45,146, 45,150, 45,154, 48,128, 4, 83, 49,128, 4, 84, 50,128, 4, 85, 51,128, 4, 86, 52,128, 4, 87, 53,128, 4, 88, 54,128, 4, 89, 55,128, 4, 90, 56,128, 4, 91, 57,128, 4, 92,177, 48, 128, 4, 94, 52, 4, 45,173, 45,177, 45,181, 45,185, 53,128, 4, 15, 54,128, 4, 98, 55,128, 4,114, 56,128, 4,116, 57, 5, 45, 201, 45,205, 45,209, 45,213, 45,217, 50,128,246,198, 51,128, 4, 95, 52,128, 4, 99, 53,128, 4,115, 54,128, 4,117, 56, 2, 45, 227, 45,241, 51, 2, 45,233, 45,237, 49,128,246,199, 50,128,246, 200,180, 54,128, 4,217,178,185, 57,128, 32, 14,179, 48, 2, 46, 3, 46, 7, 48,128, 32, 15, 49,128, 32, 13,181, 55, 7, 46, 28, 46, 98, 47,163, 47,240, 48,197, 49, 34, 49,105, 51, 2, 46, 34, 46, 48, 56, 2, 46, 40, 46, 44, 49,128, 6,106, 56,128, 6, 12, 57, 8, 46, 66, 46, 70, 46, 74, 46, 78, 46, 82, 46, 86, 46, 90, 46, 94, 50,128, 6, 96, 51,128, 6, 97, 52,128, 6, 98, 53,128, 6, 99, 54,128, 6,100, 55,128, 6,101, 56,128, 6,102, 57,128, 6,103, 52, 7, 46,114, 46,146, 46,208, 47, 14, 47, 46, 47,102, 47,158, 48, 5, 46,126, 46,130, 46,134, 46,138, 46,142, 48,128, 6,104, 49,128, 6,105, 51,128, 6, 27, 55,128, 6, 31, 57,128, 6, 33, 49, 10, 46,168, 46,172, 46,176, 46,180, 46,184, 46,188, 46,192, 46,196, 46,200, 46,204, 48,128, 6, 34, 49,128, 6, 35, 50,128, 6, 36, 51,128, 6, 37, 52,128, 6, 38, 53,128, 6, 39, 54,128, 6, 40, 55,128, 6, 41, 56,128, 6, 42, 57,128, 6, 43, 50, 10, 46,230, 46,234, 46,238, 46,242, 46,246, 46,250, 46,254, 47, 2, 47, 6, 47, 10, 48,128, 6, 44, 49,128, 6, 45, 50,128, 6, 46, 51,128, 6, 47, 52,128, 6, 48, 53,128, 6, 49, 54,128, 6, 50, 55,128, 6, 51, 56,128, 6, 52, 57,128, 6, 53, 51, 5, 47, 26, 47, 30, 47, 34, 47, 38, 47, 42, 48,128, 6, 54, 49,128, 6, 55, 50,128, 6, 56, 51,128, 6, 57, 52,128, 6, 58, 52, 9, 47, 66, 47, 70, 47, 74, 47, 78, 47, 82, 47, 86, 47, 90, 47, 94, 47, 98, 48,128, 6, 64, 49,128, 6, 65, 50,128, 6, 66, 51,128, 6, 67, 52,128, 6, 68, 53,128, 6, 69, 54,128, 6, 70, 56,128, 6, 72, 57,128, 6, 73, 53, 9, 47,122, 47,126, 47,130, 47,134, 47,138, 47,142, 47,146, 47,150, 47,154, 48,128, 6, 74, 49,128, 6, 75, 50,128, 6, 76, 51,128, 6, 77, 52,128, 6, 78, 53,128, 6, 79, 54,128, 6, 80, 55,128, 6, 81, 56,128, 6, 82,183, 48, 128, 6, 71, 53, 3, 47,171, 47,203, 47,235, 48, 5, 47,183, 47, 187, 47,191, 47,195, 47,199, 53,128, 6,164, 54,128, 6,126, 55, 128, 6,134, 56,128, 6,152, 57,128, 6,175, 49, 5, 47,215, 47, 219, 47,223, 47,227, 47,231, 49,128, 6,121, 50,128, 6,136, 51, 128, 6,145, 52,128, 6,186, 57,128, 6,210,179, 52,128, 6,213, 54, 7, 48, 0, 48, 5, 48, 10, 48, 15, 48, 53, 48,115, 48,177, 179, 54,128, 32,170,180, 53,128, 5,190,181, 56,128, 5,195, 54, 6, 48, 29, 48, 33, 48, 37, 48, 41, 48, 45, 48, 49, 52,128, 5, 208, 53,128, 5,209, 54,128, 5,210, 55,128, 5,211, 56,128, 5, 212, 57,128, 5,213, 55, 10, 48, 75, 48, 79, 48, 83, 48, 87, 48, 91, 48, 95, 48, 99, 48,103, 48,107, 48,111, 48,128, 5,214, 49, 128, 5,215, 50,128, 5,216, 51,128, 5,217, 52,128, 5,218, 53, 128, 5,219, 54,128, 5,220, 55,128, 5,221, 56,128, 5,222, 57, 128, 5,223, 56, 10, 48,137, 48,141, 48,145, 48,149, 48,153, 48, 157, 48,161, 48,165, 48,169, 48,173, 48,128, 5,224, 49,128, 5, 225, 50,128, 5,226, 51,128, 5,227, 52,128, 5,228, 53,128, 5, 229, 54,128, 5,230, 55,128, 5,231, 56,128, 5,232, 57,128, 5, 233, 57, 3, 48,185, 48,189, 48,193, 48,128, 5,234, 52,128,251, 42, 53,128,251, 43, 55, 4, 48,207, 48,221, 48,241, 48,246, 48, 2, 48,213, 48,217, 48,128,251, 75, 53,128,251, 31, 49, 3, 48, 229, 48,233, 48,237, 54,128, 5,240, 55,128, 5,241, 56,128, 5, 242,178, 51,128,251, 53, 57, 7, 49, 6, 49, 10, 49, 14, 49, 18, 49, 22, 49, 26, 49, 30, 51,128, 5,180, 52,128, 5,181, 53,128, 5,182, 54,128, 5,187, 55,128, 5,184, 56,128, 5,183, 57,128, 5,176, 56, 3, 49, 42, 49, 86, 49, 91, 48, 7, 49, 58, 49, 62, 49, 66, 49, 70, 49, 74, 49, 78, 49, 82, 48,128, 5,178, 49,128, 5,177, 50,128, 5,179, 51,128, 5,194, 52,128, 5,193, 54,128, 5,185, 55,128, 5,188,179, 57,128, 5,189, 52, 2, 49, 97, 49, 101, 49,128, 5,191, 50,128, 5,192,185,178, 57,128, 2,188, 54, 3, 49,119, 49,178, 49,185, 49, 4, 49,129, 49,145, 49,151, 49, 172, 50, 2, 49,135, 49,140,180, 56,128, 33, 5,184, 57,128, 33, 19,179,181, 50,128, 33, 22,181, 55, 3, 49,160, 49,164, 49,168, 51,128, 32, 44, 52,128, 32, 45, 53,128, 32, 46,182,182, 52,128, 32, 12,179,177,182, 55,128, 6,109,180,185,179, 55,128, 2,189, 103, 2, 49,198, 49,205,242,225,246,101,128, 0,224,117, 2, 49, 211, 49,220,234,225,242,225,244,105,128, 10,133,242,237,245,235, 232,105,128, 10, 5,104, 2, 49,235, 49,245,233,242,225,231,225, 238, 97,128, 48, 66,239,239,235,225,226,239,246,101,128, 30,163, 105, 7, 50, 16, 50, 41, 50, 48, 50, 60, 50, 85, 50,101, 50,181, 98, 2, 50, 22, 50, 31,229,238,231,225,236,105,128, 9,144,239, 240,239,237,239,230,111,128, 49, 30,228,229,246, 97,128, 9, 16, 229,227,249,242,233,236,236,233, 99,128, 4,213,231,117, 2, 50, 67, 50, 76,234,225,242,225,244,105,128, 10,144,242,237,245,235, 232,105,128, 10, 16,237,225,244,242,225,231,245,242,237,245,235, 232,105,128, 10, 72,110, 5, 50,113, 50,122, 50,136, 50,152, 50, 167,225,242,225,226,233, 99,128, 6, 57,230,233,238,225,236,225, 242,225,226,233, 99,128,254,202,233,238,233,244,233,225,236,225, 242,225,226,233, 99,128,254,203,237,229,228,233,225,236,225,242, 225,226,233, 99,128,254,204,246,229,242,244,229,228,226,242,229, 246,101,128, 2, 3,246,239,247,229,236,243,233,231,110, 3, 50, 197, 50,207, 50,214,226,229,238,231,225,236,105,128, 9,200,228, 229,246, 97,128, 9, 72,231,245,234,225,242,225,244,105,128, 10, 200,107, 2, 50,231, 50,255,225,244,225,235,225,238, 97,129, 48, 162, 50,243,232,225,236,230,247,233,228,244,104,128,255,113,239, 242,229,225,110,128, 49, 79,108, 3, 51, 15, 52, 71, 52, 80,101, 2, 51, 21, 52, 66,102,136, 5,208, 51, 41, 51, 50, 51, 65, 51, 79, 51,168, 51,182, 52, 37, 52, 51,225,242,225,226,233, 99,128, 6, 39,228,225,231,229,243,232,232,229,226,242,229,119,128,251, 48,230,233,238,225,236,225,242,225,226,233, 99,128,254,142,104, 2, 51, 85, 51,160,225,237,250, 97, 2, 51, 94, 51,127,225,226, 239,246,101, 2, 51,104, 51,113,225,242,225,226,233, 99,128, 6, 35,230,233,238,225,236,225,242,225,226,233, 99,128,254,132,226, 229,236,239,119, 2, 51,137, 51,146,225,242,225,226,233, 99,128, 6, 37,230,233,238,225,236,225,242,225,226,233, 99,128,254,136, 229,226,242,229,119,128, 5,208,236,225,237,229,228,232,229,226, 242,229,119,128,251, 79,237, 97, 2, 51,189, 51,225,228,228,225, 225,226,239,246,101, 2, 51,202, 51,211,225,242,225,226,233, 99, 128, 6, 34,230,233,238,225,236,225,242,225,226,233, 99,128,254, 130,235,243,245,242, 97, 4, 51,239, 51,248, 52, 6, 52, 22,225, 242,225,226,233, 99,128, 6, 73,230,233,238,225,236,225,242,225, 226,233, 99,128,254,240,233,238,233,244,233,225,236,225,242,225, 226,233, 99,128,254,243,237,229,228,233,225,236,225,242,225,226, 233, 99,128,254,244,240,225,244,225,232,232,229,226,242,229,119, 128,251, 46,241,225,237,225,244,243,232,229,226,242,229,119,128, 251, 47,240,104,128, 33, 53,236,229,241,245,225,108,128, 34, 76, 240,232, 97,129, 3,177, 52, 88,244,239,238,239,115,128, 3,172, 109, 4, 52,106, 52,114, 52,125, 52,159,225,227,242,239,110,128, 1, 1,239,238,239,243,240,225,227,101,128,255, 65,240,229,242, 243,225,238,100,130, 0, 38, 52,139, 52,151,237,239,238,239,243, 240,225,227,101,128,255, 6,243,237,225,236,108,128,247, 38,243, 241,245,225,242,101,128, 51,194,110, 4, 52,178, 52,189, 53, 55, 53, 65,226,239,240,239,237,239,230,111,128, 49, 34,103, 4, 52, 199, 52,210, 52,224, 53, 47,226,239,240,239,237,239,230,111,128, 49, 36,235,232,225,238,235,232,245,244,232,225,105,128, 14, 90, 236,101,131, 34, 32, 52,235, 53, 32, 53, 39,226,242,225,227,235, 229,116, 2, 52,247, 53, 11,236,229,230,116,129, 48, 8, 53, 0, 246,229,242,244,233,227,225,108,128,254, 63,242,233,231,232,116, 129, 48, 9, 53, 21,246,229,242,244,233,227,225,108,128,254, 64, 236,229,230,116,128, 35, 41,242,233,231,232,116,128, 35, 42,243, 244,242,239,109,128, 33, 43,239,244,229,236,229,233, 97,128, 3, 135,117, 2, 53, 71, 53, 83,228,225,244,244,225,228,229,246, 97, 128, 9, 82,243,246,225,242, 97, 3, 53, 95, 53,105, 53,112,226, 229,238,231,225,236,105,128, 9,130,228,229,246, 97,128, 9, 2, 231,245,234,225,242,225,244,105,128, 10,130,239,231,239,238,229, 107,128, 1, 5,112, 3, 53,140, 53,164, 53,194, 97, 2, 53,146, 53,158,225,244,239,243,241,245,225,242,101,128, 51, 0,242,229, 110,128, 36,156,239,243,244,242,239,240,232,101, 2, 53,177, 53, 188,225,242,237,229,238,233,225,110,128, 5, 90,237,239,100,128, 2,188,112, 2, 53,200, 53,205,236,101,128,248,255,242,111, 2, 53,212, 53,220,225,227,232,229,115,128, 34, 80,120, 2, 53,226, 53,246,229,241,245,225,108,129, 34, 72, 53,236,239,242,233,237, 225,231,101,128, 34, 82,233,237,225,244,229,236,249,229,241,245, 225,108,128, 34, 69,114, 4, 54, 15, 54, 42, 54, 46, 54, 91,225, 229, 97, 2, 54, 23, 54, 33,229,235,239,242,229,225,110,128, 49, 142,235,239,242,229,225,110,128, 49,141, 99,128, 35, 18,105, 2, 54, 52, 54, 66,231,232,244,232,225,236,230,242,233,238,103,128, 30,154,238,103,130, 0,229, 54, 75, 54, 83,225,227,245,244,101, 128, 1,251,226,229,236,239,119,128, 30, 1,242,239,119, 8, 54, 111, 54,118, 54,247, 55, 57, 55,107, 55,162, 55,185, 56, 4,226, 239,244,104,128, 33,148,100, 3, 54,126, 54,165, 54,212,225,243, 104, 4, 54,138, 54,145, 54,152, 54,160,228,239,247,110,128, 33, 227,236,229,230,116,128, 33,224,242,233,231,232,116,128, 33,226, 245,112,128, 33,225,226,108, 5, 54,178, 54,185, 54,192, 54,199, 54,207,226,239,244,104,128, 33,212,228,239,247,110,128, 33,211, 236,229,230,116,128, 33,208,242,233,231,232,116,128, 33,210,245, 112,128, 33,209,239,247,110,131, 33,147, 54,224, 54,231, 54,239, 236,229,230,116,128, 33,153,242,233,231,232,116,128, 33,152,247, 232,233,244,101,128, 33,233,104, 2, 54,253, 55, 48,229,225,100, 4, 55, 9, 55, 19, 55, 29, 55, 40,228,239,247,238,237,239,100, 128, 2,197,236,229,230,244,237,239,100,128, 2,194,242,233,231, 232,244,237,239,100,128, 2,195,245,240,237,239,100,128, 2,196, 239,242,233,250,229,120,128,248,231,236,229,230,116,131, 33,144, 55, 70, 55, 87, 55, 99,228,226,108,129, 33,208, 55, 78,243,244, 242,239,235,101,128, 33,205,239,246,229,242,242,233,231,232,116, 128, 33,198,247,232,233,244,101,128, 33,230,242,233,231,232,116, 132, 33,146, 55,123, 55,135, 55,143, 55,154,228,226,236,243,244, 242,239,235,101,128, 33,207,232,229,225,246,121,128, 39,158,239, 246,229,242,236,229,230,116,128, 33,196,247,232,233,244,101,128, 33,232,244,225, 98, 2, 55,170, 55,177,236,229,230,116,128, 33, 228,242,233,231,232,116,128, 33,229,245,112,132, 33,145, 55,198, 55,226, 55,244, 55,252,100, 2, 55,204, 55,216,110,129, 33,149, 55,210,226,243,101,128, 33,168,239,247,238,226,225,243,101,128, 33,168,236,229,230,116,129, 33,150, 55,235,239,230,228,239,247, 110,128, 33,197,242,233,231,232,116,128, 33,151,247,232,233,244, 101,128, 33,231,246,229,242,244,229,120,128,248,230,115, 5, 56, 25, 56,101, 56,146, 56,229, 56,239, 99, 2, 56, 31, 56, 83,233, 105, 2, 56, 38, 56, 61,227,233,242,227,245,109,129, 0, 94, 56, 49,237,239,238,239,243,240,225,227,101,128,255, 62,244,233,236, 228,101,129, 0,126, 56, 71,237,239,238,239,243,240,225,227,101, 128,255, 94,242,233,240,116,129, 2, 81, 56, 92,244,245,242,238, 229,100,128, 2, 82,237,225,236,108, 2, 56,110, 56,121,232,233, 242,225,231,225,238, 97,128, 48, 65,235,225,244,225,235,225,238, 97,129, 48,161, 56,134,232,225,236,230,247,233,228,244,104,128, 255,103,244,229,242,233,115, 2, 56,156, 56,225,107,131, 0, 42, 56,166, 56,194, 56,217, 97, 2, 56,172, 56,186,236,244,239,238, 229,225,242,225,226,233, 99,128, 6,109,242,225,226,233, 99,128, 6,109,109, 2, 56,200, 56,206,225,244,104,128, 34, 23,239,238, 239,243,240,225,227,101,128,255, 10,243,237,225,236,108,128,254, 97,109,128, 32, 66,245,240,229,242,233,239,114,128,246,233,249, 237,240,244,239,244,233,227,225,236,236,249,229,241,245,225,108, 128, 34, 67,116,132, 0, 64, 57, 15, 57, 22, 57, 34, 57, 42,233, 236,228,101,128, 0,227,237,239,238,239,243,240,225,227,101,128, 255, 32,243,237,225,236,108,128,254,107,245,242,238,229,100,128, 2, 80,117, 6, 57, 64, 57, 89, 57, 96, 57,121, 57,141, 57,157, 98, 2, 57, 70, 57, 79,229,238,231,225,236,105,128, 9,148,239, 240,239,237,239,230,111,128, 49, 32,228,229,246, 97,128, 9, 20, 231,117, 2, 57,103, 57,112,234,225,242,225,244,105,128, 10,148, 242,237,245,235,232,105,128, 10, 20,236,229,238,231,244,232,237, 225,242,235,226,229,238,231,225,236,105,128, 9,215,237,225,244, 242,225,231,245,242,237,245,235,232,105,128, 10, 76,246,239,247, 229,236,243,233,231,110, 3, 57,173, 57,183, 57,190,226,229,238, 231,225,236,105,128, 9,204,228,229,246, 97,128, 9, 76,231,245, 234,225,242,225,244,105,128, 10,204,246,225,231,242,225,232,225, 228,229,246, 97,128, 9, 61,121, 2, 57,221, 57,233,226,225,242, 237,229,238,233,225,110,128, 5, 97,233,110,130, 5,226, 57,242, 58, 1,225,236,244,239,238,229,232,229,226,242,229,119,128,251, 32,232,229,226,242,229,119,128, 5,226, 98,144, 0, 98, 58, 46, 58,181, 58,192, 58,201, 58,226, 60, 11, 60, 73, 60,146, 62, 72, 62, 84, 62,127, 62,135, 62,145, 64, 15, 64, 39, 64, 48, 97, 7, 58, 62, 58, 72, 58, 96, 58,103, 58,128, 58,152, 58,163,226,229, 238,231,225,236,105,128, 9,172,227,235,243,236,225,243,104,129, 0, 92, 58, 84,237,239,238,239,243,240,225,227,101,128,255, 60, 228,229,246, 97,128, 9, 44,231,117, 2, 58,110, 58,119,234,225, 242,225,244,105,128, 10,172,242,237,245,235,232,105,128, 10, 44, 104, 2, 58,134, 58,144,233,242,225,231,225,238, 97,128, 48,112, 244,244,232,225,105,128, 14, 63,235,225,244,225,235,225,238, 97, 128, 48,208,114,129, 0,124, 58,169,237,239,238,239,243,240,225, 227,101,128,255, 92,226,239,240,239,237,239,230,111,128, 49, 5, 227,233,242,227,236,101,128, 36,209,228,239,116, 2, 58,209, 58, 218,225,227,227,229,238,116,128, 30, 3,226,229,236,239,119,128, 30, 5,101, 6, 58,240, 59, 5, 59, 28, 59,170, 59,181, 59,193, 225,237,229,228,243,233,248,244,229,229,238,244,232,238,239,244, 229,115,128, 38,108, 99, 2, 59, 11, 59, 18,225,245,243,101,128, 34, 53,249,242,233,236,236,233, 99,128, 4, 49,104, 5, 59, 40, 59, 49, 59, 63, 59, 93, 59,152,225,242,225,226,233, 99,128, 6, 40,230,233,238,225,236,225,242,225,226,233, 99,128,254,144,105, 2, 59, 69, 59, 84,238,233,244,233,225,236,225,242,225,226,233, 99,128,254,145,242,225,231,225,238, 97,128, 48,121,237,101, 2, 59,100, 59,113,228,233,225,236,225,242,225,226,233, 99,128,254, 146,229,237,105, 2, 59,121, 59,136,238,233,244,233,225,236,225, 242,225,226,233, 99,128,252,159,243,239,236,225,244,229,228,225, 242,225,226,233, 99,128,252, 8,238,239,239,238,230,233,238,225, 236,225,242,225,226,233, 99,128,252,109,235,225,244,225,235,225, 238, 97,128, 48,217,238,225,242,237,229,238,233,225,110,128, 5, 98,116,132, 5,209, 59,205, 59,225, 59,245, 59,254, 97,129, 3, 178, 59,211,243,249,237,226,239,236,231,242,229,229,107,128, 3, 208,228,225,231,229,243,104,129,251, 49, 59,236,232,229,226,242, 229,119,128,251, 49,232,229,226,242,229,119,128, 5,209,242,225, 230,229,232,229,226,242,229,119,128,251, 76,104, 2, 60, 17, 60, 67, 97, 3, 60, 25, 60, 35, 60, 42,226,229,238,231,225,236,105, 128, 9,173,228,229,246, 97,128, 9, 45,231,117, 2, 60, 49, 60, 58,234,225,242,225,244,105,128, 10,173,242,237,245,235,232,105, 128, 10, 45,239,239,107,128, 2, 83,105, 5, 60, 85, 60, 96, 60, 107, 60,121, 60,135,232,233,242,225,231,225,238, 97,128, 48,115, 235,225,244,225,235,225,238, 97,128, 48,211,236,225,226,233,225, 236,227,236,233,227,107,128, 2,152,238,228,233,231,245,242,237, 245,235,232,105,128, 10, 2,242,245,243,241,245,225,242,101,128, 51, 49,108, 3, 60,154, 62, 55, 62, 66, 97, 2, 60,160, 62, 50, 227,107, 6, 60,175, 60,184, 60,221, 61,114, 61,169, 61,221,227, 233,242,227,236,101,128, 37,207,100, 2, 60,190, 60,199,233,225, 237,239,238,100,128, 37,198,239,247,238,240,239,233,238,244,233, 238,231,244,242,233,225,238,231,236,101,128, 37,188,108, 2, 60, 227, 61, 74,101, 2, 60,233, 61, 13,230,244,240,239,233,238,244, 233,238,103, 2, 60,248, 61, 2,240,239,233,238,244,229,114,128, 37,196,244,242,233,225,238,231,236,101,128, 37,192,238,244,233, 227,245,236,225,242,226,242,225,227,235,229,116, 2, 61, 33, 61, 53,236,229,230,116,129, 48, 16, 61, 42,246,229,242,244,233,227, 225,108,128,254, 59,242,233,231,232,116,129, 48, 17, 61, 63,246, 229,242,244,233,227,225,108,128,254, 60,239,247,229,114, 2, 61, 83, 61, 98,236,229,230,244,244,242,233,225,238,231,236,101,128, 37,227,242,233,231,232,244,244,242,233,225,238,231,236,101,128, 37,226,114, 2, 61,120, 61,131,229,227,244,225,238,231,236,101, 128, 37,172,233,231,232,244,240,239,233,238,244,233,238,103, 2, 61,148, 61,158,240,239,233,238,244,229,114,128, 37,186,244,242, 233,225,238,231,236,101,128, 37,182,115, 3, 61,177, 61,207, 61, 215,109, 2, 61,183, 61,195,225,236,236,243,241,245,225,242,101, 128, 37,170,233,236,233,238,231,230,225,227,101,128, 38, 59,241, 245,225,242,101,128, 37,160,244,225,114,128, 38, 5,245,240,112, 2, 61,229, 62, 11,229,114, 2, 61,236, 61,251,236,229,230,244, 244,242,233,225,238,231,236,101,128, 37,228,242,233,231,232,244, 244,242,233,225,238,231,236,101,128, 37,229,239,233,238,244,233, 238,103, 2, 62, 23, 62, 39,243,237,225,236,236,244,242,233,225, 238,231,236,101,128, 37,180,244,242,233,225,238,231,236,101,128, 37,178,238,107,128, 36, 35,233,238,229,226,229,236,239,119,128, 30, 7,239,227,107,128, 37,136,237,239,238,239,243,240,225,227, 101,128,255, 66,111, 3, 62, 92, 62,105, 62,116,226,225,233,237, 225,233,244,232,225,105,128, 14, 26,232,233,242,225,231,225,238, 97,128, 48,124,235,225,244,225,235,225,238, 97,128, 48,220,240, 225,242,229,110,128, 36,157,241,243,241,245,225,242,101,128, 51, 195,114, 4, 62,155, 63,149, 63,222, 64, 5,225, 99, 2, 62,162, 63, 56,101, 3, 62,170, 62,175, 62,243,229,120,128,248,244,236, 229,230,116,133, 0,123, 62,192, 62,197, 62,219, 62,227, 62,232, 226,116,128,248,243,109, 2, 62,203, 62,208,233,100,128,248,242, 239,238,239,243,240,225,227,101,128,255, 91,243,237,225,236,108, 128,254, 91,244,112,128,248,241,246,229,242,244,233,227,225,108, 128,254, 55,242,233,231,232,116,133, 0,125, 63, 5, 63, 10, 63, 32, 63, 40, 63, 45,226,116,128,248,254,109, 2, 63, 16, 63, 21, 233,100,128,248,253,239,238,239,243,240,225,227,101,128,255, 93, 243,237,225,236,108,128,254, 92,244,112,128,248,252,246,229,242, 244,233,227,225,108,128,254, 56,235,229,116, 2, 63, 64, 63,106, 236,229,230,116,132, 0, 91, 63, 79, 63, 84, 63, 89, 63,101,226, 116,128,248,240,229,120,128,248,239,237,239,238,239,243,240,225, 227,101,128,255, 59,244,112,128,248,238,242,233,231,232,116,132, 0, 93, 63,122, 63,127, 63,132, 63,144,226,116,128,248,251,229, 120,128,248,250,237,239,238,239,243,240,225,227,101,128,255, 61, 244,112,128,248,249,229,246,101,131, 2,216, 63,161, 63,172, 63, 178,226,229,236,239,247,227,237, 98,128, 3, 46,227,237, 98,128, 3, 6,233,238,246,229,242,244,229,100, 3, 63,193, 63,204, 63, 210,226,229,236,239,247,227,237, 98,128, 3, 47,227,237, 98,128, 3, 17,228,239,245,226,236,229,227,237, 98,128, 3, 97,233,228, 231,101, 2, 63,231, 63,242,226,229,236,239,247,227,237, 98,128, 3, 42,233,238,246,229,242,244,229,228,226,229,236,239,247,227, 237, 98,128, 3, 58,239,235,229,238,226,225,114,128, 0,166,115, 2, 64, 21, 64, 29,244,242,239,235,101,128, 1,128,245,240,229, 242,233,239,114,128,246,234,244,239,240,226,225,114,128, 1,131, 117, 3, 64, 56, 64, 67, 64, 78,232,233,242,225,231,225,238, 97, 128, 48,118,235,225,244,225,235,225,238, 97,128, 48,214,236,108, 2, 64, 85, 64,115,229,116,130, 32, 34, 64, 94, 64,104,233,238, 246,229,242,243,101,128, 37,216,239,240,229,242,225,244,239,114, 128, 34, 25,243,229,249,101,128, 37,206, 99,143, 0, 99, 64,156, 65,105, 65,116, 65,180, 65,211, 66, 48, 67,215, 68,199, 69, 43, 69, 92, 72, 84, 72, 92, 72,102, 72,114, 72,147, 97, 9, 64,176, 64,187, 64,197, 64,204, 64,211, 64,236, 64,246, 65, 42, 65, 51, 225,242,237,229,238,233,225,110,128, 5,110,226,229,238,231,225, 236,105,128, 9,154,227,245,244,101,128, 1, 7,228,229,246, 97, 128, 9, 26,231,117, 2, 64,218, 64,227,234,225,242,225,244,105, 128, 10,154,242,237,245,235,232,105,128, 10, 26,236,243,241,245, 225,242,101,128, 51,136,238,228,242,225,226,233,238,228,117, 4, 65, 8, 65, 18, 65, 24, 65, 31,226,229,238,231,225,236,105,128, 9,129,227,237, 98,128, 3, 16,228,229,246, 97,128, 9, 1,231, 245,234,225,242,225,244,105,128, 10,129,240,243,236,239,227,107, 128, 33,234,114, 3, 65, 59, 65, 65, 65, 91,229,239,102,128, 33, 5,239,110,130, 2,199, 65, 74, 65, 85,226,229,236,239,247,227, 237, 98,128, 3, 44,227,237, 98,128, 3, 12,242,233,225,231,229, 242,229,244,245,242,110,128, 33,181,226,239,240,239,237,239,230, 111,128, 49, 24, 99, 4, 65,126, 65,133, 65,152, 65,174,225,242, 239,110,128, 1, 13,229,228,233,236,236, 97,129, 0,231, 65,144, 225,227,245,244,101,128, 30, 9,233,242, 99, 2, 65,160, 65,165, 236,101,128, 36,210,245,237,230,236,229,120,128, 1, 9,245,242, 108,128, 2, 85,100, 2, 65,186, 65,202,239,116,129, 1, 11, 65, 193,225,227,227,229,238,116,128, 1, 11,243,241,245,225,242,101, 128, 51,197,101, 2, 65,217, 65,233,228,233,236,236, 97,129, 0, 184, 65,227,227,237, 98,128, 3, 39,238,116,132, 0,162, 65,246, 66, 14, 66, 26, 66, 37,105, 2, 65,252, 66, 4,231,242,225,228, 101,128, 33, 3,238,230,229,242,233,239,114,128,246,223,237,239, 238,239,243,240,225,227,101,128,255,224,239,236,228,243,244,249, 236,101,128,247,162,243,245,240,229,242,233,239,114,128,246,224, 104, 5, 66, 60, 66,123, 66,134, 67, 62, 67,154, 97, 4, 66, 70, 66, 81, 66, 91, 66, 98,225,242,237,229,238,233,225,110,128, 5, 121,226,229,238,231,225,236,105,128, 9,155,228,229,246, 97,128, 9, 27,231,117, 2, 66,105, 66,114,234,225,242,225,244,105,128, 10,155,242,237,245,235,232,105,128, 10, 27,226,239,240,239,237, 239,230,111,128, 49, 20,101, 6, 66,148, 66,168, 66,192, 67, 4, 67, 16, 67, 37,225,226,235,232,225,243,233,225,238,227,249,242, 233,236,236,233, 99,128, 4,189, 99, 2, 66,174, 66,182,235,237, 225,242,107,128, 39, 19,249,242,233,236,236,233, 99,128, 4, 71, 100, 2, 66,198, 66,242,229,243,227,229,238,228,229,114, 2, 66, 211, 66,231,225,226,235,232,225,243,233,225,238,227,249,242,233, 236,236,233, 99,128, 4,191,227,249,242,233,236,236,233, 99,128, 4,183,233,229,242,229,243,233,243,227,249,242,233,236,236,233, 99,128, 4,245,232,225,242,237,229,238,233,225,110,128, 5,115, 235,232,225,235,225,243,243,233,225,238,227,249,242,233,236,236, 233, 99,128, 4,204,246,229,242,244,233,227,225,236,243,244,242, 239,235,229,227,249,242,233,236,236,233, 99,128, 4,185,105,129, 3,199, 67, 68,229,245,227,104, 4, 67, 81, 67,116, 67,131, 67, 140, 97, 2, 67, 87, 67,102,227,233,242,227,236,229,235,239,242, 229,225,110,128, 50,119,240,225,242,229,238,235,239,242,229,225, 110,128, 50, 23,227,233,242,227,236,229,235,239,242,229,225,110, 128, 50,105,235,239,242,229,225,110,128, 49, 74,240,225,242,229, 238,235,239,242,229,225,110,128, 50, 9,111, 2, 67,160, 67,210, 227,104, 3, 67,169, 67,191, 67,201,225,110, 2, 67,176, 67,184, 231,244,232,225,105,128, 14, 10,244,232,225,105,128, 14, 8,233, 238,231,244,232,225,105,128, 14, 9,239,229,244,232,225,105,128, 14, 12,239,107,128, 1,136,105, 2, 67,221, 68, 67,229,245, 99, 5, 67,235, 68, 14, 68, 29, 68, 38, 68, 52, 97, 2, 67,241, 68, 0,227,233,242,227,236,229,235,239,242,229,225,110,128, 50,118, 240,225,242,229,238,235,239,242,229,225,110,128, 50, 22,227,233, 242,227,236,229,235,239,242,229,225,110,128, 50,104,235,239,242, 229,225,110,128, 49, 72,240,225,242,229,238,235,239,242,229,225, 110,128, 50, 8,245,240,225,242,229,238,235,239,242,229,225,110, 128, 50, 28,242, 99, 2, 68, 74, 68,169,236,101,132, 37,203, 68, 87, 68, 98, 68,103, 68,127,237,245,236,244,233,240,236,121,128, 34,151,239,116,128, 34,153,112, 2, 68,109, 68,115,236,245,115, 128, 34,149,239,243,244,225,236,237,225,242,107,128, 48, 54,247, 233,244,104, 2, 68,136, 68,152,236,229,230,244,232,225,236,230, 226,236,225,227,107,128, 37,208,242,233,231,232,244,232,225,236, 230,226,236,225,227,107,128, 37,209,245,237,230,236,229,120,130, 2,198, 68,182, 68,193,226,229,236,239,247,227,237, 98,128, 3, 45,227,237, 98,128, 3, 2,108, 3, 68,207, 68,213, 69, 11,229, 225,114,128, 35, 39,233,227,107, 4, 68,225, 68,236, 68,245, 68, 255,225,236,246,229,239,236,225,114,128, 1,194,228,229,238,244, 225,108,128, 1,192,236,225,244,229,242,225,108,128, 1,193,242, 229,244,242,239,230,236,229,120,128, 1,195,245, 98,129, 38, 99, 69, 18,243,245,233,116, 2, 69, 27, 69, 35,226,236,225,227,107, 128, 38, 99,247,232,233,244,101,128, 38,103,109, 3, 69, 51, 69, 65, 69, 76,227,245,226,229,228,243,241,245,225,242,101,128, 51, 164,239,238,239,243,240,225,227,101,128,255, 67,243,241,245,225, 242,229,228,243,241,245,225,242,101,128, 51,160,111, 8, 69,110, 69,121, 69,208, 70,150, 71,179, 71,210, 72, 61, 72, 70,225,242, 237,229,238,233,225,110,128, 5,129,236,239,110,131, 0, 58, 69, 133, 69,158, 69,177,237,239,110, 2, 69,141, 69,149,229,244,225, 242,121,128, 32,161,239,243,240,225,227,101,128,255, 26,115, 2, 69,164, 69,170,233,231,110,128, 32,161,237,225,236,108,128,254, 85,244,242,233,225,238,231,245,236,225,114, 2, 69,192, 69,202, 232,225,236,230,237,239,100,128, 2,209,237,239,100,128, 2,208, 109, 2, 69,214, 70,143,237, 97,134, 0, 44, 69,231, 70, 39, 70, 50, 70, 62, 70, 92, 70,115, 97, 3, 69,239, 70, 9, 70, 17,226, 239,246,101, 2, 69,248, 69,254,227,237, 98,128, 3, 19,242,233, 231,232,244,227,237, 98,128, 3, 21,227,227,229,238,116,128,246, 195,114, 2, 70, 23, 70, 30,225,226,233, 99,128, 6, 12,237,229, 238,233,225,110,128, 5, 93,233,238,230,229,242,233,239,114,128, 246,225,237,239,238,239,243,240,225,227,101,128,255, 12,242,229, 246,229,242,243,229,100, 2, 70, 75, 70, 86,225,226,239,246,229, 227,237, 98,128, 3, 20,237,239,100,128, 2,189,115, 2, 70, 98, 70,105,237,225,236,108,128,254, 80,245,240,229,242,233,239,114, 128,246,226,244,245,242,238,229,100, 2, 70,126, 70,137,225,226, 239,246,229,227,237, 98,128, 3, 18,237,239,100,128, 2,187,240, 225,243,115,128, 38, 60,110, 2, 70,156, 70,165,231,242,245,229, 238,116,128, 34, 69,116, 2, 70,171, 70,185,239,245,242,233,238, 244,229,231,242,225,108,128, 34, 46,242,239,108,142, 35, 3, 70, 219, 70,225, 70,240, 70,255, 71, 43, 71, 88, 71,102, 71,107, 71, 112, 71,117, 71,123, 71,128, 71,169, 71,174,193,195, 75,128, 0, 6, 66, 2, 70,231, 70,236,197, 76,128, 0, 7, 83,128, 0, 8, 67, 2, 70,246, 70,251,193, 78,128, 0, 24, 82,128, 0, 13, 68, 3, 71, 7, 71, 33, 71, 38, 67, 4, 71, 17, 71, 21, 71, 25, 71, 29, 49,128, 0, 17, 50,128, 0, 18, 51,128, 0, 19, 52,128, 0, 20,197, 76,128, 0,127,204, 69,128, 0, 16, 69, 5, 71, 55, 71, 59, 71, 64, 71, 69, 71, 74, 77,128, 0, 25,206, 81,128, 0, 5, 207, 84,128, 0, 4,211, 67,128, 0, 27, 84, 2, 71, 80, 71, 84, 66,128, 0, 23, 88,128, 0, 3, 70, 2, 71, 94, 71, 98, 70,128, 0, 12, 83,128, 0, 28,199, 83,128, 0, 29,200, 84,128, 0, 9, 204, 70,128, 0, 10,206,193, 75,128, 0, 21,210, 83,128, 0, 30, 83, 5, 71,140, 71,144, 71,154, 71,159, 71,164, 73,128, 0, 15, 79,129, 0, 14, 71,150, 84,128, 0, 2,212, 88,128, 0, 1,213, 66,128, 0, 26,217, 78,128, 0, 22,213, 83,128, 0, 31,214, 84, 128, 0, 11,240,249,242,233,231,232,116,129, 0,169, 71,191,115, 2, 71,197, 71,203,225,238,115,128,248,233,229,242,233,102,128, 246,217,114, 2, 71,216, 72, 44,238,229,242,226,242,225,227,235, 229,116, 2, 71,231, 72, 9,236,229,230,116,130, 48, 12, 71,242, 71,254,232,225,236,230,247,233,228,244,104,128,255, 98,246,229, 242,244,233,227,225,108,128,254, 65,242,233,231,232,116,130, 48, 13, 72, 21, 72, 33,232,225,236,230,247,233,228,244,104,128,255, 99,246,229,242,244,233,227,225,108,128,254, 66,240,239,242,225, 244,233,239,238,243,241,245,225,242,101,128, 51,127,243,241,245, 225,242,101,128, 51,199,246,229,242,235,231,243,241,245,225,242, 101,128, 51,198,240,225,242,229,110,128, 36,158,242,245,250,229, 233,242,111,128, 32,162,243,244,242,229,244,227,232,229,100,128, 2,151,245,114, 2, 72,121, 72,139,236,121, 2, 72,128, 72,134, 225,238,100,128, 34,207,239,114,128, 34,206,242,229,238,227,121, 128, 0,164,249,114, 4, 72,158, 72,166, 72,173, 72,181,194,242, 229,246,101,128,246,209,198,236,229,120,128,246,210,226,242,229, 246,101,128,246,212,230,236,229,120,128,246,213,100,146, 0,100, 72,228, 74,110, 75,134, 75,194, 76,114, 77, 68, 77,130, 78, 59, 78, 72, 78, 81, 78,107, 78,132, 78,141, 79,208, 79,216, 79,227, 79,247, 80, 19, 97, 11, 72,252, 73, 7, 73, 17, 73, 89, 73,152, 73,163, 73,174, 73,243, 74, 49, 74, 55, 74, 85,225,242,237,229, 238,233,225,110,128, 5,100,226,229,238,231,225,236,105,128, 9, 166,100, 5, 73, 29, 73, 38, 73, 44, 73, 58, 73, 74,225,242,225, 226,233, 99,128, 6, 54,229,246, 97,128, 9, 38,230,233,238,225, 236,225,242,225,226,233, 99,128,254,190,233,238,233,244,233,225, 236,225,242,225,226,233, 99,128,254,191,237,229,228,233,225,236, 225,242,225,226,233, 99,128,254,192,103, 3, 73, 97, 73,114, 73, 128,229,243,104,129, 5,188, 73,105,232,229,226,242,229,119,128, 5,188,231,229,114,129, 32, 32, 73,122,228,226,108,128, 32, 33, 117, 2, 73,134, 73,143,234,225,242,225,244,105,128, 10,166,242, 237,245,235,232,105,128, 10, 38,232,233,242,225,231,225,238, 97, 128, 48, 96,235,225,244,225,235,225,238, 97,128, 48,192,108, 3, 73,182, 73,191, 73,229,225,242,225,226,233, 99,128, 6, 47,229, 116,130, 5,211, 73,200, 73,220,228,225,231,229,243,104,129,251, 51, 73,211,232,229,226,242,229,119,128,251, 51,232,229,226,242, 229,119,128, 5,211,230,233,238,225,236,225,242,225,226,233, 99, 128,254,170,237,237, 97, 3, 73,253, 74, 6, 74, 18,225,242,225, 226,233, 99,128, 6, 79,236,239,247,225,242,225,226,233, 99,128, 6, 79,244,225,238, 97, 2, 74, 27, 74, 41,236,244,239,238,229, 225,242,225,226,233, 99,128, 6, 76,242,225,226,233, 99,128, 6, 76,238,228, 97,128, 9,100,242,231, 97, 2, 74, 63, 74, 72,232, 229,226,242,229,119,128, 5,167,236,229,230,244,232,229,226,242, 229,119,128, 5,167,243,233,225,240,238,229,245,237,225,244,225, 227,249,242,233,236,236,233,227,227,237, 98,128, 4,133, 98, 3, 74,118, 75,115, 75,125,108, 9, 74,138, 74,146, 75, 3, 75, 11, 75, 27, 75, 38, 75, 56, 75, 70, 75, 81,199,242,225,246,101,128, 246,211, 97, 2, 74,152, 74,209,238,231,236,229,226,242,225,227, 235,229,116, 2, 74,168, 74,188,236,229,230,116,129, 48, 10, 74, 177,246,229,242,244,233,227,225,108,128,254, 61,242,233,231,232, 116,129, 48, 11, 74,198,246,229,242,244,233,227,225,108,128,254, 62,114, 2, 74,215, 74,236,227,232,233,238,246,229,242,244,229, 228,226,229,236,239,247,227,237, 98,128, 3, 43,242,239,119, 2, 74,244, 74,251,236,229,230,116,128, 33,212,242,233,231,232,116, 128, 33,210,228,225,238,228, 97,128, 9,101,231,242,225,246,101, 129,246,214, 75, 21,227,237, 98,128, 3, 15,233,238,244,229,231, 242,225,108,128, 34, 44,236,239,247,236,233,238,101,129, 32, 23, 75, 50,227,237, 98,128, 3, 51,239,246,229,242,236,233,238,229, 227,237, 98,128, 3, 63,240,242,233,237,229,237,239,100,128, 2, 186,246,229,242,244,233,227,225,108, 2, 75, 94, 75,100,226,225, 114,128, 32, 22,236,233,238,229,225,226,239,246,229,227,237, 98, 128, 3, 14,239,240,239,237,239,230,111,128, 49, 9,243,241,245, 225,242,101,128, 51,200, 99, 4, 75,144, 75,151, 75,160, 75,187, 225,242,239,110,128, 1, 15,229,228,233,236,236, 97,128, 30, 17, 233,242, 99, 2, 75,168, 75,173,236,101,128, 36,211,245,237,230, 236,229,248,226,229,236,239,119,128, 30, 19,242,239,225,116,128, 1, 17,100, 4, 75,204, 76, 29, 76, 39, 76, 90, 97, 4, 75,214, 75,224, 75,231, 76, 0,226,229,238,231,225,236,105,128, 9,161, 228,229,246, 97,128, 9, 33,231,117, 2, 75,238, 75,247,234,225, 242,225,244,105,128, 10,161,242,237,245,235,232,105,128, 10, 33, 108, 2, 76, 6, 76, 15,225,242,225,226,233, 99,128, 6,136,230, 233,238,225,236,225,242,225,226,233, 99,128,251,137,228,232,225, 228,229,246, 97,128, 9, 92,232, 97, 3, 76, 48, 76, 58, 76, 65, 226,229,238,231,225,236,105,128, 9,162,228,229,246, 97,128, 9, 34,231,117, 2, 76, 72, 76, 81,234,225,242,225,244,105,128, 10, 162,242,237,245,235,232,105,128, 10, 34,239,116, 2, 76, 97, 76, 106,225,227,227,229,238,116,128, 30, 11,226,229,236,239,119,128, 30, 13,101, 8, 76,132, 76,185, 76,192, 76,217, 76,227, 76,238, 77, 27, 77, 63, 99, 2, 76,138, 76,175,233,237,225,236,243,229, 240,225,242,225,244,239,114, 2, 76,156, 76,165,225,242,225,226, 233, 99,128, 6,107,240,229,242,243,233,225,110,128, 6,107,249, 242,233,236,236,233, 99,128, 4, 52,231,242,229,101,128, 0,176, 232,105, 2, 76,199, 76,208,232,229,226,242,229,119,128, 5,173, 242,225,231,225,238, 97,128, 48,103,233,227,239,240,244,233, 99, 128, 3,239,235,225,244,225,235,225,238, 97,128, 48,199,108, 2, 76,244, 77, 11,229,244,101, 2, 76,252, 77, 3,236,229,230,116, 128, 35, 43,242,233,231,232,116,128, 35, 38,244, 97,129, 3,180, 77, 18,244,245,242,238,229,100,128, 1,141,238,239,237,233,238, 225,244,239,242,237,233,238,245,243,239,238,229,238,245,237,229, 242,225,244,239,242,226,229,238,231,225,236,105,128, 9,248,250, 104,128, 2,164,104, 2, 77, 74, 77,124, 97, 3, 77, 82, 77, 92, 77, 99,226,229,238,231,225,236,105,128, 9,167,228,229,246, 97, 128, 9, 39,231,117, 2, 77,106, 77,115,234,225,242,225,244,105, 128, 10,167,242,237,245,235,232,105,128, 10, 39,239,239,107,128, 2, 87,105, 6, 77,144, 77,193, 77,253, 78, 8, 78, 19, 78, 29, 97, 2, 77,150, 77,172,236,249,244,233,235,225,244,239,238,239, 115,129, 3,133, 77,166,227,237, 98,128, 3, 68,237,239,238,100, 129, 38,102, 77,181,243,245,233,244,247,232,233,244,101,128, 38, 98,229,242,229,243,233,115,133, 0,168, 77,212, 77,220, 77,231, 77,237, 77,245,225,227,245,244,101,128,246,215,226,229,236,239, 247,227,237, 98,128, 3, 36,227,237, 98,128, 3, 8,231,242,225, 246,101,128,246,216,244,239,238,239,115,128, 3,133,232,233,242, 225,231,225,238, 97,128, 48, 98,235,225,244,225,235,225,238, 97, 128, 48,194,244,244,239,237,225,242,107,128, 48, 3,246,105, 2, 78, 36, 78, 47,228,101,129, 0,247, 78, 43,115,128, 34, 35,243, 233,239,238,243,236,225,243,104,128, 34, 21,234,229,227,249,242, 233,236,236,233, 99,128, 4, 82,235,243,232,225,228,101,128, 37, 147,108, 2, 78, 87, 78, 98,233,238,229,226,229,236,239,119,128, 30, 15,243,241,245,225,242,101,128, 51,151,109, 2, 78,113, 78, 121,225,227,242,239,110,128, 1, 17,239,238,239,243,240,225,227, 101,128,255, 68,238,226,236,239,227,107,128, 37,132,111, 10, 78, 163, 78,175, 78,185, 78,196, 78,207, 79, 23, 79, 28, 79, 39, 79, 154, 79,180,227,232,225,228,225,244,232,225,105,128, 14, 14,228, 229,235,244,232,225,105,128, 14, 20,232,233,242,225,231,225,238, 97,128, 48,105,235,225,244,225,235,225,238, 97,128, 48,201,236, 236,225,114,132, 0, 36, 78,222, 78,233, 78,245, 79, 0,233,238, 230,229,242,233,239,114,128,246,227,237,239,238,239,243,240,225, 227,101,128,255, 4,239,236,228,243,244,249,236,101,128,247, 36, 115, 2, 79, 6, 79, 13,237,225,236,108,128,254,105,245,240,229, 242,233,239,114,128,246,228,238,103,128, 32,171,242,245,243,241, 245,225,242,101,128, 51, 38,116, 6, 79, 53, 79, 70, 79, 92, 79, 103, 79,135, 79,142,225,227,227,229,238,116,129, 2,217, 79, 64, 227,237, 98,128, 3, 7,226,229,236,239,247, 99, 2, 79, 81, 79, 86,237, 98,128, 3, 35,239,237, 98,128, 3, 35,235,225,244,225, 235,225,238, 97,128, 48,251,236,229,243,115, 2, 79,112, 79,116, 105,128, 1, 49,106,129,246,190, 79,122,243,244,242,239,235,229, 232,239,239,107,128, 2,132,237,225,244,104,128, 34,197,244,229, 228,227,233,242,227,236,101,128, 37,204,245,226,236,229,249,239, 228,240,225,244,225,104,129,251, 31, 79,171,232,229,226,242,229, 119,128,251, 31,247,238,244,225,227,107, 2, 79,191, 79,202,226, 229,236,239,247,227,237, 98,128, 3, 30,237,239,100,128, 2,213, 240,225,242,229,110,128, 36,159,243,245,240,229,242,233,239,114, 128,246,235,116, 2, 79,233, 79,239,225,233,108,128, 2, 86,239, 240,226,225,114,128, 1,140,117, 2, 79,253, 80, 8,232,233,242, 225,231,225,238, 97,128, 48,101,235,225,244,225,235,225,238, 97, 128, 48,197,122,132, 1,243, 80, 31, 80, 40, 80, 59, 80, 96,225, 236,244,239,238,101,128, 2,163, 99, 2, 80, 46, 80, 53,225,242, 239,110,128, 1,198,245,242,108,128, 2,165,101, 2, 80, 65, 80, 85,225,226,235,232,225,243,233,225,238,227,249,242,233,236,236, 233, 99,128, 4,225,227,249,242,233,236,236,233, 99,128, 4, 85, 232,229,227,249,242,233,236,236,233, 99,128, 4, 95,101,151, 0, 101, 80,159, 80,178, 80,212, 81,186, 81,248, 82, 25, 82, 37, 82, 60, 82,113, 83,225, 84, 27, 84,129, 84,245, 85,124, 85,199, 85, 230, 86, 36, 86, 89, 87, 24, 87,157, 87,177, 87,221, 88, 56, 97, 2, 80,165, 80,172,227,245,244,101,128, 0,233,242,244,104,128, 38, 65, 98, 3, 80,186, 80,195, 80,205,229,238,231,225,236,105, 128, 9,143,239,240,239,237,239,230,111,128, 49, 28,242,229,246, 101,128, 1, 21, 99, 5, 80,224, 81, 41, 81, 55, 81, 87, 81,176, 97, 2, 80,230, 81, 35,238,228,242, 97, 3, 80,241, 80,248, 81, 3,228,229,246, 97,128, 9, 13,231,245,234,225,242,225,244,105, 128, 10,141,246,239,247,229,236,243,233,231,110, 2, 81, 17, 81, 24,228,229,246, 97,128, 9, 69,231,245,234,225,242,225,244,105, 128, 10,197,242,239,110,128, 1, 27,229,228,233,236,236,225,226, 242,229,246,101,128, 30, 29,104, 2, 81, 61, 81, 72,225,242,237, 229,238,233,225,110,128, 5,101,249,233,247,238,225,242,237,229, 238,233,225,110,128, 5,135,233,242, 99, 2, 81, 95, 81,100,236, 101,128, 36,212,245,237,230,236,229,120,134, 0,234, 81,121, 81, 129, 81,137, 81,148, 81,156, 81,168,225,227,245,244,101,128, 30, 191,226,229,236,239,119,128, 30, 25,228,239,244,226,229,236,239, 119,128, 30,199,231,242,225,246,101,128, 30,193,232,239,239,235, 225,226,239,246,101,128, 30,195,244,233,236,228,101,128, 30,197, 249,242,233,236,236,233, 99,128, 4, 84,100, 4, 81,196, 81,206, 81,212, 81,222,226,236,231,242,225,246,101,128, 2, 5,229,246, 97,128, 9, 15,233,229,242,229,243,233,115,128, 0,235,239,116, 130, 1, 23, 81,231, 81,240,225,227,227,229,238,116,128, 1, 23, 226,229,236,239,119,128, 30,185,101, 2, 81,254, 82, 9,231,245, 242,237,245,235,232,105,128, 10, 15,237,225,244,242,225,231,245, 242,237,245,235,232,105,128, 10, 71,230,227,249,242,233,236,236, 233, 99,128, 4, 68,103, 2, 82, 43, 82, 50,242,225,246,101,128, 0,232,245,234,225,242,225,244,105,128, 10,143,104, 4, 82, 70, 82, 81, 82, 92, 82,102,225,242,237,229,238,233,225,110,128, 5, 103,226,239,240,239,237,239,230,111,128, 49, 29,233,242,225,231, 225,238, 97,128, 48, 72,239,239,235,225,226,239,246,101,128, 30, 187,105, 4, 82,123, 82,134, 83,192, 83,207,226,239,240,239,237, 239,230,111,128, 49, 31,231,232,116,142, 0, 56, 82,168, 82,177, 82,187, 82,217, 82,224, 83, 6, 83, 31, 83, 76, 83,110, 83,122, 83,133, 83,166, 83,174, 83,185,225,242,225,226,233, 99,128, 6, 104,226,229,238,231,225,236,105,128, 9,238,227,233,242,227,236, 101,129, 36,103, 82,198,233,238,246,229,242,243,229,243,225,238, 243,243,229,242,233,102,128, 39,145,228,229,246, 97,128, 9,110, 229,229,110, 2, 82,232, 82,241,227,233,242,227,236,101,128, 36, 113,112, 2, 82,247, 82,254,225,242,229,110,128, 36,133,229,242, 233,239,100,128, 36,153,231,117, 2, 83, 13, 83, 22,234,225,242, 225,244,105,128, 10,238,242,237,245,235,232,105,128, 10,110,104, 2, 83, 37, 83, 63, 97, 2, 83, 43, 83, 54,227,235,225,242,225, 226,233, 99,128, 6,104,238,231,250,232,239,117,128, 48, 40,238, 239,244,229,226,229,225,237,229,100,128, 38,107,105, 2, 83, 82, 83,100,228,229,239,231,242,225,240,232,233,227,240,225,242,229, 110,128, 50, 39,238,230,229,242,233,239,114,128, 32,136,237,239, 238,239,243,240,225,227,101,128,255, 24,239,236,228,243,244,249, 236,101,128,247, 56,112, 2, 83,139, 83,146,225,242,229,110,128, 36,123,229,114, 2, 83,153, 83,159,233,239,100,128, 36,143,243, 233,225,110,128, 6,248,242,239,237,225,110,128, 33,119,243,245, 240,229,242,233,239,114,128, 32,120,244,232,225,105,128, 14, 88, 238,246,229,242,244,229,228,226,242,229,246,101,128, 2, 7,239, 244,233,230,233,229,228,227,249,242,233,236,236,233, 99,128, 4, 101,107, 2, 83,231, 83,255,225,244,225,235,225,238, 97,129, 48, 168, 83,243,232,225,236,230,247,233,228,244,104,128,255,116,111, 2, 84, 5, 84, 20,238,235,225,242,231,245,242,237,245,235,232, 105,128, 10,116,242,229,225,110,128, 49, 84,108, 3, 84, 35, 84, 46, 84,107,227,249,242,233,236,236,233, 99,128, 4, 59,101, 2, 84, 52, 84, 59,237,229,238,116,128, 34, 8,246,229,110, 3, 84, 69, 84, 78, 84, 99,227,233,242,227,236,101,128, 36,106,112, 2, 84, 84, 84, 91,225,242,229,110,128, 36,126,229,242,233,239,100, 128, 36,146,242,239,237,225,110,128, 33,122,236,233,240,243,233, 115,129, 32, 38, 84,118,246,229,242,244,233,227,225,108,128, 34, 238,109, 5, 84,141, 84,169, 84,180, 84,200, 84,211,225,227,242, 239,110,130, 1, 19, 84,153, 84,161,225,227,245,244,101,128, 30, 23,231,242,225,246,101,128, 30, 21,227,249,242,233,236,236,233, 99,128, 4, 60,228,225,243,104,129, 32, 20, 84,189,246,229,242, 244,233,227,225,108,128,254, 49,239,238,239,243,240,225,227,101, 128,255, 69,112, 2, 84,217, 84,237,232,225,243,233,243,237,225, 242,235,225,242,237,229,238,233,225,110,128, 5, 91,244,249,243, 229,116,128, 34, 5,110, 6, 85, 3, 85, 14, 85, 25, 85, 69, 85, 101, 85,116,226,239,240,239,237,239,230,111,128, 49, 35,227,249, 242,233,236,236,233, 99,128, 4, 61,100, 2, 85, 31, 85, 50,225, 243,104,129, 32, 19, 85, 39,246,229,242,244,233,227,225,108,128, 254, 50,229,243,227,229,238,228,229,242,227,249,242,233,236,236, 233, 99,128, 4,163,103,130, 1, 75, 85, 77, 85, 88,226,239,240, 239,237,239,230,111,128, 49, 37,232,229,227,249,242,233,236,236, 233, 99,128, 4,165,232,239,239,235,227,249,242,233,236,236,233, 99,128, 4,200,243,240,225,227,101,128, 32, 2,111, 3, 85,132, 85,140, 85,149,231,239,238,229,107,128, 1, 25,235,239,242,229, 225,110,128, 49, 83,240,229,110,130, 2, 91, 85,159, 85,168,227, 236,239,243,229,100,128, 2,154,242,229,246,229,242,243,229,100, 130, 2, 92, 85,183, 85,192,227,236,239,243,229,100,128, 2, 94, 232,239,239,107,128, 2, 93,112, 2, 85,205, 85,212,225,242,229, 110,128, 36,160,243,233,236,239,110,129, 3,181, 85,222,244,239, 238,239,115,128, 3,173,241,117, 2, 85,237, 86, 25,225,108,130, 0, 61, 85,246, 86, 2,237,239,238,239,243,240,225,227,101,128, 255, 29,115, 2, 86, 8, 86, 15,237,225,236,108,128,254,102,245, 240,229,242,233,239,114,128, 32,124,233,246,225,236,229,238,227, 101,128, 34, 97,114, 3, 86, 44, 86, 55, 86, 66,226,239,240,239, 237,239,230,111,128, 49, 38,227,249,242,233,236,236,233, 99,128, 4, 64,229,246,229,242,243,229,100,129, 2, 88, 86, 78,227,249, 242,233,236,236,233, 99,128, 4, 77,115, 6, 86,103, 86,114, 86, 134, 86,215, 87, 4, 87, 14,227,249,242,233,236,236,233, 99,128, 4, 65,228,229,243,227,229,238,228,229,242,227,249,242,233,236, 236,233, 99,128, 4,171,104,132, 2,131, 86,146, 86,153, 86,184, 86,199,227,245,242,108,128, 2,134,239,242,116, 2, 86,161, 86, 168,228,229,246, 97,128, 9, 14,246,239,247,229,236,243,233,231, 238,228,229,246, 97,128, 9, 70,242,229,246,229,242,243,229,228, 236,239,239,112,128, 1,170,243,241,245,225,244,242,229,246,229, 242,243,229,100,128, 2,133,237,225,236,108, 2, 86,224, 86,235, 232,233,242,225,231,225,238, 97,128, 48, 71,235,225,244,225,235, 225,238, 97,129, 48,167, 86,248,232,225,236,230,247,233,228,244, 104,128,255,106,244,233,237,225,244,229,100,128, 33, 46,245,240, 229,242,233,239,114,128,246,236,116, 5, 87, 36, 87, 62, 87, 66, 87, 83, 87,149, 97,130, 3,183, 87, 44, 87, 54,242,237,229,238, 233,225,110,128, 5,104,244,239,238,239,115,128, 3,174,104,128, 0,240,233,236,228,101,129, 30,189, 87, 75,226,229,236,239,119, 128, 30, 27,238,225,232,244, 97, 3, 87, 95, 87,127, 87,136,230, 239,245,235,104, 2, 87,105, 87,114,232,229,226,242,229,119,128, 5,145,236,229,230,244,232,229,226,242,229,119,128, 5,145,232, 229,226,242,229,119,128, 5,145,236,229,230,244,232,229,226,242, 229,119,128, 5,145,245,242,238,229,100,128, 1,221,117, 2, 87, 163, 87,172,235,239,242,229,225,110,128, 49, 97,242,111,128, 32, 172,246,239,247,229,236,243,233,231,110, 3, 87,193, 87,203, 87, 210,226,229,238,231,225,236,105,128, 9,199,228,229,246, 97,128, 9, 71,231,245,234,225,242,225,244,105,128, 10,199,120, 2, 87, 227, 88, 44,227,236,225,109,132, 0, 33, 87,242, 87,253, 88, 24, 88, 36,225,242,237,229,238,233,225,110,128, 5, 92,100, 2, 88, 3, 88, 8,226,108,128, 32, 60,239,247,110,129, 0,161, 88, 16, 243,237,225,236,108,128,247,161,237,239,238,239,243,240,225,227, 101,128,255, 1,243,237,225,236,108,128,247, 33,233,243,244,229, 238,244,233,225,108,128, 34, 3,250,104,131, 2,146, 88, 67, 88, 86, 88, 97, 99, 2, 88, 73, 88, 80,225,242,239,110,128, 1,239, 245,242,108,128, 2,147,242,229,246,229,242,243,229,100,128, 1, 185,244,225,233,108,128, 1,186,102,140, 0,102, 88,132, 88,214, 88,225, 88,234, 88,246, 89, 93, 89,109, 91,117, 91,130, 91,156, 93, 33, 93, 41, 97, 4, 88,142, 88,149, 88,160, 88,171,228,229, 246, 97,128, 9, 94,231,245,242,237,245,235,232,105,128, 10, 94, 232,242,229,238,232,229,233,116,128, 33, 9,244,232, 97, 3, 88, 181, 88,190, 88,202,225,242,225,226,233, 99,128, 6, 78,236,239, 247,225,242,225,226,233, 99,128, 6, 78,244,225,238,225,242,225, 226,233, 99,128, 6, 75,226,239,240,239,237,239,230,111,128, 49, 8,227,233,242,227,236,101,128, 36,213,228,239,244,225,227,227, 229,238,116,128, 30, 31,101, 3, 88,254, 89, 76, 89, 86,104, 4, 89, 8, 89, 31, 89, 45, 89, 61,225,114, 2, 89, 15, 89, 22,225, 226,233, 99,128, 6, 65,237,229,238,233,225,110,128, 5,134,230, 233,238,225,236,225,242,225,226,233, 99,128,254,210,233,238,233, 244,233,225,236,225,242,225,226,233, 99,128,254,211,237,229,228, 233,225,236,225,242,225,226,233, 99,128,254,212,233,227,239,240, 244,233, 99,128, 3,229,237,225,236,101,128, 38, 64,102,130,251, 0, 89,101, 89,105,105,128,251, 3,108,128,251, 4,105,136,251, 1, 89,129, 89,169, 89,180, 89,202, 90, 68, 90, 85, 90, 93, 90, 106,230,244,229,229,110, 2, 89,139, 89,148,227,233,242,227,236, 101,128, 36,110,112, 2, 89,154, 89,161,225,242,229,110,128, 36, 130,229,242,233,239,100,128, 36,150,231,245,242,229,228,225,243, 104,128, 32, 18,236,236,229,100, 2, 89,189, 89,195,226,239,120, 128, 37,160,242,229,227,116,128, 37,172,238,225,108, 5, 89,216, 89,255, 90, 16, 90, 33, 90, 49,235,225,102,130, 5,218, 89,226, 89,246,228,225,231,229,243,104,129,251, 58, 89,237,232,229,226, 242,229,119,128,251, 58,232,229,226,242,229,119,128, 5,218,237, 229,109,129, 5,221, 90, 7,232,229,226,242,229,119,128, 5,221, 238,245,110,129, 5,223, 90, 24,232,229,226,242,229,119,128, 5, 223,240,101,129, 5,227, 90, 40,232,229,226,242,229,119,128, 5, 227,244,243,225,228,105,129, 5,229, 90, 59,232,229,226,242,229, 119,128, 5,229,242,243,244,244,239,238,229,227,232,233,238,229, 243,101,128, 2,201,243,232,229,249,101,128, 37,201,244,225,227, 249,242,233,236,236,233, 99,128, 4,115,246,101,142, 0, 53, 90, 139, 90,148, 90,158, 90,188, 90,195, 90,205, 90,230, 91, 1, 91, 35, 91, 47, 91, 58, 91, 91, 91, 99, 91,110,225,242,225,226,233, 99,128, 6,101,226,229,238,231,225,236,105,128, 9,235,227,233, 242,227,236,101,129, 36,100, 90,169,233,238,246,229,242,243,229, 243,225,238,243,243,229,242,233,102,128, 39,142,228,229,246, 97, 128, 9,107,229,233,231,232,244,232,115,128, 33, 93,231,117, 2, 90,212, 90,221,234,225,242,225,244,105,128, 10,235,242,237,245, 235,232,105,128, 10,107,232, 97, 2, 90,237, 90,248,227,235,225, 242,225,226,233, 99,128, 6,101,238,231,250,232,239,117,128, 48, 37,105, 2, 91, 7, 91, 25,228,229,239,231,242,225,240,232,233, 227,240,225,242,229,110,128, 50, 36,238,230,229,242,233,239,114, 128, 32,133,237,239,238,239,243,240,225,227,101,128,255, 21,239, 236,228,243,244,249,236,101,128,247, 53,112, 2, 91, 64, 91, 71, 225,242,229,110,128, 36,120,229,114, 2, 91, 78, 91, 84,233,239, 100,128, 36,140,243,233,225,110,128, 6,245,242,239,237,225,110, 128, 33,116,243,245,240,229,242,233,239,114,128, 32,117,244,232, 225,105,128, 14, 85,108,129,251, 2, 91,123,239,242,233,110,128, 1,146,109, 2, 91,136, 91,147,239,238,239,243,240,225,227,101, 128,255, 70,243,241,245,225,242,101,128, 51,153,111, 4, 91,166, 91,188, 91,200, 91,207,230, 97, 2, 91,173, 91,181,238,244,232, 225,105,128, 14, 31,244,232,225,105,128, 14, 29,238,231,237,225, 238,244,232,225,105,128, 14, 79,242,225,236,108,128, 34, 0,245, 114,142, 0, 52, 91,240, 91,249, 92, 3, 92, 33, 92, 40, 92, 65, 92, 92, 92,126, 92,138, 92,157, 92,168, 92,201, 92,209, 92,220, 225,242,225,226,233, 99,128, 6,100,226,229,238,231,225,236,105, 128, 9,234,227,233,242,227,236,101,129, 36, 99, 92, 14,233,238, 246,229,242,243,229,243,225,238,243,243,229,242,233,102,128, 39, 141,228,229,246, 97,128, 9,106,231,117, 2, 92, 47, 92, 56,234, 225,242,225,244,105,128, 10,234,242,237,245,235,232,105,128, 10, 106,232, 97, 2, 92, 72, 92, 83,227,235,225,242,225,226,233, 99, 128, 6,100,238,231,250,232,239,117,128, 48, 36,105, 2, 92, 98, 92,116,228,229,239,231,242,225,240,232,233,227,240,225,242,229, 110,128, 50, 35,238,230,229,242,233,239,114,128, 32,132,237,239, 238,239,243,240,225,227,101,128,255, 20,238,245,237,229,242,225, 244,239,242,226,229,238,231,225,236,105,128, 9,247,239,236,228, 243,244,249,236,101,128,247, 52,112, 2, 92,174, 92,181,225,242, 229,110,128, 36,119,229,114, 2, 92,188, 92,194,233,239,100,128, 36,139,243,233,225,110,128, 6,244,242,239,237,225,110,128, 33, 115,243,245,240,229,242,233,239,114,128, 32,116,116, 2, 92,226, 93, 8,229,229,110, 2, 92,234, 92,243,227,233,242,227,236,101, 128, 36,109,112, 2, 92,249, 93, 0,225,242,229,110,128, 36,129, 229,242,233,239,100,128, 36,149,104, 2, 93, 14, 93, 19,225,105, 128, 14, 84,244,239,238,229,227,232,233,238,229,243,101,128, 2, 203,240,225,242,229,110,128, 36,161,242, 97, 2, 93, 48, 93, 56, 227,244,233,239,110,128, 32, 68,238, 99,128, 32,163,103,144, 0, 103, 93, 97, 94, 43, 94, 66, 94,127, 94,144, 95, 65, 96, 58, 96, 143, 96,156, 97, 14, 97, 39, 97, 67, 97, 89, 98, 34, 98, 56, 98, 158, 97, 9, 93,117, 93,127, 93,134, 93,141, 93,205, 93,230, 93, 241, 93,252, 94, 30,226,229,238,231,225,236,105,128, 9,151,227, 245,244,101,128, 1,245,228,229,246, 97,128, 9, 23,102, 4, 93, 151, 93,160, 93,174, 93,190,225,242,225,226,233, 99,128, 6,175, 230,233,238,225,236,225,242,225,226,233, 99,128,251,147,233,238, 233,244,233,225,236,225,242,225,226,233, 99,128,251,148,237,229, 228,233,225,236,225,242,225,226,233, 99,128,251,149,231,117, 2, 93,212, 93,221,234,225,242,225,244,105,128, 10,151,242,237,245, 235,232,105,128, 10, 23,232,233,242,225,231,225,238, 97,128, 48, 76,235,225,244,225,235,225,238, 97,128, 48,172,237,237, 97,130, 3,179, 94, 6, 94, 19,236,225,244,233,238,243,237,225,236,108, 128, 2, 99,243,245,240,229,242,233,239,114,128, 2,224,238,231, 233,225,227,239,240,244,233, 99,128, 3,235, 98, 2, 94, 49, 94, 59,239,240,239,237,239,230,111,128, 49, 13,242,229,246,101,128, 1, 31, 99, 4, 94, 76, 94, 83, 94, 92, 94,114,225,242,239,110, 128, 1,231,229,228,233,236,236, 97,128, 1, 35,233,242, 99, 2, 94,100, 94,105,236,101,128, 36,214,245,237,230,236,229,120,128, 1, 29,239,237,237,225,225,227,227,229,238,116,128, 1, 35,228, 239,116,129, 1, 33, 94,135,225,227,227,229,238,116,128, 1, 33, 101, 6, 94,158, 94,169, 94,180, 94,191, 94,210, 95, 56,227,249, 242,233,236,236,233, 99,128, 4, 51,232,233,242,225,231,225,238, 97,128, 48, 82,235,225,244,225,235,225,238, 97,128, 48,178,239, 237,229,244,242,233,227,225,236,236,249,229,241,245,225,108,128, 34, 81,114, 3, 94,218, 95, 11, 95, 21,229,243,104, 3, 94,228, 94,243, 94,252,225,227,227,229,238,244,232,229,226,242,229,119, 128, 5,156,232,229,226,242,229,119,128, 5,243,237,245,241,228, 225,237,232,229,226,242,229,119,128, 5,157,237,225,238,228,226, 236,115,128, 0,223,243,232,225,249,233,109, 2, 95, 32, 95, 47, 225,227,227,229,238,244,232,229,226,242,229,119,128, 5,158,232, 229,226,242,229,119,128, 5,244,244,225,237,225,242,107,128, 48, 19,104, 5, 95, 77, 95,210, 96, 17, 96, 42, 96, 48, 97, 4, 95, 87, 95, 97, 95,120, 95,145,226,229,238,231,225,236,105,128, 9, 152,100, 2, 95,103, 95,114,225,242,237,229,238,233,225,110,128, 5,114,229,246, 97,128, 9, 24,231,117, 2, 95,127, 95,136,234, 225,242,225,244,105,128, 10,152,242,237,245,235,232,105,128, 10, 24,233,110, 4, 95,156, 95,165, 95,179, 95,195,225,242,225,226, 233, 99,128, 6, 58,230,233,238,225,236,225,242,225,226,233, 99, 128,254,206,233,238,233,244,233,225,236,225,242,225,226,233, 99, 128,254,207,237,229,228,233,225,236,225,242,225,226,233, 99,128, 254,208,101, 3, 95,218, 95,239, 96, 0,237,233,228,228,236,229, 232,239,239,235,227,249,242,233,236,236,233, 99,128, 4,149,243, 244,242,239,235,229,227,249,242,233,236,236,233, 99,128, 4,147, 245,240,244,245,242,238,227,249,242,233,236,236,233, 99,128, 4, 145,232, 97, 2, 96, 24, 96, 31,228,229,246, 97,128, 9, 90,231, 245,242,237,245,235,232,105,128, 10, 90,239,239,107,128, 2, 96, 250,243,241,245,225,242,101,128, 51,147,105, 3, 96, 66, 96, 77, 96, 88,232,233,242,225,231,225,238, 97,128, 48, 78,235,225,244, 225,235,225,238, 97,128, 48,174,109, 2, 96, 94, 96,105,225,242, 237,229,238,233,225,110,128, 5, 99,229,108,130, 5,210, 96,114, 96,134,228,225,231,229,243,104,129,251, 50, 96,125,232,229,226, 242,229,119,128,251, 50,232,229,226,242,229,119,128, 5,210,234, 229,227,249,242,233,236,236,233, 99,128, 4, 83,236,239,244,244, 225,108, 2, 96,167, 96,184,233,238,246,229,242,244,229,228,243, 244,242,239,235,101,128, 1,190,243,244,239,112,132, 2,148, 96, 199, 96,210, 96,216, 96,248,233,238,246,229,242,244,229,100,128, 2,150,237,239,100,128, 2,192,242,229,246,229,242,243,229,100, 130, 2,149, 96,231, 96,237,237,239,100,128, 2,193,243,245,240, 229,242,233,239,114,128, 2,228,243,244,242,239,235,101,129, 2, 161, 97, 3,242,229,246,229,242,243,229,100,128, 2,162,109, 2, 97, 20, 97, 28,225,227,242,239,110,128, 30, 33,239,238,239,243, 240,225,227,101,128,255, 71,111, 2, 97, 45, 97, 56,232,233,242, 225,231,225,238, 97,128, 48, 84,235,225,244,225,235,225,238, 97, 128, 48,180,240, 97, 2, 97, 74, 97, 80,242,229,110,128, 36,162, 243,241,245,225,242,101,128, 51,172,114, 2, 97, 95, 97,192, 97, 2, 97,101, 97,109,228,233,229,238,116,128, 34, 7,246,101,134, 0, 96, 97,126, 97,137, 97,154, 97,161, 97,170, 97,182,226,229, 236,239,247,227,237, 98,128, 3, 22, 99, 2, 97,143, 97,148,237, 98,128, 3, 0,239,237, 98,128, 3, 0,228,229,246, 97,128, 9, 83,236,239,247,237,239,100,128, 2,206,237,239,238,239,243,240, 225,227,101,128,255, 64,244,239,238,229,227,237, 98,128, 3, 64, 229,225,244,229,114,132, 0, 62, 97,208, 97,227, 97,239, 98, 26, 229,241,245,225,108,129, 34,101, 97,218,239,242,236,229,243,115, 128, 34,219,237,239,238,239,243,240,225,227,101,128,255, 30,111, 2, 97,245, 98, 15,114, 2, 97,251, 98, 8,229,241,245,233,246, 225,236,229,238,116,128, 34,115,236,229,243,115,128, 34,119,246, 229,242,229,241,245,225,108,128, 34,103,243,237,225,236,108,128, 254,101,115, 2, 98, 40, 98, 48,227,242,233,240,116,128, 2, 97, 244,242,239,235,101,128, 1,229,117, 4, 98, 66, 98, 77, 98,134, 98,145,232,233,242,225,231,225,238, 97,128, 48, 80,233,108, 2, 98, 84, 98,109,236,229,237,239,116, 2, 98, 94, 98,101,236,229, 230,116,128, 0,171,242,233,231,232,116,128, 0,187,243,233,238, 231,108, 2, 98,119, 98,126,236,229,230,116,128, 32, 57,242,233, 231,232,116,128, 32, 58,235,225,244,225,235,225,238, 97,128, 48, 176,242,225,237,245,243,241,245,225,242,101,128, 51, 24,249,243, 241,245,225,242,101,128, 51,201,104,144, 0,104, 98,204,101, 90, 101,125,101,162,101,202,103, 90,103,110,104, 75,104, 87,104, 99, 105,167,105,175,105,186,105,195,106, 19,106, 23, 97, 13, 98,232, 99, 15, 99, 25, 99, 55, 99, 80, 99,158, 99,170, 99,195, 99,210, 99,239, 99,252,100, 54,100, 63, 97, 2, 98,238, 99, 1,226,235, 232,225,243,233,225,238,227,249,242,233,236,236,233, 99,128, 4, 169,236,244,239,238,229,225,242,225,226,233, 99,128, 6,193,226, 229,238,231,225,236,105,128, 9,185,228,101, 2, 99, 32, 99, 50, 243,227,229,238,228,229,242,227,249,242,233,236,236,233, 99,128, 4,179,246, 97,128, 9, 57,231,117, 2, 99, 62, 99, 71,234,225, 242,225,244,105,128, 10,185,242,237,245,235,232,105,128, 10, 57, 104, 4, 99, 90, 99, 99, 99,113, 99,143,225,242,225,226,233, 99, 128, 6, 45,230,233,238,225,236,225,242,225,226,233, 99,128,254, 162,105, 2, 99,119, 99,134,238,233,244,233,225,236,225,242,225, 226,233, 99,128,254,163,242,225,231,225,238, 97,128, 48,111,237, 229,228,233,225,236,225,242,225,226,233, 99,128,254,164,233,244, 245,243,241,245,225,242,101,128, 51, 42,235,225,244,225,235,225, 238, 97,129, 48,207, 99,183,232,225,236,230,247,233,228,244,104, 128,255,138,236,225,238,244,231,245,242,237,245,235,232,105,128, 10, 77,237,250, 97, 2, 99,218, 99,227,225,242,225,226,233, 99, 128, 6, 33,236,239,247,225,242,225,226,233, 99,128, 6, 33,238, 231,245,236,230,233,236,236,229,114,128, 49,100,114, 2,100, 2, 100, 18,228,243,233,231,238,227,249,242,233,236,236,233, 99,128, 4, 74,240,239,239,110, 2,100, 27,100, 40,236,229,230,244,226, 225,242,226,245,112,128, 33,188,242,233,231,232,244,226,225,242, 226,245,112,128, 33,192,243,241,245,225,242,101,128, 51,202,244, 225,102, 3,100, 73,100,165,101, 0,240,225,244,225,104,134, 5, 178,100, 93,100, 98,100,112,100,121,100,136,100,152,177, 54,128, 5,178, 50, 2,100,104,100,108, 51,128, 5,178,102,128, 5,178, 232,229,226,242,229,119,128, 5,178,238,225,242,242,239,247,232, 229,226,242,229,119,128, 5,178,241,245,225,242,244,229,242,232, 229,226,242,229,119,128, 5,178,247,233,228,229,232,229,226,242, 229,119,128, 5,178,241,225,237,225,244,115,135, 5,179,100,188, 100,193,100,198,100,203,100,212,100,227,100,243,177, 98,128, 5, 179,178, 56,128, 5,179,179, 52,128, 5,179,232,229,226,242,229, 119,128, 5,179,238,225,242,242,239,247,232,229,226,242,229,119, 128, 5,179,241,245,225,242,244,229,242,232,229,226,242,229,119, 128, 5,179,247,233,228,229,232,229,226,242,229,119,128, 5,179, 243,229,231,239,108,135, 5,177,101, 22,101, 27,101, 32,101, 37, 101, 46,101, 61,101, 77,177, 55,128, 5,177,178, 52,128, 5,177, 179, 48,128, 5,177,232,229,226,242,229,119,128, 5,177,238,225, 242,242,239,247,232,229,226,242,229,119,128, 5,177,241,245,225, 242,244,229,242,232,229,226,242,229,119,128, 5,177,247,233,228, 229,232,229,226,242,229,119,128, 5,177, 98, 3,101, 98,101,103, 101,113,225,114,128, 1, 39,239,240,239,237,239,230,111,128, 49, 15,242,229,246,229,226,229,236,239,119,128, 30, 43, 99, 2,101, 131,101,140,229,228,233,236,236, 97,128, 30, 41,233,242, 99, 2, 101,148,101,153,236,101,128, 36,215,245,237,230,236,229,120,128, 1, 37,100, 2,101,168,101,178,233,229,242,229,243,233,115,128, 30, 39,239,116, 2,101,185,101,194,225,227,227,229,238,116,128, 30, 35,226,229,236,239,119,128, 30, 37,101,136, 5,212,101,222, 101,255,102, 19,102,248,103, 8,103, 53,103, 62,103, 75,225,242, 116,129, 38,101,101,230,243,245,233,116, 2,101,239,101,247,226, 236,225,227,107,128, 38,101,247,232,233,244,101,128, 38, 97,228, 225,231,229,243,104,129,251, 52,102, 10,232,229,226,242,229,119, 128,251, 52,104, 6,102, 33,102, 61,102, 69,102,119,102,165,102, 214, 97, 2,102, 39,102, 53,236,244,239,238,229,225,242,225,226, 233, 99,128, 6,193,242,225,226,233, 99,128, 6, 71,229,226,242, 229,119,128, 5,212,230,233,238,225,236, 97, 2,102, 80,102,111, 236,116, 2,102, 87,102, 99,239,238,229,225,242,225,226,233, 99, 128,251,167,244,247,239,225,242,225,226,233, 99,128,254,234,242, 225,226,233, 99,128,254,234,232,225,237,250,225,225,226,239,246, 101, 2,102,134,102,148,230,233,238,225,236,225,242,225,226,233, 99,128,251,165,233,243,239,236,225,244,229,228,225,242,225,226, 233, 99,128,251,164,105, 2,102,171,102,205,238,233,244,233,225, 236, 97, 2,102,183,102,197,236,244,239,238,229,225,242,225,226, 233, 99,128,251,168,242,225,226,233, 99,128,254,235,242,225,231, 225,238, 97,128, 48,120,237,229,228,233,225,236, 97, 2,102,226, 102,240,236,244,239,238,229,225,242,225,226,233, 99,128,251,169, 242,225,226,233, 99,128,254,236,233,243,229,233,229,242,225,243, 241,245,225,242,101,128, 51,123,107, 2,103, 14,103, 38,225,244, 225,235,225,238, 97,129, 48,216,103, 26,232,225,236,230,247,233, 228,244,104,128,255,141,245,244,225,225,242,245,243,241,245,225, 242,101,128, 51, 54,238,231,232,239,239,107,128, 2,103,242,245, 244,245,243,241,245,225,242,101,128, 51, 57,116,129, 5,215,103, 81,232,229,226,242,229,119,128, 5,215,232,239,239,107,129, 2, 102,103, 99,243,245,240,229,242,233,239,114,128, 2,177,105, 4, 103,120,103,205,103,216,103,241,229,245,104, 4,103,132,103,167, 103,182,103,191, 97, 2,103,138,103,153,227,233,242,227,236,229, 235,239,242,229,225,110,128, 50,123,240,225,242,229,238,235,239, 242,229,225,110,128, 50, 27,227,233,242,227,236,229,235,239,242, 229,225,110,128, 50,109,235,239,242,229,225,110,128, 49, 78,240, 225,242,229,238,235,239,242,229,225,110,128, 50, 13,232,233,242, 225,231,225,238, 97,128, 48,114,235,225,244,225,235,225,238, 97, 129, 48,210,103,229,232,225,236,230,247,233,228,244,104,128,255, 139,242,233,113,134, 5,180,104, 3,104, 8,104, 22,104, 31,104, 46,104, 62,177, 52,128, 5,180, 50, 2,104, 14,104, 18, 49,128, 5,180,100,128, 5,180,232,229,226,242,229,119,128, 5,180,238, 225,242,242,239,247,232,229,226,242,229,119,128, 5,180,241,245, 225,242,244,229,242,232,229,226,242,229,119,128, 5,180,247,233, 228,229,232,229,226,242,229,119,128, 5,180,236,233,238,229,226, 229,236,239,119,128, 30,150,237,239,238,239,243,240,225,227,101, 128,255, 72,111, 9,104,119,104,130,104,154,104,179,105, 11,105, 24,105,110,105,150,105,161,225,242,237,229,238,233,225,110,128, 5,112,232,105, 2,104,137,104,145,240,244,232,225,105,128, 14, 43,242,225,231,225,238, 97,128, 48,123,235,225,244,225,235,225, 238, 97,129, 48,219,104,167,232,225,236,230,247,233,228,244,104, 128,255,142,236,225,109,135, 5,185,104,199,104,204,104,209,104, 214,104,223,104,238,104,254,177, 57,128, 5,185,178, 54,128, 5, 185,179, 50,128, 5,185,232,229,226,242,229,119,128, 5,185,238, 225,242,242,239,247,232,229,226,242,229,119,128, 5,185,241,245, 225,242,244,229,242,232,229,226,242,229,119,128, 5,185,247,233, 228,229,232,229,226,242,229,119,128, 5,185,238,239,235,232,245, 235,244,232,225,105,128, 14, 46,111, 2,105, 30,105,100,107, 4, 105, 40,105, 52,105, 58,105, 80,225,226,239,246,229,227,239,237, 98,128, 3, 9,227,237, 98,128, 3, 9,240,225,236,225,244,225, 236,233,250,229,228,226,229,236,239,247,227,237, 98,128, 3, 33, 242,229,244,242,239,230,236,229,248,226,229,236,239,247,227,237, 98,128, 3, 34,238,243,241,245,225,242,101,128, 51, 66,114, 2, 105,116,105,143,105, 2,105,122,105,131,227,239,240,244,233, 99, 128, 3,233,250,239,238,244,225,236,226,225,114,128, 32, 21,238, 227,237, 98,128, 3, 27,244,243,240,242,233,238,231,115,128, 38, 104,245,243,101,128, 35, 2,240,225,242,229,110,128, 36,163,243, 245,240,229,242,233,239,114,128, 2,176,244,245,242,238,229,100, 128, 2,101,117, 4,105,205,105,216,105,229,105,254,232,233,242, 225,231,225,238, 97,128, 48,117,233,233,244,239,243,241,245,225, 242,101,128, 51, 51,235,225,244,225,235,225,238, 97,129, 48,213, 105,242,232,225,236,230,247,233,228,244,104,128,255,140,238,231, 225,242,245,237,236,225,245,116,129, 2,221,106, 13,227,237, 98, 128, 3, 11,118,128, 1,149,249,240,232,229,110,132, 0, 45,106, 39,106, 50,106, 62,106, 85,233,238,230,229,242,233,239,114,128, 246,229,237,239,238,239,243,240,225,227,101,128,255, 13,115, 2, 106, 68,106, 75,237,225,236,108,128,254, 99,245,240,229,242,233, 239,114,128,246,230,244,247,111,128, 32, 16,105,149, 0,105,106, 137,106,160,106,194,106,241,110,123,110,243,111, 24,111, 51,111, 213,111,217,111,255,112, 21,112,105,113, 14,113, 89,113, 97,113, 110,113,197,113,254,114, 26,114, 70,225, 99, 2,106,144,106,150, 245,244,101,128, 0,237,249,242,233,236,236,233, 99,128, 4, 79, 98, 3,106,168,106,177,106,187,229,238,231,225,236,105,128, 9, 135,239,240,239,237,239,230,111,128, 49, 39,242,229,246,101,128, 1, 45, 99, 3,106,202,106,209,106,231,225,242,239,110,128, 1, 208,233,242, 99, 2,106,217,106,222,236,101,128, 36,216,245,237, 230,236,229,120,128, 0,238,249,242,233,236,236,233, 99,128, 4, 86,100, 4,106,251,107, 5,110, 80,110,113,226,236,231,242,225, 246,101,128, 2, 9,101, 2,107, 11,110, 75,239,231,242,225,240, 104, 7,107, 32,107, 46,107, 59,109,244,110, 19,110, 32,110, 44, 229,225,242,244,232,227,233,242,227,236,101,128, 50,143,230,233, 242,229,227,233,242,227,236,101,128, 50,139,233, 99, 14,107, 90, 107,106,107,205,108, 3,108, 69,108, 98,108,114,108,171,108,220, 108,232,109, 3,109, 70,109,208,109,237,225,236,236,233,225,238, 227,229,240,225,242,229,110,128, 50, 63, 99, 4,107,116,107,127, 107,141,107,148,225,236,236,240,225,242,229,110,128, 50, 58,229, 238,244,242,229,227,233,242,227,236,101,128, 50,165,236,239,243, 101,128, 48, 6,111, 3,107,156,107,171,107,191,237,237, 97,129, 48, 1,107,164,236,229,230,116,128,255,100,238,231,242,225,244, 245,236,225,244,233,239,238,240,225,242,229,110,128, 50, 55,242, 242,229,227,244,227,233,242,227,236,101,128, 50,163,101, 3,107, 213,107,225,107,242,225,242,244,232,240,225,242,229,110,128, 50, 47,238,244,229,242,240,242,233,243,229,240,225,242,229,110,128, 50, 61,248,227,229,236,236,229,238,244,227,233,242,227,236,101, 128, 50,157,102, 2,108, 9,108, 24,229,243,244,233,246,225,236, 240,225,242,229,110,128, 50, 64,105, 2,108, 30,108, 59,238,225, 238,227,233,225,108, 2,108, 42,108, 51,227,233,242,227,236,101, 128, 50,150,240,225,242,229,110,128, 50, 54,242,229,240,225,242, 229,110,128, 50, 43,104, 2,108, 75,108, 86,225,246,229,240,225, 242,229,110,128, 50, 50,233,231,232,227,233,242,227,236,101,128, 50,164,233,244,229,242,225,244,233,239,238,237,225,242,107,128, 48, 5,108, 3,108,122,108,148,108,160,225,226,239,114, 2,108, 131,108,140,227,233,242,227,236,101,128, 50,152,240,225,242,229, 110,128, 50, 56,229,230,244,227,233,242,227,236,101,128, 50,167, 239,247,227,233,242,227,236,101,128, 50,166,109, 2,108,177,108, 209,101, 2,108,183,108,198,228,233,227,233,238,229,227,233,242, 227,236,101,128, 50,169,244,225,236,240,225,242,229,110,128, 50, 46,239,239,238,240,225,242,229,110,128, 50, 42,238,225,237,229, 240,225,242,229,110,128, 50, 52,112, 2,108,238,108,246,229,242, 233,239,100,128, 48, 2,242,233,238,244,227,233,242,227,236,101, 128, 50,158,114, 2,109, 9,109, 57,101, 3,109, 17,109, 28,109, 43,225,227,232,240,225,242,229,110,128, 50, 67,240,242,229,243, 229,238,244,240,225,242,229,110,128, 50, 57,243,239,245,242,227, 229,240,225,242,229,110,128, 50, 62,233,231,232,244,227,233,242, 227,236,101,128, 50,168,115, 5,109, 82,109,111,109,125,109,150, 109,178,101, 2,109, 88,109,101,227,242,229,244,227,233,242,227, 236,101,128, 50,153,236,230,240,225,242,229,110,128, 50, 66,239, 227,233,229,244,249,240,225,242,229,110,128, 50, 51,112, 2,109, 131,109,137,225,227,101,128, 48, 0,229,227,233,225,236,240,225, 242,229,110,128, 50, 53,116, 2,109,156,109,167,239,227,235,240, 225,242,229,110,128, 50, 49,245,228,249,240,225,242,229,110,128, 50, 59,117, 2,109,184,109,193,238,240,225,242,229,110,128, 50, 48,240,229,242,246,233,243,229,240,225,242,229,110,128, 50, 60, 119, 2,109,214,109,226,225,244,229,242,240,225,242,229,110,128, 50, 44,239,239,228,240,225,242,229,110,128, 50, 45,250,229,242, 111,128, 48, 7,109, 2,109,250,110, 7,229,244,225,236,227,233, 242,227,236,101,128, 50,142,239,239,238,227,233,242,227,236,101, 128, 50,138,238,225,237,229,227,233,242,227,236,101,128, 50,148, 243,245,238,227,233,242,227,236,101,128, 50,144,119, 2,110, 50, 110, 63,225,244,229,242,227,233,242,227,236,101,128, 50,140,239, 239,228,227,233,242,227,236,101,128, 50,141,246, 97,128, 9, 7, 233,229,242,229,243,233,115,130, 0,239,110, 94,110,102,225,227, 245,244,101,128, 30, 47,227,249,242,233,236,236,233, 99,128, 4, 229,239,244,226,229,236,239,119,128, 30,203,101, 3,110,131,110, 147,110,158,226,242,229,246,229,227,249,242,233,236,236,233, 99, 128, 4,215,227,249,242,233,236,236,233, 99,128, 4, 53,245,238, 103, 4,110,170,110,205,110,220,110,229, 97, 2,110,176,110,191, 227,233,242,227,236,229,235,239,242,229,225,110,128, 50,117,240, 225,242,229,238,235,239,242,229,225,110,128, 50, 21,227,233,242, 227,236,229,235,239,242,229,225,110,128, 50,103,235,239,242,229, 225,110,128, 49, 71,240,225,242,229,238,235,239,242,229,225,110, 128, 50, 7,103, 2,110,249,111, 0,242,225,246,101,128, 0,236, 117, 2,111, 6,111, 15,234,225,242,225,244,105,128, 10,135,242, 237,245,235,232,105,128, 10, 7,104, 2,111, 30,111, 40,233,242, 225,231,225,238, 97,128, 48, 68,239,239,235,225,226,239,246,101, 128, 30,201,105, 8,111, 69,111, 79,111, 90,111, 97,111,122,111, 138,111,153,111,169,226,229,238,231,225,236,105,128, 9,136,227, 249,242,233,236,236,233, 99,128, 4, 56,228,229,246, 97,128, 9, 8,231,117, 2,111,104,111,113,234,225,242,225,244,105,128, 10, 136,242,237,245,235,232,105,128, 10, 8,237,225,244,242,225,231, 245,242,237,245,235,232,105,128, 10, 64,238,246,229,242,244,229, 228,226,242,229,246,101,128, 2, 11,243,232,239,242,244,227,249, 242,233,236,236,233, 99,128, 4, 57,246,239,247,229,236,243,233, 231,110, 3,111,185,111,195,111,202,226,229,238,231,225,236,105, 128, 9,192,228,229,246, 97,128, 9, 64,231,245,234,225,242,225, 244,105,128, 10,192,106,128, 1, 51,107, 2,111,223,111,247,225, 244,225,235,225,238, 97,129, 48,164,111,235,232,225,236,230,247, 233,228,244,104,128,255,114,239,242,229,225,110,128, 49, 99,108, 2,112, 5,112, 10,228,101,128, 2,220,245,249,232,229,226,242, 229,119,128, 5,172,109, 2,112, 27,112, 94, 97, 3,112, 35,112, 55,112, 80,227,242,239,110,129, 1, 43,112, 44,227,249,242,233, 236,236,233, 99,128, 4,227,231,229,239,242,225,240,240,242,239, 248,233,237,225,244,229,236,249,229,241,245,225,108,128, 34, 83, 244,242,225,231,245,242,237,245,235,232,105,128, 10, 63,239,238, 239,243,240,225,227,101,128,255, 73,110, 5,112,117,112,127,112, 136,112,148,112,232,227,242,229,237,229,238,116,128, 34, 6,230, 233,238,233,244,121,128, 34, 30,233,225,242,237,229,238,233,225, 110,128, 5,107,116, 2,112,154,112,222,101, 2,112,160,112,211, 231,242,225,108,131, 34, 43,112,173,112,191,112,196, 98, 2,112, 179,112,187,239,244,244,239,109,128, 35, 33,116,128, 35, 33,229, 120,128,248,245,116, 2,112,202,112,207,239,112,128, 35, 32,112, 128, 35, 32,242,243,229,227,244,233,239,110,128, 34, 41,233,243, 241,245,225,242,101,128, 51, 5,118, 3,112,240,112,249,113, 2, 226,245,236,236,229,116,128, 37,216,227,233,242,227,236,101,128, 37,217,243,237,233,236,229,230,225,227,101,128, 38, 59,111, 3, 113, 22,113, 33,113, 41,227,249,242,233,236,236,233, 99,128, 4, 81,231,239,238,229,107,128, 1, 47,244, 97,131, 3,185,113, 52, 113, 73,113, 81,228,233,229,242,229,243,233,115,129, 3,202,113, 65,244,239,238,239,115,128, 3,144,236,225,244,233,110,128, 2, 105,244,239,238,239,115,128, 3,175,240,225,242,229,110,128, 36, 164,242,233,231,245,242,237,245,235,232,105,128, 10,114,115, 4, 113,120,113,165,113,179,113,187,237,225,236,108, 2,113,129,113, 140,232,233,242,225,231,225,238, 97,128, 48, 67,235,225,244,225, 235,225,238, 97,129, 48,163,113,153,232,225,236,230,247,233,228, 244,104,128,255,104,243,232,225,242,226,229,238,231,225,236,105, 128, 9,250,244,242,239,235,101,128, 2,104,245,240,229,242,233, 239,114,128,246,237,116, 2,113,203,113,237,229,242,225,244,233, 239,110, 2,113,215,113,226,232,233,242,225,231,225,238, 97,128, 48,157,235,225,244,225,235,225,238, 97,128, 48,253,233,236,228, 101,129, 1, 41,113,246,226,229,236,239,119,128, 30, 45,117, 2, 114, 4,114, 15,226,239,240,239,237,239,230,111,128, 49, 41,227, 249,242,233,236,236,233, 99,128, 4, 78,246,239,247,229,236,243, 233,231,110, 3,114, 42,114, 52,114, 59,226,229,238,231,225,236, 105,128, 9,191,228,229,246, 97,128, 9, 63,231,245,234,225,242, 225,244,105,128, 10,191,250,232,233,244,243, 97, 2,114, 81,114, 92,227,249,242,233,236,236,233, 99,128, 4,117,228,226,236,231, 242,225,246,229,227,249,242,233,236,236,233, 99,128, 4,119,106, 138, 0,106,114,135,114,198,114,209,115, 3,115, 19,115,132,115, 201,115,206,115,218,115,226, 97, 4,114,145,114,156,114,166,114, 173,225,242,237,229,238,233,225,110,128, 5,113,226,229,238,231, 225,236,105,128, 9,156,228,229,246, 97,128, 9, 28,231,117, 2, 114,180,114,189,234,225,242,225,244,105,128, 10,156,242,237,245, 235,232,105,128, 10, 28,226,239,240,239,237,239,230,111,128, 49, 16, 99, 3,114,217,114,224,114,246,225,242,239,110,128, 1,240, 233,242, 99, 2,114,232,114,237,236,101,128, 36,217,245,237,230, 236,229,120,128, 1, 53,242,239,243,243,229,228,244,225,233,108, 128, 2,157,228,239,244,236,229,243,243,243,244,242,239,235,101, 128, 2, 95,101, 3,115, 27,115, 38,115,103,227,249,242,233,236, 236,233, 99,128, 4, 88,229,109, 4,115, 49,115, 58,115, 72,115, 88,225,242,225,226,233, 99,128, 6, 44,230,233,238,225,236,225, 242,225,226,233, 99,128,254,158,233,238,233,244,233,225,236,225, 242,225,226,233, 99,128,254,159,237,229,228,233,225,236,225,242, 225,226,233, 99,128,254,160,104, 2,115,109,115,118,225,242,225, 226,233, 99,128, 6,152,230,233,238,225,236,225,242,225,226,233, 99,128,251,139,104, 2,115,138,115,188, 97, 3,115,146,115,156, 115,163,226,229,238,231,225,236,105,128, 9,157,228,229,246, 97, 128, 9, 29,231,117, 2,115,170,115,179,234,225,242,225,244,105, 128, 10,157,242,237,245,235,232,105,128, 10, 29,229,232,225,242, 237,229,238,233,225,110,128, 5,123,233,115,128, 48, 4,237,239, 238,239,243,240,225,227,101,128,255, 74,240,225,242,229,110,128, 36,165,243,245,240,229,242,233,239,114,128, 2,178,107,146, 0, 107,116, 21,118,110,118,121,118,183,118,194,119, 28,119, 42,120, 150,121, 90,121,103,121,129,121,178,122, 60,122, 82,122, 95,122, 118,122,160,122,170, 97, 12,116, 47,116, 79,116,101,116,131,116, 245,117, 14,117, 44,117, 69,117,175,117,189,118, 56,118, 85, 98, 2,116, 53,116, 70,225,243,232,235,233,242,227,249,242,233,236, 236,233, 99,128, 4,161,229,238,231,225,236,105,128, 9,149, 99, 2,116, 85,116, 91,245,244,101,128, 30, 49,249,242,233,236,236, 233, 99,128, 4, 58,228,101, 2,116,108,116,126,243,227,229,238, 228,229,242,227,249,242,233,236,236,233, 99,128, 4,155,246, 97, 128, 9, 21,102,135, 5,219,116,149,116,158,116,178,116,192,116, 201,116,217,116,232,225,242,225,226,233, 99,128, 6, 67,228,225, 231,229,243,104,129,251, 59,116,169,232,229,226,242,229,119,128, 251, 59,230,233,238,225,236,225,242,225,226,233, 99,128,254,218, 232,229,226,242,229,119,128, 5,219,233,238,233,244,233,225,236, 225,242,225,226,233, 99,128,254,219,237,229,228,233,225,236,225, 242,225,226,233, 99,128,254,220,242,225,230,229,232,229,226,242, 229,119,128,251, 77,231,117, 2,116,252,117, 5,234,225,242,225, 244,105,128, 10,149,242,237,245,235,232,105,128, 10, 21,104, 2, 117, 20,117, 30,233,242,225,231,225,238, 97,128, 48, 75,239,239, 235,227,249,242,233,236,236,233, 99,128, 4,196,235,225,244,225, 235,225,238, 97,129, 48,171,117, 57,232,225,236,230,247,233,228, 244,104,128,255,118,112, 2,117, 75,117, 96,240, 97,129, 3,186, 117, 82,243,249,237,226,239,236,231,242,229,229,107,128, 3,240, 249,229,239,245,110, 3,117,108,117,122,117,156,237,233,229,245, 237,235,239,242,229,225,110,128, 49,113,112, 2,117,128,117,143, 232,233,229,245,240,232,235,239,242,229,225,110,128, 49,132,233, 229,245,240,235,239,242,229,225,110,128, 49,120,243,243,225,238, 231,240,233,229,245,240,235,239,242,229,225,110,128, 49,121,242, 239,242,233,233,243,241,245,225,242,101,128, 51, 13,115, 5,117, 201,117,245,118, 4,118, 12,118, 40,232,233,228,225,225,245,244, 111, 2,117,214,117,223,225,242,225,226,233, 99,128, 6, 64,238, 239,243,233,228,229,226,229,225,242,233,238,231,225,242,225,226, 233, 99,128, 6, 64,237,225,236,236,235,225,244,225,235,225,238, 97,128, 48,245,241,245,225,242,101,128, 51,132,242, 97, 2,118, 19,118, 28,225,242,225,226,233, 99,128, 6, 80,244,225,238,225, 242,225,226,233, 99,128, 6, 77,244,242,239,235,229,227,249,242, 233,236,236,233, 99,128, 4,159,244,225,232,233,242,225,240,242, 239,236,239,238,231,237,225,242,235,232,225,236,230,247,233,228, 244,104,128,255,112,246,229,242,244,233,227,225,236,243,244,242, 239,235,229,227,249,242,233,236,236,233, 99,128, 4,157,226,239, 240,239,237,239,230,111,128, 49, 14, 99, 4,118,131,118,153,118, 162,118,170, 97, 2,118,137,118,147,236,243,241,245,225,242,101, 128, 51,137,242,239,110,128, 1,233,229,228,233,236,236, 97,128, 1, 55,233,242,227,236,101,128, 36,218,239,237,237,225,225,227, 227,229,238,116,128, 1, 55,228,239,244,226,229,236,239,119,128, 30, 51,101, 4,118,204,118,231,119, 0,119, 12,104, 2,118,210, 118,221,225,242,237,229,238,233,225,110,128, 5,132,233,242,225, 231,225,238, 97,128, 48, 81,235,225,244,225,235,225,238, 97,129, 48,177,118,244,232,225,236,230,247,233,228,244,104,128,255,121, 238,225,242,237,229,238,233,225,110,128, 5,111,243,237,225,236, 236,235,225,244,225,235,225,238, 97,128, 48,246,231,242,229,229, 238,236,225,238,228,233, 99,128, 1, 56,104, 6,119, 56,119,185, 119,196,119,221,120, 52,120,140, 97, 5,119, 68,119, 78,119, 89, 119, 96,119,121,226,229,238,231,225,236,105,128, 9,150,227,249, 242,233,236,236,233, 99,128, 4, 69,228,229,246, 97,128, 9, 22, 231,117, 2,119,103,119,112,234,225,242,225,244,105,128, 10,150, 242,237,245,235,232,105,128, 10, 22,104, 4,119,131,119,140,119, 154,119,170,225,242,225,226,233, 99,128, 6, 46,230,233,238,225, 236,225,242,225,226,233, 99,128,254,166,233,238,233,244,233,225, 236,225,242,225,226,233, 99,128,254,167,237,229,228,233,225,236, 225,242,225,226,233, 99,128,254,168,229,233,227,239,240,244,233, 99,128, 3,231,232, 97, 2,119,203,119,210,228,229,246, 97,128, 9, 89,231,245,242,237,245,235,232,105,128, 10, 89,233,229,245, 235,104, 4,119,235,120, 14,120, 29,120, 38, 97, 2,119,241,120, 0,227,233,242,227,236,229,235,239,242,229,225,110,128, 50,120, 240,225,242,229,238,235,239,242,229,225,110,128, 50, 24,227,233, 242,227,236,229,235,239,242,229,225,110,128, 50,106,235,239,242, 229,225,110,128, 49, 75,240,225,242,229,238,235,239,242,229,225, 110,128, 50, 10,111, 4,120, 62,120,111,120,121,120,126,235,104, 4,120, 73,120, 82,120, 91,120,101,225,233,244,232,225,105,128, 14, 2,239,238,244,232,225,105,128, 14, 5,245,225,244,244,232, 225,105,128, 14, 3,247,225,233,244,232,225,105,128, 14, 4,237, 245,244,244,232,225,105,128, 14, 91,239,107,128, 1,153,242,225, 235,232,225,238,231,244,232,225,105,128, 14, 6,250,243,241,245, 225,242,101,128, 51,145,105, 4,120,160,120,171,120,196,120,245, 232,233,242,225,231,225,238, 97,128, 48, 77,235,225,244,225,235, 225,238, 97,129, 48,173,120,184,232,225,236,230,247,233,228,244, 104,128,255,119,242,111, 3,120,205,120,220,120,236,231,245,242, 225,237,245,243,241,245,225,242,101,128, 51, 21,237,229,229,244, 239,242,245,243,241,245,225,242,101,128, 51, 22,243,241,245,225, 242,101,128, 51, 20,249,229,239,107, 5,121, 4,121, 39,121, 54, 121, 63,121, 77, 97, 2,121, 10,121, 25,227,233,242,227,236,229, 235,239,242,229,225,110,128, 50,110,240,225,242,229,238,235,239, 242,229,225,110,128, 50, 14,227,233,242,227,236,229,235,239,242, 229,225,110,128, 50, 96,235,239,242,229,225,110,128, 49, 49,240, 225,242,229,238,235,239,242,229,225,110,128, 50, 0,243,233,239, 243,235,239,242,229,225,110,128, 49, 51,234,229,227,249,242,233, 236,236,233, 99,128, 4, 92,108, 2,121,109,121,120,233,238,229, 226,229,236,239,119,128, 30, 53,243,241,245,225,242,101,128, 51, 152,109, 3,121,137,121,151,121,162,227,245,226,229,228,243,241, 245,225,242,101,128, 51,166,239,238,239,243,240,225,227,101,128, 255, 75,243,241,245,225,242,229,228,243,241,245,225,242,101,128, 51,162,111, 5,121,190,121,216,121,254,122, 10,122, 24,104, 2, 121,196,121,206,233,242,225,231,225,238, 97,128, 48, 83,237,243, 241,245,225,242,101,128, 51,192,235, 97, 2,121,223,121,231,233, 244,232,225,105,128, 14, 1,244,225,235,225,238, 97,129, 48,179, 121,242,232,225,236,230,247,233,228,244,104,128,255,122,239,240, 239,243,241,245,225,242,101,128, 51, 30,240,240,225,227,249,242, 233,236,236,233, 99,128, 4,129,114, 2,122, 30,122, 50,229,225, 238,243,244,225,238,228,225,242,228,243,249,237,226,239,108,128, 50,127,239,238,233,243,227,237, 98,128, 3, 67,240, 97, 2,122, 67,122, 73,242,229,110,128, 36,166,243,241,245,225,242,101,128, 51,170,243,233,227,249,242,233,236,236,233, 99,128, 4,111,116, 2,122,101,122,110,243,241,245,225,242,101,128, 51,207,245,242, 238,229,100,128, 2,158,117, 2,122,124,122,135,232,233,242,225, 231,225,238, 97,128, 48, 79,235,225,244,225,235,225,238, 97,129, 48,175,122,148,232,225,236,230,247,233,228,244,104,128,255,120, 246,243,241,245,225,242,101,128, 51,184,247,243,241,245,225,242, 101,128, 51,190,108,146, 0,108,122,220,124,247,125, 20,125, 86, 125,124,126, 20,126, 29,126, 45,126, 69,126, 87,126,205,126,246, 127,125,127,133,127,166,127,175,127,183,127,245, 97, 7,122,236, 122,246,122,253,123, 4,123, 29,123, 45,124,235,226,229,238,231, 225,236,105,128, 9,178,227,245,244,101,128, 1, 58,228,229,246, 97,128, 9, 50,231,117, 2,123, 11,123, 20,234,225,242,225,244, 105,128, 10,178,242,237,245,235,232,105,128, 10, 50,235,235,232, 225,238,231,249,225,239,244,232,225,105,128, 14, 69,109, 10,123, 67,124, 6,124, 23,124, 61,124, 75,124, 94,124,110,124,130,124, 150,124,173, 97, 2,123, 73,123,254,236,229,102, 4,123, 85,123, 99,123,191,123,208,230,233,238,225,236,225,242,225,226,233, 99, 128,254,252,232,225,237,250, 97, 2,123,109,123,150,225,226,239, 246,101, 2,123,119,123,133,230,233,238,225,236,225,242,225,226, 233, 99,128,254,248,233,243,239,236,225,244,229,228,225,242,225, 226,233, 99,128,254,247,226,229,236,239,119, 2,123,160,123,174, 230,233,238,225,236,225,242,225,226,233, 99,128,254,250,233,243, 239,236,225,244,229,228,225,242,225,226,233, 99,128,254,249,233, 243,239,236,225,244,229,228,225,242,225,226,233, 99,128,254,251, 237,225,228,228,225,225,226,239,246,101, 2,123,223,123,237,230, 233,238,225,236,225,242,225,226,233, 99,128,254,246,233,243,239, 236,225,244,229,228,225,242,225,226,233, 99,128,254,245,242,225, 226,233, 99,128, 6, 68,226,228, 97,129, 3,187,124, 14,243,244, 242,239,235,101,128, 1,155,229,100,130, 5,220,124, 32,124, 52, 228,225,231,229,243,104,129,251, 60,124, 43,232,229,226,242,229, 119,128,251, 60,232,229,226,242,229,119,128, 5,220,230,233,238, 225,236,225,242,225,226,233, 99,128,254,222,232,225,232,233,238, 233,244,233,225,236,225,242,225,226,233, 99,128,252,202,233,238, 233,244,233,225,236,225,242,225,226,233, 99,128,254,223,234,229, 229,237,233,238,233,244,233,225,236,225,242,225,226,233, 99,128, 252,201,235,232,225,232,233,238,233,244,233,225,236,225,242,225, 226,233, 99,128,252,203,236,225,237,232,229,232,233,243,239,236, 225,244,229,228,225,242,225,226,233, 99,128,253,242,237,101, 2, 124,180,124,193,228,233,225,236,225,242,225,226,233, 99,128,254, 224,229,109, 2,124,200,124,219,232,225,232,233,238,233,244,233, 225,236,225,242,225,226,233, 99,128,253,136,233,238,233,244,233, 225,236,225,242,225,226,233, 99,128,252,204,242,231,229,227,233, 242,227,236,101,128, 37,239, 98, 3,124,255,125, 4,125, 10,225, 114,128, 1,154,229,236,116,128, 2,108,239,240,239,237,239,230, 111,128, 49, 12, 99, 4,125, 30,125, 37,125, 46,125, 73,225,242, 239,110,128, 1, 62,229,228,233,236,236, 97,128, 1, 60,233,242, 99, 2,125, 54,125, 59,236,101,128, 36,219,245,237,230,236,229, 248,226,229,236,239,119,128, 30, 61,239,237,237,225,225,227,227, 229,238,116,128, 1, 60,228,239,116,130, 1, 64,125, 96,125,105, 225,227,227,229,238,116,128, 1, 64,226,229,236,239,119,129, 30, 55,125,115,237,225,227,242,239,110,128, 30, 57,101, 3,125,132, 125,170,126, 15,230,116, 2,125,139,125,155,225,238,231,236,229, 225,226,239,246,229,227,237, 98,128, 3, 26,244,225,227,235,226, 229,236,239,247,227,237, 98,128, 3, 24,243,115,132, 0, 60,125, 183,125,205,125,217,126, 7,229,241,245,225,108,129, 34,100,125, 193,239,242,231,242,229,225,244,229,114,128, 34,218,237,239,238, 239,243,240,225,227,101,128,255, 28,111, 2,125,223,125,252,114, 2,125,229,125,242,229,241,245,233,246,225,236,229,238,116,128, 34,114,231,242,229,225,244,229,114,128, 34,118,246,229,242,229, 241,245,225,108,128, 34,102,243,237,225,236,108,128,254,100,250, 104,128, 2,110,230,226,236,239,227,107,128, 37,140,232,239,239, 235,242,229,244,242,239,230,236,229,120,128, 2,109,105, 2,126, 51,126, 56,242, 97,128, 32,164,247,238,225,242,237,229,238,233, 225,110,128, 5,108,106,129, 1,201,126, 75,229,227,249,242,233, 236,236,233, 99,128, 4, 89,108,132,246,192,126, 99,126,123,126, 134,126,143, 97, 2,126,105,126,112,228,229,246, 97,128, 9, 51, 231,245,234,225,242,225,244,105,128, 10,179,233,238,229,226,229, 236,239,119,128, 30, 59,236,225,228,229,246, 97,128, 9, 52,246, 239,227,225,236,233, 99, 3,126,157,126,167,126,174,226,229,238, 231,225,236,105,128, 9,225,228,229,246, 97,128, 9, 97,246,239, 247,229,236,243,233,231,110, 2,126,188,126,198,226,229,238,231, 225,236,105,128, 9,227,228,229,246, 97,128, 9, 99,109, 3,126, 213,126,226,126,237,233,228,228,236,229,244,233,236,228,101,128, 2,107,239,238,239,243,240,225,227,101,128,255, 76,243,241,245, 225,242,101,128, 51,208,111, 6,127, 4,127, 16,127, 58,127, 69, 127, 75,127,117,227,232,245,236,225,244,232,225,105,128, 14, 44, 231,233,227,225,108, 3,127, 28,127, 34,127, 53,225,238,100,128, 34, 39,238,239,116,129, 0,172,127, 42,242,229,246,229,242,243, 229,100,128, 35, 16,239,114,128, 34, 40,236,233,238,231,244,232, 225,105,128, 14, 37,238,231,115,128, 1,127,247,236,233,238,101, 2,127, 85,127,108, 99, 2,127, 91,127,103,229,238,244,229,242, 236,233,238,101,128,254, 78,237, 98,128, 3, 50,228,225,243,232, 229,100,128,254, 77,250,229,238,231,101,128, 37,202,240,225,242, 229,110,128, 36,167,115, 3,127,141,127,148,127,156,236,225,243, 104,128, 1, 66,241,245,225,242,101,128, 33, 19,245,240,229,242, 233,239,114,128,246,238,244,243,232,225,228,101,128, 37,145,245, 244,232,225,105,128, 14, 38,246,239,227,225,236,233, 99, 3,127, 197,127,207,127,214,226,229,238,231,225,236,105,128, 9,140,228, 229,246, 97,128, 9, 12,246,239,247,229,236,243,233,231,110, 2, 127,228,127,238,226,229,238,231,225,236,105,128, 9,226,228,229, 246, 97,128, 9, 98,248,243,241,245,225,242,101,128, 51,211,109, 144, 0,109,128, 35,130,144,130,169,130,196,130,221,132, 18,132, 40,133, 95,133,125,133,174,134, 25,134, 47,134, 72,134, 81,135, 108,135,136, 97, 12,128, 61,128, 71,128,135,128,142,128,167,128, 215,130, 51,130, 76,130, 81,130, 95,130,107,130,112,226,229,238, 231,225,236,105,128, 9,174, 99, 2,128, 77,128,129,242,239,110, 132, 0,175,128, 91,128,102,128,108,128,117,226,229,236,239,247, 227,237, 98,128, 3, 49,227,237, 98,128, 3, 4,236,239,247,237, 239,100,128, 2,205,237,239,238,239,243,240,225,227,101,128,255, 227,245,244,101,128, 30, 63,228,229,246, 97,128, 9, 46,231,117, 2,128,149,128,158,234,225,242,225,244,105,128, 10,174,242,237, 245,235,232,105,128, 10, 46,104, 2,128,173,128,205,225,240,225, 235,104, 2,128,183,128,192,232,229,226,242,229,119,128, 5,164, 236,229,230,244,232,229,226,242,229,119,128, 5,164,233,242,225, 231,225,238, 97,128, 48,126,105, 5,128,227,129, 40,129,103,129, 133,130, 39,227,232,225,244,244,225,247, 97, 3,128,242,129, 17, 129, 24,236,239,119, 2,128,250,129, 5,236,229,230,244,244,232, 225,105,128,248,149,242,233,231,232,244,244,232,225,105,128,248, 148,244,232,225,105,128, 14, 75,245,240,240,229,242,236,229,230, 244,244,232,225,105,128,248,147,229,107, 3,129, 49,129, 80,129, 87,236,239,119, 2,129, 57,129, 68,236,229,230,244,244,232,225, 105,128,248,140,242,233,231,232,244,244,232,225,105,128,248,139, 244,232,225,105,128, 14, 72,245,240,240,229,242,236,229,230,244, 244,232,225,105,128,248,138,232,225,238,225,235,225,116, 2,129, 115,129,126,236,229,230,244,244,232,225,105,128,248,132,244,232, 225,105,128, 14, 49,116, 3,129,141,129,169,129,232,225,233,235, 232,117, 2,129,151,129,162,236,229,230,244,244,232,225,105,128, 248,137,244,232,225,105,128, 14, 71,232,111, 3,129,178,129,209, 129,216,236,239,119, 2,129,186,129,197,236,229,230,244,244,232, 225,105,128,248,143,242,233,231,232,244,244,232,225,105,128,248, 142,244,232,225,105,128, 14, 73,245,240,240,229,242,236,229,230, 244,244,232,225,105,128,248,141,242,105, 3,129,241,130, 16,130, 23,236,239,119, 2,129,249,130, 4,236,229,230,244,244,232,225, 105,128,248,146,242,233,231,232,244,244,232,225,105,128,248,145, 244,232,225,105,128, 14, 74,245,240,240,229,242,236,229,230,244, 244,232,225,105,128,248,144,249,225,237,239,235,244,232,225,105, 128, 14, 70,235,225,244,225,235,225,238, 97,129, 48,222,130, 64, 232,225,236,230,247,233,228,244,104,128,255,143,236,101,128, 38, 66,238,243,249,239,238,243,241,245,225,242,101,128, 51, 71,241, 225,230,232,229,226,242,229,119,128, 5,190,242,115,128, 38, 66, 115, 2,130,118,130,136,239,242,225,227,233,242,227,236,229,232, 229,226,242,229,119,128, 5,175,241,245,225,242,101,128, 51,131, 98, 2,130,150,130,160,239,240,239,237,239,230,111,128, 49, 7, 243,241,245,225,242,101,128, 51,212, 99, 2,130,175,130,183,233, 242,227,236,101,128, 36,220,245,226,229,228,243,241,245,225,242, 101,128, 51,165,228,239,116, 2,130,204,130,213,225,227,227,229, 238,116,128, 30, 65,226,229,236,239,119,128, 30, 67,101, 7,130, 237,131,108,131,119,131,134,131,159,131,196,131,208,101, 2,130, 243,131, 95,109, 4,130,253,131, 6,131, 20,131, 36,225,242,225, 226,233, 99,128, 6, 69,230,233,238,225,236,225,242,225,226,233, 99,128,254,226,233,238,233,244,233,225,236,225,242,225,226,233, 99,128,254,227,237,101, 2,131, 43,131, 56,228,233,225,236,225, 242,225,226,233, 99,128,254,228,229,237,105, 2,131, 64,131, 79, 238,233,244,233,225,236,225,242,225,226,233, 99,128,252,209,243, 239,236,225,244,229,228,225,242,225,226,233, 99,128,252, 72,244, 239,242,245,243,241,245,225,242,101,128, 51, 77,232,233,242,225, 231,225,238, 97,128, 48,129,233,250,233,229,242,225,243,241,245, 225,242,101,128, 51,126,235,225,244,225,235,225,238, 97,129, 48, 225,131,147,232,225,236,230,247,233,228,244,104,128,255,146,109, 130, 5,222,131,167,131,187,228,225,231,229,243,104,129,251, 62, 131,178,232,229,226,242,229,119,128,251, 62,232,229,226,242,229, 119,128, 5,222,238,225,242,237,229,238,233,225,110,128, 5,116, 242,235,232, 97, 3,131,219,131,228,132, 5,232,229,226,242,229, 119,128, 5,165,235,229,230,245,236, 97, 2,131,239,131,248,232, 229,226,242,229,119,128, 5,166,236,229,230,244,232,229,226,242, 229,119,128, 5,166,236,229,230,244,232,229,226,242,229,119,128, 5,165,104, 2,132, 24,132, 30,239,239,107,128, 2,113,250,243, 241,245,225,242,101,128, 51,146,105, 6,132, 54,132, 91,132,228, 132,239,133, 8,133, 65,228,100, 2,132, 61,132, 86,236,229,228, 239,244,235,225,244,225,235,225,238,225,232,225,236,230,247,233, 228,244,104,128,255,101,239,116,128, 0,183,229,245,109, 5,132, 105,132,140,132,155,132,164,132,215, 97, 2,132,111,132,126,227, 233,242,227,236,229,235,239,242,229,225,110,128, 50,114,240,225, 242,229,238,235,239,242,229,225,110,128, 50, 18,227,233,242,227, 236,229,235,239,242,229,225,110,128, 50,100,235,239,242,229,225, 110,128, 49, 65,112, 2,132,170,132,202, 97, 2,132,176,132,190, 238,243,233,239,243,235,239,242,229,225,110,128, 49,112,242,229, 238,235,239,242,229,225,110,128, 50, 4,233,229,245,240,235,239, 242,229,225,110,128, 49,110,243,233,239,243,235,239,242,229,225, 110,128, 49,111,232,233,242,225,231,225,238, 97,128, 48,127,235, 225,244,225,235,225,238, 97,129, 48,223,132,252,232,225,236,230, 247,233,228,244,104,128,255,144,238,117, 2,133, 15,133, 60,115, 132, 34, 18,133, 27,133, 38,133, 47,133, 53,226,229,236,239,247, 227,237, 98,128, 3, 32,227,233,242,227,236,101,128, 34,150,237, 239,100,128, 2,215,240,236,245,115,128, 34, 19,244,101,128, 32, 50,242,105, 2,133, 72,133, 86,226,225,225,242,245,243,241,245, 225,242,101,128, 51, 74,243,241,245,225,242,101,128, 51, 73,108, 2,133,101,133,116,239,238,231,236,229,231,244,245,242,238,229, 100,128, 2,112,243,241,245,225,242,101,128, 51,150,109, 3,133, 133,133,147,133,158,227,245,226,229,228,243,241,245,225,242,101, 128, 51,163,239,238,239,243,240,225,227,101,128,255, 77,243,241, 245,225,242,229,228,243,241,245,225,242,101,128, 51,159,111, 5, 133,186,133,212,133,237,133,247,134, 0,104, 2,133,192,133,202, 233,242,225,231,225,238, 97,128, 48,130,237,243,241,245,225,242, 101,128, 51,193,235,225,244,225,235,225,238, 97,129, 48,226,133, 225,232,225,236,230,247,233,228,244,104,128,255,147,236,243,241, 245,225,242,101,128, 51,214,237,225,244,232,225,105,128, 14, 33, 246,229,242,243,243,241,245,225,242,101,129, 51,167,134, 15,228, 243,241,245,225,242,101,128, 51,168,240, 97, 2,134, 32,134, 38, 242,229,110,128, 36,168,243,241,245,225,242,101,128, 51,171,115, 2,134, 53,134, 62,243,241,245,225,242,101,128, 51,179,245,240, 229,242,233,239,114,128,246,239,244,245,242,238,229,100,128, 2, 111,117,141, 0,181,134,111,134,115,134,125,134,149,134,159,134, 181,134,192,134,217,134,240,134,250,135, 24,135, 88,135, 98, 49, 128, 0,181,225,243,241,245,225,242,101,128, 51,130,227,104, 2, 134,132,134,142,231,242,229,225,244,229,114,128, 34,107,236,229, 243,115,128, 34,106,230,243,241,245,225,242,101,128, 51,140,103, 2,134,165,134,172,242,229,229,107,128, 3,188,243,241,245,225, 242,101,128, 51,141,232,233,242,225,231,225,238, 97,128, 48,128, 235,225,244,225,235,225,238, 97,129, 48,224,134,205,232,225,236, 230,247,233,228,244,104,128,255,145,108, 2,134,223,134,232,243, 241,245,225,242,101,128, 51,149,244,233,240,236,121,128, 0,215, 237,243,241,245,225,242,101,128, 51,155,238,225,104, 2,135, 2, 135, 11,232,229,226,242,229,119,128, 5,163,236,229,230,244,232, 229,226,242,229,119,128, 5,163,115, 2,135, 30,135, 79,233, 99, 3,135, 39,135, 56,135, 67,225,236,238,239,244,101,129, 38,106, 135, 50,228,226,108,128, 38,107,230,236,225,244,243,233,231,110, 128, 38,109,243,232,225,242,240,243,233,231,110,128, 38,111,243, 241,245,225,242,101,128, 51,178,246,243,241,245,225,242,101,128, 51,182,247,243,241,245,225,242,101,128, 51,188,118, 2,135,114, 135,127,237,229,231,225,243,241,245,225,242,101,128, 51,185,243, 241,245,225,242,101,128, 51,183,119, 2,135,142,135,155,237,229, 231,225,243,241,245,225,242,101,128, 51,191,243,241,245,225,242, 101,128, 51,189,110,150, 0,110,135,212,136, 90,136,114,136,180, 136,205,137, 7,137, 17,137, 84,137,127,139,161,139,179,139,204, 139,235,140, 5,140, 70,142, 52,142, 60,142, 85,142, 93,143, 61, 143, 71,143, 81, 97, 8,135,230,135,250,136, 1,136, 8,136, 33, 136, 44,136, 69,136, 81, 98, 2,135,236,135,245,229,238,231,225, 236,105,128, 9,168,236, 97,128, 34, 7,227,245,244,101,128, 1, 68,228,229,246, 97,128, 9, 40,231,117, 2,136, 15,136, 24,234, 225,242,225,244,105,128, 10,168,242,237,245,235,232,105,128, 10, 40,232,233,242,225,231,225,238, 97,128, 48,106,235,225,244,225, 235,225,238, 97,129, 48,202,136, 57,232,225,236,230,247,233,228, 244,104,128,255,133,240,239,243,244,242,239,240,232,101,128, 1, 73,243,241,245,225,242,101,128, 51,129, 98, 2,136, 96,136,106, 239,240,239,237,239,230,111,128, 49, 11,243,240,225,227,101,128, 0,160, 99, 4,136,124,136,131,136,140,136,167,225,242,239,110, 128, 1, 72,229,228,233,236,236, 97,128, 1, 70,233,242, 99, 2, 136,148,136,153,236,101,128, 36,221,245,237,230,236,229,248,226, 229,236,239,119,128, 30, 75,239,237,237,225,225,227,227,229,238, 116,128, 1, 70,228,239,116, 2,136,188,136,197,225,227,227,229, 238,116,128, 30, 69,226,229,236,239,119,128, 30, 71,101, 3,136, 213,136,224,136,249,232,233,242,225,231,225,238, 97,128, 48,109, 235,225,244,225,235,225,238, 97,129, 48,205,136,237,232,225,236, 230,247,233,228,244,104,128,255,136,247,243,232,229,241,229,236, 243,233,231,110,128, 32,170,230,243,241,245,225,242,101,128, 51, 139,103, 2,137, 23,137, 73, 97, 3,137, 31,137, 41,137, 48,226, 229,238,231,225,236,105,128, 9,153,228,229,246, 97,128, 9, 25, 231,117, 2,137, 55,137, 64,234,225,242,225,244,105,128, 10,153, 242,237,245,235,232,105,128, 10, 25,239,238,231,245,244,232,225, 105,128, 14, 7,104, 2,137, 90,137,100,233,242,225,231,225,238, 97,128, 48,147,239,239,107, 2,137,108,137,115,236,229,230,116, 128, 2,114,242,229,244,242,239,230,236,229,120,128, 2,115,105, 4,137,137,138, 50,138, 61,138,119,229,245,110, 7,137,155,137, 190,137,222,137,236,137,245,138, 22,138, 35, 97, 2,137,161,137, 176,227,233,242,227,236,229,235,239,242,229,225,110,128, 50,111, 240,225,242,229,238,235,239,242,229,225,110,128, 50, 15,227,105, 2,137,197,137,209,229,245,227,235,239,242,229,225,110,128, 49, 53,242,227,236,229,235,239,242,229,225,110,128, 50, 97,232,233, 229,245,232,235,239,242,229,225,110,128, 49, 54,235,239,242,229, 225,110,128, 49, 52,240, 97, 2,137,252,138, 10,238,243,233,239, 243,235,239,242,229,225,110,128, 49,104,242,229,238,235,239,242, 229,225,110,128, 50, 1,243,233,239,243,235,239,242,229,225,110, 128, 49,103,244,233,235,229,245,244,235,239,242,229,225,110,128, 49,102,232,233,242,225,231,225,238, 97,128, 48,107,107, 2,138, 67,138, 91,225,244,225,235,225,238, 97,129, 48,203,138, 79,232, 225,236,230,247,233,228,244,104,128,255,134,232,225,232,233,116, 2,138,101,138,112,236,229,230,244,244,232,225,105,128,248,153, 244,232,225,105,128, 14, 77,238,101,141, 0, 57,138,150,138,159, 138,169,138,199,138,206,138,231,139, 2,139, 36,139, 48,139, 59, 139, 92,139,100,139,111,225,242,225,226,233, 99,128, 6,105,226, 229,238,231,225,236,105,128, 9,239,227,233,242,227,236,101,129, 36,104,138,180,233,238,246,229,242,243,229,243,225,238,243,243, 229,242,233,102,128, 39,146,228,229,246, 97,128, 9,111,231,117, 2,138,213,138,222,234,225,242,225,244,105,128, 10,239,242,237, 245,235,232,105,128, 10,111,232, 97, 2,138,238,138,249,227,235, 225,242,225,226,233, 99,128, 6,105,238,231,250,232,239,117,128, 48, 41,105, 2,139, 8,139, 26,228,229,239,231,242,225,240,232, 233,227,240,225,242,229,110,128, 50, 40,238,230,229,242,233,239, 114,128, 32,137,237,239,238,239,243,240,225,227,101,128,255, 25, 239,236,228,243,244,249,236,101,128,247, 57,112, 2,139, 65,139, 72,225,242,229,110,128, 36,124,229,114, 2,139, 79,139, 85,233, 239,100,128, 36,144,243,233,225,110,128, 6,249,242,239,237,225, 110,128, 33,120,243,245,240,229,242,233,239,114,128, 32,121,116, 2,139,117,139,155,229,229,110, 2,139,125,139,134,227,233,242, 227,236,101,128, 36,114,112, 2,139,140,139,147,225,242,229,110, 128, 36,134,229,242,233,239,100,128, 36,154,232,225,105,128, 14, 89,106,129, 1,204,139,167,229,227,249,242,233,236,236,233, 99, 128, 4, 90,235,225,244,225,235,225,238, 97,129, 48,243,139,192, 232,225,236,230,247,233,228,244,104,128,255,157,108, 2,139,210, 139,224,229,231,242,233,231,232,244,236,239,238,103,128, 1,158, 233,238,229,226,229,236,239,119,128, 30, 73,109, 2,139,241,139, 252,239,238,239,243,240,225,227,101,128,255, 78,243,241,245,225, 242,101,128, 51,154,110, 2,140, 11,140, 61, 97, 3,140, 19,140, 29,140, 36,226,229,238,231,225,236,105,128, 9,163,228,229,246, 97,128, 9, 35,231,117, 2,140, 43,140, 52,234,225,242,225,244, 105,128, 10,163,242,237,245,235,232,105,128, 10, 35,238,225,228, 229,246, 97,128, 9, 41,111, 6,140, 84,140, 95,140,120,140,161, 141,113,142, 40,232,233,242,225,231,225,238, 97,128, 48,110,235, 225,244,225,235,225,238, 97,129, 48,206,140,108,232,225,236,230, 247,233,228,244,104,128,255,137,110, 3,140,128,140,144,140,153, 226,242,229,225,235,233,238,231,243,240,225,227,101,128, 0,160, 229,238,244,232,225,105,128, 14, 19,245,244,232,225,105,128, 14, 25,239,110, 7,140,178,140,187,140,201,140,235,140,251,141, 36, 141, 95,225,242,225,226,233, 99,128, 6, 70,230,233,238,225,236, 225,242,225,226,233, 99,128,254,230,231,232,245,238,238, 97, 2, 140,212,140,221,225,242,225,226,233, 99,128, 6,186,230,233,238, 225,236,225,242,225,226,233, 99,128,251,159,233,238,233,244,233, 225,236,225,242,225,226,233, 99,128,254,231,234,229,229,237,105, 2,141, 5,141, 20,238,233,244,233,225,236,225,242,225,226,233, 99,128,252,210,243,239,236,225,244,229,228,225,242,225,226,233, 99,128,252, 75,237,101, 2,141, 43,141, 56,228,233,225,236,225, 242,225,226,233, 99,128,254,232,229,237,105, 2,141, 64,141, 79, 238,233,244,233,225,236,225,242,225,226,233, 99,128,252,213,243, 239,236,225,244,229,228,225,242,225,226,233, 99,128,252, 78,238, 239,239,238,230,233,238,225,236,225,242,225,226,233, 99,128,252, 141,116, 7,141,129,141,140,141,169,141,204,141,216,141,236,142, 6,227,239,238,244,225,233,238,115,128, 34, 12,101, 2,141,146, 141,162,236,229,237,229,238,116,129, 34, 9,141,157,239,102,128, 34, 9,241,245,225,108,128, 34, 96,231,242,229,225,244,229,114, 129, 34,111,141,181,238,239,114, 2,141,189,141,197,229,241,245, 225,108,128, 34,113,236,229,243,115,128, 34,121,233,228,229,238, 244,233,227,225,108,128, 34, 98,236,229,243,115,129, 34,110,141, 225,238,239,242,229,241,245,225,108,128, 34,112,112, 2,141,242, 141,252,225,242,225,236,236,229,108,128, 34, 38,242,229,227,229, 228,229,115,128, 34,128,243,117, 3,142, 15,142, 22,142, 31,226, 243,229,116,128, 34,132,227,227,229,229,228,115,128, 34,129,240, 229,242,243,229,116,128, 34,133,247,225,242,237,229,238,233,225, 110,128, 5,118,240,225,242,229,110,128, 36,169,115, 2,142, 66, 142, 75,243,241,245,225,242,101,128, 51,177,245,240,229,242,233, 239,114,128, 32,127,244,233,236,228,101,128, 0,241,117,132, 3, 189,142,105,142,116,142,197,143, 24,232,233,242,225,231,225,238, 97,128, 48,108,107, 2,142,122,142,146,225,244,225,235,225,238, 97,129, 48,204,142,134,232,225,236,230,247,233,228,244,104,128, 255,135,244, 97, 3,142,155,142,165,142,172,226,229,238,231,225, 236,105,128, 9,188,228,229,246, 97,128, 9, 60,231,117, 2,142, 179,142,188,234,225,242,225,244,105,128, 10,188,242,237,245,235, 232,105,128, 10, 60,109, 2,142,203,142,237,226,229,242,243,233, 231,110,130, 0, 35,142,217,142,229,237,239,238,239,243,240,225, 227,101,128,255, 3,243,237,225,236,108,128,254, 95,229,114, 2, 142,244,143, 20,225,236,243,233,231,110, 2,142,255,143, 7,231, 242,229,229,107,128, 3,116,236,239,247,229,242,231,242,229,229, 107,128, 3,117,111,128, 33, 22,110,130, 5,224,143, 32,143, 52, 228,225,231,229,243,104,129,251, 64,143, 43,232,229,226,242,229, 119,128,251, 64,232,229,226,242,229,119,128, 5,224,246,243,241, 245,225,242,101,128, 51,181,247,243,241,245,225,242,101,128, 51, 187,249, 97, 3,143, 90,143,100,143,107,226,229,238,231,225,236, 105,128, 9,158,228,229,246, 97,128, 9, 30,231,117, 2,143,114, 143,123,234,225,242,225,244,105,128, 10,158,242,237,245,235,232, 105,128, 10, 30,111,147, 0,111,143,174,143,196,144, 18,144,188, 145, 4,145, 19,145, 59,145,182,145,203,145,241,145,252,146,174, 148, 8,148, 72,148,105,148,151,149, 24,149, 71,149, 83, 97, 2, 143,180,143,187,227,245,244,101,128, 0,243,238,231,244,232,225, 105,128, 14, 45, 98, 4,143,206,143,248,144, 1,144, 11,225,242, 242,229,100,130, 2,117,143,218,143,229,227,249,242,233,236,236, 233, 99,128, 4,233,228,233,229,242,229,243,233,243,227,249,242, 233,236,236,233, 99,128, 4,235,229,238,231,225,236,105,128, 9, 147,239,240,239,237,239,230,111,128, 49, 27,242,229,246,101,128, 1, 79, 99, 3,144, 26,144, 99,144,178, 97, 2,144, 32,144, 93, 238,228,242, 97, 3,144, 43,144, 50,144, 61,228,229,246, 97,128, 9, 17,231,245,234,225,242,225,244,105,128, 10,145,246,239,247, 229,236,243,233,231,110, 2,144, 75,144, 82,228,229,246, 97,128, 9, 73,231,245,234,225,242,225,244,105,128, 10,201,242,239,110, 128, 1,210,233,242, 99, 2,144,107,144,112,236,101,128, 36,222, 245,237,230,236,229,120,133, 0,244,144,131,144,139,144,150,144, 158,144,170,225,227,245,244,101,128, 30,209,228,239,244,226,229, 236,239,119,128, 30,217,231,242,225,246,101,128, 30,211,232,239, 239,235,225,226,239,246,101,128, 30,213,244,233,236,228,101,128, 30,215,249,242,233,236,236,233, 99,128, 4, 62,100, 4,144,198, 144,221,144,227,144,250,226,108, 2,144,205,144,213,225,227,245, 244,101,128, 1, 81,231,242,225,246,101,128, 2, 13,229,246, 97, 128, 9, 19,233,229,242,229,243,233,115,129, 0,246,144,239,227, 249,242,233,236,236,233, 99,128, 4,231,239,244,226,229,236,239, 119,128, 30,205,101,129, 1, 83,145, 10,235,239,242,229,225,110, 128, 49, 90,103, 3,145, 27,145, 42,145, 49,239,238,229,107,129, 2,219,145, 36,227,237, 98,128, 3, 40,242,225,246,101,128, 0, 242,245,234,225,242,225,244,105,128, 10,147,104, 4,145, 69,145, 80,145, 90,145,168,225,242,237,229,238,233,225,110,128, 5,133, 233,242,225,231,225,238, 97,128, 48, 74,111, 2,145, 96,145,106, 239,235,225,226,239,246,101,128, 30,207,242,110,133, 1,161,145, 121,145,129,145,140,145,148,145,160,225,227,245,244,101,128, 30, 219,228,239,244,226,229,236,239,119,128, 30,227,231,242,225,246, 101,128, 30,221,232,239,239,235,225,226,239,246,101,128, 30,223, 244,233,236,228,101,128, 30,225,245,238,231,225,242,245,237,236, 225,245,116,128, 1, 81,105,129, 1,163,145,188,238,246,229,242, 244,229,228,226,242,229,246,101,128, 2, 15,107, 2,145,209,145, 233,225,244,225,235,225,238, 97,129, 48,170,145,221,232,225,236, 230,247,233,228,244,104,128,255,117,239,242,229,225,110,128, 49, 87,236,229,232,229,226,242,229,119,128, 5,171,109, 6,146, 10, 146, 38,146, 45,146,134,146,145,146,163,225,227,242,239,110,130, 1, 77,146, 22,146, 30,225,227,245,244,101,128, 30, 83,231,242, 225,246,101,128, 30, 81,228,229,246, 97,128, 9, 80,229,231, 97, 133, 3,201,146, 61,146, 65,146, 76,146, 90,146,106, 49,128, 3, 214,227,249,242,233,236,236,233, 99,128, 4, 97,236,225,244,233, 238,227,236,239,243,229,100,128, 2,119,242,239,245,238,228,227, 249,242,233,236,236,233, 99,128, 4,123,116, 2,146,112,146,127, 233,244,236,239,227,249,242,233,236,236,233, 99,128, 4,125,239, 238,239,115,128, 3,206,231,245,234,225,242,225,244,105,128, 10, 208,233,227,242,239,110,129, 3,191,146,155,244,239,238,239,115, 128, 3,204,239,238,239,243,240,225,227,101,128,255, 79,238,101, 145, 0, 49,146,213,146,222,146,232,147, 6,147, 31,147, 40,147, 49,147, 74,147,108,147,142,147,154,147,173,147,184,147,217,147, 227,147,235,147,246,225,242,225,226,233, 99,128, 6, 97,226,229, 238,231,225,236,105,128, 9,231,227,233,242,227,236,101,129, 36, 96,146,243,233,238,246,229,242,243,229,243,225,238,243,243,229, 242,233,102,128, 39,138,100, 2,147, 12,147, 18,229,246, 97,128, 9,103,239,244,229,238,236,229,225,228,229,114,128, 32, 36,229, 233,231,232,244,104,128, 33, 91,230,233,244,244,229,100,128,246, 220,231,117, 2,147, 56,147, 65,234,225,242,225,244,105,128, 10, 231,242,237,245,235,232,105,128, 10,103,232, 97, 3,147, 83,147, 94,147, 99,227,235,225,242,225,226,233, 99,128, 6, 97,236,102, 128, 0,189,238,231,250,232,239,117,128, 48, 33,105, 2,147,114, 147,132,228,229,239,231,242,225,240,232,233,227,240,225,242,229, 110,128, 50, 32,238,230,229,242,233,239,114,128, 32,129,237,239, 238,239,243,240,225,227,101,128,255, 17,238,245,237,229,242,225, 244,239,242,226,229,238,231,225,236,105,128, 9,244,239,236,228, 243,244,249,236,101,128,247, 49,112, 2,147,190,147,197,225,242, 229,110,128, 36,116,229,114, 2,147,204,147,210,233,239,100,128, 36,136,243,233,225,110,128, 6,241,241,245,225,242,244,229,114, 128, 0,188,242,239,237,225,110,128, 33,112,243,245,240,229,242, 233,239,114,128, 0,185,244,104, 2,147,253,148, 2,225,105,128, 14, 81,233,242,100,128, 33, 83,111, 3,148, 16,148, 50,148, 66, 103, 2,148, 22,148, 40,239,238,229,107,129, 1,235,148, 31,237, 225,227,242,239,110,128, 1,237,245,242,237,245,235,232,105,128, 10, 19,237,225,244,242,225,231,245,242,237,245,235,232,105,128, 10, 75,240,229,110,128, 2, 84,112, 3,148, 80,148, 87,148, 98, 225,242,229,110,128, 36,170,229,238,226,245,236,236,229,116,128, 37,230,244,233,239,110,128, 35, 37,114, 2,148,111,148,140,100, 2,148,117,148,128,230,229,237,233,238,233,238,101,128, 0,170, 237,225,243,227,245,236,233,238,101,128, 0,186,244,232,239,231, 239,238,225,108,128, 34, 31,115, 5,148,163,148,195,148,212,149, 1,149, 14,232,239,242,116, 2,148,172,148,179,228,229,246, 97, 128, 9, 18,246,239,247,229,236,243,233,231,238,228,229,246, 97, 128, 9, 74,236,225,243,104,129, 0,248,148,204,225,227,245,244, 101,128, 1,255,237,225,236,108, 2,148,221,148,232,232,233,242, 225,231,225,238, 97,128, 48, 73,235,225,244,225,235,225,238, 97, 129, 48,169,148,245,232,225,236,230,247,233,228,244,104,128,255, 107,244,242,239,235,229,225,227,245,244,101,128, 1,255,245,240, 229,242,233,239,114,128,246,240,116, 2,149, 30,149, 41,227,249, 242,233,236,236,233, 99,128, 4,127,233,236,228,101,130, 0,245, 149, 52,149, 60,225,227,245,244,101,128, 30, 77,228,233,229,242, 229,243,233,115,128, 30, 79,245,226,239,240,239,237,239,230,111, 128, 49, 33,118, 2,149, 89,149,170,229,114, 2,149, 96,149,162, 236,233,238,101,131, 32, 62,149,109,149,132,149,155, 99, 2,149, 115,149,127,229,238,244,229,242,236,233,238,101,128,254, 74,237, 98,128, 3, 5,100, 2,149,138,149,146,225,243,232,229,100,128, 254, 73,226,236,247,225,246,121,128,254, 76,247,225,246,121,128, 254, 75,243,227,239,242,101,128, 0,175,239,247,229,236,243,233, 231,110, 3,149,185,149,195,149,202,226,229,238,231,225,236,105, 128, 9,203,228,229,246, 97,128, 9, 75,231,245,234,225,242,225, 244,105,128, 10,203,112,145, 0,112,149,251,152,123,152,134,152, 143,152,155,154, 80,154, 90,155, 82,156,101,156,191,156,217,157, 92,157,100,158, 2,158, 60,158, 88,158, 98, 97, 14,150, 25,150, 57,150, 67,150, 74,150, 81,150,129,150,140,150,154,150,165,150, 212,150,226,151,238,152, 21,152,111, 97, 2,150, 31,150, 43,237, 240,243,243,241,245,225,242,101,128, 51,128,243,229,238,244,239, 243,241,245,225,242,101,128, 51, 43,226,229,238,231,225,236,105, 128, 9,170,227,245,244,101,128, 30, 85,228,229,246, 97,128, 9, 42,103, 2,150, 87,150,105,101, 2,150, 93,150,100,228,239,247, 110,128, 33,223,245,112,128, 33,222,117, 2,150,111,150,120,234, 225,242,225,244,105,128, 10,170,242,237,245,235,232,105,128, 10, 42,232,233,242,225,231,225,238, 97,128, 48,113,233,249,225,238, 238,239,233,244,232,225,105,128, 14, 47,235,225,244,225,235,225, 238, 97,128, 48,209,108, 2,150,171,150,196,225,244,225,236,233, 250,225,244,233,239,238,227,249,242,233,236,236,233,227,227,237, 98,128, 4,132,239,227,232,235,225,227,249,242,233,236,236,233, 99,128, 4,192,238,243,233,239,243,235,239,242,229,225,110,128, 49,127,114, 3,150,234,150,255,151,227, 97, 2,150,240,150,248, 231,242,225,240,104,128, 0,182,236,236,229,108,128, 34, 37,229, 110, 2,151, 6,151,116,236,229,230,116,136, 0, 40,151, 29,151, 44,151, 49,151, 54,151, 65,151, 77,151,100,151,105,225,236,244, 239,238,229,225,242,225,226,233, 99,128,253, 62,226,116,128,248, 237,229,120,128,248,236,233,238,230,229,242,233,239,114,128, 32, 141,237,239,238,239,243,240,225,227,101,128,255, 8,115, 2,151, 83,151, 90,237,225,236,108,128,254, 89,245,240,229,242,233,239, 114,128, 32,125,244,112,128,248,235,246,229,242,244,233,227,225, 108,128,254, 53,242,233,231,232,116,136, 0, 41,151,140,151,155, 151,160,151,165,151,176,151,188,151,211,151,216,225,236,244,239, 238,229,225,242,225,226,233, 99,128,253, 63,226,116,128,248,248, 229,120,128,248,247,233,238,230,229,242,233,239,114,128, 32,142, 237,239,238,239,243,240,225,227,101,128,255, 9,115, 2,151,194, 151,201,237,225,236,108,128,254, 90,245,240,229,242,233,239,114, 128, 32,126,244,112,128,248,246,246,229,242,244,233,227,225,108, 128,254, 54,244,233,225,236,228,233,230,102,128, 34, 2,115, 3, 151,246,152, 1,152, 13,229,241,232,229,226,242,229,119,128, 5, 192,232,244,225,232,229,226,242,229,119,128, 5,153,241,245,225, 242,101,128, 51,169,244,225,104,134, 5,183,152, 39,152, 53,152, 58,152, 67,152, 82,152, 98, 49, 2,152, 45,152, 49, 49,128, 5, 183,100,128, 5,183,178, 97,128, 5,183,232,229,226,242,229,119, 128, 5,183,238,225,242,242,239,247,232,229,226,242,229,119,128, 5,183,241,245,225,242,244,229,242,232,229,226,242,229,119,128, 5,183,247,233,228,229,232,229,226,242,229,119,128, 5,183,250, 229,242,232,229,226,242,229,119,128, 5,161,226,239,240,239,237, 239,230,111,128, 49, 6,227,233,242,227,236,101,128, 36,223,228, 239,244,225,227,227,229,238,116,128, 30, 87,101,137, 5,228,152, 177,152,188,152,208,152,220,152,240,153, 86,153, 97,153,118,154, 73,227,249,242,233,236,236,233, 99,128, 4, 63,228,225,231,229, 243,104,129,251, 68,152,199,232,229,226,242,229,119,128,251, 68, 229,250,233,243,241,245,225,242,101,128, 51, 59,230,233,238,225, 236,228,225,231,229,243,232,232,229,226,242,229,119,128,251, 67, 104, 5,152,252,153, 19,153, 27,153, 41,153, 71,225,114, 2,153, 3,153, 10,225,226,233, 99,128, 6,126,237,229,238,233,225,110, 128, 5,122,229,226,242,229,119,128, 5,228,230,233,238,225,236, 225,242,225,226,233, 99,128,251, 87,105, 2,153, 47,153, 62,238, 233,244,233,225,236,225,242,225,226,233, 99,128,251, 88,242,225, 231,225,238, 97,128, 48,122,237,229,228,233,225,236,225,242,225, 226,233, 99,128,251, 89,235,225,244,225,235,225,238, 97,128, 48, 218,237,233,228,228,236,229,232,239,239,235,227,249,242,233,236, 236,233, 99,128, 4,167,114, 5,153,130,153,142,153,184,154, 49, 154, 62,225,230,229,232,229,226,242,229,119,128,251, 78,227,229, 238,116,131, 0, 37,153,155,153,164,153,176,225,242,225,226,233, 99,128, 6,106,237,239,238,239,243,240,225,227,101,128,255, 5, 243,237,225,236,108,128,254,106,105, 2,153,190,154, 31,239,100, 134, 0, 46,153,207,153,218,153,229,153,241,153,252,154, 8,225, 242,237,229,238,233,225,110,128, 5,137,227,229,238,244,229,242, 229,100,128, 0,183,232,225,236,230,247,233,228,244,104,128,255, 97,233,238,230,229,242,233,239,114,128,246,231,237,239,238,239, 243,240,225,227,101,128,255, 14,115, 2,154, 14,154, 21,237,225, 236,108,128,254, 82,245,240,229,242,233,239,114,128,246,232,243, 240,239,237,229,238,233,231,242,229,229,235,227,237, 98,128, 3, 66,240,229,238,228,233,227,245,236,225,114,128, 34,165,244,232, 239,245,243,225,238,100,128, 32, 48,243,229,244, 97,128, 32,167, 230,243,241,245,225,242,101,128, 51,138,104, 3,154, 98,154,148, 155, 29, 97, 3,154,106,154,116,154,123,226,229,238,231,225,236, 105,128, 9,171,228,229,246, 97,128, 9, 43,231,117, 2,154,130, 154,139,234,225,242,225,244,105,128, 10,171,242,237,245,235,232, 105,128, 10, 43,105,133, 3,198,154,162,154,166,154,252,155, 4, 155, 15, 49,128, 3,213,229,245,240,104, 4,154,179,154,214,154, 229,154,238, 97, 2,154,185,154,200,227,233,242,227,236,229,235, 239,242,229,225,110,128, 50,122,240,225,242,229,238,235,239,242, 229,225,110,128, 50, 26,227,233,242,227,236,229,235,239,242,229, 225,110,128, 50,108,235,239,242,229,225,110,128, 49, 77,240,225, 242,229,238,235,239,242,229,225,110,128, 50, 12,236,225,244,233, 110,128, 2,120,238,244,232,245,244,232,225,105,128, 14, 58,243, 249,237,226,239,236,231,242,229,229,107,128, 3,213,111, 3,155, 37,155, 42,155, 68,239,107,128, 1,165,240,104, 2,155, 49,155, 58,225,238,244,232,225,105,128, 14, 30,245,238,231,244,232,225, 105,128, 14, 28,243,225,237,240,232,225,239,244,232,225,105,128, 14, 32,105,133, 3,192,155, 96,156, 52,156, 63,156, 74,156, 88, 229,245,112, 6,155,112,155,147,155,179,155,207,155,221,156, 17, 97, 2,155,118,155,133,227,233,242,227,236,229,235,239,242,229, 225,110,128, 50,115,240,225,242,229,238,235,239,242,229,225,110, 128, 50, 19,227,105, 2,155,154,155,166,229,245,227,235,239,242, 229,225,110,128, 49,118,242,227,236,229,235,239,242,229,225,110, 128, 50,101,107, 2,155,185,155,199,233,249,229,239,235,235,239, 242,229,225,110,128, 49,114,239,242,229,225,110,128, 49, 66,240, 225,242,229,238,235,239,242,229,225,110,128, 50, 5,243,233,239, 115, 2,155,230,156, 2,107, 2,155,236,155,250,233,249,229,239, 235,235,239,242,229,225,110,128, 49,116,239,242,229,225,110,128, 49, 68,244,233,235,229,245,244,235,239,242,229,225,110,128, 49, 117,116, 2,156, 23,156, 38,232,233,229,245,244,232,235,239,242, 229,225,110,128, 49,119,233,235,229,245,244,235,239,242,229,225, 110,128, 49,115,232,233,242,225,231,225,238, 97,128, 48,116,235, 225,244,225,235,225,238, 97,128, 48,212,243,249,237,226,239,236, 231,242,229,229,107,128, 3,214,247,242,225,242,237,229,238,233, 225,110,128, 5,131,236,245,115,132, 0, 43,156,115,156,126,156, 135,156,168,226,229,236,239,247,227,237, 98,128, 3, 31,227,233, 242,227,236,101,128, 34,149,109, 2,156,141,156,148,233,238,245, 115,128, 0,177,111, 2,156,154,156,158,100,128, 2,214,238,239, 243,240,225,227,101,128,255, 11,115, 2,156,174,156,181,237,225, 236,108,128,254, 98,245,240,229,242,233,239,114,128, 32,122,109, 2,156,197,156,208,239,238,239,243,240,225,227,101,128,255, 80, 243,241,245,225,242,101,128, 51,216,111, 5,156,229,156,240,157, 51,157, 62,157, 72,232,233,242,225,231,225,238, 97,128, 48,125, 233,238,244,233,238,231,233,238,228,229,120, 4,157, 4,157, 16, 157, 28,157, 41,228,239,247,238,247,232,233,244,101,128, 38, 31, 236,229,230,244,247,232,233,244,101,128, 38, 28,242,233,231,232, 244,247,232,233,244,101,128, 38, 30,245,240,247,232,233,244,101, 128, 38, 29,235,225,244,225,235,225,238, 97,128, 48,221,240,236, 225,244,232,225,105,128, 14, 27,243,244,225,236,237,225,242,107, 129, 48, 18,157, 85,230,225,227,101,128, 48, 32,240,225,242,229, 110,128, 36,171,114, 3,157,108,157,134,157,159,101, 2,157,114, 157,122,227,229,228,229,115,128, 34,122,243,227,242,233,240,244, 233,239,110,128, 33, 30,233,237,101, 2,157,142,157,148,237,239, 100,128, 2,185,242,229,246,229,242,243,229,100,128, 32, 53,111, 4,157,169,157,176,157,186,157,199,228,245,227,116,128, 34, 15, 234,229,227,244,233,246,101,128, 35, 5,236,239,238,231,229,228, 235,225,238, 97,128, 48,252,112, 2,157,205,157,242,101, 2,157, 211,157,218,236,236,239,114,128, 35, 24,242,243,117, 2,157,226, 157,233,226,243,229,116,128, 34,130,240,229,242,243,229,116,128, 34,131,239,242,244,233,239,110,129, 34, 55,157,253,225,108,128, 34, 29,115, 2,158, 8,158, 51,105,130, 3,200,158, 16,158, 27, 227,249,242,233,236,236,233, 99,128, 4,113,236,233,240,238,229, 245,237,225,244,225,227,249,242,233,236,236,233,227,227,237, 98, 128, 4,134,243,241,245,225,242,101,128, 51,176,117, 2,158, 66, 158, 77,232,233,242,225,231,225,238, 97,128, 48,119,235,225,244, 225,235,225,238, 97,128, 48,215,246,243,241,245,225,242,101,128, 51,180,247,243,241,245,225,242,101,128, 51,186,113,136, 0,113, 158,128,159,177,159,188,159,197,159,204,159,216,159,254,160, 6, 97, 4,158,138,158,161,158,225,159,160,100, 2,158,144,158,150, 229,246, 97,128, 9, 88,237,225,232,229,226,242,229,119,128, 5, 168,102, 4,158,171,158,180,158,194,158,210,225,242,225,226,233, 99,128, 6, 66,230,233,238,225,236,225,242,225,226,233, 99,128, 254,214,233,238,233,244,233,225,236,225,242,225,226,233, 99,128, 254,215,237,229,228,233,225,236,225,242,225,226,233, 99,128,254, 216,237,225,244,115,136, 5,184,158,248,159, 12,159, 26,159, 31, 159, 36,159, 45,159, 60,159,147, 49, 3,159, 0,159, 4,159, 8, 48,128, 5,184, 97,128, 5,184, 99,128, 5,184, 50, 2,159, 18, 159, 22, 55,128, 5,184, 57,128, 5,184,179, 51,128, 5,184,228, 101,128, 5,184,232,229,226,242,229,119,128, 5,184,238,225,242, 242,239,247,232,229,226,242,229,119,128, 5,184,113, 2,159, 66, 159,132,225,244,225,110, 4,159, 79,159, 88,159,103,159,119,232, 229,226,242,229,119,128, 5,184,238,225,242,242,239,247,232,229, 226,242,229,119,128, 5,184,241,245,225,242,244,229,242,232,229, 226,242,229,119,128, 5,184,247,233,228,229,232,229,226,242,229, 119,128, 5,184,245,225,242,244,229,242,232,229,226,242,229,119, 128, 5,184,247,233,228,229,232,229,226,242,229,119,128, 5,184, 242,238,229,249,240,225,242,225,232,229,226,242,229,119,128, 5, 159,226,239,240,239,237,239,230,111,128, 49, 17,227,233,242,227, 236,101,128, 36,224,232,239,239,107,128, 2,160,237,239,238,239, 243,240,225,227,101,128,255, 81,239,102,130, 5,231,159,225,159, 245,228,225,231,229,243,104,129,251, 71,159,236,232,229,226,242, 229,119,128,251, 71,232,229,226,242,229,119,128, 5,231,240,225, 242,229,110,128, 36,172,117, 4,160, 16,160, 28,160,117,160,204, 225,242,244,229,242,238,239,244,101,128, 38,105,226,245,244,115, 135, 5,187,160, 49,160, 54,160, 59,160, 64,160, 73,160, 88,160, 104,177, 56,128, 5,187,178, 53,128, 5,187,179, 49,128, 5,187, 232,229,226,242,229,119,128, 5,187,238,225,242,242,239,247,232, 229,226,242,229,119,128, 5,187,241,245,225,242,244,229,242,232, 229,226,242,229,119,128, 5,187,247,233,228,229,232,229,226,242, 229,119,128, 5,187,229,243,244,233,239,110,133, 0, 63,160,136, 160,159,160,176,160,184,160,196,225,114, 2,160,143,160,150,225, 226,233, 99,128, 6, 31,237,229,238,233,225,110,128, 5, 94,228, 239,247,110,129, 0,191,160,168,243,237,225,236,108,128,247,191, 231,242,229,229,107,128, 3,126,237,239,238,239,243,240,225,227, 101,128,255, 31,243,237,225,236,108,128,247, 63,239,244,101, 4, 160,216,161, 31,161, 51,161, 80,228,226,108,133, 0, 34,160,232, 160,239,160,246,161, 2,161, 23,226,225,243,101,128, 32, 30,236, 229,230,116,128, 32, 28,237,239,238,239,243,240,225,227,101,128, 255, 2,240,242,233,237,101,129, 48, 30,161, 12,242,229,246,229, 242,243,229,100,128, 48, 29,242,233,231,232,116,128, 32, 29,236, 229,230,116,129, 32, 24,161, 40,242,229,246,229,242,243,229,100, 128, 32, 27,114, 2,161, 57,161, 67,229,246,229,242,243,229,100, 128, 32, 27,233,231,232,116,129, 32, 25,161, 76,110,128, 1, 73, 243,233,238,231,108, 2,161, 90,161, 97,226,225,243,101,128, 32, 26,101,129, 0, 39,161,103,237,239,238,239,243,240,225,227,101, 128,255, 7,114,145, 0,114,161,153,162,157,162,168,162,215,163, 10,164, 27,164, 51,164,146,166,180,166,217,166,229,167, 27,167, 35,167,197,167,208,167,243,168, 87, 97, 11,161,177,161,188,161, 198,161,205,162, 14,162, 30,162, 55,162, 66,162, 91,162,114,162, 151,225,242,237,229,238,233,225,110,128, 5,124,226,229,238,231, 225,236,105,128, 9,176,227,245,244,101,128, 1, 85,100, 4,161, 215,161,221,161,235,162, 5,229,246, 97,128, 9, 48,233,227,225, 108,129, 34, 26,161,230,229,120,128,248,229,239,246,229,242,243, 243,241,245,225,242,101,129, 51,174,161,251,228,243,241,245,225, 242,101,128, 51,175,243,241,245,225,242,101,128, 51,173,230,101, 129, 5,191,162, 21,232,229,226,242,229,119,128, 5,191,231,117, 2,162, 37,162, 46,234,225,242,225,244,105,128, 10,176,242,237, 245,235,232,105,128, 10, 48,232,233,242,225,231,225,238, 97,128, 48,137,235,225,244,225,235,225,238, 97,129, 48,233,162, 79,232, 225,236,230,247,233,228,244,104,128,255,151,236,239,247,229,242, 228,233,225,231,239,238,225,236,226,229,238,231,225,236,105,128, 9,241,109, 2,162,120,162,143,233,228,228,236,229,228,233,225, 231,239,238,225,236,226,229,238,231,225,236,105,128, 9,240,243, 232,239,242,110,128, 2,100,244,233,111,128, 34, 54,226,239,240, 239,237,239,230,111,128, 49, 22, 99, 4,162,178,162,185,162,194, 162,202,225,242,239,110,128, 1, 89,229,228,233,236,236, 97,128, 1, 87,233,242,227,236,101,128, 36,225,239,237,237,225,225,227, 227,229,238,116,128, 1, 87,100, 2,162,221,162,231,226,236,231, 242,225,246,101,128, 2, 17,239,116, 2,162,238,162,247,225,227, 227,229,238,116,128, 30, 89,226,229,236,239,119,129, 30, 91,163, 1,237,225,227,242,239,110,128, 30, 93,101, 6,163, 24,163, 69, 163,104,163,159,163,184,163,217,102, 2,163, 30,163, 43,229,242, 229,238,227,229,237,225,242,107,128, 32, 59,236,229,248,243,117, 2,163, 53,163, 60,226,243,229,116,128, 34,134,240,229,242,243, 229,116,128, 34,135,231,233,243,244,229,114, 2,163, 80,163, 85, 229,100,128, 0,174,115, 2,163, 91,163, 97,225,238,115,128,248, 232,229,242,233,102,128,246,218,104, 3,163,112,163,135,163,149, 225,114, 2,163,119,163,126,225,226,233, 99,128, 6, 49,237,229, 238,233,225,110,128, 5,128,230,233,238,225,236,225,242,225,226, 233, 99,128,254,174,233,242,225,231,225,238, 97,128, 48,140,235, 225,244,225,235,225,238, 97,129, 48,236,163,172,232,225,236,230, 247,233,228,244,104,128,255,154,243,104,130, 5,232,163,193,163, 208,228,225,231,229,243,232,232,229,226,242,229,119,128,251, 72, 232,229,226,242,229,119,128, 5,232,118, 3,163,225,163,238,164, 14,229,242,243,229,228,244,233,236,228,101,128, 34, 61,233, 97, 2,163,245,163,254,232,229,226,242,229,119,128, 5,151,237,245, 231,242,225,243,232,232,229,226,242,229,119,128, 5,151,236,239, 231,233,227,225,236,238,239,116,128, 35, 16,230,233,243,232,232, 239,239,107,129, 2,126,164, 40,242,229,246,229,242,243,229,100, 128, 2,127,104, 2,164, 57,164, 80, 97, 2,164, 63,164, 73,226, 229,238,231,225,236,105,128, 9,221,228,229,246, 97,128, 9, 93, 111,131, 3,193,164, 90,164,119,164,133,239,107,129, 2,125,164, 97,244,245,242,238,229,100,129, 2,123,164,108,243,245,240,229, 242,233,239,114,128, 2,181,243,249,237,226,239,236,231,242,229, 229,107,128, 3,241,244,233,227,232,239,239,235,237,239,100,128, 2,222,105, 6,164,160,165,204,165,250,166, 5,166, 30,166,166, 229,245,108, 9,164,182,164,217,164,232,164,246,165, 36,165, 50, 165,136,165,149,165,184, 97, 2,164,188,164,203,227,233,242,227, 236,229,235,239,242,229,225,110,128, 50,113,240,225,242,229,238, 235,239,242,229,225,110,128, 50, 17,227,233,242,227,236,229,235, 239,242,229,225,110,128, 50, 99,232,233,229,245,232,235,239,242, 229,225,110,128, 49, 64,107, 2,164,252,165, 28,233,249,229,239, 107, 2,165, 6,165, 15,235,239,242,229,225,110,128, 49, 58,243, 233,239,243,235,239,242,229,225,110,128, 49,105,239,242,229,225, 110,128, 49, 57,237,233,229,245,237,235,239,242,229,225,110,128, 49, 59,112, 3,165, 58,165, 90,165,105, 97, 2,165, 64,165, 78, 238,243,233,239,243,235,239,242,229,225,110,128, 49,108,242,229, 238,235,239,242,229,225,110,128, 50, 3,232,233,229,245,240,232, 235,239,242,229,225,110,128, 49, 63,233,229,245,112, 2,165,114, 165,123,235,239,242,229,225,110,128, 49, 60,243,233,239,243,235, 239,242,229,225,110,128, 49,107,243,233,239,243,235,239,242,229, 225,110,128, 49, 61,116, 2,165,155,165,170,232,233,229,245,244, 232,235,239,242,229,225,110,128, 49, 62,233,235,229,245,244,235, 239,242,229,225,110,128, 49,106,249,229,239,242,233,238,232,233, 229,245,232,235,239,242,229,225,110,128, 49,109,231,232,116, 2, 165,212,165,220,225,238,231,236,101,128, 34, 31,116, 2,165,226, 165,240,225,227,235,226,229,236,239,247,227,237, 98,128, 3, 25, 242,233,225,238,231,236,101,128, 34,191,232,233,242,225,231,225, 238, 97,128, 48,138,235,225,244,225,235,225,238, 97,129, 48,234, 166, 18,232,225,236,230,247,233,228,244,104,128,255,152,110, 2, 166, 36,166,152,103,131, 2,218,166, 46,166, 57,166, 63,226,229, 236,239,247,227,237, 98,128, 3, 37,227,237, 98,128, 3, 10,232, 225,236,102, 2,166, 72,166,118,236,229,230,116,131, 2,191,166, 85,166, 96,166,107,225,242,237,229,238,233,225,110,128, 5, 89, 226,229,236,239,247,227,237, 98,128, 3, 28,227,229,238,244,229, 242,229,100,128, 2,211,242,233,231,232,116,130, 2,190,166,130, 166,141,226,229,236,239,247,227,237, 98,128, 3, 57,227,229,238, 244,229,242,229,100,128, 2,210,246,229,242,244,229,228,226,242, 229,246,101,128, 2, 19,244,244,239,242,245,243,241,245,225,242, 101,128, 51, 81,108, 2,166,186,166,197,233,238,229,226,229,236, 239,119,128, 30, 95,239,238,231,236,229,103,129, 2,124,166,208, 244,245,242,238,229,100,128, 2,122,237,239,238,239,243,240,225, 227,101,128,255, 82,111, 3,166,237,166,248,167, 17,232,233,242, 225,231,225,238, 97,128, 48,141,235,225,244,225,235,225,238, 97, 129, 48,237,167, 5,232,225,236,230,247,233,228,244,104,128,255, 155,242,245,225,244,232,225,105,128, 14, 35,240,225,242,229,110, 128, 36,173,114, 3,167, 43,167, 79,167,109, 97, 3,167, 51,167, 61,167, 68,226,229,238,231,225,236,105,128, 9,220,228,229,246, 97,128, 9, 49,231,245,242,237,245,235,232,105,128, 10, 92,229, 104, 2,167, 86,167, 95,225,242,225,226,233, 99,128, 6,145,230, 233,238,225,236,225,242,225,226,233, 99,128,251,141,246,239,227, 225,236,233, 99, 4,167,125,167,135,167,142,167,153,226,229,238, 231,225,236,105,128, 9,224,228,229,246, 97,128, 9, 96,231,245, 234,225,242,225,244,105,128, 10,224,246,239,247,229,236,243,233, 231,110, 3,167,169,167,179,167,186,226,229,238,231,225,236,105, 128, 9,196,228,229,246, 97,128, 9, 68,231,245,234,225,242,225, 244,105,128, 10,196,243,245,240,229,242,233,239,114,128,246,241, 116, 2,167,214,167,222,226,236,239,227,107,128, 37,144,245,242, 238,229,100,129, 2,121,167,232,243,245,240,229,242,233,239,114, 128, 2,180,117, 4,167,253,168, 8,168, 33,168, 80,232,233,242, 225,231,225,238, 97,128, 48,139,235,225,244,225,235,225,238, 97, 129, 48,235,168, 21,232,225,236,230,247,233,228,244,104,128,255, 153,112, 2,168, 39,168, 74,229,101, 2,168, 46,168, 60,237,225, 242,235,226,229,238,231,225,236,105,128, 9,242,243,233,231,238, 226,229,238,231,225,236,105,128, 9,243,233,225,104,128,246,221, 244,232,225,105,128, 14, 36,246,239,227,225,236,233, 99, 4,168, 103,168,113,168,120,168,131,226,229,238,231,225,236,105,128, 9, 139,228,229,246, 97,128, 9, 11,231,245,234,225,242,225,244,105, 128, 10,139,246,239,247,229,236,243,233,231,110, 3,168,147,168, 157,168,164,226,229,238,231,225,236,105,128, 9,195,228,229,246, 97,128, 9, 67,231,245,234,225,242,225,244,105,128, 10,195,115, 147, 0,115,168,217,170,187,170,198,171, 68,171,107,174, 49,174, 60,176,203,179, 85,179,131,179,158,180, 93,180,160,181,193,181, 203,182,133,182,206,183,120,183,130, 97, 9,168,237,168,247,169, 12,169, 84,169,109,169,120,169,145,169,177,169,217,226,229,238, 231,225,236,105,128, 9,184,227,245,244,101,129, 1, 91,169, 0, 228,239,244,225,227,227,229,238,116,128, 30,101,100, 5,169, 24, 169, 33,169, 39,169, 53,169, 69,225,242,225,226,233, 99,128, 6, 53,229,246, 97,128, 9, 56,230,233,238,225,236,225,242,225,226, 233, 99,128,254,186,233,238,233,244,233,225,236,225,242,225,226, 233, 99,128,254,187,237,229,228,233,225,236,225,242,225,226,233, 99,128,254,188,231,117, 2,169, 91,169,100,234,225,242,225,244, 105,128, 10,184,242,237,245,235,232,105,128, 10, 56,232,233,242, 225,231,225,238, 97,128, 48, 85,235,225,244,225,235,225,238, 97, 129, 48,181,169,133,232,225,236,230,247,233,228,244,104,128,255, 123,236,236,225,236,236,225,232,239,245,225,236,225,249,232,229, 247,225,243,225,236,236,225,237,225,242,225,226,233, 99,128,253, 250,237,229,235,104,130, 5,225,169,188,169,208,228,225,231,229, 243,104,129,251, 65,169,199,232,229,226,242,229,119,128,251, 65, 232,229,226,242,229,119,128, 5,225,242, 97, 5,169,230,170, 48, 170, 56,170,106,170,114, 97, 5,169,242,169,250,170, 2,170, 33, 170, 41,225,244,232,225,105,128, 14, 50,229,244,232,225,105,128, 14, 65,233,237,225,233,109, 2,170, 12,170, 23,225,236,225,233, 244,232,225,105,128, 14, 68,245,225,238,244,232,225,105,128, 14, 67,237,244,232,225,105,128, 14, 51,244,232,225,105,128, 14, 48, 229,244,232,225,105,128, 14, 64,105, 3,170, 64,170, 88,170, 99, 105, 2,170, 70,170, 81,236,229,230,244,244,232,225,105,128,248, 134,244,232,225,105,128, 14, 53,236,229,230,244,244,232,225,105, 128,248,133,244,232,225,105,128, 14, 52,239,244,232,225,105,128, 14, 66,117, 3,170,122,170,172,170,179,101, 3,170,130,170,154, 170,165,101, 2,170,136,170,147,236,229,230,244,244,232,225,105, 128,248,136,244,232,225,105,128, 14, 55,236,229,230,244,244,232, 225,105,128,248,135,244,232,225,105,128, 14, 54,244,232,225,105, 128, 14, 56,245,244,232,225,105,128, 14, 57,226,239,240,239,237, 239,230,111,128, 49, 25, 99, 5,170,210,170,231,170,240,171, 33, 171, 55,225,242,239,110,129, 1, 97,170,219,228,239,244,225,227, 227,229,238,116,128, 30,103,229,228,233,236,236, 97,128, 1, 95, 232,247, 97,131, 2, 89,170,252,171, 7,171, 26,227,249,242,233, 236,236,233, 99,128, 4,217,228,233,229,242,229,243,233,243,227, 249,242,233,236,236,233, 99,128, 4,219,232,239,239,107,128, 2, 90,233,242, 99, 2,171, 41,171, 46,236,101,128, 36,226,245,237, 230,236,229,120,128, 1, 93,239,237,237,225,225,227,227,229,238, 116,128, 2, 25,228,239,116, 2,171, 76,171, 85,225,227,227,229, 238,116,128, 30, 97,226,229,236,239,119,129, 30, 99,171, 95,228, 239,244,225,227,227,229,238,116,128, 30,105,101, 9,171,127,171, 143,171,178,171,243,172, 90,172,117,172,142,172,223,172,250,225, 231,245,236,236,226,229,236,239,247,227,237, 98,128, 3, 60, 99, 2,171,149,171,171,239,238,100,129, 32, 51,171,157,244,239,238, 229,227,232,233,238,229,243,101,128, 2,202,244,233,239,110,128, 0,167,229,110, 4,171,189,171,198,171,212,171,228,225,242,225, 226,233, 99,128, 6, 51,230,233,238,225,236,225,242,225,226,233, 99,128,254,178,233,238,233,244,233,225,236,225,242,225,226,233, 99,128,254,179,237,229,228,233,225,236,225,242,225,226,233, 99, 128,254,180,231,239,108,135, 5,182,172, 7,172, 21,172, 26,172, 35,172, 50,172, 66,172, 77, 49, 2,172, 13,172, 17, 51,128, 5, 182,102,128, 5,182,178, 99,128, 5,182,232,229,226,242,229,119, 128, 5,182,238,225,242,242,239,247,232,229,226,242,229,119,128, 5,182,241,245,225,242,244,229,242,232,229,226,242,229,119,128, 5,182,244,225,232,229,226,242,229,119,128, 5,146,247,233,228, 229,232,229,226,242,229,119,128, 5,182,104, 2,172, 96,172,107, 225,242,237,229,238,233,225,110,128, 5,125,233,242,225,231,225, 238, 97,128, 48, 91,235,225,244,225,235,225,238, 97,129, 48,187, 172,130,232,225,236,230,247,233,228,244,104,128,255,126,237,105, 2,172,149,172,192,227,239,236,239,110,131, 0, 59,172,163,172, 172,172,184,225,242,225,226,233, 99,128, 6, 27,237,239,238,239, 243,240,225,227,101,128,255, 27,243,237,225,236,108,128,254, 84, 246,239,233,227,229,228,237,225,242,235,235,225,238, 97,129, 48, 156,172,211,232,225,236,230,247,233,228,244,104,128,255,159,238, 116, 2,172,230,172,240,233,243,241,245,225,242,101,128, 51, 34, 239,243,241,245,225,242,101,128, 51, 35,246,229,110,142, 0, 55, 173, 28,173, 37,173, 47,173, 77,173, 84,173, 94,173,119,173,146, 173,180,173,192,173,203,173,236,173,244,173,255,225,242,225,226, 233, 99,128, 6,103,226,229,238,231,225,236,105,128, 9,237,227, 233,242,227,236,101,129, 36,102,173, 58,233,238,246,229,242,243, 229,243,225,238,243,243,229,242,233,102,128, 39,144,228,229,246, 97,128, 9,109,229,233,231,232,244,232,115,128, 33, 94,231,117, 2,173,101,173,110,234,225,242,225,244,105,128, 10,237,242,237, 245,235,232,105,128, 10,109,232, 97, 2,173,126,173,137,227,235, 225,242,225,226,233, 99,128, 6,103,238,231,250,232,239,117,128, 48, 39,105, 2,173,152,173,170,228,229,239,231,242,225,240,232, 233,227,240,225,242,229,110,128, 50, 38,238,230,229,242,233,239, 114,128, 32,135,237,239,238,239,243,240,225,227,101,128,255, 23, 239,236,228,243,244,249,236,101,128,247, 55,112, 2,173,209,173, 216,225,242,229,110,128, 36,122,229,114, 2,173,223,173,229,233, 239,100,128, 36,142,243,233,225,110,128, 6,247,242,239,237,225, 110,128, 33,118,243,245,240,229,242,233,239,114,128, 32,119,116, 2,174, 5,174, 43,229,229,110, 2,174, 13,174, 22,227,233,242, 227,236,101,128, 36,112,112, 2,174, 28,174, 35,225,242,229,110, 128, 36,132,229,242,233,239,100,128, 36,152,232,225,105,128, 14, 87,230,244,232,249,240,232,229,110,128, 0,173,104, 7,174, 76, 175, 50,175, 61,175, 75,176, 20,176, 33,176,197, 97, 6,174, 90, 174,101,174,111,174,122,175, 9,175, 34,225,242,237,229,238,233, 225,110,128, 5,119,226,229,238,231,225,236,105,128, 9,182,227, 249,242,233,236,236,233, 99,128, 4, 72,100, 2,174,128,174,224, 228, 97, 4,174,139,174,148,174,179,174,193,225,242,225,226,233, 99,128, 6, 81,228,225,237,237, 97, 2,174,158,174,167,225,242, 225,226,233, 99,128,252, 97,244,225,238,225,242,225,226,233, 99, 128,252, 94,230,225,244,232,225,225,242,225,226,233, 99,128,252, 96,235,225,243,242, 97, 2,174,203,174,212,225,242,225,226,233, 99,128,252, 98,244,225,238,225,242,225,226,233, 99,128,252, 95, 101,132, 37,146,174,236,174,243,174,251,175, 4,228,225,242,107, 128, 37,147,236,233,231,232,116,128, 37,145,237,229,228,233,245, 109,128, 37,146,246, 97,128, 9, 54,231,117, 2,175, 16,175, 25, 234,225,242,225,244,105,128, 10,182,242,237,245,235,232,105,128, 10, 54,236,243,232,229,236,229,244,232,229,226,242,229,119,128, 5,147,226,239,240,239,237,239,230,111,128, 49, 21,227,232,225, 227,249,242,233,236,236,233, 99,128, 4, 73,101, 4,175, 85,175, 150,175,160,175,177,229,110, 4,175, 96,175,105,175,119,175,135, 225,242,225,226,233, 99,128, 6, 52,230,233,238,225,236,225,242, 225,226,233, 99,128,254,182,233,238,233,244,233,225,236,225,242, 225,226,233, 99,128,254,183,237,229,228,233,225,236,225,242,225, 226,233, 99,128,254,184,233,227,239,240,244,233, 99,128, 3,227, 241,229,108,129, 32,170,175,168,232,229,226,242,229,119,128, 32, 170,246, 97,134, 5,176,175,194,175,209,175,223,175,232,175,247, 176, 7, 49, 2,175,200,175,205,177, 53,128, 5,176, 53,128, 5, 176, 50, 2,175,215,175,219, 50,128, 5,176,101,128, 5,176,232, 229,226,242,229,119,128, 5,176,238,225,242,242,239,247,232,229, 226,242,229,119,128, 5,176,241,245,225,242,244,229,242,232,229, 226,242,229,119,128, 5,176,247,233,228,229,232,229,226,242,229, 119,128, 5,176,232,225,227,249,242,233,236,236,233, 99,128, 4, 187,105, 2,176, 39,176, 50,237,225,227,239,240,244,233, 99,128, 3,237,110,131, 5,233,176, 60,176,143,176,152,100, 2,176, 66, 176,132,225,231,229,243,104,130,251, 73,176, 78,176, 87,232,229, 226,242,229,119,128,251, 73,115, 2,176, 93,176,113,232,233,238, 228,239,116,129,251, 44,176,104,232,229,226,242,229,119,128,251, 44,233,238,228,239,116,129,251, 45,176,123,232,229,226,242,229, 119,128,251, 45,239,244,232,229,226,242,229,119,128, 5,193,232, 229,226,242,229,119,128, 5,233,115, 2,176,158,176,178,232,233, 238,228,239,116,129,251, 42,176,169,232,229,226,242,229,119,128, 251, 42,233,238,228,239,116,129,251, 43,176,188,232,229,226,242, 229,119,128,251, 43,239,239,107,128, 2,130,105, 8,176,221,177, 9,177, 20,177, 45,177, 75,177, 83,177, 96,178, 11,231,237, 97, 131, 3,195,176,233,176,237,176,245, 49,128, 3,194,230,233,238, 225,108,128, 3,194,236,245,238,225,244,229,243,249,237,226,239, 236,231,242,229,229,107,128, 3,242,232,233,242,225,231,225,238, 97,128, 48, 87,235,225,244,225,235,225,238, 97,129, 48,183,177, 33,232,225,236,230,247,233,228,244,104,128,255,124,236,245,113, 2,177, 53,177, 62,232,229,226,242,229,119,128, 5,189,236,229, 230,244,232,229,226,242,229,119,128, 5,189,237,233,236,225,114, 128, 34, 60,238,228,239,244,232,229,226,242,229,119,128, 5,194, 239,115, 6,177,111,177,146,177,178,177,206,177,220,177,252, 97, 2,177,117,177,132,227,233,242,227,236,229,235,239,242,229,225, 110,128, 50,116,240,225,242,229,238,235,239,242,229,225,110,128, 50, 20,227,105, 2,177,153,177,165,229,245,227,235,239,242,229, 225,110,128, 49,126,242,227,236,229,235,239,242,229,225,110,128, 50,102,107, 2,177,184,177,198,233,249,229,239,235,235,239,242, 229,225,110,128, 49,122,239,242,229,225,110,128, 49, 69,238,233, 229,245,238,235,239,242,229,225,110,128, 49,123,112, 2,177,226, 177,239,225,242,229,238,235,239,242,229,225,110,128, 50, 6,233, 229,245,240,235,239,242,229,225,110,128, 49,125,244,233,235,229, 245,244,235,239,242,229,225,110,128, 49,124,120,141, 0, 54,178, 41,178, 50,178, 60,178, 90,178, 97,178,122,178,149,178,183,178, 195,178,206,178,239,178,247,179, 2,225,242,225,226,233, 99,128, 6,102,226,229,238,231,225,236,105,128, 9,236,227,233,242,227, 236,101,129, 36,101,178, 71,233,238,246,229,242,243,229,243,225, 238,243,243,229,242,233,102,128, 39,143,228,229,246, 97,128, 9, 108,231,117, 2,178,104,178,113,234,225,242,225,244,105,128, 10, 236,242,237,245,235,232,105,128, 10,108,232, 97, 2,178,129,178, 140,227,235,225,242,225,226,233, 99,128, 6,102,238,231,250,232, 239,117,128, 48, 38,105, 2,178,155,178,173,228,229,239,231,242, 225,240,232,233,227,240,225,242,229,110,128, 50, 37,238,230,229, 242,233,239,114,128, 32,134,237,239,238,239,243,240,225,227,101, 128,255, 22,239,236,228,243,244,249,236,101,128,247, 54,112, 2, 178,212,178,219,225,242,229,110,128, 36,121,229,114, 2,178,226, 178,232,233,239,100,128, 36,141,243,233,225,110,128, 6,246,242, 239,237,225,110,128, 33,117,243,245,240,229,242,233,239,114,128, 32,118,116, 2,179, 8,179, 79,229,229,110, 2,179, 16,179, 58, 99, 2,179, 22,179, 30,233,242,227,236,101,128, 36,111,245,242, 242,229,238,227,249,228,229,238,239,237,233,238,225,244,239,242, 226,229,238,231,225,236,105,128, 9,249,112, 2,179, 64,179, 71, 225,242,229,110,128, 36,131,229,242,233,239,100,128, 36,151,232, 225,105,128, 14, 86,108, 2,179, 91,179,111,225,243,104,129, 0, 47,179, 99,237,239,238,239,243,240,225,227,101,128,255, 15,239, 238,103,129, 1,127,179,119,228,239,244,225,227,227,229,238,116, 128, 30,155,109, 2,179,137,179,147,233,236,229,230,225,227,101, 128, 38, 58,239,238,239,243,240,225,227,101,128,255, 83,111, 6, 179,172,179,222,179,233,180, 2,180, 47,180, 58,102, 2,179,178, 179,192,240,225,243,245,241,232,229,226,242,229,119,128, 5,195, 116, 2,179,198,179,207,232,249,240,232,229,110,128, 0,173,243, 233,231,238,227,249,242,233,236,236,233, 99,128, 4, 76,232,233, 242,225,231,225,238, 97,128, 48, 93,235,225,244,225,235,225,238, 97,129, 48,189,179,246,232,225,236,230,247,233,228,244,104,128, 255,127,236,233,228,245,115, 2,180, 12,180, 29,236,239,238,231, 239,246,229,242,236,225,249,227,237, 98,128, 3, 56,243,232,239, 242,244,239,246,229,242,236,225,249,227,237, 98,128, 3, 55,242, 245,243,233,244,232,225,105,128, 14, 41,115, 3,180, 66,180, 76, 180, 84,225,236,225,244,232,225,105,128, 14, 40,239,244,232,225, 105,128, 14, 11,245,225,244,232,225,105,128, 14, 42,240, 97, 3, 180,102,180,122,180,154,227,101,129, 0, 32,180,109,232,225,227, 235,225,242,225,226,233, 99,128, 0, 32,228,101,129, 38, 96,180, 129,243,245,233,116, 2,180,138,180,146,226,236,225,227,107,128, 38, 96,247,232,233,244,101,128, 38,100,242,229,110,128, 36,174, 241,245,225,242,101, 11,180,188,180,199,180,213,180,238,180,255, 181, 25,181, 40,181, 73,181,100,181,156,181,171,226,229,236,239, 247,227,237, 98,128, 3, 59, 99, 2,180,205,180,209, 99,128, 51, 196,109,128, 51,157,228,233,225,231,239,238,225,236,227,242,239, 243,243,232,225,244,227,232,230,233,236,108,128, 37,169,232,239, 242,233,250,239,238,244,225,236,230,233,236,108,128, 37,164,107, 2,181, 5,181, 9,103,128, 51,143,109,129, 51,158,181, 15,227, 225,240,233,244,225,108,128, 51,206,108, 2,181, 31,181, 35,110, 128, 51,209,239,103,128, 51,210,109, 4,181, 50,181, 54,181, 59, 181, 63,103,128, 51,142,233,108,128, 51,213,109,128, 51,156,243, 241,245,225,242,229,100,128, 51,161,239,242,244,232,239,231,239, 238,225,236,227,242,239,243,243,232,225,244,227,232,230,233,236, 108,128, 37,166,245,240,240,229,114, 2,181,110,181,133,236,229, 230,244,244,239,236,239,247,229,242,242,233,231,232,244,230,233, 236,108,128, 37,167,242,233,231,232,244,244,239,236,239,247,229, 242,236,229,230,244,230,233,236,108,128, 37,168,246,229,242,244, 233,227,225,236,230,233,236,108,128, 37,165,247,232,233,244,229, 247,233,244,232,243,237,225,236,236,226,236,225,227,107,128, 37, 163,242,243,241,245,225,242,101,128, 51,219,115, 2,181,209,182, 123, 97, 4,181,219,181,229,181,236,181,247,226,229,238,231,225, 236,105,128, 9,183,228,229,246, 97,128, 9, 55,231,245,234,225, 242,225,244,105,128, 10,183,238,103, 8,182, 10,182, 24,182, 38, 182, 52,182, 67,182, 81,182, 95,182,108,227,233,229,245,227,235, 239,242,229,225,110,128, 49, 73,232,233,229,245,232,235,239,242, 229,225,110,128, 49,133,233,229,245,238,231,235,239,242,229,225, 110,128, 49,128,235,233,249,229,239,235,235,239,242,229,225,110, 128, 49, 50,238,233,229,245,238,235,239,242,229,225,110,128, 49, 101,240,233,229,245,240,235,239,242,229,225,110,128, 49, 67,243, 233,239,243,235,239,242,229,225,110,128, 49, 70,244,233,235,229, 245,244,235,239,242,229,225,110,128, 49, 56,245,240,229,242,233, 239,114,128,246,242,116, 2,182,139,182,162,229,242,236,233,238, 103,129, 0,163,182,150,237,239,238,239,243,240,225,227,101,128, 255,225,242,239,235,101, 2,182,171,182,188,236,239,238,231,239, 246,229,242,236,225,249,227,237, 98,128, 3, 54,243,232,239,242, 244,239,246,229,242,236,225,249,227,237, 98,128, 3, 53,117, 7, 182,222,182,254,183, 20,183, 31,183, 72,183, 82,183, 86,226,243, 229,116,130, 34,130,182,233,182,244,238,239,244,229,241,245,225, 108,128, 34,138,239,242,229,241,245,225,108,128, 34,134, 99, 2, 183, 4,183, 12,227,229,229,228,115,128, 34,123,232,244,232,225, 116,128, 34, 11,232,233,242,225,231,225,238, 97,128, 48, 89,107, 2,183, 37,183, 61,225,244,225,235,225,238, 97,129, 48,185,183, 49,232,225,236,230,247,233,228,244,104,128,255,125,245,238,225, 242,225,226,233, 99,128, 6, 82,237,237,225,244,233,239,110,128, 34, 17,110,128, 38, 60,240,229,242,243,229,116,130, 34,131,183, 99,183,110,238,239,244,229,241,245,225,108,128, 34,139,239,242, 229,241,245,225,108,128, 34,135,246,243,241,245,225,242,101,128, 51,220,249,239,245,247,225,229,242,225,243,241,245,225,242,101, 128, 51,124,116,144, 0,116,183,183,184,192,184,213,185,100,185, 140,187,188,191, 70,192,145,192,157,192,169,193,202,193,227,194, 57,194,237,195,165,195,255, 97, 10,183,205,183,215,183,236,183, 243,184, 12,184, 90,184,107,184,132,184,146,184,150,226,229,238, 231,225,236,105,128, 9,164,227,107, 2,183,222,183,229,228,239, 247,110,128, 34,164,236,229,230,116,128, 34,163,228,229,246, 97, 128, 9, 36,231,117, 2,183,250,184, 3,234,225,242,225,244,105, 128, 10,164,242,237,245,235,232,105,128, 10, 36,104, 4,184, 22, 184, 31,184, 45,184, 75,225,242,225,226,233, 99,128, 6, 55,230, 233,238,225,236,225,242,225,226,233, 99,128,254,194,105, 2,184, 51,184, 66,238,233,244,233,225,236,225,242,225,226,233, 99,128, 254,195,242,225,231,225,238, 97,128, 48, 95,237,229,228,233,225, 236,225,242,225,226,233, 99,128,254,196,233,243,249,239,245,229, 242,225,243,241,245,225,242,101,128, 51,125,235,225,244,225,235, 225,238, 97,129, 48,191,184,120,232,225,236,230,247,233,228,244, 104,128,255,128,244,247,229,229,236,225,242,225,226,233, 99,128, 6, 64,117,128, 3,196,118,130, 5,234,184,158,184,183,228,225, 231,229,115,129,251, 74,184,168,104,129,251, 74,184,174,232,229, 226,242,229,119,128,251, 74,232,229,226,242,229,119,128, 5,234, 98, 2,184,198,184,203,225,114,128, 1,103,239,240,239,237,239, 230,111,128, 49, 10, 99, 6,184,227,184,234,184,241,184,250,185, 60,185, 87,225,242,239,110,128, 1,101,227,245,242,108,128, 2, 168,229,228,233,236,236, 97,128, 1, 99,232,229,104, 4,185, 6, 185, 15,185, 29,185, 45,225,242,225,226,233, 99,128, 6,134,230, 233,238,225,236,225,242,225,226,233, 99,128,251,123,233,238,233, 244,233,225,236,225,242,225,226,233, 99,128,251,124,237,229,228, 233,225,236,225,242,225,226,233, 99,128,251,125,233,242, 99, 2, 185, 68,185, 73,236,101,128, 36,227,245,237,230,236,229,248,226, 229,236,239,119,128, 30,113,239,237,237,225,225,227,227,229,238, 116,128, 1, 99,100, 2,185,106,185,116,233,229,242,229,243,233, 115,128, 30,151,239,116, 2,185,123,185,132,225,227,227,229,238, 116,128, 30,107,226,229,236,239,119,128, 30,109,101, 9,185,160, 185,171,185,191,186,201,186,226,187, 34,187,101,187,106,187,158, 227,249,242,233,236,236,233, 99,128, 4, 66,228,229,243,227,229, 238,228,229,242,227,249,242,233,236,236,233, 99,128, 4,173,104, 7,185,207,185,216,185,230,186, 14,186, 44,186, 85,186,183,225, 242,225,226,233, 99,128, 6, 42,230,233,238,225,236,225,242,225, 226,233, 99,128,254,150,232,225,232,105, 2,185,239,185,254,238, 233,244,233,225,236,225,242,225,226,233, 99,128,252,162,243,239, 236,225,244,229,228,225,242,225,226,233, 99,128,252, 12,105, 2, 186, 20,186, 35,238,233,244,233,225,236,225,242,225,226,233, 99, 128,254,151,242,225,231,225,238, 97,128, 48,102,234,229,229,237, 105, 2,186, 54,186, 69,238,233,244,233,225,236,225,242,225,226, 233, 99,128,252,161,243,239,236,225,244,229,228,225,242,225,226, 233, 99,128,252, 11,109, 2,186, 91,186,125,225,242,226,245,244, 97, 2,186,102,186,111,225,242,225,226,233, 99,128, 6, 41,230, 233,238,225,236,225,242,225,226,233, 99,128,254,148,101, 2,186, 131,186,144,228,233,225,236,225,242,225,226,233, 99,128,254,152, 229,237,105, 2,186,152,186,167,238,233,244,233,225,236,225,242, 225,226,233, 99,128,252,164,243,239,236,225,244,229,228,225,242, 225,226,233, 99,128,252, 14,238,239,239,238,230,233,238,225,236, 225,242,225,226,233, 99,128,252,115,235,225,244,225,235,225,238, 97,129, 48,198,186,214,232,225,236,230,247,233,228,244,104,128, 255,131,108, 2,186,232,186,251,229,240,232,239,238,101,129, 33, 33,186,243,226,236,225,227,107,128, 38, 14,233,243,232, 97, 2, 187, 4,187, 19,231,229,228,239,236,225,232,229,226,242,229,119, 128, 5,160,241,229,244,225,238,225,232,229,226,242,229,119,128, 5,169,110, 4,187, 44,187, 53,187, 72,187, 93,227,233,242,227, 236,101,128, 36,105,233,228,229,239,231,242,225,240,232,233,227, 240,225,242,229,110,128, 50, 41,112, 2,187, 78,187, 85,225,242, 229,110,128, 36,125,229,242,233,239,100,128, 36,145,242,239,237, 225,110,128, 33,121,243,104,128, 2,167,116,131, 5,216,187,116, 187,136,187,145,228,225,231,229,243,104,129,251, 56,187,127,232, 229,226,242,229,119,128,251, 56,232,229,226,242,229,119,128, 5, 216,243,229,227,249,242,233,236,236,233, 99,128, 4,181,246,233, 114, 2,187,166,187,175,232,229,226,242,229,119,128, 5,155,236, 229,230,244,232,229,226,242,229,119,128, 5,155,104, 6,187,202, 188, 98,188,220,189, 96,190, 3,191, 60, 97, 5,187,214,187,224, 187,231,188, 0,188, 29,226,229,238,231,225,236,105,128, 9,165, 228,229,246, 97,128, 9, 37,231,117, 2,187,238,187,247,234,225, 242,225,244,105,128, 10,165,242,237,245,235,232,105,128, 10, 37, 108, 2,188, 6,188, 15,225,242,225,226,233, 99,128, 6, 48,230, 233,238,225,236,225,242,225,226,233, 99,128,254,172,238,244,232, 225,235,232,225,116, 3,188, 44,188, 75,188, 82,236,239,119, 2, 188, 52,188, 63,236,229,230,244,244,232,225,105,128,248,152,242, 233,231,232,244,244,232,225,105,128,248,151,244,232,225,105,128, 14, 76,245,240,240,229,242,236,229,230,244,244,232,225,105,128, 248,150,101, 3,188,106,188,170,188,193,104, 4,188,116,188,125, 188,139,188,155,225,242,225,226,233, 99,128, 6, 43,230,233,238, 225,236,225,242,225,226,233, 99,128,254,154,233,238,233,244,233, 225,236,225,242,225,226,233, 99,128,254,155,237,229,228,233,225, 236,225,242,225,226,233, 99,128,254,156,242,101, 2,188,177,188, 186,229,248,233,243,244,115,128, 34, 3,230,239,242,101,128, 34, 52,244, 97,130, 3,184,188,202,188,206, 49,128, 3,209,243,249, 237,226,239,236,231,242,229,229,107,128, 3,209,105, 2,188,226, 189, 56,229,245,244,104, 4,188,239,189, 18,189, 33,189, 42, 97, 2,188,245,189, 4,227,233,242,227,236,229,235,239,242,229,225, 110,128, 50,121,240,225,242,229,238,235,239,242,229,225,110,128, 50, 25,227,233,242,227,236,229,235,239,242,229,225,110,128, 50, 107,235,239,242,229,225,110,128, 49, 76,240,225,242,229,238,235, 239,242,229,225,110,128, 50, 11,242,244,229,229,110, 2,189, 66, 189, 75,227,233,242,227,236,101,128, 36,108,112, 2,189, 81,189, 88,225,242,229,110,128, 36,128,229,242,233,239,100,128, 36,148, 111, 6,189,110,189,127,189,132,189,146,189,151,189,204,238,225, 238,231,237,239,238,244,232,239,244,232,225,105,128, 14, 17,239, 107,128, 1,173,240,232,245,244,232,225,239,244,232,225,105,128, 14, 18,242,110,128, 0,254,244,104, 3,189,160,189,184,189,194, 97, 2,189,166,189,176,232,225,238,244,232,225,105,128, 14, 23, 238,244,232,225,105,128, 14, 16,239,238,231,244,232,225,105,128, 14, 24,245,238,231,244,232,225,105,128, 14, 22,245,243,225,238, 100, 2,189,214,189,225,227,249,242,233,236,236,233, 99,128, 4, 130,243,243,229,240,225,242,225,244,239,114, 2,189,240,189,249, 225,242,225,226,233, 99,128, 6,108,240,229,242,243,233,225,110, 128, 6,108,242,229,101,144, 0, 51,190, 41,190, 50,190, 60,190, 90,190, 97,190,107,190,132,190,159,190,193,190,205,190,224,190, 235,191, 12,191, 34,191, 42,191, 53,225,242,225,226,233, 99,128, 6, 99,226,229,238,231,225,236,105,128, 9,233,227,233,242,227, 236,101,129, 36, 98,190, 71,233,238,246,229,242,243,229,243,225, 238,243,243,229,242,233,102,128, 39,140,228,229,246, 97,128, 9, 105,229,233,231,232,244,232,115,128, 33, 92,231,117, 2,190,114, 190,123,234,225,242,225,244,105,128, 10,233,242,237,245,235,232, 105,128, 10,105,232, 97, 2,190,139,190,150,227,235,225,242,225, 226,233, 99,128, 6, 99,238,231,250,232,239,117,128, 48, 35,105, 2,190,165,190,183,228,229,239,231,242,225,240,232,233,227,240, 225,242,229,110,128, 50, 34,238,230,229,242,233,239,114,128, 32, 131,237,239,238,239,243,240,225,227,101,128,255, 19,238,245,237, 229,242,225,244,239,242,226,229,238,231,225,236,105,128, 9,246, 239,236,228,243,244,249,236,101,128,247, 51,112, 2,190,241,190, 248,225,242,229,110,128, 36,118,229,114, 2,190,255,191, 5,233, 239,100,128, 36,138,243,233,225,110,128, 6,243,241,245,225,242, 244,229,242,115,129, 0,190,191, 25,229,237,228,225,243,104,128, 246,222,242,239,237,225,110,128, 33,114,243,245,240,229,242,233, 239,114,128, 0,179,244,232,225,105,128, 14, 83,250,243,241,245, 225,242,101,128, 51,148,105, 7,191, 86,191, 97,191,212,192, 54, 192, 66,192,115,192,132,232,233,242,225,231,225,238, 97,128, 48, 97,107, 2,191,103,191,127,225,244,225,235,225,238, 97,129, 48, 193,191,115,232,225,236,230,247,233,228,244,104,128,255,129,229, 245,116, 4,191,139,191,174,191,189,191,198, 97, 2,191,145,191, 160,227,233,242,227,236,229,235,239,242,229,225,110,128, 50,112, 240,225,242,229,238,235,239,242,229,225,110,128, 50, 16,227,233, 242,227,236,229,235,239,242,229,225,110,128, 50, 98,235,239,242, 229,225,110,128, 49, 55,240,225,242,229,238,235,239,242,229,225, 110,128, 50, 2,236,228,101,133, 2,220,191,228,191,239,192, 0, 192, 12,192, 40,226,229,236,239,247,227,237, 98,128, 3, 48, 99, 2,191,245,191,250,237, 98,128, 3, 3,239,237, 98,128, 3, 3, 228,239,245,226,236,229,227,237, 98,128, 3, 96,111, 2,192, 18, 192, 28,240,229,242,225,244,239,114,128, 34, 60,246,229,242,236, 225,249,227,237, 98,128, 3, 52,246,229,242,244,233,227,225,236, 227,237, 98,128, 3, 62,237,229,243,227,233,242,227,236,101,128, 34,151,112, 2,192, 72,192,102,229,232, 97, 2,192, 80,192, 89, 232,229,226,242,229,119,128, 5,150,236,229,230,244,232,229,226, 242,229,119,128, 5,150,240,233,231,245,242,237,245,235,232,105, 128, 10,112,244,236,239,227,249,242,233,236,236,233,227,227,237, 98,128, 4,131,247,238,225,242,237,229,238,233,225,110,128, 5, 127,236,233,238,229,226,229,236,239,119,128, 30,111,237,239,238, 239,243,240,225,227,101,128,255, 84,111, 7,192,185,192,196,192, 207,192,232,193, 96,193,108,193,192,225,242,237,229,238,233,225, 110,128, 5,105,232,233,242,225,231,225,238, 97,128, 48,104,235, 225,244,225,235,225,238, 97,129, 48,200,192,220,232,225,236,230, 247,233,228,244,104,128,255,132,110, 3,192,240,193, 82,193, 87, 101, 4,192,250,193, 63,193, 70,193, 76,226,225,114, 4,193, 6, 193, 35,193, 45,193, 54,229,248,244,242, 97, 2,193, 16,193, 26, 232,233,231,232,237,239,100,128, 2,229,236,239,247,237,239,100, 128, 2,233,232,233,231,232,237,239,100,128, 2,230,236,239,247, 237,239,100,128, 2,232,237,233,228,237,239,100,128, 2,231,230, 233,246,101,128, 1,189,243,233,120,128, 1,133,244,247,111,128, 1,168,239,115,128, 3,132,243,241,245,225,242,101,128, 51, 39, 240,225,244,225,235,244,232,225,105,128, 14, 15,242,244,239,233, 243,229,243,232,229,236,236,226,242,225,227,235,229,116, 2,193, 131,193,161,236,229,230,116,130, 48, 20,193,142,193,150,243,237, 225,236,108,128,254, 93,246,229,242,244,233,227,225,108,128,254, 57,242,233,231,232,116,130, 48, 21,193,173,193,181,243,237,225, 236,108,128,254, 94,246,229,242,244,233,227,225,108,128,254, 58, 244,225,239,244,232,225,105,128, 14, 21,240, 97, 2,193,209,193, 221,236,225,244,225,236,232,239,239,107,128, 1,171,242,229,110, 128, 36,175,114, 3,193,235,194, 10,194, 25,225,228,229,237,225, 242,107,129, 33, 34,193,247,115, 2,193,253,194, 3,225,238,115, 128,248,234,229,242,233,102,128,246,219,229,244,242,239,230,236, 229,248,232,239,239,107,128, 2,136,233,225,103, 4,194, 37,194, 42,194, 47,194, 52,228,110,128, 37,188,236,102,128, 37,196,242, 116,128, 37,186,245,112,128, 37,178,115,132, 2,166,194, 69,194, 108,194,214,194,227,225,228,105,130, 5,230,194, 79,194, 99,228, 225,231,229,243,104,129,251, 70,194, 90,232,229,226,242,229,119, 128,251, 70,232,229,226,242,229,119,128, 5,230,101, 2,194,114, 194,125,227,249,242,233,236,236,233, 99,128, 4, 70,242,101,134, 5,181,194,142,194,156,194,161,194,170,194,185,194,201, 49, 2, 194,148,194,152, 50,128, 5,181,101,128, 5,181,178, 98,128, 5, 181,232,229,226,242,229,119,128, 5,181,238,225,242,242,239,247, 232,229,226,242,229,119,128, 5,181,241,245,225,242,244,229,242, 232,229,226,242,229,119,128, 5,181,247,233,228,229,232,229,226, 242,229,119,128, 5,181,232,229,227,249,242,233,236,236,233, 99, 128, 4, 91,245,240,229,242,233,239,114,128,246,243,116, 4,194, 247,195, 41,195,106,195,157, 97, 3,194,255,195, 9,195, 16,226, 229,238,231,225,236,105,128, 9,159,228,229,246, 97,128, 9, 31, 231,117, 2,195, 23,195, 32,234,225,242,225,244,105,128, 10,159, 242,237,245,235,232,105,128, 10, 31,229,104, 4,195, 52,195, 61, 195, 75,195, 91,225,242,225,226,233, 99,128, 6,121,230,233,238, 225,236,225,242,225,226,233, 99,128,251,103,233,238,233,244,233, 225,236,225,242,225,226,233, 99,128,251,104,237,229,228,233,225, 236,225,242,225,226,233, 99,128,251,105,232, 97, 3,195,115,195, 125,195,132,226,229,238,231,225,236,105,128, 9,160,228,229,246, 97,128, 9, 32,231,117, 2,195,139,195,148,234,225,242,225,244, 105,128, 10,160,242,237,245,235,232,105,128, 10, 32,245,242,238, 229,100,128, 2,135,117, 3,195,173,195,184,195,209,232,233,242, 225,231,225,238, 97,128, 48,100,235,225,244,225,235,225,238, 97, 129, 48,196,195,197,232,225,236,230,247,233,228,244,104,128,255, 130,243,237,225,236,108, 2,195,219,195,230,232,233,242,225,231, 225,238, 97,128, 48, 99,235,225,244,225,235,225,238, 97,129, 48, 195,195,243,232,225,236,230,247,233,228,244,104,128,255,111,119, 2,196, 5,196,110,101, 2,196, 11,196, 59,236,246,101, 3,196, 21,196, 30,196, 51,227,233,242,227,236,101,128, 36,107,112, 2, 196, 36,196, 43,225,242,229,110,128, 36,127,229,242,233,239,100, 128, 36,147,242,239,237,225,110,128, 33,123,238,244,121, 3,196, 69,196, 78,196, 89,227,233,242,227,236,101,128, 36,115,232,225, 238,231,250,232,239,117,128, 83, 68,112, 2,196, 95,196,102,225, 242,229,110,128, 36,135,229,242,233,239,100,128, 36,155,111,142, 0, 50,196,142,196,151,196,161,196,191,196,243,197, 12,197, 39, 197, 73,197, 85,197,104,197,115,197,148,197,156,197,180,225,242, 225,226,233, 99,128, 6, 98,226,229,238,231,225,236,105,128, 9, 232,227,233,242,227,236,101,129, 36, 97,196,172,233,238,246,229, 242,243,229,243,225,238,243,243,229,242,233,102,128, 39,139,100, 2,196,197,196,203,229,246, 97,128, 9,104,239,116, 2,196,210, 196,221,229,238,236,229,225,228,229,114,128, 32, 37,236,229,225, 228,229,114,129, 32, 37,196,232,246,229,242,244,233,227,225,108, 128,254, 48,231,117, 2,196,250,197, 3,234,225,242,225,244,105, 128, 10,232,242,237,245,235,232,105,128, 10,104,232, 97, 2,197, 19,197, 30,227,235,225,242,225,226,233, 99,128, 6, 98,238,231, 250,232,239,117,128, 48, 34,105, 2,197, 45,197, 63,228,229,239, 231,242,225,240,232,233,227,240,225,242,229,110,128, 50, 33,238, 230,229,242,233,239,114,128, 32,130,237,239,238,239,243,240,225, 227,101,128,255, 18,238,245,237,229,242,225,244,239,242,226,229, 238,231,225,236,105,128, 9,245,239,236,228,243,244,249,236,101, 128,247, 50,112, 2,197,121,197,128,225,242,229,110,128, 36,117, 229,114, 2,197,135,197,141,233,239,100,128, 36,137,243,233,225, 110,128, 6,242,242,239,237,225,110,128, 33,113,115, 2,197,162, 197,170,244,242,239,235,101,128, 1,187,245,240,229,242,233,239, 114,128, 0,178,244,104, 2,197,187,197,192,225,105,128, 14, 82, 233,242,228,115,128, 33, 84,117,145, 0,117,197,237,197,245,198, 30,198, 87,198,225,199, 6,199,129,199,145,199,196,200, 10,200, 91,200,100,200,219,200,243,201, 95,201,123,201,237,225,227,245, 244,101,128, 0,250, 98, 4,197,255,198, 4,198, 13,198, 23,225, 114,128, 2,137,229,238,231,225,236,105,128, 9,137,239,240,239, 237,239,230,111,128, 49, 40,242,229,246,101,128, 1,109, 99, 3, 198, 38,198, 45,198, 77,225,242,239,110,128, 1,212,233,242, 99, 2,198, 53,198, 58,236,101,128, 36,228,245,237,230,236,229,120, 129, 0,251,198, 69,226,229,236,239,119,128, 30,119,249,242,233, 236,236,233, 99,128, 4, 67,100, 5,198, 99,198,110,198,133,198, 139,198,215,225,244,244,225,228,229,246, 97,128, 9, 81,226,108, 2,198,117,198,125,225,227,245,244,101,128, 1,113,231,242,225, 246,101,128, 2, 21,229,246, 97,128, 9, 9,233,229,242,229,243, 233,115,133, 0,252,198,159,198,167,198,175,198,198,198,206,225, 227,245,244,101,128, 1,216,226,229,236,239,119,128, 30,115, 99, 2,198,181,198,188,225,242,239,110,128, 1,218,249,242,233,236, 236,233, 99,128, 4,241,231,242,225,246,101,128, 1,220,237,225, 227,242,239,110,128, 1,214,239,244,226,229,236,239,119,128, 30, 229,103, 2,198,231,198,238,242,225,246,101,128, 0,249,117, 2, 198,244,198,253,234,225,242,225,244,105,128, 10,137,242,237,245, 235,232,105,128, 10, 9,104, 3,199, 14,199, 24,199,102,233,242, 225,231,225,238, 97,128, 48, 70,111, 2,199, 30,199, 40,239,235, 225,226,239,246,101,128, 30,231,242,110,133, 1,176,199, 55,199, 63,199, 74,199, 82,199, 94,225,227,245,244,101,128, 30,233,228, 239,244,226,229,236,239,119,128, 30,241,231,242,225,246,101,128, 30,235,232,239,239,235,225,226,239,246,101,128, 30,237,244,233, 236,228,101,128, 30,239,245,238,231,225,242,245,237,236,225,245, 116,129, 1,113,199,118,227,249,242,233,236,236,233, 99,128, 4, 243,233,238,246,229,242,244,229,228,226,242,229,246,101,128, 2, 23,107, 3,199,153,199,177,199,188,225,244,225,235,225,238, 97, 129, 48,166,199,165,232,225,236,230,247,233,228,244,104,128,255, 115,227,249,242,233,236,236,233, 99,128, 4,121,239,242,229,225, 110,128, 49, 92,109, 2,199,202,199,255, 97, 2,199,208,199,241, 227,242,239,110,130, 1,107,199,219,199,230,227,249,242,233,236, 236,233, 99,128, 4,239,228,233,229,242,229,243,233,115,128, 30, 123,244,242,225,231,245,242,237,245,235,232,105,128, 10, 65,239, 238,239,243,240,225,227,101,128,255, 85,110, 2,200, 16,200, 71, 228,229,242,243,227,239,242,101,132, 0, 95,200, 35,200, 41,200, 53,200, 64,228,226,108,128, 32, 23,237,239,238,239,243,240,225, 227,101,128,255, 63,246,229,242,244,233,227,225,108,128,254, 51, 247,225,246,121,128,254, 79,105, 2,200, 77,200, 82,239,110,128, 34, 42,246,229,242,243,225,108,128, 34, 0,239,231,239,238,229, 107,128, 1,115,112, 5,200,112,200,119,200,127,200,142,200,193, 225,242,229,110,128, 36,176,226,236,239,227,107,128, 37,128,240, 229,242,228,239,244,232,229,226,242,229,119,128, 5,196,243,233, 236,239,110,131, 3,197,200,156,200,177,200,185,228,233,229,242, 229,243,233,115,129, 3,203,200,169,244,239,238,239,115,128, 3, 176,236,225,244,233,110,128, 2,138,244,239,238,239,115,128, 3, 205,244,225,227,107, 2,200,202,200,213,226,229,236,239,247,227, 237, 98,128, 3, 29,237,239,100,128, 2,212,114, 2,200,225,200, 237,225,231,245,242,237,245,235,232,105,128, 10,115,233,238,103, 128, 1,111,115, 3,200,251,201, 10,201, 55,232,239,242,244,227, 249,242,233,236,236,233, 99,128, 4, 94,237,225,236,108, 2,201, 19,201, 30,232,233,242,225,231,225,238, 97,128, 48, 69,235,225, 244,225,235,225,238, 97,129, 48,165,201, 43,232,225,236,230,247, 233,228,244,104,128,255,105,244,242,225,233,231,232,116, 2,201, 67,201, 78,227,249,242,233,236,236,233, 99,128, 4,175,243,244, 242,239,235,229,227,249,242,233,236,236,233, 99,128, 4,177,244, 233,236,228,101,130, 1,105,201,107,201,115,225,227,245,244,101, 128, 30,121,226,229,236,239,119,128, 30,117,117, 5,201,135,201, 145,201,152,201,177,201,193,226,229,238,231,225,236,105,128, 9, 138,228,229,246, 97,128, 9, 10,231,117, 2,201,159,201,168,234, 225,242,225,244,105,128, 10,138,242,237,245,235,232,105,128, 10, 10,237,225,244,242,225,231,245,242,237,245,235,232,105,128, 10, 66,246,239,247,229,236,243,233,231,110, 3,201,209,201,219,201, 226,226,229,238,231,225,236,105,128, 9,194,228,229,246, 97,128, 9, 66,231,245,234,225,242,225,244,105,128, 10,194,246,239,247, 229,236,243,233,231,110, 3,201,253,202, 7,202, 14,226,229,238, 231,225,236,105,128, 9,193,228,229,246, 97,128, 9, 65,231,245, 234,225,242,225,244,105,128, 10,193,118,139, 0,118,202, 51,202, 199,202,208,202,219,203,148,203,155,203,253,204, 9,204,109,204, 117,204,138, 97, 4,202, 61,202, 68,202, 93,202,104,228,229,246, 97,128, 9, 53,231,117, 2,202, 75,202, 84,234,225,242,225,244, 105,128, 10,181,242,237,245,235,232,105,128, 10, 53,235,225,244, 225,235,225,238, 97,128, 48,247,118,132, 5,213,202,116,202,143, 202,175,202,187,228,225,231,229,243,104,130,251, 53,202,129,202, 134,182, 53,128,251, 53,232,229,226,242,229,119,128,251, 53,104, 2,202,149,202,157,229,226,242,229,119,128, 5,213,239,236,225, 109,129,251, 75,202,166,232,229,226,242,229,119,128,251, 75,246, 225,246,232,229,226,242,229,119,128, 5,240,249,239,228,232,229, 226,242,229,119,128, 5,241,227,233,242,227,236,101,128, 36,229, 228,239,244,226,229,236,239,119,128, 30,127,101, 6,202,233,202, 244,203, 52,203, 63,203, 69,203,136,227,249,242,233,236,236,233, 99,128, 4, 50,104, 4,202,254,203, 7,203, 21,203, 37,225,242, 225,226,233, 99,128, 6,164,230,233,238,225,236,225,242,225,226, 233, 99,128,251,107,233,238,233,244,233,225,236,225,242,225,226, 233, 99,128,251,108,237,229,228,233,225,236,225,242,225,226,233, 99,128,251,109,235,225,244,225,235,225,238, 97,128, 48,249,238, 245,115,128, 38, 64,242,244,233,227,225,108, 2,203, 80,203, 86, 226,225,114,128, 0,124,236,233,238,101, 4,203, 99,203,110,203, 121,203,130,225,226,239,246,229,227,237, 98,128, 3, 13,226,229, 236,239,247,227,237, 98,128, 3, 41,236,239,247,237,239,100,128, 2,204,237,239,100,128, 2,200,247,225,242,237,229,238,233,225, 110,128, 5,126,232,239,239,107,128, 2,139,105, 3,203,163,203, 174,203,213,235,225,244,225,235,225,238, 97,128, 48,248,242,225, 237, 97, 3,203,185,203,195,203,202,226,229,238,231,225,236,105, 128, 9,205,228,229,246, 97,128, 9, 77,231,245,234,225,242,225, 244,105,128, 10,205,243,225,242,231, 97, 3,203,225,203,235,203, 242,226,229,238,231,225,236,105,128, 9,131,228,229,246, 97,128, 9, 3,231,245,234,225,242,225,244,105,128, 10,131,237,239,238, 239,243,240,225,227,101,128,255, 86,111, 3,204, 17,204, 28,204, 98,225,242,237,229,238,233,225,110,128, 5,120,233,227,229,100, 2,204, 37,204, 73,233,244,229,242,225,244,233,239,110, 2,204, 51,204, 62,232,233,242,225,231,225,238, 97,128, 48,158,235,225, 244,225,235,225,238, 97,128, 48,254,237,225,242,235,235,225,238, 97,129, 48,155,204, 86,232,225,236,230,247,233,228,244,104,128, 255,158,235,225,244,225,235,225,238, 97,128, 48,250,240,225,242, 229,110,128, 36,177,116, 2,204,123,204,130,233,236,228,101,128, 30,125,245,242,238,229,100,128, 2,140,117, 2,204,144,204,155, 232,233,242,225,231,225,238, 97,128, 48,148,235,225,244,225,235, 225,238, 97,128, 48,244,119,143, 0,119,204,200,205,177,205,187, 205,210,205,250,206, 61,206, 69,208, 40,208, 81,208, 93,208,168, 208,176,208,183,208,194,208,203, 97, 8,204,218,204,225,204,235, 204,246,205, 28,205, 60,205, 72,205,108,227,245,244,101,128, 30, 131,229,235,239,242,229,225,110,128, 49, 89,232,233,242,225,231, 225,238, 97,128, 48,143,107, 2,204,252,205, 20,225,244,225,235, 225,238, 97,129, 48,239,205, 8,232,225,236,230,247,233,228,244, 104,128,255,156,239,242,229,225,110,128, 49, 88,243,237,225,236, 108, 2,205, 38,205, 49,232,233,242,225,231,225,238, 97,128, 48, 142,235,225,244,225,235,225,238, 97,128, 48,238,244,244,239,243, 241,245,225,242,101,128, 51, 87,118, 2,205, 78,205, 86,229,228, 225,243,104,128, 48, 28,249,245,238,228,229,242,243,227,239,242, 229,246,229,242,244,233,227,225,108,128,254, 52,119, 3,205,116, 205,125,205,139,225,242,225,226,233, 99,128, 6, 72,230,233,238, 225,236,225,242,225,226,233, 99,128,254,238,232,225,237,250,225, 225,226,239,246,101, 2,205,154,205,163,225,242,225,226,233, 99, 128, 6, 36,230,233,238,225,236,225,242,225,226,233, 99,128,254, 134,226,243,241,245,225,242,101,128, 51,221,227,233,242, 99, 2, 205,196,205,201,236,101,128, 36,230,245,237,230,236,229,120,128, 1,117,100, 2,205,216,205,226,233,229,242,229,243,233,115,128, 30,133,239,116, 2,205,233,205,242,225,227,227,229,238,116,128, 30,135,226,229,236,239,119,128, 30,137,101, 4,206, 4,206, 15, 206, 27,206, 51,232,233,242,225,231,225,238, 97,128, 48,145,233, 229,242,243,244,242,225,243,115,128, 33, 24,107, 2,206, 33,206, 43,225,244,225,235,225,238, 97,128, 48,241,239,242,229,225,110, 128, 49, 94,239,235,239,242,229,225,110,128, 49, 93,231,242,225, 246,101,128, 30,129,232,233,244,101, 8,206, 90,206, 99,206,183, 207, 17,207,101,207,146,207,198,207,254,226,245,236,236,229,116, 128, 37,230, 99, 2,206,105,206,125,233,242,227,236,101,129, 37, 203,206,115,233,238,246,229,242,243,101,128, 37,217,239,242,238, 229,242,226,242,225,227,235,229,116, 2,206,142,206,162,236,229, 230,116,129, 48, 14,206,151,246,229,242,244,233,227,225,108,128, 254, 67,242,233,231,232,116,129, 48, 15,206,172,246,229,242,244, 233,227,225,108,128,254, 68,100, 2,206,189,206,230,233,225,237, 239,238,100,129, 37,199,206,200,227,239,238,244,225,233,238,233, 238,231,226,236,225,227,235,243,237,225,236,236,228,233,225,237, 239,238,100,128, 37,200,239,247,238,240,239,233,238,244,233,238, 103, 2,206,246,207, 6,243,237,225,236,236,244,242,233,225,238, 231,236,101,128, 37,191,244,242,233,225,238,231,236,101,128, 37, 189,236,101, 2,207, 24,207, 66,230,244,240,239,233,238,244,233, 238,103, 2,207, 39,207, 55,243,237,225,236,236,244,242,233,225, 238,231,236,101,128, 37,195,244,242,233,225,238,231,236,101,128, 37,193,238,244,233,227,245,236,225,242,226,242,225,227,235,229, 116, 2,207, 86,207, 93,236,229,230,116,128, 48, 22,242,233,231, 232,116,128, 48, 23,242,233,231,232,244,240,239,233,238,244,233, 238,103, 2,207,119,207,135,243,237,225,236,236,244,242,233,225, 238,231,236,101,128, 37,185,244,242,233,225,238,231,236,101,128, 37,183,115, 3,207,154,207,184,207,192,109, 2,207,160,207,172, 225,236,236,243,241,245,225,242,101,128, 37,171,233,236,233,238, 231,230,225,227,101,128, 38, 58,241,245,225,242,101,128, 37,161, 244,225,114,128, 38, 6,116, 2,207,204,207,215,229,236,229,240, 232,239,238,101,128, 38, 15,239,242,244,239,233,243,229,243,232, 229,236,236,226,242,225,227,235,229,116, 2,207,239,207,246,236, 229,230,116,128, 48, 24,242,233,231,232,116,128, 48, 25,245,240, 240,239,233,238,244,233,238,103, 2,208, 13,208, 29,243,237,225, 236,236,244,242,233,225,238,231,236,101,128, 37,181,244,242,233, 225,238,231,236,101,128, 37,179,105, 2,208, 46,208, 57,232,233, 242,225,231,225,238, 97,128, 48,144,107, 2,208, 63,208, 73,225, 244,225,235,225,238, 97,128, 48,240,239,242,229,225,110,128, 49, 95,237,239,238,239,243,240,225,227,101,128,255, 87,111, 4,208, 103,208,114,208,139,208,157,232,233,242,225,231,225,238, 97,128, 48,146,235,225,244,225,235,225,238, 97,129, 48,242,208,127,232, 225,236,230,247,233,228,244,104,128,255,102,110,129, 32,169,208, 145,237,239,238,239,243,240,225,227,101,128,255,230,247,225,229, 238,244,232,225,105,128, 14, 39,240,225,242,229,110,128, 36,178, 242,233,238,103,128, 30,152,243,245,240,229,242,233,239,114,128, 2,183,244,245,242,238,229,100,128, 2,141,249,238,110,128, 1, 191,120,137, 0,120,208,231,208,242,208,253,209, 6,209, 33,209, 46,209, 50,209, 62,209, 70,225,226,239,246,229,227,237, 98,128, 3, 61,226,239,240,239,237,239,230,111,128, 49, 18,227,233,242, 227,236,101,128, 36,231,100, 2,209, 12,209, 22,233,229,242,229, 243,233,115,128, 30,141,239,244,225,227,227,229,238,116,128, 30, 139,229,232,225,242,237,229,238,233,225,110,128, 5,109,105,128, 3,190,237,239,238,239,243,240,225,227,101,128,255, 88,240,225, 242,229,110,128, 36,179,243,245,240,229,242,233,239,114,128, 2, 227,121,143, 0,121,209,115,210, 74,210, 97,210,137,212,103,212, 111,212,128,212,192,212,204,213,201,213,241,213,253,214, 8,214, 29,215, 2, 97, 11,209,139,209,151,209,161,209,168,209,175,209, 185,209,210,209,221,210, 3,210, 16,210, 62,225,228,239,243,241, 245,225,242,101,128, 51, 78,226,229,238,231,225,236,105,128, 9, 175,227,245,244,101,128, 0,253,228,229,246, 97,128, 9, 47,229, 235,239,242,229,225,110,128, 49, 82,231,117, 2,209,192,209,201, 234,225,242,225,244,105,128, 10,175,242,237,245,235,232,105,128, 10, 47,232,233,242,225,231,225,238, 97,128, 48,132,107, 2,209, 227,209,251,225,244,225,235,225,238, 97,129, 48,228,209,239,232, 225,236,230,247,233,228,244,104,128,255,148,239,242,229,225,110, 128, 49, 81,237,225,235,235,225,238,244,232,225,105,128, 14, 78, 243,237,225,236,108, 2,210, 26,210, 37,232,233,242,225,231,225, 238, 97,128, 48,131,235,225,244,225,235,225,238, 97,129, 48,227, 210, 50,232,225,236,230,247,233,228,244,104,128,255,108,244,227, 249,242,233,236,236,233, 99,128, 4, 99,227,233,242, 99, 2,210, 83,210, 88,236,101,128, 36,232,245,237,230,236,229,120,128, 1, 119,100, 2,210,103,210,113,233,229,242,229,243,233,115,128, 0, 255,239,116, 2,210,120,210,129,225,227,227,229,238,116,128, 30, 143,226,229,236,239,119,128, 30,245,101, 7,210,153,211,161,211, 170,211,188,211,220,212, 40,212, 91,104, 8,210,171,210,180,210, 214,210,228,211, 45,211, 61,211,120,211,138,225,242,225,226,233, 99,128, 6, 74,226,225,242,242,229,101, 2,210,191,210,200,225, 242,225,226,233, 99,128, 6,210,230,233,238,225,236,225,242,225, 226,233, 99,128,251,175,230,233,238,225,236,225,242,225,226,233, 99,128,254,242,232,225,237,250,225,225,226,239,246,101, 4,210, 247,211, 0,211, 14,211, 30,225,242,225,226,233, 99,128, 6, 38, 230,233,238,225,236,225,242,225,226,233, 99,128,254,138,233,238, 233,244,233,225,236,225,242,225,226,233, 99,128,254,139,237,229, 228,233,225,236,225,242,225,226,233, 99,128,254,140,233,238,233, 244,233,225,236,225,242,225,226,233, 99,128,254,243,237,101, 2, 211, 68,211, 81,228,233,225,236,225,242,225,226,233, 99,128,254, 244,229,237,105, 2,211, 89,211,104,238,233,244,233,225,236,225, 242,225,226,233, 99,128,252,221,243,239,236,225,244,229,228,225, 242,225,226,233, 99,128,252, 88,238,239,239,238,230,233,238,225, 236,225,242,225,226,233, 99,128,252,148,244,232,242,229,229,228, 239,244,243,226,229,236,239,247,225,242,225,226,233, 99,128, 6, 209,235,239,242,229,225,110,128, 49, 86,110,129, 0,165,211,176, 237,239,238,239,243,240,225,227,101,128,255,229,111, 2,211,194, 211,203,235,239,242,229,225,110,128, 49, 85,242,233,238,232,233, 229,245,232,235,239,242,229,225,110,128, 49,134,114, 3,211,228, 212, 8,212, 20,225,232,226,229,238,249,239,237,111, 2,211,242, 211,251,232,229,226,242,229,119,128, 5,170,236,229,230,244,232, 229,226,242,229,119,128, 5,170,233,227,249,242,233,236,236,233, 99,128, 4, 75,245,228,233,229,242,229,243,233,243,227,249,242, 233,236,236,233, 99,128, 4,249,243,233,229,245,238,103, 3,212, 53,212, 62,212, 78,235,239,242,229,225,110,128, 49,129,240,225, 238,243,233,239,243,235,239,242,229,225,110,128, 49,131,243,233, 239,243,235,239,242,229,225,110,128, 49,130,244,233,246,232,229, 226,242,229,119,128, 5,154,231,242,225,246,101,128, 30,243,232, 239,239,107,129, 1,180,212,120,225,226,239,246,101,128, 30,247, 105, 5,212,140,212,151,212,162,212,171,212,179,225,242,237,229, 238,233,225,110,128, 5,117,227,249,242,233,236,236,233, 99,128, 4, 87,235,239,242,229,225,110,128, 49, 98,238,249,225,238,103, 128, 38, 47,247,238,225,242,237,229,238,233,225,110,128, 5,130, 237,239,238,239,243,240,225,227,101,128,255, 89,111, 7,212,220, 213, 34,213, 45,213, 55,213, 93,213,139,213,148,100,131, 5,217, 212,230,212,250,213, 3,228,225,231,229,243,104,129,251, 57,212, 241,232,229,226,242,229,119,128,251, 57,232,229,226,242,229,119, 128, 5,217,249,239,100, 2,213, 11,213, 20,232,229,226,242,229, 119,128, 5,242,240,225,244,225,232,232,229,226,242,229,119,128, 251, 31,232,233,242,225,231,225,238, 97,128, 48,136,233,235,239, 242,229,225,110,128, 49,137,107, 2,213, 61,213, 85,225,244,225, 235,225,238, 97,129, 48,232,213, 73,232,225,236,230,247,233,228, 244,104,128,255,150,239,242,229,225,110,128, 49, 91,243,237,225, 236,108, 2,213,103,213,114,232,233,242,225,231,225,238, 97,128, 48,135,235,225,244,225,235,225,238, 97,129, 48,231,213,127,232, 225,236,230,247,233,228,244,104,128,255,110,244,231,242,229,229, 107,128, 3,243,121, 2,213,154,213,191, 97, 2,213,160,213,170, 229,235,239,242,229,225,110,128, 49,136,107, 2,213,176,213,184, 239,242,229,225,110,128, 49,135,244,232,225,105,128, 14, 34,233, 238,231,244,232,225,105,128, 14, 13,112, 2,213,207,213,214,225, 242,229,110,128, 36,180,239,231,229,231,242,225,237,237,229,238, 105,129, 3,122,213,230,231,242,229,229,235,227,237, 98,128, 3, 69,114,129, 1,166,213,247,233,238,103,128, 30,153,243,245,240, 229,242,233,239,114,128, 2,184,116, 2,214, 14,214, 21,233,236, 228,101,128, 30,249,245,242,238,229,100,128, 2,142,117, 5,214, 41,214, 52,214, 62,214,100,214,232,232,233,242,225,231,225,238, 97,128, 48,134,233,235,239,242,229,225,110,128, 49,140,107, 2, 214, 68,214, 92,225,244,225,235,225,238, 97,129, 48,230,214, 80, 232,225,236,230,247,233,228,244,104,128,255,149,239,242,229,225, 110,128, 49, 96,115, 3,214,108,214,146,214,187,226,233,103, 2, 214,116,214,127,227,249,242,233,236,236,233, 99,128, 4,107,233, 239,244,233,230,233,229,228,227,249,242,233,236,236,233, 99,128, 4,109,236,233,244,244,236,101, 2,214,157,214,168,227,249,242, 233,236,236,233, 99,128, 4,103,233,239,244,233,230,233,229,228, 227,249,242,233,236,236,233, 99,128, 4,105,237,225,236,108, 2, 214,196,214,207,232,233,242,225,231,225,238, 97,128, 48,133,235, 225,244,225,235,225,238, 97,129, 48,229,214,220,232,225,236,230, 247,233,228,244,104,128,255,109,249,101, 2,214,239,214,248,235, 239,242,229,225,110,128, 49,139,239,235,239,242,229,225,110,128, 49,138,249, 97, 2,215, 9,215, 19,226,229,238,231,225,236,105, 128, 9,223,228,229,246, 97,128, 9, 95,122,142, 0,122,215, 58, 216, 66,216, 77,216,120,216,147,217,182,218, 34,218, 76,218, 88, 218,100,218,128,218,136,218,152,218,161, 97, 10,215, 80,215, 91, 215, 98,215,105,215,116,215,194,215,224,215,235,216, 15,216, 27, 225,242,237,229,238,233,225,110,128, 5,102,227,245,244,101,128, 1,122,228,229,246, 97,128, 9, 91,231,245,242,237,245,235,232, 105,128, 10, 91,104, 4,215,126,215,135,215,149,215,179,225,242, 225,226,233, 99,128, 6, 56,230,233,238,225,236,225,242,225,226, 233, 99,128,254,198,105, 2,215,155,215,170,238,233,244,233,225, 236,225,242,225,226,233, 99,128,254,199,242,225,231,225,238, 97, 128, 48, 86,237,229,228,233,225,236,225,242,225,226,233, 99,128, 254,200,233,110, 2,215,201,215,210,225,242,225,226,233, 99,128, 6, 50,230,233,238,225,236,225,242,225,226,233, 99,128,254,176, 235,225,244,225,235,225,238, 97,128, 48,182,241,229,102, 2,215, 243,216, 1,231,225,228,239,236,232,229,226,242,229,119,128, 5, 149,241,225,244,225,238,232,229,226,242,229,119,128, 5,148,242, 241,225,232,229,226,242,229,119,128, 5,152,249,233,110,130, 5, 214,216, 37,216, 57,228,225,231,229,243,104,129,251, 54,216, 48, 232,229,226,242,229,119,128,251, 54,232,229,226,242,229,119,128, 5,214,226,239,240,239,237,239,230,111,128, 49, 23, 99, 3,216, 85,216, 92,216,114,225,242,239,110,128, 1,126,233,242, 99, 2, 216,100,216,105,236,101,128, 36,233,245,237,230,236,229,120,128, 30,145,245,242,108,128, 2,145,228,239,116,130, 1,124,216,130, 216,139,225,227,227,229,238,116,128, 1,124,226,229,236,239,119, 128, 30,147,101, 6,216,161,216,172,216,215,216,226,216,237,217, 177,227,249,242,233,236,236,233, 99,128, 4, 55,100, 2,216,178, 216,197,229,243,227,229,238,228,229,242,227,249,242,233,236,236, 233, 99,128, 4,153,233,229,242,229,243,233,243,227,249,242,233, 236,236,233, 99,128, 4,223,232,233,242,225,231,225,238, 97,128, 48, 92,235,225,244,225,235,225,238, 97,128, 48,188,242,111,140, 0, 48,217, 10,217, 19,217, 29,217, 36,217, 61,217, 74,217, 85, 217, 97,217,108,217,118,217,129,217,136,225,242,225,226,233, 99, 128, 6, 96,226,229,238,231,225,236,105,128, 9,230,228,229,246, 97,128, 9,102,231,117, 2,217, 43,217, 52,234,225,242,225,244, 105,128, 10,230,242,237,245,235,232,105,128, 10,102,232,225,227, 235,225,242,225,226,233, 99,128, 6, 96,233,238,230,229,242,233, 239,114,128, 32,128,237,239,238,239,243,240,225,227,101,128,255, 16,239,236,228,243,244,249,236,101,128,247, 48,240,229,242,243, 233,225,110,128, 6,240,243,245,240,229,242,233,239,114,128, 32, 112,244,232,225,105,128, 14, 80,247,233,228,244,104, 3,217,148, 217,157,217,169,234,239,233,238,229,114,128,254,255,238,239,238, 234,239,233,238,229,114,128, 32, 12,243,240,225,227,101,128, 32, 11,244, 97,128, 3,182,104, 2,217,188,217,199,226,239,240,239, 237,239,230,111,128, 49, 19,101, 4,217,209,217,220,217,236,217, 247,225,242,237,229,238,233,225,110,128, 5,106,226,242,229,246, 229,227,249,242,233,236,236,233, 99,128, 4,194,227,249,242,233, 236,236,233, 99,128, 4, 54,100, 2,217,253,218, 16,229,243,227, 229,238,228,229,242,227,249,242,233,236,236,233, 99,128, 4,151, 233,229,242,229,243,233,243,227,249,242,233,236,236,233, 99,128, 4,221,105, 3,218, 42,218, 53,218, 64,232,233,242,225,231,225, 238, 97,128, 48, 88,235,225,244,225,235,225,238, 97,128, 48,184, 238,239,242,232,229,226,242,229,119,128, 5,174,236,233,238,229, 226,229,236,239,119,128, 30,149,237,239,238,239,243,240,225,227, 101,128,255, 90,111, 2,218,106,218,117,232,233,242,225,231,225, 238, 97,128, 48, 94,235,225,244,225,235,225,238, 97,128, 48,190, 240,225,242,229,110,128, 36,181,242,229,244,242,239,230,236,229, 248,232,239,239,107,128, 2,144,243,244,242,239,235,101,128, 1, 182,117, 2,218,167,218,178,232,233,242,225,231,225,238, 97,128, 48, 90,235,225,244,225,235,225,238, 97,128, 48,186 }; #ifndef FT_CONFIG_OPTION_PIC #define PSCMAPS_SERVICES_GET pscmaps_services #define PSCMAPS_INTERFACE_GET pscmaps_interface #else /* FT_CONFIG_OPTION_PIC */ #include FT_SERVICE_POSTSCRIPT_CMAPS_H typedef struct PSModulePIC_ { FT_ServiceDescRec* pscmaps_services; FT_Service_PsCMapsRec pscmaps_interface; } PSModulePIC; #define GET_PIC( lib ) \ ( (PSModulePIC*)((lib)->pic_container.psnames) ) #define PSCMAPS_SERVICES_GET ( GET_PIC( library )->pscmaps_services ) #define PSCMAPS_INTERFACE_GET ( GET_PIC( library )->pscmaps_interface ) /* see pspic.c for the implementation */ void psnames_module_class_pic_free( FT_Library library ); FT_Error psnames_module_class_pic_init( FT_Library library ); #endif /* FT_CONFIG_OPTION_PIC */ FT_CALLBACK_DEF( int ) compare_uni_maps( const void* a, const void* b ) { PS_UniMap* map1 = (PS_UniMap*)a; PS_UniMap* map2 = (PS_UniMap*)b; FT_UInt32 unicode1 = BASE_GLYPH( map1->unicode ); FT_UInt32 unicode2 = BASE_GLYPH( map2->unicode ); /* sort base glyphs before glyph variants */ if ( unicode1 == unicode2 ) { if ( map1->unicode > map2->unicode ) return 1; else if ( map1->unicode < map2->unicode ) return -1; else return 0; } else { if ( unicode1 > unicode2 ) return 1; else if ( unicode1 < unicode2 ) return -1; else return 0; } } #define EXTRA_GLYPH_LIST_SIZE 10 static const FT_UInt32 ft_extra_glyph_unicodes[EXTRA_GLYPH_LIST_SIZE] = { /* WGL 4 */ 0x0394, 0x03A9, 0x2215, 0x00AD, 0x02C9, 0x03BC, 0x2219, 0x00A0, /* Romanian */ 0x021A, 0x021B }; static const char ft_extra_glyph_names[] = { 'D','e','l','t','a',0, 'O','m','e','g','a',0, 'f','r','a','c','t','i','o','n',0, 'h','y','p','h','e','n',0, 'm','a','c','r','o','n',0, 'm','u',0, 'p','e','r','i','o','d','c','e','n','t','e','r','e','d',0, 's','p','a','c','e',0, 'T','c','o','m','m','a','a','c','c','e','n','t',0, 't','c','o','m','m','a','a','c','c','e','n','t',0 }; static const FT_Int ft_extra_glyph_name_offsets[EXTRA_GLYPH_LIST_SIZE] = { 0, 6, 12, 21, 28, 35, 38, 53, 59, 72 }; static void ps_check_extra_glyph_name( const char* gname, FT_UInt glyph, FT_UInt* extra_glyphs, FT_UInt *states ) { FT_UInt n; for ( n = 0; n < EXTRA_GLYPH_LIST_SIZE; n++ ) { if ( ft_strcmp( ft_extra_glyph_names + ft_extra_glyph_name_offsets[n], gname ) == 0 ) { if ( states[n] == 0 ) { /* mark this extra glyph as a candidate for the cmap */ states[n] = 1; extra_glyphs[n] = glyph; } return; } } } static void ps_check_extra_glyph_unicode( FT_UInt32 uni_char, FT_UInt *states ) { FT_UInt n; for ( n = 0; n < EXTRA_GLYPH_LIST_SIZE; n++ ) { if ( uni_char == ft_extra_glyph_unicodes[n] ) { /* disable this extra glyph from being added to the cmap */ states[n] = 2; return; } } } #ifndef FT_CONFIG_OPTION_PIC #define FT_DEFINE_SERVICE_PSCMAPSREC( class_, \ unicode_value_, \ unicodes_init_, \ unicodes_char_index_, \ unicodes_char_next_, \ macintosh_name_, \ adobe_std_strings_, \ adobe_std_encoding_, \ adobe_expert_encoding_ ) \ static const FT_Service_PsCMapsRec class_ = \ { \ unicode_value_, unicodes_init_, \ unicodes_char_index_, unicodes_char_next_, macintosh_name_, \ adobe_std_strings_, adobe_std_encoding_, adobe_expert_encoding_ \ }; #else /* FT_CONFIG_OPTION_PIC */ #define FT_DEFINE_SERVICE_PSCMAPSREC( class_, \ unicode_value_, \ unicodes_init_, \ unicodes_char_index_, \ unicodes_char_next_, \ macintosh_name_, \ adobe_std_strings_, \ adobe_std_encoding_, \ adobe_expert_encoding_ ) \ void \ FT_Init_Class_ ## class_( FT_Library library, \ FT_Service_PsCMapsRec* clazz ) \ { \ FT_UNUSED( library ); \ \ clazz->unicode_value = unicode_value_; \ clazz->unicodes_init = unicodes_init_; \ clazz->unicodes_char_index = unicodes_char_index_; \ clazz->unicodes_char_next = unicodes_char_next_; \ clazz->macintosh_name = macintosh_name_; \ clazz->adobe_std_strings = adobe_std_strings_; \ clazz->adobe_std_encoding = adobe_std_encoding_; \ clazz->adobe_expert_encoding = adobe_expert_encoding_; \ } #endif /* FT_CONFIG_OPTION_PIC */ static FT_UInt32 ps_unicode_value( const char* glyph_name ); static FT_Error ps_unicodes_init( FT_Memory memory, PS_Unicodes table, FT_UInt num_glyphs, PS_GetGlyphNameFunc get_glyph_name, PS_FreeGlyphNameFunc free_glyph_name, FT_Pointer glyph_data ); static FT_UInt ps_unicodes_char_index( PS_Unicodes table, FT_UInt32 unicode ); static FT_UInt32 ps_unicodes_char_next( PS_Unicodes table, FT_UInt32 *unicode ); static const char* ps_get_macintosh_name( FT_UInt name_index ); static const char* ps_get_standard_strings( FT_UInt sid ); #ifdef FT_CONFIG_OPTION_ADOBE_GLYPH_LIST FT_DEFINE_SERVICE_PSCMAPSREC( pscmaps_interface, (PS_Unicode_ValueFunc) ps_unicode_value, (PS_Unicodes_InitFunc) ps_unicodes_init, (PS_Unicodes_CharIndexFunc)ps_unicodes_char_index, (PS_Unicodes_CharNextFunc) ps_unicodes_char_next, (PS_Macintosh_NameFunc) ps_get_macintosh_name, (PS_Adobe_Std_StringsFunc) ps_get_standard_strings, t1_standard_encoding, t1_expert_encoding ) #else FT_DEFINE_SERVICE_PSCMAPSREC( pscmaps_interface, NULL, NULL, NULL, NULL, (PS_Macintosh_NameFunc) ps_get_macintosh_name, (PS_Adobe_Std_StringsFunc) ps_get_standard_strings, t1_standard_encoding, t1_expert_encoding ) #endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */ FT_DEFINE_SERVICEDESCREC1( pscmaps_services, FT_SERVICE_ID_POSTSCRIPT_CMAPS, &PSCMAPS_INTERFACE_GET ) static FT_Pointer psnames_get_service( FT_Module module, const char* service_id ) { /* PSCMAPS_SERVICES_GET derefers `library' in PIC mode */ #ifdef FT_CONFIG_OPTION_PIC FT_Library library; if ( !module ) return NULL; library = module->library; if ( !library ) return NULL; #else FT_UNUSED( module ); #endif return ft_service_list_lookup( PSCMAPS_SERVICES_GET, service_id ); } static unsigned long ft_get_adobe_glyph_index( const char* name, const char* limit ) { int c = 0; int count, min, max; const unsigned char* p = ft_adobe_glyph_list; if ( name == 0 || name >= limit ) goto NotFound; c = *name++; count = p[1]; p += 2; min = 0; max = count; while ( min < max ) { int mid = ( min + max ) >> 1; const unsigned char* q = p + mid * 2; int c2; q = ft_adobe_glyph_list + ( ( (int)q[0] << 8 ) | q[1] ); c2 = q[0] & 127; if ( c2 == c ) { p = q; goto Found; } if ( c2 < c ) min = mid + 1; else max = mid; } goto NotFound; Found: for (;;) { /* assert (*p & 127) == c */ if ( name >= limit ) { if ( (p[0] & 128) == 0 && (p[1] & 128) != 0 ) return (unsigned long)( ( (int)p[2] << 8 ) | p[3] ); goto NotFound; } c = *name++; if ( p[0] & 128 ) { p++; if ( c != (p[0] & 127) ) goto NotFound; continue; } p++; count = p[0] & 127; if ( p[0] & 128 ) p += 2; p++; for ( ; count > 0; count--, p += 2 ) { int offset = ( (int)p[0] << 8 ) | p[1]; const unsigned char* q = ft_adobe_glyph_list + offset; if ( c == ( q[0] & 127 ) ) { p = q; goto NextIter; } } goto NotFound; NextIter: ; } NotFound: return 0; } static FT_UInt32 ps_unicode_value( const char* glyph_name ) { /* If the name begins with `uni', then the glyph name may be a */ /* hard-coded unicode character code. */ if ( glyph_name[0] == 'u' && glyph_name[1] == 'n' && glyph_name[2] == 'i' ) { /* determine whether the next four characters following are */ /* hexadecimal. */ /* XXX: Add code to deal with ligatures, i.e. glyph names like */ /* `uniXXXXYYYYZZZZ'... */ FT_Int count; FT_UInt32 value = 0; const char* p = glyph_name + 3; for ( count = 4; count > 0; count--, p++ ) { char c = *p; unsigned int d; d = (unsigned char)c - '0'; if ( d >= 10 ) { d = (unsigned char)c - 'A'; if ( d >= 6 ) d = 16; else d += 10; } /* Exit if a non-uppercase hexadecimal character was found */ /* -- this also catches character codes below `0' since such */ /* negative numbers cast to `unsigned int' are far too big. */ if ( d >= 16 ) break; value = ( value << 4 ) + d; } /* there must be exactly four hex digits */ if ( count == 0 ) { if ( *p == '\0' ) return value; if ( *p == '.' ) return (FT_UInt32)( value | VARIANT_BIT ); } } /* If the name begins with `u', followed by four to six uppercase */ /* hexadecimal digits, it is a hard-coded unicode character code. */ if ( glyph_name[0] == 'u' ) { FT_Int count; FT_UInt32 value = 0; const char* p = glyph_name + 1; for ( count = 6; count > 0; count--, p++ ) { char c = *p; unsigned int d; d = (unsigned char)c - '0'; if ( d >= 10 ) { d = (unsigned char)c - 'A'; if ( d >= 6 ) d = 16; else d += 10; } if ( d >= 16 ) break; value = ( value << 4 ) + d; } if ( count <= 2 ) { if ( *p == '\0' ) return value; if ( *p == '.' ) return (FT_UInt32)( value | VARIANT_BIT ); } } /* Look for a non-initial dot in the glyph name in order to */ /* find variants like `A.swash', `e.final', etc. */ { const char* p = glyph_name; const char* dot = NULL; for ( ; *p; p++ ) { if ( *p == '.' && p > glyph_name ) { dot = p; break; } } /* now look up the glyph in the Adobe Glyph List */ if ( !dot ) return (FT_UInt32)ft_get_adobe_glyph_index( glyph_name, p ); else return (FT_UInt32)( ft_get_adobe_glyph_index( glyph_name, dot ) | VARIANT_BIT ); } } static FT_Error ps_unicodes_init( FT_Memory memory, PS_Unicodes table, FT_UInt num_glyphs, PS_GetGlyphNameFunc get_glyph_name, PS_FreeGlyphNameFunc free_glyph_name, FT_Pointer glyph_data ) { FT_Error error; FT_UInt extra_glyph_list_states[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; FT_UInt extra_glyphs[EXTRA_GLYPH_LIST_SIZE]; /* we first allocate the table */ table->num_maps = 0; table->maps = 0; if ( !FT_NEW_ARRAY( table->maps, num_glyphs + EXTRA_GLYPH_LIST_SIZE ) ) { FT_UInt n; FT_UInt count; PS_UniMap* map; FT_UInt32 uni_char; map = table->maps; for ( n = 0; n < num_glyphs; n++ ) { const char* gname = get_glyph_name( glyph_data, n ); if ( gname ) { ps_check_extra_glyph_name( gname, n, extra_glyphs, extra_glyph_list_states ); uni_char = ps_unicode_value( gname ); if ( BASE_GLYPH( uni_char ) != 0 ) { ps_check_extra_glyph_unicode( uni_char, extra_glyph_list_states ); map->unicode = uni_char; map->glyph_index = n; map++; } if ( free_glyph_name ) free_glyph_name( glyph_data, gname ); } } for ( n = 0; n < EXTRA_GLYPH_LIST_SIZE; n++ ) { if ( extra_glyph_list_states[n] == 1 ) { /* This glyph name has an additional representation. */ /* Add it to the cmap. */ map->unicode = ft_extra_glyph_unicodes[n]; map->glyph_index = extra_glyphs[n]; map++; } } /* now compress the table a bit */ count = (FT_UInt)( map - table->maps ); if ( count == 0 ) { /* No unicode chars here! */ FT_FREE( table->maps ); if ( !error ) error = FT_THROW( No_Unicode_Glyph_Name ); } else { /* Reallocate if the number of used entries is much smaller. */ if ( count < num_glyphs / 2 ) { (void)FT_RENEW_ARRAY( table->maps, num_glyphs, count ); error = FT_Err_Ok; } /* Sort the table in increasing order of unicode values, */ /* taking care of glyph variants. */ ft_qsort( table->maps, count, sizeof ( PS_UniMap ), compare_uni_maps ); } table->num_maps = count; } return error; } static FT_UInt ps_unicodes_char_index( PS_Unicodes table, FT_UInt32 unicode ) { PS_UniMap *min, *max, *mid, *result = NULL; /* Perform a binary search on the table. */ min = table->maps; max = min + table->num_maps - 1; while ( min <= max ) { FT_UInt32 base_glyph; mid = min + ( ( max - min ) >> 1 ); if ( mid->unicode == unicode ) { result = mid; break; } base_glyph = BASE_GLYPH( mid->unicode ); if ( base_glyph == unicode ) result = mid; /* remember match but continue search for base glyph */ if ( min == max ) break; if ( base_glyph < unicode ) min = mid + 1; else max = mid - 1; } if ( result ) return result->glyph_index; else return 0; } static FT_UInt32 ps_unicodes_char_next( PS_Unicodes table, FT_UInt32 *unicode ) { FT_UInt result = 0; FT_UInt32 char_code = *unicode + 1; { FT_UInt min = 0; FT_UInt max = table->num_maps; FT_UInt mid; PS_UniMap* map; FT_UInt32 base_glyph; while ( min < max ) { mid = min + ( ( max - min ) >> 1 ); map = table->maps + mid; if ( map->unicode == char_code ) { result = map->glyph_index; goto Exit; } base_glyph = BASE_GLYPH( map->unicode ); if ( base_glyph == char_code ) result = map->glyph_index; if ( base_glyph < char_code ) min = mid + 1; else max = mid; } if ( result ) goto Exit; /* we have a variant glyph */ /* we didn't find it; check whether we have a map just above it */ char_code = 0; if ( min < table->num_maps ) { map = table->maps + min; result = map->glyph_index; char_code = BASE_GLYPH( map->unicode ); } } Exit: *unicode = char_code; return result; } static const char* ps_get_macintosh_name( FT_UInt name_index ) { if ( name_index >= FT_NUM_MAC_NAMES ) name_index = 0; return ft_standard_glyph_names + ft_mac_names[name_index]; } static const char* ps_get_standard_strings( FT_UInt sid ) { if ( sid >= FT_NUM_SID_NAMES ) return 0; return ft_standard_glyph_names + ft_sid_names[sid]; } // ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ #ifndef FT_CONFIG_OPTION_PIC #define PSCMAPS_SERVICES_GET pscmaps_services #define PSCMAPS_INTERFACE_GET pscmaps_interface #else /* FT_CONFIG_OPTION_PIC */ #include FT_SERVICE_POSTSCRIPT_CMAPS_H typedef struct PSModulePIC_ { FT_ServiceDescRec* pscmaps_services; FT_Service_PsCMapsRec pscmaps_interface; } PSModulePIC; #define GET_PIC( lib ) \ ( (PSModulePIC*)((lib)->pic_container.psnames) ) #define PSCMAPS_SERVICES_GET ( GET_PIC( library )->pscmaps_services ) #define PSCMAPS_INTERFACE_GET ( GET_PIC( library )->pscmaps_interface ) /* see pspic.c for the implementation */ void psnames_module_class_pic_free( FT_Library library ); FT_Error psnames_module_class_pic_init( FT_Library library ); #endif /* FT_CONFIG_OPTION_PIC */ #ifndef FT_CONFIG_OPTION_POSTSCRIPT_NAMES #define PUT_PS_NAMES_SERVICE( a ) NULL #else #define PUT_PS_NAMES_SERVICE( a ) a #endif FT_DEFINE_MODULE( psnames_module_class, 0, /* this is not a font driver, nor a renderer */ sizeof ( FT_ModuleRec ), "psnames", /* driver name */ 0x10000L, /* driver version */ 0x20000L, /* driver requires FreeType 2 or above */ PUT_PS_NAMES_SERVICE( (void*)&PSCMAPS_INTERFACE_GET ), /* module specific interface */ (FT_Module_Constructor)NULL, (FT_Module_Destructor) NULL, (FT_Module_Requester) PUT_PS_NAMES_SERVICE( psnames_get_service ) ) // ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ FT_DECLARE_RENDERER( ft_raster1_renderer_class ) FT_DECLARE_RENDERER( ft_raster5_renderer_class ) #define FT_RASTER_FLAG_DEFAULT 0x0 #define FT_RASTER_FLAG_AA 0x1 #define FT_RASTER_FLAG_DIRECT 0x2 #define FT_RASTER_FLAG_CLIP 0x4 #ifndef FT_CONFIG_OPTION_PIC #define FT_STANDARD_RASTER_GET ft_standard_raster #else /* FT_CONFIG_OPTION_PIC */ typedef struct RasterPIC_ { int ref_count; FT_Raster_Funcs ft_standard_raster; } RasterPIC; #define GET_PIC( lib ) \ ( (RasterPIC*)( (lib)->pic_container.raster ) ) #define FT_STANDARD_RASTER_GET ( GET_PIC( library )->ft_standard_raster ) /* see rastpic.c for the implementation */ void ft_raster1_renderer_class_pic_free( FT_Library library ); void ft_raster5_renderer_class_pic_free( FT_Library library ); FT_Error ft_raster1_renderer_class_pic_init( FT_Library library ); FT_Error ft_raster5_renderer_class_pic_init( FT_Library library ); #endif /* FT_CONFIG_OPTION_PIC */ static FT_Error ft_raster1_init( FT_Renderer render ) { FT_Library library = FT_MODULE_LIBRARY( render ); render->clazz->raster_class->raster_reset( render->raster, library->raster_pool, library->raster_pool_size ); return FT_Err_Ok; } /* set render-specific mode */ static FT_Error ft_raster1_set_mode( FT_Renderer render, FT_ULong mode_tag, FT_Pointer data ) { /* we simply pass it to the raster */ return render->clazz->raster_class->raster_set_mode( render->raster, mode_tag, data ); } /* transform a given glyph image */ static FT_Error ft_raster1_transform( FT_Renderer render, FT_GlyphSlot slot, const FT_Matrix* matrix, const FT_Vector* delta ) { FT_Error error = FT_Err_Ok; if ( slot->format != render->glyph_format ) { error = FT_THROW( Invalid_Argument ); goto Exit; } if ( matrix ) FT_Outline_Transform( &slot->outline, matrix ); if ( delta ) FT_Outline_Translate( &slot->outline, delta->x, delta->y ); Exit: return error; } /* return the glyph's control box */ static void ft_raster1_get_cbox( FT_Renderer render, FT_GlyphSlot slot, FT_BBox* cbox ) { FT_MEM_ZERO( cbox, sizeof ( *cbox ) ); if ( slot->format == render->glyph_format ) FT_Outline_Get_CBox( &slot->outline, cbox ); } /* convert a slot's glyph image into a bitmap */ static FT_Error ft_raster1_render( FT_Renderer render, FT_GlyphSlot slot, FT_Render_Mode mode, const FT_Vector* origin ) { FT_Error error; FT_Outline* outline; FT_BBox cbox; FT_UInt width, height, pitch; FT_Bitmap* bitmap; FT_Memory memory; FT_Raster_Params params; /* check glyph image format */ if ( slot->format != render->glyph_format ) { error = FT_THROW( Invalid_Argument ); goto Exit; } /* check rendering mode */ #ifndef FT_CONFIG_OPTION_PIC if ( mode != FT_RENDER_MODE_MONO ) { /* raster1 is only capable of producing monochrome bitmaps */ if ( render->clazz == &ft_raster1_renderer_class ) return FT_THROW( Cannot_Render_Glyph ); } else { /* raster5 is only capable of producing 5-gray-levels bitmaps */ if ( render->clazz == &ft_raster5_renderer_class ) return FT_THROW( Cannot_Render_Glyph ); } #else /* FT_CONFIG_OPTION_PIC */ /* When PIC is enabled, we cannot get to the class object */ /* so instead we check the final character in the class name */ /* ("raster5" or "raster1"). Yes this is a hack. */ /* The "correct" thing to do is have different render function */ /* for each of the classes. */ if ( mode != FT_RENDER_MODE_MONO ) { /* raster1 is only capable of producing monochrome bitmaps */ if ( render->clazz->root.module_name[6] == '1' ) return FT_THROW( Cannot_Render_Glyph ); } else { /* raster5 is only capable of producing 5-gray-levels bitmaps */ if ( render->clazz->root.module_name[6] == '5' ) return FT_THROW( Cannot_Render_Glyph ); } #endif /* FT_CONFIG_OPTION_PIC */ outline = &slot->outline; /* translate the outline to the new origin if needed */ if ( origin ) FT_Outline_Translate( outline, origin->x, origin->y ); /* compute the control box, and grid fit it */ FT_Outline_Get_CBox( outline, &cbox ); /* undocumented but confirmed: bbox values get rounded */ #if 1 cbox.xMin = FT_PIX_ROUND( cbox.xMin ); cbox.yMin = FT_PIX_ROUND( cbox.yMin ); cbox.xMax = FT_PIX_ROUND( cbox.xMax ); cbox.yMax = FT_PIX_ROUND( cbox.yMax ); #else cbox.xMin = FT_PIX_FLOOR( cbox.xMin ); cbox.yMin = FT_PIX_FLOOR( cbox.yMin ); cbox.xMax = FT_PIX_CEIL( cbox.xMax ); cbox.yMax = FT_PIX_CEIL( cbox.yMax ); #endif width = (FT_UInt)( ( cbox.xMax - cbox.xMin ) >> 6 ); height = (FT_UInt)( ( cbox.yMax - cbox.yMin ) >> 6 ); if ( width > FT_USHORT_MAX || height > FT_USHORT_MAX ) { error = FT_THROW( Invalid_Argument ); goto Exit; } bitmap = &slot->bitmap; memory = render->root.memory; /* release old bitmap buffer */ if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) { FT_FREE( bitmap->buffer ); slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; } /* allocate new one, depends on pixel format */ if ( !( mode & FT_RENDER_MODE_MONO ) ) { /* we pad to 32 bits, only for backwards compatibility with FT 1.x */ pitch = FT_PAD_CEIL( width, 4 ); bitmap->pixel_mode = FT_PIXEL_MODE_GRAY; bitmap->num_grays = 256; } else { pitch = ( ( width + 15 ) >> 4 ) << 1; bitmap->pixel_mode = FT_PIXEL_MODE_MONO; } bitmap->width = width; bitmap->rows = height; bitmap->pitch = pitch; if ( FT_ALLOC_MULT( bitmap->buffer, pitch, height ) ) goto Exit; slot->internal->flags |= FT_GLYPH_OWN_BITMAP; /* translate outline to render it into the bitmap */ FT_Outline_Translate( outline, -cbox.xMin, -cbox.yMin ); /* set up parameters */ params.target = bitmap; params.source = outline; params.flags = 0; if ( bitmap->pixel_mode == FT_PIXEL_MODE_GRAY ) params.flags |= FT_RASTER_FLAG_AA; /* render outline into the bitmap */ error = render->raster_render( render->raster, ¶ms ); FT_Outline_Translate( outline, cbox.xMin, cbox.yMin ); if ( error ) goto Exit; slot->format = FT_GLYPH_FORMAT_BITMAP; slot->bitmap_left = (FT_Int)( cbox.xMin >> 6 ); slot->bitmap_top = (FT_Int)( cbox.yMax >> 6 ); Exit: return error; } #ifndef FT_CONFIG_OPTION_PIC #define FT_DEFINE_RASTER_FUNCS( \ class_, \ glyph_format_, \ raster_new_, \ raster_reset_, \ raster_set_mode_, \ raster_render_, \ raster_done_ ) \ const FT_Raster_Funcs class_ = \ { \ glyph_format_, \ raster_new_, \ raster_reset_, \ raster_set_mode_, \ raster_render_, \ raster_done_ \ }; #else /* FT_CONFIG_OPTION_PIC */ #define FT_DEFINE_RASTER_FUNCS( \ class_, \ glyph_format_, \ raster_new_, \ raster_reset_, \ raster_set_mode_, \ raster_render_, \ raster_done_ ) \ void \ FT_Init_Class_ ## class_( FT_Raster_Funcs* clazz ) \ { \ clazz->glyph_format = glyph_format_; \ clazz->raster_new = raster_new_; \ clazz->raster_reset = raster_reset_; \ clazz->raster_set_mode = raster_set_mode_; \ clazz->raster_render = raster_render_; \ clazz->raster_done = raster_done_; \ } #endif /* FT_CONFIG_OPTION_PIC */ typedef int (*FT_Raster_NewFunc)( void* memory, FT_Raster* raster ); #define FT_Raster_New_Func FT_Raster_NewFunc typedef void (*FT_Raster_ResetFunc)( FT_Raster raster, unsigned char* pool_base, unsigned long pool_size ); #define FT_Raster_Reset_Func FT_Raster_ResetFunc typedef int (*FT_Raster_SetModeFunc)( FT_Raster raster, unsigned long mode, void* args ); #define FT_Raster_Set_Mode_Func FT_Raster_SetModeFunc typedef int (*FT_Raster_RenderFunc)( FT_Raster raster, const FT_Raster_Params* params ); #define FT_Raster_Render_Func FT_Raster_RenderFunc typedef void (*FT_Raster_DoneFunc)( FT_Raster raster ); #define FT_Raster_Done_Func FT_Raster_DoneFunc typedef int Int; typedef unsigned int UInt; typedef short Short; typedef unsigned short UShort, *PUShort; typedef long Long, *PLong; typedef unsigned long ULong; typedef unsigned char Byte, *PByte; typedef char Bool; typedef union Alignment_ { long l; void* p; void (*f)(void); } Alignment, *PAlignment; typedef struct TPoint_ { Long x; Long y; } TPoint; /* values for the `flags' bit field */ #define Flow_Up 0x8 #define Overshoot_Top 0x10 #define Overshoot_Bottom 0x20 /* States of each line, arc, and profile */ typedef enum TStates_ { Unknown_State, Ascending_State, Descending_State, Flat_State } TStates; typedef struct TProfile_ TProfile; typedef TProfile* PProfile; struct TProfile_ { FT_F26Dot6 X; /* current coordinate during sweep */ PProfile link; /* link to next profile (various purposes) */ PLong offset; /* start of profile's data in render pool */ unsigned flags; /* Bit 0-2: drop-out mode */ /* Bit 3: profile orientation (up/down) */ /* Bit 4: is top profile? */ /* Bit 5: is bottom profile? */ long height; /* profile's height in scanlines */ long start; /* profile's starting scanline */ unsigned countL; /* number of lines to step before this */ /* profile becomes drawable */ PProfile next; /* next profile in same contour, used */ /* during drop-out control */ }; typedef PProfile TProfileList; typedef PProfile* PProfileList; /* Simple record used to implement a stack of bands, required */ /* by the sub-banding mechanism */ typedef struct black_TBand_ { Short y_min; /* band's minimum */ Short y_max; /* band's maximum */ } black_TBand; #define AlignProfileSize \ ( ( sizeof ( TProfile ) + sizeof ( Alignment ) - 1 ) / sizeof ( long ) ) #undef RAS_ARG #undef RAS_ARGS #undef RAS_VAR #undef RAS_VARS #ifdef FT_STATIC_RASTER #define RAS_ARGS /* void */ #define RAS_ARG /* void */ #define RAS_VARS /* void */ #define RAS_VAR /* void */ #define FT_UNUSED_RASTER do { } while ( 0 ) #else /* !FT_STATIC_RASTER */ #define RAS_ARGS black_PWorker worker, #define RAS_ARG black_PWorker worker #define RAS_VARS worker, #define RAS_VAR worker #define FT_UNUSED_RASTER FT_UNUSED( worker ) #endif /* !FT_STATIC_RASTER */ typedef struct black_TWorker_ black_TWorker, *black_PWorker; typedef void Function_Sweep_Init( RAS_ARGS Short* min, Short* max ); typedef void Function_Sweep_Span( RAS_ARGS Short y, FT_F26Dot6 x1, FT_F26Dot6 x2, PProfile left, PProfile right ); typedef void Function_Sweep_Step( RAS_ARG ); #define MaxBezier 32 /* The maximum number of stacked Bezier curves. */ /* Setting this constant to more than 32 is a */ /* pure waste of space. */ #define Pixel_Bits 6 /* fractional bits of *input* coordinates */ struct black_TWorker_ { Int precision_bits; /* precision related variables */ Int precision; Int precision_half; Int precision_shift; Int precision_step; Int precision_jitter; Int scale_shift; /* == precision_shift for bitmaps */ /* == precision_shift+1 for pixmaps */ PLong buff; /* The profiles buffer */ PLong sizeBuff; /* Render pool size */ PLong maxBuff; /* Profiles buffer size */ PLong top; /* Current cursor in buffer */ FT_Error error; Int numTurns; /* number of Y-turns in outline */ TPoint* arc; /* current Bezier arc pointer */ UShort bWidth; /* target bitmap width */ PByte bTarget; /* target bitmap buffer */ PByte gTarget; /* target pixmap buffer */ Long lastX, lastY; Long minY, maxY; UShort num_Profs; /* current number of profiles */ Bool fresh; /* signals a fresh new profile which */ /* `start' field must be completed */ Bool joint; /* signals that the last arc ended */ /* exactly on a scanline. Allows */ /* removal of doublets */ PProfile cProfile; /* current profile */ PProfile fProfile; /* head of linked list of profiles */ PProfile gProfile; /* contour's first profile in case */ /* of impact */ TStates state; /* rendering state */ FT_Bitmap target; /* description of target bit/pixmap */ FT_Outline outline; Long traceOfs; /* current offset in target bitmap */ Long traceG; /* current offset in target pixmap */ Short traceIncr; /* sweep's increment in target bitmap */ Short gray_min_x; /* current min x during gray rendering */ Short gray_max_x; /* current max x during gray rendering */ /* dispatch variables */ Function_Sweep_Init* Proc_Sweep_Init; Function_Sweep_Span* Proc_Sweep_Span; Function_Sweep_Span* Proc_Sweep_Drop; Function_Sweep_Step* Proc_Sweep_Step; Byte dropOutControl; /* current drop_out control method */ Bool second_pass; /* indicates whether a horizontal pass */ /* should be performed to control */ /* drop-out accurately when calling */ /* Render_Glyph. Note that there is */ /* no horizontal pass during gray */ /* rendering. */ TPoint arcs[3 * MaxBezier + 1]; /* The Bezier stack */ black_TBand band_stack[16]; /* band stack used for sub-banding */ Int band_top; /* band stack top */ #ifdef FT_RASTER_OPTION_ANTI_ALIASING Byte* grays; Byte gray_lines[RASTER_GRAY_LINES]; /* Intermediate table used to render the */ /* graylevels pixmaps. */ /* gray_lines is a buffer holding two */ /* monochrome scanlines */ Short gray_width; /* width in bytes of one monochrome */ /* intermediate scanline of gray_lines. */ /* Each gray pixel takes 2 bits long there */ /* The gray_lines must hold 2 lines, thus with size */ /* in bytes of at least `gray_width*2'. */ #endif /* FT_RASTER_ANTI_ALIASING */ }; typedef struct black_TWorker_ black_TWorker, *black_PWorker; typedef struct black_TRaster_ { char* buffer; long buffer_size; void* memory; black_PWorker worker; Byte grays[5]; Short gray_width; } black_TRaster, *black_PRaster; static void ft_black_init( black_PRaster raster ) { #ifdef FT_RASTER_OPTION_ANTI_ALIASING FT_UInt n; /* set default 5-levels gray palette */ for ( n = 0; n < 5; n++ ) raster->grays[n] = n * 255 / 4; raster->gray_width = RASTER_GRAY_LINES / 2; #else FT_UNUSED( raster ); #endif } static int ft_black_new( FT_Memory memory, black_PRaster *araster ) { FT_Error error; black_PRaster raster = NULL; *araster = 0; if ( !FT_NEW( raster ) ) { raster->memory = memory; ft_black_init( raster ); *araster = raster; } return error; } static void ft_black_done( black_PRaster raster ) { FT_Memory memory = (FT_Memory)raster->memory; FT_FREE( raster ); } static void ft_black_reset( black_PRaster raster, char* pool_base, long pool_size ) { if ( raster ) { if ( pool_base && pool_size >= (long)sizeof ( black_TWorker ) + 2048 ) { black_PWorker worker = (black_PWorker)pool_base; raster->buffer = pool_base + ( ( sizeof ( *worker ) + 7 ) & ~7 ); raster->buffer_size = (long)( pool_base + pool_size - (char*)raster->buffer ); raster->worker = worker; } else { raster->buffer = NULL; raster->buffer_size = 0; raster->worker = NULL; } } } static void ft_black_set_mode( black_PRaster raster, unsigned long mode, const char* palette ) { #ifdef FT_RASTER_OPTION_ANTI_ALIASING if ( mode == FT_MAKE_TAG( 'p', 'a', 'l', '5' ) ) { /* set 5-levels gray palette */ raster->grays[0] = palette[0]; raster->grays[1] = palette[1]; raster->grays[2] = palette[2]; raster->grays[3] = palette[3]; raster->grays[4] = palette[4]; } #else FT_UNUSED( raster ); FT_UNUSED( mode ); FT_UNUSED( palette ); #endif } #define FT_Err_None FT_Err_Ok #define FT_Err_Not_Ini FT_Err_Raster_Uninitialized #define FT_Err_Overflow FT_Err_Raster_Overflow #define FT_Err_Neg_Height FT_Err_Raster_Negative_Height #define FT_Err_Invalid FT_Err_Invalid_Outline #define FT_Err_Unsupported FT_Err_Cannot_Render_Glyph #ifdef FT_STATIC_RASTER static black_TWorker cur_ras; #define ras cur_ras #else /* !FT_STATIC_RASTER */ #define ras (*worker) #endif /* !FT_STATIC_RASTER */ #ifdef FT_RASTER_OPTION_ANTI_ALIASING /*************************************************************************/ /* */ /* */ /* Render_Gray_Glyph */ /* */ /* */ /* Render a glyph with grayscaling. Sub-banding if needed. */ /* */ /* */ /* FreeType error code. 0 means success. */ /* */ FT_LOCAL_DEF( FT_Error ) Render_Gray_Glyph( RAS_ARG ) { Long pixel_width; FT_Error error; Set_High_Precision( RAS_VARS ras.outline.flags & FT_OUTLINE_HIGH_PRECISION ); ras.scale_shift = ras.precision_shift + 1; if ( ras.outline.flags & FT_OUTLINE_IGNORE_DROPOUTS ) ras.dropOutControl = 2; else { if ( ras.outline.flags & FT_OUTLINE_SMART_DROPOUTS ) ras.dropOutControl = 4; else ras.dropOutControl = 0; if ( !( ras.outline.flags & FT_OUTLINE_INCLUDE_STUBS ) ) ras.dropOutControl += 1; } ras.second_pass = !( ras.outline.flags & FT_OUTLINE_SINGLE_PASS ); /* Vertical Sweep */ ras.band_top = 0; ras.band_stack[0].y_min = 0; ras.band_stack[0].y_max = 2 * ras.target.rows - 1; ras.bWidth = ras.gray_width; pixel_width = 2 * ( ( ras.target.width + 3 ) >> 2 ); if ( ras.bWidth > pixel_width ) ras.bWidth = pixel_width; ras.bWidth = ras.bWidth * 8; ras.bTarget = (Byte*)ras.gray_lines; ras.gTarget = (Byte*)ras.target.buffer; ras.Proc_Sweep_Init = Vertical_Gray_Sweep_Init; ras.Proc_Sweep_Span = Vertical_Sweep_Span; ras.Proc_Sweep_Drop = Vertical_Sweep_Drop; ras.Proc_Sweep_Step = Vertical_Gray_Sweep_Step; error = Render_Single_Pass( RAS_VARS 0 ); if ( error ) return error; /* Horizontal Sweep */ if ( ras.second_pass && ras.dropOutControl != 2 ) { ras.Proc_Sweep_Init = Horizontal_Sweep_Init; ras.Proc_Sweep_Span = Horizontal_Gray_Sweep_Span; ras.Proc_Sweep_Drop = Horizontal_Gray_Sweep_Drop; ras.Proc_Sweep_Step = Horizontal_Sweep_Step; ras.band_top = 0; ras.band_stack[0].y_min = 0; ras.band_stack[0].y_max = ras.target.width * 2 - 1; error = Render_Single_Pass( RAS_VARS 1 ); if ( error ) return error; } return Raster_Err_None; } #else /* !FT_RASTER_OPTION_ANTI_ALIASING */ FT_LOCAL_DEF( FT_Error ) Render_Gray_Glyph( RAS_ARG ) { FT_UNUSED_RASTER; return FT_THROW( Unsupported ); } #endif /* !FT_RASTER_OPTION_ANTI_ALIASING */ #undef FLOOR #undef CEILING #undef TRUNC #undef SCALED #define FLOOR( x ) ( (x) & -ras.precision ) #define CEILING( x ) ( ( (x) + ras.precision - 1 ) & -ras.precision ) #define TRUNC( x ) ( (Long)(x) >> ras.precision_bits ) #define FRAC( x ) ( (x) & ( ras.precision - 1 ) ) #define SCALED( x ) ( ( (ULong)(x) << ras.scale_shift ) - ras.precision_half ) #define IS_BOTTOM_OVERSHOOT( x ) \ (Bool)( CEILING( x ) - x >= ras.precision_half ) #define IS_TOP_OVERSHOOT( x ) \ (Bool)( x - FLOOR( x ) >= ras.precision_half ) static void Vertical_Sweep_Init( RAS_ARGS Short* min, Short* max ) { Long pitch = ras.target.pitch; FT_UNUSED( max ); ras.traceIncr = (Short)-pitch; ras.traceOfs = -*min * pitch; if ( pitch > 0 ) ras.traceOfs += ( ras.target.rows - 1 ) * pitch; ras.gray_min_x = 0; ras.gray_max_x = 0; } static void Vertical_Sweep_Span( RAS_ARGS Short y, FT_F26Dot6 x1, FT_F26Dot6 x2, PProfile left, PProfile right ) { Long e1, e2; Byte* target; FT_UNUSED( y ); FT_UNUSED( left ); FT_UNUSED( right ); /* Drop-out control */ e1 = TRUNC( CEILING( x1 ) ); if ( x2 - x1 - ras.precision <= ras.precision_jitter ) e2 = e1; else e2 = TRUNC( FLOOR( x2 ) ); if ( e2 >= 0 && e1 < ras.bWidth ) { int c1, c2; Byte f1, f2; if ( e1 < 0 ) e1 = 0; if ( e2 >= ras.bWidth ) e2 = ras.bWidth - 1; c1 = (Short)( e1 >> 3 ); c2 = (Short)( e2 >> 3 ); f1 = (Byte) ( 0xFF >> ( e1 & 7 ) ); f2 = (Byte) ~( 0x7F >> ( e2 & 7 ) ); if ( ras.gray_min_x > c1 ) ras.gray_min_x = (short)c1; if ( ras.gray_max_x < c2 ) ras.gray_max_x = (short)c2; target = ras.bTarget + ras.traceOfs + c1; c2 -= c1; if ( c2 > 0 ) { target[0] |= f1; /* memset() is slower than the following code on many platforms. */ /* This is due to the fact that, in the vast majority of cases, */ /* the span length in bytes is relatively small. */ c2--; while ( c2 > 0 ) { *(++target) = 0xFF; c2--; } target[1] |= f2; } else *target |= ( f1 & f2 ); } } static void Vertical_Sweep_Drop( RAS_ARGS Short y, FT_F26Dot6 x1, FT_F26Dot6 x2, PProfile left, PProfile right ) { Long e1, e2, pxl; Short c1, f1; /* Drop-out control */ /* e2 x2 x1 e1 */ /* */ /* ^ | */ /* | | */ /* +-------------+---------------------+------------+ */ /* | | */ /* | v */ /* */ /* pixel contour contour pixel */ /* center center */ /* drop-out mode scan conversion rules (as defined in OpenType) */ /* --------------------------------------------------------------- */ /* 0 1, 2, 3 */ /* 1 1, 2, 4 */ /* 2 1, 2 */ /* 3 same as mode 2 */ /* 4 1, 2, 5 */ /* 5 1, 2, 6 */ /* 6, 7 same as mode 2 */ e1 = CEILING( x1 ); e2 = FLOOR ( x2 ); pxl = e1; if ( e1 > e2 ) { Int dropOutControl = left->flags & 7; if ( e1 == e2 + ras.precision ) { switch ( dropOutControl ) { case 0: /* simple drop-outs including stubs */ pxl = e2; break; case 4: /* smart drop-outs including stubs */ pxl = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half ); break; case 1: /* simple drop-outs excluding stubs */ case 5: /* smart drop-outs excluding stubs */ /* Drop-out Control Rules #4 and #6 */ /* The specification neither provides an exact definition */ /* of a `stub' nor gives exact rules to exclude them. */ /* */ /* Here the constraints we use to recognize a stub. */ /* */ /* upper stub: */ /* */ /* - P_Left and P_Right are in the same contour */ /* - P_Right is the successor of P_Left in that contour */ /* - y is the top of P_Left and P_Right */ /* */ /* lower stub: */ /* */ /* - P_Left and P_Right are in the same contour */ /* - P_Left is the successor of P_Right in that contour */ /* - y is the bottom of P_Left */ /* */ /* We draw a stub if the following constraints are met. */ /* */ /* - for an upper or lower stub, there is top or bottom */ /* overshoot, respectively */ /* - the covered interval is greater or equal to a half */ /* pixel */ /* upper stub test */ if ( left->next == right && left->height <= 0 && !( left->flags & Overshoot_Top && x2 - x1 >= ras.precision_half ) ) return; /* lower stub test */ if ( right->next == left && left->start == y && !( left->flags & Overshoot_Bottom && x2 - x1 >= ras.precision_half ) ) return; if ( dropOutControl == 1 ) pxl = e2; else pxl = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half ); break; default: /* modes 2, 3, 6, 7 */ return; /* no drop-out control */ } /* undocumented but confirmed: If the drop-out would result in a */ /* pixel outside of the bounding box, use the pixel inside of the */ /* bounding box instead */ if ( pxl < 0 ) pxl = e1; else if ( TRUNC( pxl ) >= ras.bWidth ) pxl = e2; /* check that the other pixel isn't set */ e1 = pxl == e1 ? e2 : e1; e1 = TRUNC( e1 ); c1 = (Short)( e1 >> 3 ); f1 = (Short)( e1 & 7 ); if ( e1 >= 0 && e1 < ras.bWidth && ras.bTarget[ras.traceOfs + c1] & ( 0x80 >> f1 ) ) return; } else return; } e1 = TRUNC( pxl ); if ( e1 >= 0 && e1 < ras.bWidth ) { c1 = (Short)( e1 >> 3 ); f1 = (Short)( e1 & 7 ); if ( ras.gray_min_x > c1 ) ras.gray_min_x = c1; if ( ras.gray_max_x < c1 ) ras.gray_max_x = c1; ras.bTarget[ras.traceOfs + c1] |= (char)( 0x80 >> f1 ); } } static void Vertical_Sweep_Step( RAS_ARG ) { ras.traceOfs += ras.traceIncr; } /***********************************************************************/ /* */ /* Horizontal Sweep Procedure Set */ /* */ /* These four routines are used during the horizontal black/white */ /* sweep phase by the generic Draw_Sweep() function. */ /* */ /***********************************************************************/ static void Horizontal_Sweep_Init( RAS_ARGS Short* min, Short* max ) { /* nothing, really */ FT_UNUSED_RASTER; FT_UNUSED( min ); FT_UNUSED( max ); } static void Horizontal_Sweep_Span( RAS_ARGS Short y, FT_F26Dot6 x1, FT_F26Dot6 x2, PProfile left, PProfile right ) { FT_UNUSED( left ); FT_UNUSED( right ); if ( x2 - x1 < ras.precision ) { Long e1, e2; e1 = CEILING( x1 ); e2 = FLOOR ( x2 ); if ( e1 == e2 ) { Byte f1; PByte bits; bits = ras.bTarget + ( y >> 3 ); f1 = (Byte)( 0x80 >> ( y & 7 ) ); e1 = TRUNC( e1 ); if ( e1 >= 0 && e1 < ras.target.rows ) { PByte p; p = bits - e1 * ras.target.pitch; if ( ras.target.pitch > 0 ) p += ( ras.target.rows - 1 ) * ras.target.pitch; p[0] |= f1; } } } } static void Horizontal_Sweep_Drop( RAS_ARGS Short y, FT_F26Dot6 x1, FT_F26Dot6 x2, PProfile left, PProfile right ) { Long e1, e2, pxl; PByte bits; Byte f1; /* During the horizontal sweep, we only take care of drop-outs */ /* e1 + <-- pixel center */ /* | */ /* x1 ---+--> <-- contour */ /* | */ /* | */ /* x2 <--+--- <-- contour */ /* | */ /* | */ /* e2 + <-- pixel center */ e1 = CEILING( x1 ); e2 = FLOOR ( x2 ); pxl = e1; if ( e1 > e2 ) { Int dropOutControl = left->flags & 7; if ( e1 == e2 + ras.precision ) { switch ( dropOutControl ) { case 0: /* simple drop-outs including stubs */ pxl = e2; break; case 4: /* smart drop-outs including stubs */ pxl = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half ); break; case 1: /* simple drop-outs excluding stubs */ case 5: /* smart drop-outs excluding stubs */ /* see Vertical_Sweep_Drop for details */ /* rightmost stub test */ if ( left->next == right && left->height <= 0 && !( left->flags & Overshoot_Top && x2 - x1 >= ras.precision_half ) ) return; /* leftmost stub test */ if ( right->next == left && left->start == y && !( left->flags & Overshoot_Bottom && x2 - x1 >= ras.precision_half ) ) return; if ( dropOutControl == 1 ) pxl = e2; else pxl = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half ); break; default: /* modes 2, 3, 6, 7 */ return; /* no drop-out control */ } /* undocumented but confirmed: If the drop-out would result in a */ /* pixel outside of the bounding box, use the pixel inside of the */ /* bounding box instead */ if ( pxl < 0 ) pxl = e1; else if ( TRUNC( pxl ) >= ras.target.rows ) pxl = e2; /* check that the other pixel isn't set */ e1 = pxl == e1 ? e2 : e1; e1 = TRUNC( e1 ); bits = ras.bTarget + ( y >> 3 ); f1 = (Byte)( 0x80 >> ( y & 7 ) ); bits -= e1 * ras.target.pitch; if ( ras.target.pitch > 0 ) bits += ( ras.target.rows - 1 ) * ras.target.pitch; if ( e1 >= 0 && e1 < ras.target.rows && *bits & f1 ) return; } else return; } bits = ras.bTarget + ( y >> 3 ); f1 = (Byte)( 0x80 >> ( y & 7 ) ); e1 = TRUNC( pxl ); if ( e1 >= 0 && e1 < ras.target.rows ) { bits -= e1 * ras.target.pitch; if ( ras.target.pitch > 0 ) bits += ( ras.target.rows - 1 ) * ras.target.pitch; bits[0] |= f1; } } static void Horizontal_Sweep_Step( RAS_ARG ) { /* Nothing, really */ FT_UNUSED_RASTER; } static void Set_High_Precision( RAS_ARGS Int High ) { /* * `precision_step' is used in `Bezier_Up' to decide when to split a * given y-monotonous Bezier arc that crosses a scanline before * approximating it as a straight segment. The default value of 32 (for * low accuracy) corresponds to * * 32 / 64 == 0.5 pixels , * * while for the high accuracy case we have * * 256/ (1 << 12) = 0.0625 pixels . * * `precision_jitter' is an epsilon threshold used in * `Vertical_Sweep_Span' to deal with small imperfections in the Bezier * decomposition (after all, we are working with approximations only); * it avoids switching on additional pixels which would cause artifacts * otherwise. * * The value of `precision_jitter' has been determined heuristically. * */ if ( High ) { ras.precision_bits = 12; ras.precision_step = 256; ras.precision_jitter = 30; } else { ras.precision_bits = 6; ras.precision_step = 32; ras.precision_jitter = 2; } FT_TRACE6(( "Set_High_Precision(%s)\n", High ? "true" : "false" )); ras.precision = 1 << ras.precision_bits; ras.precision_half = ras.precision / 2; ras.precision_shift = ras.precision_bits - Pixel_Bits; } #ifndef SUCCESS #define SUCCESS 0 #endif #ifndef FAILURE #define FAILURE 1 #endif static void Init_Linked( TProfileList* l ) { *l = NULL; } static void InsNew( PProfileList list, PProfile profile ) { PProfile *old, current; Long x; old = list; current = *old; x = profile->X; while ( current ) { if ( x < current->X ) break; old = ¤t->link; current = *old; } profile->link = current; *old = profile; } static void DelOld( PProfileList list, PProfile profile ) { PProfile *old, current; old = list; current = *old; while ( current ) { if ( current == profile ) { *old = current->link; return; } old = ¤t->link; current = *old; } /* we should never get there, unless the profile was not part of */ /* the list. */ } static void Sort( PProfileList list ) { PProfile *old, current, next; /* First, set the new X coordinate of each profile */ current = *list; while ( current ) { current->X = *current->offset; current->offset += current->flags & Flow_Up ? 1 : -1; current->height--; current = current->link; } /* Then sort them */ old = list; current = *old; if ( !current ) return; next = current->link; while ( next ) { if ( current->X <= next->X ) { old = ¤t->link; current = *old; if ( !current ) return; } else { *old = next; current->link = next->link; next->link = current; old = list; current = *old; } next = current->link; } } static Bool Draw_Sweep( RAS_ARG ) { Short y, y_change, y_height; PProfile P, Q, P_Left, P_Right; Short min_Y, max_Y, top, bottom, dropouts; Long x1, x2, xs, e1, e2; TProfileList waiting; TProfileList draw_left, draw_right; /* initialize empty linked lists */ Init_Linked( &waiting ); Init_Linked( &draw_left ); Init_Linked( &draw_right ); /* first, compute min and max Y */ P = ras.fProfile; max_Y = (Short)TRUNC( ras.minY ); min_Y = (Short)TRUNC( ras.maxY ); while ( P ) { Q = P->link; bottom = (Short)P->start; top = (Short)( P->start + P->height - 1 ); if ( min_Y > bottom ) min_Y = bottom; if ( max_Y < top ) max_Y = top; P->X = 0; InsNew( &waiting, P ); P = Q; } /* check the Y-turns */ if ( ras.numTurns == 0 ) { ras.error = FT_THROW( Invalid ); return FAILURE; } /* now initialize the sweep */ ras.Proc_Sweep_Init( RAS_VARS &min_Y, &max_Y ); /* then compute the distance of each profile from min_Y */ P = waiting; while ( P ) { P->countL = (UShort)( P->start - min_Y ); P = P->link; } /* let's go */ y = min_Y; y_height = 0; if ( ras.numTurns > 0 && ras.sizeBuff[-ras.numTurns] == min_Y ) ras.numTurns--; while ( ras.numTurns > 0 ) { /* check waiting list for new activations */ P = waiting; while ( P ) { Q = P->link; P->countL -= y_height; if ( P->countL == 0 ) { DelOld( &waiting, P ); if ( P->flags & Flow_Up ) InsNew( &draw_left, P ); else InsNew( &draw_right, P ); } P = Q; } /* sort the drawing lists */ Sort( &draw_left ); Sort( &draw_right ); y_change = (Short)ras.sizeBuff[-ras.numTurns--]; y_height = (Short)( y_change - y ); while ( y < y_change ) { /* let's trace */ dropouts = 0; P_Left = draw_left; P_Right = draw_right; while ( P_Left ) { x1 = P_Left ->X; x2 = P_Right->X; if ( x1 > x2 ) { xs = x1; x1 = x2; x2 = xs; } e1 = FLOOR( x1 ); e2 = CEILING( x2 ); if ( x2 - x1 <= ras.precision && e1 != x1 && e2 != x2 ) { if ( e1 > e2 || e2 == e1 + ras.precision ) { Int dropOutControl = P_Left->flags & 7; if ( dropOutControl != 2 ) { /* a drop-out was detected */ P_Left ->X = x1; P_Right->X = x2; /* mark profile for drop-out processing */ P_Left->countL = 1; dropouts++; } goto Skip_To_Next; } } ras.Proc_Sweep_Span( RAS_VARS y, x1, x2, P_Left, P_Right ); Skip_To_Next: P_Left = P_Left->link; P_Right = P_Right->link; } /* handle drop-outs _after_ the span drawing -- */ /* drop-out processing has been moved out of the loop */ /* for performance tuning */ if ( dropouts > 0 ) goto Scan_DropOuts; Next_Line: ras.Proc_Sweep_Step( RAS_VAR ); y++; if ( y < y_change ) { Sort( &draw_left ); Sort( &draw_right ); } } /* now finalize the profiles that need it */ P = draw_left; while ( P ) { Q = P->link; if ( P->height == 0 ) DelOld( &draw_left, P ); P = Q; } P = draw_right; while ( P ) { Q = P->link; if ( P->height == 0 ) DelOld( &draw_right, P ); P = Q; } } /* for gray-scaling, flush the bitmap scanline cache */ while ( y <= max_Y ) { ras.Proc_Sweep_Step( RAS_VAR ); y++; } return SUCCESS; Scan_DropOuts: P_Left = draw_left; P_Right = draw_right; while ( P_Left ) { if ( P_Left->countL ) { P_Left->countL = 0; #if 0 dropouts--; /* -- this is useful when debugging only */ #endif ras.Proc_Sweep_Drop( RAS_VARS y, P_Left->X, P_Right->X, P_Left, P_Right ); } P_Left = P_Left->link; P_Right = P_Right->link; } goto Next_Line; } #undef SWAP_ #define SWAP_( x, y ) do \ { \ Long swap = x; \ \ \ x = y; \ y = swap; \ } while ( 0 ) static Bool New_Profile( RAS_ARGS TStates aState, Bool overshoot ) { if ( !ras.fProfile ) { ras.cProfile = (PProfile)ras.top; ras.fProfile = ras.cProfile; ras.top += AlignProfileSize; } if ( ras.top >= ras.maxBuff ) { ras.error = FT_THROW( Overflow ); return FAILURE; } ras.cProfile->flags = 0; ras.cProfile->start = 0; ras.cProfile->height = 0; ras.cProfile->offset = ras.top; ras.cProfile->link = (PProfile)0; ras.cProfile->next = (PProfile)0; ras.cProfile->flags = ras.dropOutControl; switch ( aState ) { case Ascending_State: ras.cProfile->flags |= Flow_Up; if ( overshoot ) ras.cProfile->flags |= Overshoot_Bottom; FT_TRACE6(( "New ascending profile = %p\n", ras.cProfile )); break; case Descending_State: if ( overshoot ) ras.cProfile->flags |= Overshoot_Top; FT_TRACE6(( "New descending profile = %p\n", ras.cProfile )); break; default: FT_ERROR(( "New_Profile: invalid profile direction\n" )); ras.error = FT_THROW( Invalid ); return FAILURE; } if ( !ras.gProfile ) ras.gProfile = ras.cProfile; ras.state = aState; ras.fresh = TRUE; ras.joint = FALSE; return SUCCESS; } /*************************************************************************/ /* */ /* */ /* End_Profile */ /* */ /* */ /* Finalize the current profile. */ /* */ /* */ /* overshoot :: Whether the profile's unrounded end position differs */ /* by at least a half pixel. */ /* */ /* */ /* SUCCESS on success. FAILURE in case of overflow or incoherency. */ /* */ static Bool End_Profile( RAS_ARGS Bool overshoot ) { Long h; h = (Long)( ras.top - ras.cProfile->offset ); if ( h < 0 ) { FT_ERROR(( "End_Profile: negative height encountered\n" )); ras.error = FT_THROW( Neg_Height ); return FAILURE; } if ( h > 0 ) { PProfile oldProfile; FT_TRACE6(( "Ending profile %p, start = %ld, height = %ld\n", ras.cProfile, ras.cProfile->start, h )); ras.cProfile->height = h; if ( overshoot ) { if ( ras.cProfile->flags & Flow_Up ) ras.cProfile->flags |= Overshoot_Top; else ras.cProfile->flags |= Overshoot_Bottom; } oldProfile = ras.cProfile; ras.cProfile = (PProfile)ras.top; ras.top += AlignProfileSize; ras.cProfile->height = 0; ras.cProfile->offset = ras.top; oldProfile->next = ras.cProfile; ras.num_Profs++; } if ( ras.top >= ras.maxBuff ) { FT_TRACE1(( "overflow in End_Profile\n" )); ras.error = FT_THROW( Overflow ); return FAILURE; } ras.joint = FALSE; return SUCCESS; } static Bool Insert_Y_Turn( RAS_ARGS Int y ) { PLong y_turns; Int n; n = ras.numTurns - 1; y_turns = ras.sizeBuff - ras.numTurns; /* look for first y value that is <= */ while ( n >= 0 && y < y_turns[n] ) n--; /* if it is <, simply insert it, ignore if == */ if ( n >= 0 && y > y_turns[n] ) while ( n >= 0 ) { Int y2 = (Int)y_turns[n]; y_turns[n] = y; y = y2; n--; } if ( n < 0 ) { ras.maxBuff--; if ( ras.maxBuff <= ras.top ) { ras.error = FT_THROW( Overflow ); return FAILURE; } ras.numTurns++; ras.sizeBuff[-ras.numTurns] = y; } return SUCCESS; } /*************************************************************************/ /* */ /* */ /* Finalize_Profile_Table */ /* */ /* */ /* Adjust all links in the profiles list. */ /* */ /* */ /* SUCCESS on success. FAILURE in case of overflow. */ /* */ static Bool Finalize_Profile_Table( RAS_ARG ) { UShort n; PProfile p; n = ras.num_Profs; p = ras.fProfile; if ( n > 1 && p ) { while ( n > 0 ) { Int bottom, top; if ( n > 1 ) p->link = (PProfile)( p->offset + p->height ); else p->link = NULL; if ( p->flags & Flow_Up ) { bottom = (Int)p->start; top = (Int)( p->start + p->height - 1 ); } else { bottom = (Int)( p->start - p->height + 1 ); top = (Int)p->start; p->start = bottom; p->offset += p->height - 1; } if ( Insert_Y_Turn( RAS_VARS bottom ) || Insert_Y_Turn( RAS_VARS top + 1 ) ) return FAILURE; p = p->link; n--; } } else ras.fProfile = NULL; return SUCCESS; } /*************************************************************************/ /* */ /* */ /* Split_Conic */ /* */ /* */ /* Subdivide one conic Bezier into two joint sub-arcs in the Bezier */ /* stack. */ /* */ /* */ /* None (subdivided Bezier is taken from the top of the stack). */ /* */ /* */ /* This routine is the `beef' of this component. It is _the_ inner */ /* loop that should be optimized to hell to get the best performance. */ /* */ static void Split_Conic( TPoint* base ) { Long a, b; base[4].x = base[2].x; b = base[1].x; a = base[3].x = ( base[2].x + b ) / 2; b = base[1].x = ( base[0].x + b ) / 2; base[2].x = ( a + b ) / 2; base[4].y = base[2].y; b = base[1].y; a = base[3].y = ( base[2].y + b ) / 2; b = base[1].y = ( base[0].y + b ) / 2; base[2].y = ( a + b ) / 2; /* hand optimized. gcc doesn't seem to be too good at common */ /* expression substitution and instruction scheduling ;-) */ } /*************************************************************************/ /* */ /* */ /* Split_Cubic */ /* */ /* */ /* Subdivide a third-order Bezier arc into two joint sub-arcs in the */ /* Bezier stack. */ /* */ /* */ /* This routine is the `beef' of the component. It is one of _the_ */ /* inner loops that should be optimized like hell to get the best */ /* performance. */ /* */ static void Split_Cubic( TPoint* base ) { Long a, b, c, d; base[6].x = base[3].x; c = base[1].x; d = base[2].x; base[1].x = a = ( base[0].x + c + 1 ) >> 1; base[5].x = b = ( base[3].x + d + 1 ) >> 1; c = ( c + d + 1 ) >> 1; base[2].x = a = ( a + c + 1 ) >> 1; base[4].x = b = ( b + c + 1 ) >> 1; base[3].x = ( a + b + 1 ) >> 1; base[6].y = base[3].y; c = base[1].y; d = base[2].y; base[1].y = a = ( base[0].y + c + 1 ) >> 1; base[5].y = b = ( base[3].y + d + 1 ) >> 1; c = ( c + d + 1 ) >> 1; base[2].y = a = ( a + c + 1 ) >> 1; base[4].y = b = ( b + c + 1 ) >> 1; base[3].y = ( a + b + 1 ) >> 1; } #define FMulDiv( a, b, c ) ( (a) * (b) / (c) ) #define SMulDiv FT_MulDiv #define SMulDiv_No_Round FT_MulDiv_No_Round /*************************************************************************/ /* */ /* */ /* Line_Up */ /* */ /* */ /* Compute the x-coordinates of an ascending line segment and store */ /* them in the render pool. */ /* */ /* */ /* x1 :: The x-coordinate of the segment's start point. */ /* */ /* y1 :: The y-coordinate of the segment's start point. */ /* */ /* x2 :: The x-coordinate of the segment's end point. */ /* */ /* y2 :: The y-coordinate of the segment's end point. */ /* */ /* miny :: A lower vertical clipping bound value. */ /* */ /* maxy :: An upper vertical clipping bound value. */ /* */ /* */ /* SUCCESS on success, FAILURE on render pool overflow. */ /* */ static Bool Line_Up( RAS_ARGS Long x1, Long y1, Long x2, Long y2, Long miny, Long maxy ) { Long Dx, Dy; Int e1, e2, f1, f2, size; /* XXX: is `Short' sufficient? */ Long Ix, Rx, Ax; PLong top; Dx = x2 - x1; Dy = y2 - y1; if ( Dy <= 0 || y2 < miny || y1 > maxy ) return SUCCESS; if ( y1 < miny ) { /* Take care: miny-y1 can be a very large value; we use */ /* a slow MulDiv function to avoid clipping bugs */ x1 += SMulDiv( Dx, miny - y1, Dy ); e1 = (Int)TRUNC( miny ); f1 = 0; } else { e1 = (Int)TRUNC( y1 ); f1 = (Int)FRAC( y1 ); } if ( y2 > maxy ) { /* x2 += FMulDiv( Dx, maxy - y2, Dy ); UNNECESSARY */ e2 = (Int)TRUNC( maxy ); f2 = 0; } else { e2 = (Int)TRUNC( y2 ); f2 = (Int)FRAC( y2 ); } if ( f1 > 0 ) { if ( e1 == e2 ) return SUCCESS; else { x1 += SMulDiv( Dx, ras.precision - f1, Dy ); e1 += 1; } } else if ( ras.joint ) { ras.top--; ras.joint = FALSE; } ras.joint = (char)( f2 == 0 ); if ( ras.fresh ) { ras.cProfile->start = e1; ras.fresh = FALSE; } size = e2 - e1 + 1; if ( ras.top + size >= ras.maxBuff ) { ras.error = FT_THROW( Overflow ); return FAILURE; } if ( Dx > 0 ) { Ix = SMulDiv_No_Round( ras.precision, Dx, Dy ); Rx = ( ras.precision * Dx ) % Dy; Dx = 1; } else { Ix = -SMulDiv_No_Round( ras.precision, -Dx, Dy ); Rx = ( ras.precision * -Dx ) % Dy; Dx = -1; } Ax = -Dy; top = ras.top; while ( size > 0 ) { *top++ = x1; x1 += Ix; Ax += Rx; if ( Ax >= 0 ) { Ax -= Dy; x1 += Dx; } size--; } ras.top = top; return SUCCESS; } /*************************************************************************/ /* */ /* */ /* Line_Down */ /* */ /* */ /* Compute the x-coordinates of an descending line segment and store */ /* them in the render pool. */ /* */ /* */ /* x1 :: The x-coordinate of the segment's start point. */ /* */ /* y1 :: The y-coordinate of the segment's start point. */ /* */ /* x2 :: The x-coordinate of the segment's end point. */ /* */ /* y2 :: The y-coordinate of the segment's end point. */ /* */ /* miny :: A lower vertical clipping bound value. */ /* */ /* maxy :: An upper vertical clipping bound value. */ /* */ /* */ /* SUCCESS on success, FAILURE on render pool overflow. */ /* */ static Bool Line_Down( RAS_ARGS Long x1, Long y1, Long x2, Long y2, Long miny, Long maxy ) { Bool result, fresh; fresh = ras.fresh; result = Line_Up( RAS_VARS x1, -y1, x2, -y2, -maxy, -miny ); if ( fresh && !ras.fresh ) ras.cProfile->start = -ras.cProfile->start; return result; } /* A function type describing the functions used to split Bezier arcs */ typedef void (*TSplitter)( TPoint* base ); /*************************************************************************/ /* */ /* */ /* Bezier_Up */ /* */ /* */ /* Compute the x-coordinates of an ascending Bezier arc and store */ /* them in the render pool. */ /* */ /* */ /* degree :: The degree of the Bezier arc (either 2 or 3). */ /* */ /* splitter :: The function to split Bezier arcs. */ /* */ /* miny :: A lower vertical clipping bound value. */ /* */ /* maxy :: An upper vertical clipping bound value. */ /* */ /* */ /* SUCCESS on success, FAILURE on render pool overflow. */ /* */ static Bool Bezier_Up( RAS_ARGS Int degree, TSplitter splitter, Long miny, Long maxy ) { Long y1, y2, e, e2, e0; Short f1; TPoint* arc; TPoint* start_arc; PLong top; arc = ras.arc; y1 = arc[degree].y; y2 = arc[0].y; top = ras.top; if ( y2 < miny || y1 > maxy ) goto Fin; e2 = FLOOR( y2 ); if ( e2 > maxy ) e2 = maxy; e0 = miny; if ( y1 < miny ) e = miny; else { e = CEILING( y1 ); f1 = (Short)( FRAC( y1 ) ); e0 = e; if ( f1 == 0 ) { if ( ras.joint ) { top--; ras.joint = FALSE; } *top++ = arc[degree].x; e += ras.precision; } } if ( ras.fresh ) { ras.cProfile->start = TRUNC( e0 ); ras.fresh = FALSE; } if ( e2 < e ) goto Fin; if ( ( top + TRUNC( e2 - e ) + 1 ) >= ras.maxBuff ) { ras.top = top; ras.error = FT_THROW( Overflow ); return FAILURE; } start_arc = arc; while ( arc >= start_arc && e <= e2 ) { ras.joint = FALSE; y2 = arc[0].y; if ( y2 > e ) { y1 = arc[degree].y; if ( y2 - y1 >= ras.precision_step ) { splitter( arc ); arc += degree; } else { *top++ = arc[degree].x + FMulDiv( arc[0].x - arc[degree].x, e - y1, y2 - y1 ); arc -= degree; e += ras.precision; } } else { if ( y2 == e ) { ras.joint = TRUE; *top++ = arc[0].x; e += ras.precision; } arc -= degree; } } Fin: ras.top = top; ras.arc -= degree; return SUCCESS; } /*************************************************************************/ /* */ /* */ /* Bezier_Down */ /* */ /* */ /* Compute the x-coordinates of an descending Bezier arc and store */ /* them in the render pool. */ /* */ /* */ /* degree :: The degree of the Bezier arc (either 2 or 3). */ /* */ /* splitter :: The function to split Bezier arcs. */ /* */ /* miny :: A lower vertical clipping bound value. */ /* */ /* maxy :: An upper vertical clipping bound value. */ /* */ /* */ /* SUCCESS on success, FAILURE on render pool overflow. */ /* */ static Bool Bezier_Down( RAS_ARGS Int degree, TSplitter splitter, Long miny, Long maxy ) { TPoint* arc = ras.arc; Bool result, fresh; arc[0].y = -arc[0].y; arc[1].y = -arc[1].y; arc[2].y = -arc[2].y; if ( degree > 2 ) arc[3].y = -arc[3].y; fresh = ras.fresh; result = Bezier_Up( RAS_VARS degree, splitter, -maxy, -miny ); if ( fresh && !ras.fresh ) ras.cProfile->start = -ras.cProfile->start; arc[0].y = -arc[0].y; return result; } static Bool Line_To( RAS_ARGS Long x, Long y ) { /* First, detect a change of direction */ switch ( ras.state ) { case Unknown_State: if ( y > ras.lastY ) { if ( New_Profile( RAS_VARS Ascending_State, IS_BOTTOM_OVERSHOOT( ras.lastY ) ) ) return FAILURE; } else { if ( y < ras.lastY ) if ( New_Profile( RAS_VARS Descending_State, IS_TOP_OVERSHOOT( ras.lastY ) ) ) return FAILURE; } break; case Ascending_State: if ( y < ras.lastY ) { if ( End_Profile( RAS_VARS IS_TOP_OVERSHOOT( ras.lastY ) ) || New_Profile( RAS_VARS Descending_State, IS_TOP_OVERSHOOT( ras.lastY ) ) ) return FAILURE; } break; case Descending_State: if ( y > ras.lastY ) { if ( End_Profile( RAS_VARS IS_BOTTOM_OVERSHOOT( ras.lastY ) ) || New_Profile( RAS_VARS Ascending_State, IS_BOTTOM_OVERSHOOT( ras.lastY ) ) ) return FAILURE; } break; default: ; } /* Then compute the lines */ switch ( ras.state ) { case Ascending_State: if ( Line_Up( RAS_VARS ras.lastX, ras.lastY, x, y, ras.minY, ras.maxY ) ) return FAILURE; break; case Descending_State: if ( Line_Down( RAS_VARS ras.lastX, ras.lastY, x, y, ras.minY, ras.maxY ) ) return FAILURE; break; default: ; } ras.lastX = x; ras.lastY = y; return SUCCESS; } static Bool Conic_To( RAS_ARGS Long cx, Long cy, Long x, Long y ) { Long y1, y2, y3, x3, ymin, ymax; TStates state_bez; ras.arc = ras.arcs; ras.arc[2].x = ras.lastX; ras.arc[2].y = ras.lastY; ras.arc[1].x = cx; ras.arc[1].y = cy; ras.arc[0].x = x; ras.arc[0].y = y; do { y1 = ras.arc[2].y; y2 = ras.arc[1].y; y3 = ras.arc[0].y; x3 = ras.arc[0].x; /* first, categorize the Bezier arc */ if ( y1 <= y3 ) { ymin = y1; ymax = y3; } else { ymin = y3; ymax = y1; } if ( y2 < ymin || y2 > ymax ) { /* this arc has no given direction, split it! */ Split_Conic( ras.arc ); ras.arc += 2; } else if ( y1 == y3 ) { /* this arc is flat, ignore it and pop it from the Bezier stack */ ras.arc -= 2; } else { /* the arc is y-monotonous, either ascending or descending */ /* detect a change of direction */ state_bez = y1 < y3 ? Ascending_State : Descending_State; if ( ras.state != state_bez ) { Bool o = state_bez == Ascending_State ? IS_BOTTOM_OVERSHOOT( y1 ) : IS_TOP_OVERSHOOT( y1 ); /* finalize current profile if any */ if ( ras.state != Unknown_State && End_Profile( RAS_VARS o ) ) goto Fail; /* create a new profile */ if ( New_Profile( RAS_VARS state_bez, o ) ) goto Fail; } /* now call the appropriate routine */ if ( state_bez == Ascending_State ) { if ( Bezier_Up( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) ) goto Fail; } else if ( Bezier_Down( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) ) goto Fail; } } while ( ras.arc >= ras.arcs ); ras.lastX = x3; ras.lastY = y3; return SUCCESS; Fail: return FAILURE; } static Bool Cubic_To( RAS_ARGS Long cx1, Long cy1, Long cx2, Long cy2, Long x, Long y ) { Long y1, y2, y3, y4, x4, ymin1, ymax1, ymin2, ymax2; TStates state_bez; ras.arc = ras.arcs; ras.arc[3].x = ras.lastX; ras.arc[3].y = ras.lastY; ras.arc[2].x = cx1; ras.arc[2].y = cy1; ras.arc[1].x = cx2; ras.arc[1].y = cy2; ras.arc[0].x = x; ras.arc[0].y = y; do { y1 = ras.arc[3].y; y2 = ras.arc[2].y; y3 = ras.arc[1].y; y4 = ras.arc[0].y; x4 = ras.arc[0].x; /* first, categorize the Bezier arc */ if ( y1 <= y4 ) { ymin1 = y1; ymax1 = y4; } else { ymin1 = y4; ymax1 = y1; } if ( y2 <= y3 ) { ymin2 = y2; ymax2 = y3; } else { ymin2 = y3; ymax2 = y2; } if ( ymin2 < ymin1 || ymax2 > ymax1 ) { /* this arc has no given direction, split it! */ Split_Cubic( ras.arc ); ras.arc += 3; } else if ( y1 == y4 ) { /* this arc is flat, ignore it and pop it from the Bezier stack */ ras.arc -= 3; } else { state_bez = ( y1 <= y4 ) ? Ascending_State : Descending_State; /* detect a change of direction */ if ( ras.state != state_bez ) { Bool o = state_bez == Ascending_State ? IS_BOTTOM_OVERSHOOT( y1 ) : IS_TOP_OVERSHOOT( y1 ); /* finalize current profile if any */ if ( ras.state != Unknown_State && End_Profile( RAS_VARS o ) ) goto Fail; if ( New_Profile( RAS_VARS state_bez, o ) ) goto Fail; } /* compute intersections */ if ( state_bez == Ascending_State ) { if ( Bezier_Up( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) ) goto Fail; } else if ( Bezier_Down( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) ) goto Fail; } } while ( ras.arc >= ras.arcs ); ras.lastX = x4; ras.lastY = y4; return SUCCESS; Fail: return FAILURE; } static Bool Decompose_Curve( RAS_ARGS UShort first, UShort last, int flipped ) { FT_Vector v_last; FT_Vector v_control; FT_Vector v_start; FT_Vector* points; FT_Vector* point; FT_Vector* limit; char* tags; unsigned tag; /* current point's state */ points = ras.outline.points; limit = points + last; v_start.x = SCALED( points[first].x ); v_start.y = SCALED( points[first].y ); v_last.x = SCALED( points[last].x ); v_last.y = SCALED( points[last].y ); if ( flipped ) { SWAP_( v_start.x, v_start.y ); SWAP_( v_last.x, v_last.y ); } v_control = v_start; point = points + first; tags = ras.outline.tags + first; /* set scan mode if necessary */ if ( tags[0] & FT_CURVE_TAG_HAS_SCANMODE ) ras.dropOutControl = (Byte)tags[0] >> 5; tag = FT_CURVE_TAG( tags[0] ); /* A contour cannot start with a cubic control point! */ if ( tag == FT_CURVE_TAG_CUBIC ) goto Invalid_Outline; /* check first point to determine origin */ if ( tag == FT_CURVE_TAG_CONIC ) { /* first point is conic control. Yes, this happens. */ if ( FT_CURVE_TAG( ras.outline.tags[last] ) == FT_CURVE_TAG_ON ) { /* start at last point if it is on the curve */ v_start = v_last; limit--; } else { /* if both first and last points are conic, */ /* start at their middle and record its position */ /* for closure */ v_start.x = ( v_start.x + v_last.x ) / 2; v_start.y = ( v_start.y + v_last.y ) / 2; /* v_last = v_start; */ } point--; tags--; } ras.lastX = v_start.x; ras.lastY = v_start.y; while ( point < limit ) { point++; tags++; tag = FT_CURVE_TAG( tags[0] ); switch ( tag ) { case FT_CURVE_TAG_ON: /* emit a single line_to */ { Long x, y; x = SCALED( point->x ); y = SCALED( point->y ); if ( flipped ) SWAP_( x, y ); if ( Line_To( RAS_VARS x, y ) ) goto Fail; continue; } case FT_CURVE_TAG_CONIC: /* consume conic arcs */ v_control.x = SCALED( point[0].x ); v_control.y = SCALED( point[0].y ); if ( flipped ) SWAP_( v_control.x, v_control.y ); Do_Conic: if ( point < limit ) { FT_Vector v_middle; Long x, y; point++; tags++; tag = FT_CURVE_TAG( tags[0] ); x = SCALED( point[0].x ); y = SCALED( point[0].y ); if ( flipped ) SWAP_( x, y ); if ( tag == FT_CURVE_TAG_ON ) { if ( Conic_To( RAS_VARS v_control.x, v_control.y, x, y ) ) goto Fail; continue; } if ( tag != FT_CURVE_TAG_CONIC ) goto Invalid_Outline; v_middle.x = ( v_control.x + x ) / 2; v_middle.y = ( v_control.y + y ) / 2; if ( Conic_To( RAS_VARS v_control.x, v_control.y, v_middle.x, v_middle.y ) ) goto Fail; v_control.x = x; v_control.y = y; goto Do_Conic; } if ( Conic_To( RAS_VARS v_control.x, v_control.y, v_start.x, v_start.y ) ) goto Fail; goto Close; default: /* FT_CURVE_TAG_CUBIC */ { Long x1, y1, x2, y2, x3, y3; if ( point + 1 > limit || FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC ) goto Invalid_Outline; point += 2; tags += 2; x1 = SCALED( point[-2].x ); y1 = SCALED( point[-2].y ); x2 = SCALED( point[-1].x ); y2 = SCALED( point[-1].y ); if ( flipped ) { SWAP_( x1, y1 ); SWAP_( x2, y2 ); } if ( point <= limit ) { x3 = SCALED( point[0].x ); y3 = SCALED( point[0].y ); if ( flipped ) SWAP_( x3, y3 ); if ( Cubic_To( RAS_VARS x1, y1, x2, y2, x3, y3 ) ) goto Fail; continue; } if ( Cubic_To( RAS_VARS x1, y1, x2, y2, v_start.x, v_start.y ) ) goto Fail; goto Close; } } } /* close the contour with a line segment */ if ( Line_To( RAS_VARS v_start.x, v_start.y ) ) goto Fail; Close: return SUCCESS; Invalid_Outline: ras.error = FT_THROW( Invalid ); Fail: return FAILURE; } static Bool Convert_Glyph( RAS_ARGS int flipped ) { int i; unsigned start; ras.fProfile = NULL; ras.joint = FALSE; ras.fresh = FALSE; ras.maxBuff = ras.sizeBuff - AlignProfileSize; ras.numTurns = 0; ras.cProfile = (PProfile)ras.top; ras.cProfile->offset = ras.top; ras.num_Profs = 0; start = 0; for ( i = 0; i < ras.outline.n_contours; i++ ) { PProfile lastProfile; Bool o; ras.state = Unknown_State; ras.gProfile = NULL; if ( Decompose_Curve( RAS_VARS (unsigned short)start, ras.outline.contours[i], flipped ) ) return FAILURE; start = ras.outline.contours[i] + 1; /* we must now check whether the extreme arcs join or not */ if ( FRAC( ras.lastY ) == 0 && ras.lastY >= ras.minY && ras.lastY <= ras.maxY ) if ( ras.gProfile && ( ras.gProfile->flags & Flow_Up ) == ( ras.cProfile->flags & Flow_Up ) ) ras.top--; /* Note that ras.gProfile can be nil if the contour was too small */ /* to be drawn. */ lastProfile = ras.cProfile; if ( ras.cProfile->flags & Flow_Up ) o = IS_TOP_OVERSHOOT( ras.lastY ); else o = IS_BOTTOM_OVERSHOOT( ras.lastY ); if ( End_Profile( RAS_VARS o ) ) return FAILURE; /* close the `next profile in contour' linked list */ if ( ras.gProfile ) lastProfile->next = ras.gProfile; } if ( Finalize_Profile_Table( RAS_VAR ) ) return FAILURE; return (Bool)( ras.top < ras.maxBuff ? SUCCESS : FAILURE ); } static int Render_Single_Pass( RAS_ARGS Bool flipped ) { Short i, j, k; while ( ras.band_top >= 0 ) { ras.maxY = (Long)ras.band_stack[ras.band_top].y_max * ras.precision; ras.minY = (Long)ras.band_stack[ras.band_top].y_min * ras.precision; ras.top = ras.buff; ras.error = FT_Err_None; if ( Convert_Glyph( RAS_VARS flipped ) ) { if ( ras.error != FT_Err_Overflow ) return FAILURE; ras.error = FT_Err_None; /* sub-banding */ #ifdef DEBUG_RASTER ClearBand( RAS_VARS TRUNC( ras.minY ), TRUNC( ras.maxY ) ); #endif i = ras.band_stack[ras.band_top].y_min; j = ras.band_stack[ras.band_top].y_max; k = (Short)( ( i + j ) / 2 ); if ( ras.band_top >= 7 || k < i ) { ras.band_top = 0; ras.error = FT_THROW( Invalid ); return ras.error; } ras.band_stack[ras.band_top + 1].y_min = k; ras.band_stack[ras.band_top + 1].y_max = j; ras.band_stack[ras.band_top].y_max = (Short)( k - 1 ); ras.band_top++; } else { if ( ras.fProfile ) if ( Draw_Sweep( RAS_VAR ) ) return ras.error; ras.band_top--; } } return SUCCESS; } FT_LOCAL_DEF( FT_Error ) Render_Glyph( RAS_ARG ) { FT_Error error; Set_High_Precision( RAS_VARS ras.outline.flags & FT_OUTLINE_HIGH_PRECISION ); ras.scale_shift = ras.precision_shift; if ( ras.outline.flags & FT_OUTLINE_IGNORE_DROPOUTS ) ras.dropOutControl = 2; else { if ( ras.outline.flags & FT_OUTLINE_SMART_DROPOUTS ) ras.dropOutControl = 4; else ras.dropOutControl = 0; if ( !( ras.outline.flags & FT_OUTLINE_INCLUDE_STUBS ) ) ras.dropOutControl += 1; } ras.second_pass = (FT_Byte)( !( ras.outline.flags & FT_OUTLINE_SINGLE_PASS ) ); /* Vertical Sweep */ ras.Proc_Sweep_Init = Vertical_Sweep_Init; ras.Proc_Sweep_Span = Vertical_Sweep_Span; ras.Proc_Sweep_Drop = Vertical_Sweep_Drop; ras.Proc_Sweep_Step = Vertical_Sweep_Step; ras.band_top = 0; ras.band_stack[0].y_min = 0; ras.band_stack[0].y_max = (short)( ras.target.rows - 1 ); ras.bWidth = (unsigned short)ras.target.width; ras.bTarget = (Byte*)ras.target.buffer; if ( ( error = Render_Single_Pass( RAS_VARS 0 ) ) != 0 ) return error; /* Horizontal Sweep */ if ( ras.second_pass && ras.dropOutControl != 2 ) { ras.Proc_Sweep_Init = Horizontal_Sweep_Init; ras.Proc_Sweep_Span = Horizontal_Sweep_Span; ras.Proc_Sweep_Drop = Horizontal_Sweep_Drop; ras.Proc_Sweep_Step = Horizontal_Sweep_Step; ras.band_top = 0; ras.band_stack[0].y_min = 0; ras.band_stack[0].y_max = (short)( ras.target.width - 1 ); if ( ( error = Render_Single_Pass( RAS_VARS 1 ) ) != 0 ) return error; } return FT_Err_None; } static int ft_black_render( black_PRaster raster, const FT_Raster_Params* params ) { const FT_Outline* outline = (const FT_Outline*)params->source; const FT_Bitmap* target_map = params->target; black_PWorker worker; if ( !raster || !raster->buffer || !raster->buffer_size ) return FT_THROW( Not_Ini ); if ( !outline ) return FT_THROW( Invalid ); /* return immediately if the outline is empty */ if ( outline->n_points == 0 || outline->n_contours <= 0 ) return FT_Err_None; if ( !outline->contours || !outline->points ) return FT_THROW( Invalid ); if ( outline->n_points != outline->contours[outline->n_contours - 1] + 1 ) return FT_THROW( Invalid ); worker = raster->worker; /* this version of the raster does not support direct rendering, sorry */ if ( params->flags & FT_RASTER_FLAG_DIRECT ) return FT_THROW( Unsupported ); if ( !target_map ) return FT_THROW( Invalid ); /* nothing to do */ if ( !target_map->width || !target_map->rows ) return FT_Err_None; if ( !target_map->buffer ) return FT_THROW( Invalid ); ras.outline = *outline; ras.target = *target_map; worker->buff = (PLong) raster->buffer; worker->sizeBuff = worker->buff + raster->buffer_size / sizeof ( Long ); #ifdef FT_RASTER_OPTION_ANTI_ALIASING worker->grays = raster->grays; worker->gray_width = raster->gray_width; FT_MEM_ZERO( worker->gray_lines, worker->gray_width * 2 ); #endif return ( params->flags & FT_RASTER_FLAG_AA ) ? Render_Gray_Glyph( RAS_VAR ) : Render_Glyph( RAS_VAR ); } FT_DEFINE_RASTER_FUNCS( ft_standard_raster, FT_GLYPH_FORMAT_OUTLINE, (FT_Raster_New_Func) ft_black_new, (FT_Raster_Reset_Func) ft_black_reset, (FT_Raster_Set_Mode_Func)ft_black_set_mode, (FT_Raster_Render_Func) ft_black_render, (FT_Raster_Done_Func) ft_black_done ) FT_DEFINE_RENDERER( ft_raster1_renderer_class, FT_MODULE_RENDERER, sizeof ( FT_RendererRec ), "raster1", 0x10000L, 0x20000L, 0, /* module specific interface */ (FT_Module_Constructor)ft_raster1_init, (FT_Module_Destructor) 0, (FT_Module_Requester) 0 , FT_GLYPH_FORMAT_OUTLINE, (FT_Renderer_RenderFunc) ft_raster1_render, (FT_Renderer_TransformFunc)ft_raster1_transform, (FT_Renderer_GetCBoxFunc) ft_raster1_get_cbox, (FT_Renderer_SetModeFunc) ft_raster1_set_mode, (FT_Raster_Funcs*) &FT_STANDARD_RASTER_GET ) FT_DEFINE_RENDERER( ft_raster5_renderer_class, FT_MODULE_RENDERER, sizeof ( FT_RendererRec ), "raster5", 0x10000L, 0x20000L, 0, /* module specific interface */ (FT_Module_Constructor)ft_raster1_init, (FT_Module_Destructor) 0, (FT_Module_Requester) 0 , FT_GLYPH_FORMAT_OUTLINE, (FT_Renderer_RenderFunc) ft_raster1_render, (FT_Renderer_TransformFunc)ft_raster1_transform, (FT_Renderer_GetCBoxFunc) ft_raster1_get_cbox, (FT_Renderer_SetModeFunc) ft_raster1_set_mode, (FT_Raster_Funcs*) &FT_STANDARD_RASTER_GET ) // ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ static FT_Error ft_smooth_init( FT_Renderer render ) { FT_Library library = FT_MODULE_LIBRARY( render ); render->clazz->raster_class->raster_reset( render->raster, library->raster_pool, library->raster_pool_size ); return 0; } /* sets render-specific mode */ static FT_Error ft_smooth_set_mode( FT_Renderer render, FT_ULong mode_tag, FT_Pointer data ) { /* we simply pass it to the raster */ return render->clazz->raster_class->raster_set_mode( render->raster, mode_tag, data ); } /* transform a given glyph image */ static FT_Error ft_smooth_transform( FT_Renderer render, FT_GlyphSlot slot, const FT_Matrix* matrix, const FT_Vector* delta ) { FT_Error error = FT_Err_Ok; if ( slot->format != render->glyph_format ) { error = FT_THROW( Invalid_Argument ); goto Exit; } if ( matrix ) FT_Outline_Transform( &slot->outline, matrix ); if ( delta ) FT_Outline_Translate( &slot->outline, delta->x, delta->y ); Exit: return error; } /* return the glyph's control box */ static void ft_smooth_get_cbox( FT_Renderer render, FT_GlyphSlot slot, FT_BBox* cbox ) { FT_MEM_ZERO( cbox, sizeof ( *cbox ) ); if ( slot->format == render->glyph_format ) FT_Outline_Get_CBox( &slot->outline, cbox ); } /* convert a slot's glyph image into a bitmap */ static FT_Error ft_smooth_render_generic( FT_Renderer render, FT_GlyphSlot slot, FT_Render_Mode mode, const FT_Vector* origin, FT_Render_Mode required_mode ) { FT_Error error; FT_Outline* outline = NULL; FT_BBox cbox; FT_Pos width, height, pitch; #ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING FT_Pos height_org, width_org; #endif FT_Bitmap* bitmap = &slot->bitmap; FT_Memory memory = render->root.memory; FT_Int hmul = mode == FT_RENDER_MODE_LCD; FT_Int vmul = mode == FT_RENDER_MODE_LCD_V; FT_Pos x_shift = 0; FT_Pos y_shift = 0; FT_Pos x_left, y_top; FT_Raster_Params params; FT_Bool have_translated_origin = FALSE; FT_Bool have_outline_shifted = FALSE; FT_Bool have_buffer = FALSE; /* check glyph image format */ if ( slot->format != render->glyph_format ) { error = FT_THROW( Invalid_Argument ); goto Exit; } /* check mode */ if ( mode != required_mode ) { error = FT_THROW( Cannot_Render_Glyph ); goto Exit; } outline = &slot->outline; /* translate the outline to the new origin if needed */ if ( origin ) { FT_Outline_Translate( outline, origin->x, origin->y ); have_translated_origin = TRUE; } /* compute the control box, and grid fit it */ FT_Outline_Get_CBox( outline, &cbox ); cbox.xMin = FT_PIX_FLOOR( cbox.xMin ); cbox.yMin = FT_PIX_FLOOR( cbox.yMin ); cbox.xMax = FT_PIX_CEIL( cbox.xMax ); cbox.yMax = FT_PIX_CEIL( cbox.yMax ); if ( cbox.xMin < 0 && cbox.xMax > FT_INT_MAX + cbox.xMin ) { FT_ERROR(( "ft_smooth_render_generic: glyph too large:" " xMin = %d, xMax = %d\n", cbox.xMin >> 6, cbox.xMax >> 6 )); error = FT_THROW( Raster_Overflow ); goto Exit; } else width = ( cbox.xMax - cbox.xMin ) >> 6; if ( cbox.yMin < 0 && cbox.yMax > FT_INT_MAX + cbox.yMin ) { FT_ERROR(( "ft_smooth_render_generic: glyph too large:" " yMin = %d, yMax = %d\n", cbox.yMin >> 6, cbox.yMax >> 6 )); error = FT_THROW( Raster_Overflow ); goto Exit; } else height = ( cbox.yMax - cbox.yMin ) >> 6; #ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING width_org = width; height_org = height; #endif /* release old bitmap buffer */ if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) { FT_FREE( bitmap->buffer ); slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; } /* allocate new one */ pitch = width; if ( hmul ) { width = width * 3; pitch = FT_PAD_CEIL( width, 4 ); } if ( vmul ) height *= 3; x_shift = (FT_Int) cbox.xMin; y_shift = (FT_Int) cbox.yMin; x_left = (FT_Int)( cbox.xMin >> 6 ); y_top = (FT_Int)( cbox.yMax >> 6 ); #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING if ( slot->library->lcd_filter_func ) { FT_Int extra = slot->library->lcd_extra; if ( hmul ) { x_shift -= 64 * ( extra >> 1 ); width += 3 * extra; pitch = FT_PAD_CEIL( width, 4 ); x_left -= extra >> 1; } if ( vmul ) { y_shift -= 64 * ( extra >> 1 ); height += 3 * extra; y_top += extra >> 1; } } #endif #if FT_UINT_MAX > 0xFFFFU /* Required check is (pitch * height < FT_ULONG_MAX), */ /* but we care realistic cases only. Always pitch <= width. */ if ( width > 0x7FFF || height > 0x7FFF ) { FT_ERROR(( "ft_smooth_render_generic: glyph too large: %u x %u\n", width, height )); error = FT_THROW( Raster_Overflow ); goto Exit; } #endif bitmap->pixel_mode = FT_PIXEL_MODE_GRAY; bitmap->num_grays = 256; bitmap->width = width; bitmap->rows = height; bitmap->pitch = pitch; /* translate outline to render it into the bitmap */ FT_Outline_Translate( outline, -x_shift, -y_shift ); have_outline_shifted = TRUE; if ( FT_ALLOC( bitmap->buffer, (FT_ULong)pitch * height ) ) goto Exit; else have_buffer = TRUE; slot->internal->flags |= FT_GLYPH_OWN_BITMAP; /* set up parameters */ params.target = bitmap; params.source = outline; params.flags = FT_RASTER_FLAG_AA; #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING /* implode outline if needed */ { FT_Vector* points = outline->points; FT_Vector* points_end = points + outline->n_points; FT_Vector* vec; if ( hmul ) for ( vec = points; vec < points_end; vec++ ) vec->x *= 3; if ( vmul ) for ( vec = points; vec < points_end; vec++ ) vec->y *= 3; } /* render outline into the bitmap */ error = render->raster_render( render->raster, ¶ms ); /* deflate outline if needed */ { FT_Vector* points = outline->points; FT_Vector* points_end = points + outline->n_points; FT_Vector* vec; if ( hmul ) for ( vec = points; vec < points_end; vec++ ) vec->x /= 3; if ( vmul ) for ( vec = points; vec < points_end; vec++ ) vec->y /= 3; } if ( error ) goto Exit; if ( slot->library->lcd_filter_func ) slot->library->lcd_filter_func( bitmap, mode, slot->library ); #else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ /* render outline into bitmap */ error = render->raster_render( render->raster, ¶ms ); if ( error ) goto Exit; /* expand it horizontally */ if ( hmul ) { FT_Byte* line = bitmap->buffer; FT_UInt hh; for ( hh = height_org; hh > 0; hh--, line += pitch ) { FT_UInt xx; FT_Byte* end = line + width; for ( xx = width_org; xx > 0; xx-- ) { FT_UInt pixel = line[xx-1]; end[-3] = (FT_Byte)pixel; end[-2] = (FT_Byte)pixel; end[-1] = (FT_Byte)pixel; end -= 3; } } } /* expand it vertically */ if ( vmul ) { FT_Byte* read = bitmap->buffer + ( height - height_org ) * pitch; FT_Byte* write = bitmap->buffer; FT_UInt hh; for ( hh = height_org; hh > 0; hh-- ) { ft_memcpy( write, read, pitch ); write += pitch; ft_memcpy( write, read, pitch ); write += pitch; ft_memcpy( write, read, pitch ); write += pitch; read += pitch; } } #endif /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ /* * XXX: on 16bit system, we return an error for huge bitmap * to prevent an overflow. */ if ( x_left > FT_INT_MAX || y_top > FT_INT_MAX ) { error = FT_THROW( Invalid_Pixel_Size ); goto Exit; } slot->format = FT_GLYPH_FORMAT_BITMAP; slot->bitmap_left = (FT_Int)x_left; slot->bitmap_top = (FT_Int)y_top; /* everything is fine; don't deallocate buffer */ have_buffer = FALSE; error = FT_Err_Ok; Exit: if ( have_outline_shifted ) FT_Outline_Translate( outline, x_shift, y_shift ); if ( have_translated_origin ) FT_Outline_Translate( outline, -origin->x, -origin->y ); if ( have_buffer ) { FT_FREE( bitmap->buffer ); slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; } return error; } /* convert a slot's glyph image into a bitmap */ static FT_Error ft_smooth_render( FT_Renderer render, FT_GlyphSlot slot, FT_Render_Mode mode, const FT_Vector* origin ) { if ( mode == FT_RENDER_MODE_LIGHT ) mode = FT_RENDER_MODE_NORMAL; return ft_smooth_render_generic( render, slot, mode, origin, FT_RENDER_MODE_NORMAL ); } typedef long TCoord; /* integer scanline/pixel coordinate */ typedef long TPos; /* sub-pixel coordinate */ #if PIXEL_BITS <= 7 typedef int TArea; #else /* PIXEL_BITS >= 8 */ /* approximately determine the size of integers using an ANSI-C header */ #if FT_UINT_MAX == 0xFFFFU typedef long TArea; #else typedef int TArea; #endif #endif /* PIXEL_BITS >= 8 */ /* maximum number of gray spans in a call to the span callback */ #define FT_MAX_GRAY_SPANS 32 typedef struct TCell_* PCell; typedef struct TCell_ { TPos x; /* same with gray_TWorker.ex */ TCoord cover; /* same with gray_TWorker.cover */ TArea area; PCell next; } TCell; typedef void (*FT_SpanFunc)( int y, int count, const FT_Span* spans, void* user ); #define FT_Raster_Span_Func FT_SpanFunc typedef struct gray_TWorker_ { TCoord ex, ey; TPos min_ex, max_ex; TPos min_ey, max_ey; TPos count_ex, count_ey; TArea area; TCoord cover; int invalid; PCell cells; FT_PtrDist max_cells; FT_PtrDist num_cells; TCoord cx, cy; TPos x, y; TPos last_ey; FT_Vector bez_stack[32 * 3 + 1]; int lev_stack[32]; FT_Outline outline; FT_Bitmap target; FT_BBox clip_box; FT_Span gray_spans[FT_MAX_GRAY_SPANS]; int num_gray_spans; FT_Raster_Span_Func render_span; void* render_span_data; int span_y; int band_size; int band_shoot; ft_jmp_buf jump_buffer; void* buffer; long buffer_size; PCell* ycells; TPos ycount; } gray_TWorker, *gray_PWorker; typedef struct gray_TRaster_ { void* buffer; long buffer_size; int band_size; void* memory; gray_PWorker worker; } gray_TRaster, *gray_PRaster; static int gray_raster_new( FT_Memory memory, FT_Raster* araster ) { FT_Error error; gray_PRaster raster = NULL; *araster = 0; if ( !FT_ALLOC( raster, sizeof ( gray_TRaster ) ) ) { raster->memory = memory; *araster = (FT_Raster)raster; } return error; } static void gray_raster_done( FT_Raster raster ) { FT_Memory memory = (FT_Memory)((gray_PRaster)raster)->memory; FT_FREE( raster ); } static void gray_raster_reset( FT_Raster raster, char* pool_base, long pool_size ) { gray_PRaster rast = (gray_PRaster)raster; if ( raster ) { if ( pool_base && pool_size >= (long)sizeof ( gray_TWorker ) + 2048 ) { gray_PWorker worker = (gray_PWorker)pool_base; rast->worker = worker; rast->buffer = pool_base + ( ( sizeof ( gray_TWorker ) + sizeof ( TCell ) - 1 ) & ~( sizeof ( TCell ) - 1 ) ); rast->buffer_size = (long)( ( pool_base + pool_size ) - (char*)rast->buffer ) & ~( sizeof ( TCell ) - 1 ); rast->band_size = (int)( rast->buffer_size / ( sizeof ( TCell ) * 8 ) ); } else { rast->buffer = NULL; rast->buffer_size = 0; rast->worker = NULL; } } } #undef RAS_ARG #undef RAS_ARG_ #undef RAS_VAR #undef RAS_VAR_ #ifndef FT_STATIC_RASTER #define RAS_ARG gray_PWorker worker #define RAS_ARG_ gray_PWorker worker, #define RAS_VAR worker #define RAS_VAR_ worker, #else /* FT_STATIC_RASTER */ #define RAS_ARG /* empty */ #define RAS_ARG_ /* empty */ #define RAS_VAR /* empty */ #define RAS_VAR_ /* empty */ #endif /* FT_STATIC_RASTER */ #define FT_Err_Invalid_Mode FT_Err_Cannot_Render_Glyph #define FT_Err_Memory_Overflow FT_Err_Out_Of_Memory #define PIXEL_BITS 8 #undef FLOOR #undef CEILING #undef TRUNC #undef SCALED #define ONE_PIXEL ( 1L << PIXEL_BITS ) #define PIXEL_MASK ( -1L << PIXEL_BITS ) #define TRUNC( x ) ( (TCoord)( (x) >> PIXEL_BITS ) ) #define SUBPIXELS( x ) ( (TPos)(x) << PIXEL_BITS ) #define FLOOR( x ) ( (x) & -ONE_PIXEL ) #define CEILING( x ) ( ( (x) + ONE_PIXEL - 1 ) & -ONE_PIXEL ) #define ROUND( x ) ( ( (x) + ONE_PIXEL / 2 ) & -ONE_PIXEL ) #if PIXEL_BITS >= 6 #define UPSCALE( x ) ( (x) << ( PIXEL_BITS - 6 ) ) #define DOWNSCALE( x ) ( (x) >> ( PIXEL_BITS - 6 ) ) #else #define UPSCALE( x ) ( (x) >> ( 6 - PIXEL_BITS ) ) #define DOWNSCALE( x ) ( (x) << ( 6 - PIXEL_BITS ) ) #endif /* Compute `dividend / divisor' and return both its quotient and */ /* remainder, cast to a specific type. This macro also ensures that */ /* the remainder is always positive. */ #define FT_DIV_MOD( type, dividend, divisor, quotient, remainder ) \ FT_BEGIN_STMNT \ (quotient) = (type)( (dividend) / (divisor) ); \ (remainder) = (type)( (dividend) % (divisor) ); \ if ( (remainder) < 0 ) \ { \ (quotient)--; \ (remainder) += (type)(divisor); \ } \ FT_END_STMNT #ifdef __arm__ /* Work around a bug specific to GCC which make the compiler fail to */ /* optimize a division and modulo operation on the same parameters */ /* into a single call to `__aeabi_idivmod'. See */ /* */ /* http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43721 */ #undef FT_DIV_MOD #define FT_DIV_MOD( type, dividend, divisor, quotient, remainder ) \ FT_BEGIN_STMNT \ (quotient) = (type)( (dividend) / (divisor) ); \ (remainder) = (type)( (dividend) - (quotient) * (divisor) ); \ if ( (remainder) < 0 ) \ { \ (quotient)--; \ (remainder) += (type)(divisor); \ } \ FT_END_STMNT #endif /* __arm__ */ static void gray_init_cells( RAS_ARG_ void* buffer, long byte_size ) { ras.buffer = buffer; ras.buffer_size = byte_size; ras.ycells = (PCell*) buffer; ras.cells = NULL; ras.max_cells = 0; ras.num_cells = 0; ras.area = 0; ras.cover = 0; ras.invalid = 1; } static void gray_render_span( int y, int count, const FT_Span* spans, gray_PWorker worker ) { unsigned char* p; FT_Bitmap* map = &worker->target; /* first of all, compute the scanline offset */ p = (unsigned char*)map->buffer - y * map->pitch; if ( map->pitch >= 0 ) p += (unsigned)( ( map->rows - 1 ) * map->pitch ); for ( ; count > 0; count--, spans++ ) { unsigned char coverage = spans->coverage; if ( coverage ) { /* For small-spans it is faster to do it by ourselves than * calling `memset'. This is mainly due to the cost of the * function call. */ if ( spans->len >= 8 ) FT_MEM_SET( p + spans->x, (unsigned char)coverage, spans->len ); else { unsigned char* q = p + spans->x; switch ( spans->len ) { case 7: *q++ = (unsigned char)coverage; case 6: *q++ = (unsigned char)coverage; case 5: *q++ = (unsigned char)coverage; case 4: *q++ = (unsigned char)coverage; case 3: *q++ = (unsigned char)coverage; case 2: *q++ = (unsigned char)coverage; case 1: *q = (unsigned char)coverage; default: ; } } } } } typedef struct gray_TBand_ { TPos min, max; } gray_TBand; #ifndef FT_CONFIG_OPTION_PIC #define FT_DEFINE_OUTLINE_FUNCS( \ class_, \ move_to_, \ line_to_, \ conic_to_, \ cubic_to_, \ shift_, \ delta_ ) \ static const FT_Outline_Funcs class_ = \ { \ move_to_, \ line_to_, \ conic_to_, \ cubic_to_, \ shift_, \ delta_ \ }; #else /* FT_CONFIG_OPTION_PIC */ #define FT_DEFINE_OUTLINE_FUNCS( \ class_, \ move_to_, \ line_to_, \ conic_to_, \ cubic_to_, \ shift_, \ delta_ ) \ static FT_Error \ Init_Class_ ## class_( FT_Outline_Funcs* clazz ) \ { \ clazz->move_to = move_to_; \ clazz->line_to = line_to_; \ clazz->conic_to = conic_to_; \ clazz->cubic_to = cubic_to_; \ clazz->shift = shift_; \ clazz->delta = delta_; \ \ return FT_Err_Ok; \ } #endif /* FT_CONFIG_OPTION_PIC */ static void gray_record_cell( RAS_ARG ); static void gray_set_cell( RAS_ARG_ TCoord ex, TCoord ey ) { /* Move the cell pointer to a new position. We set the `invalid' */ /* flag to indicate that the cell isn't part of those we're interested */ /* in during the render phase. This means that: */ /* */ /* . the new vertical position must be within min_ey..max_ey-1. */ /* . the new horizontal position must be strictly less than max_ex */ /* */ /* Note that if a cell is to the left of the clipping region, it is */ /* actually set to the (min_ex-1) horizontal position. */ /* All cells that are on the left of the clipping region go to the */ /* min_ex - 1 horizontal position. */ ey -= ras.min_ey; if ( ex > ras.max_ex ) ex = ras.max_ex; ex -= ras.min_ex; if ( ex < 0 ) ex = -1; /* are we moving to a different cell ? */ if ( ex != ras.ex || ey != ras.ey ) { /* record the current one if it is valid */ if ( !ras.invalid ) gray_record_cell( RAS_VAR ); ras.area = 0; ras.cover = 0; ras.ex = ex; ras.ey = ey; } ras.invalid = ( (unsigned)ey >= (unsigned)ras.count_ey || ex >= ras.count_ex ); } static void gray_start_cell( RAS_ARG_ TCoord ex, TCoord ey ) { if ( ex > ras.max_ex ) ex = (TCoord)( ras.max_ex ); if ( ex < ras.min_ex ) ex = (TCoord)( ras.min_ex - 1 ); ras.area = 0; ras.cover = 0; ras.ex = ex - ras.min_ex; ras.ey = ey - ras.min_ey; ras.last_ey = SUBPIXELS( ey ); ras.invalid = 0; gray_set_cell( RAS_VAR_ ex, ey ); } static int gray_move_to( const FT_Vector* to, gray_PWorker worker ) { TPos x, y; /* record current cell, if any */ if ( !ras.invalid ) gray_record_cell( RAS_VAR ); /* start to a new position */ x = UPSCALE( to->x ); y = UPSCALE( to->y ); gray_start_cell( RAS_VAR_ TRUNC( x ), TRUNC( y ) ); worker->x = x; worker->y = y; return 0; } static void gray_render_scanline( RAS_ARG_ TCoord ey, TPos x1, TCoord y1, TPos x2, TCoord y2 ) { TCoord ex1, ex2, fx1, fx2, delta, mod; long p, first, dx; int incr; dx = x2 - x1; ex1 = TRUNC( x1 ); ex2 = TRUNC( x2 ); fx1 = (TCoord)( x1 - SUBPIXELS( ex1 ) ); fx2 = (TCoord)( x2 - SUBPIXELS( ex2 ) ); /* trivial case. Happens often */ if ( y1 == y2 ) { gray_set_cell( RAS_VAR_ ex2, ey ); return; } /* everything is located in a single cell. That is easy! */ /* */ if ( ex1 == ex2 ) { delta = y2 - y1; ras.area += (TArea)(( fx1 + fx2 ) * delta); ras.cover += delta; return; } /* ok, we'll have to render a run of adjacent cells on the same */ /* scanline... */ /* */ p = ( ONE_PIXEL - fx1 ) * ( y2 - y1 ); first = ONE_PIXEL; incr = 1; if ( dx < 0 ) { p = fx1 * ( y2 - y1 ); first = 0; incr = -1; dx = -dx; } FT_DIV_MOD( TCoord, p, dx, delta, mod ); ras.area += (TArea)(( fx1 + first ) * delta); ras.cover += delta; ex1 += incr; gray_set_cell( RAS_VAR_ ex1, ey ); y1 += delta; if ( ex1 != ex2 ) { TCoord lift, rem; p = ONE_PIXEL * ( y2 - y1 + delta ); FT_DIV_MOD( TCoord, p, dx, lift, rem ); mod -= (int)dx; while ( ex1 != ex2 ) { delta = lift; mod += rem; if ( mod >= 0 ) { mod -= (TCoord)dx; delta++; } ras.area += (TArea)(ONE_PIXEL * delta); ras.cover += delta; y1 += delta; ex1 += incr; gray_set_cell( RAS_VAR_ ex1, ey ); } } delta = y2 - y1; ras.area += (TArea)(( fx2 + ONE_PIXEL - first ) * delta); ras.cover += delta; } static void gray_render_line( RAS_ARG_ TPos to_x, TPos to_y ) { TCoord ey1, ey2, fy1, fy2, mod; TPos dx, dy, x, x2; long p, first; int delta, rem, lift, incr; ey1 = TRUNC( ras.last_ey ); ey2 = TRUNC( to_y ); /* if (ey2 >= ras.max_ey) ey2 = ras.max_ey-1; */ fy1 = (TCoord)( ras.y - ras.last_ey ); fy2 = (TCoord)( to_y - SUBPIXELS( ey2 ) ); dx = to_x - ras.x; dy = to_y - ras.y; /* perform vertical clipping */ { TCoord min, max; min = ey1; max = ey2; if ( ey1 > ey2 ) { min = ey2; max = ey1; } if ( min >= ras.max_ey || max < ras.min_ey ) goto End; } /* everything is on a single scanline */ if ( ey1 == ey2 ) { gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, to_x, fy2 ); goto End; } /* vertical line - avoid calling gray_render_scanline */ incr = 1; if ( dx == 0 ) { TCoord ex = TRUNC( ras.x ); TCoord two_fx = (TCoord)( ( ras.x - SUBPIXELS( ex ) ) << 1 ); TArea area; first = ONE_PIXEL; if ( dy < 0 ) { first = 0; incr = -1; } delta = (int)( first - fy1 ); ras.area += (TArea)two_fx * delta; ras.cover += delta; ey1 += incr; gray_set_cell( RAS_VAR_ ex, ey1 ); delta = (int)( first + first - ONE_PIXEL ); area = (TArea)two_fx * delta; while ( ey1 != ey2 ) { ras.area += area; ras.cover += delta; ey1 += incr; gray_set_cell( RAS_VAR_ ex, ey1 ); } delta = (int)( fy2 - ONE_PIXEL + first ); ras.area += (TArea)two_fx * delta; ras.cover += delta; goto End; } /* ok, we have to render several scanlines */ p = ( ONE_PIXEL - fy1 ) * dx; first = ONE_PIXEL; incr = 1; if ( dy < 0 ) { p = fy1 * dx; first = 0; incr = -1; dy = -dy; } FT_DIV_MOD( int, p, dy, delta, mod ); x = ras.x + delta; gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, x, (TCoord)first ); ey1 += incr; gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 ); if ( ey1 != ey2 ) { p = ONE_PIXEL * dx; FT_DIV_MOD( int, p, dy, lift, rem ); mod -= (int)dy; while ( ey1 != ey2 ) { delta = lift; mod += rem; if ( mod >= 0 ) { mod -= (int)dy; delta++; } x2 = x + delta; gray_render_scanline( RAS_VAR_ ey1, x, (TCoord)( ONE_PIXEL - first ), x2, (TCoord)first ); x = x2; ey1 += incr; gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 ); } } gray_render_scanline( RAS_VAR_ ey1, x, (TCoord)( ONE_PIXEL - first ), to_x, fy2 ); End: ras.x = to_x; ras.y = to_y; ras.last_ey = SUBPIXELS( ey2 ); } static int gray_line_to( const FT_Vector* to, gray_PWorker worker ) { gray_render_line( RAS_VAR_ UPSCALE( to->x ), UPSCALE( to->y ) ); return 0; } static void gray_split_conic( FT_Vector* base ) { TPos a, b; base[4].x = base[2].x; b = base[1].x; a = base[3].x = ( base[2].x + b ) / 2; b = base[1].x = ( base[0].x + b ) / 2; base[2].x = ( a + b ) / 2; base[4].y = base[2].y; b = base[1].y; a = base[3].y = ( base[2].y + b ) / 2; b = base[1].y = ( base[0].y + b ) / 2; base[2].y = ( a + b ) / 2; } static void gray_render_conic( RAS_ARG_ const FT_Vector* control, const FT_Vector* to ) { TPos dx, dy; TPos min, max, y; int top, level; int* levels; FT_Vector* arc; levels = ras.lev_stack; arc = ras.bez_stack; arc[0].x = UPSCALE( to->x ); arc[0].y = UPSCALE( to->y ); arc[1].x = UPSCALE( control->x ); arc[1].y = UPSCALE( control->y ); arc[2].x = ras.x; arc[2].y = ras.y; top = 0; dx = FT_ABS( arc[2].x + arc[0].x - 2 * arc[1].x ); dy = FT_ABS( arc[2].y + arc[0].y - 2 * arc[1].y ); if ( dx < dy ) dx = dy; if ( dx < ONE_PIXEL / 4 ) goto Draw; /* short-cut the arc that crosses the current band */ min = max = arc[0].y; y = arc[1].y; if ( y < min ) min = y; if ( y > max ) max = y; y = arc[2].y; if ( y < min ) min = y; if ( y > max ) max = y; if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < ras.min_ey ) goto Draw; level = 0; do { dx >>= 2; level++; } while ( dx > ONE_PIXEL / 4 ); levels[0] = level; do { level = levels[top]; if ( level > 0 ) { gray_split_conic( arc ); arc += 2; top++; levels[top] = levels[top - 1] = level - 1; continue; } Draw: gray_render_line( RAS_VAR_ arc[0].x, arc[0].y ); top--; arc -= 2; } while ( top >= 0 ); } static int gray_conic_to( const FT_Vector* control, const FT_Vector* to, gray_PWorker worker ) { gray_render_conic( RAS_VAR_ control, to ); return 0; } static void gray_split_cubic( FT_Vector* base ) { TPos a, b, c, d; base[6].x = base[3].x; c = base[1].x; d = base[2].x; base[1].x = a = ( base[0].x + c ) / 2; base[5].x = b = ( base[3].x + d ) / 2; c = ( c + d ) / 2; base[2].x = a = ( a + c ) / 2; base[4].x = b = ( b + c ) / 2; base[3].x = ( a + b ) / 2; base[6].y = base[3].y; c = base[1].y; d = base[2].y; base[1].y = a = ( base[0].y + c ) / 2; base[5].y = b = ( base[3].y + d ) / 2; c = ( c + d ) / 2; base[2].y = a = ( a + c ) / 2; base[4].y = b = ( b + c ) / 2; base[3].y = ( a + b ) / 2; } static void gray_render_cubic( RAS_ARG_ const FT_Vector* control1, const FT_Vector* control2, const FT_Vector* to ) { FT_Vector* arc; TPos min, max, y; arc = ras.bez_stack; arc[0].x = UPSCALE( to->x ); arc[0].y = UPSCALE( to->y ); arc[1].x = UPSCALE( control2->x ); arc[1].y = UPSCALE( control2->y ); arc[2].x = UPSCALE( control1->x ); arc[2].y = UPSCALE( control1->y ); arc[3].x = ras.x; arc[3].y = ras.y; /* Short-cut the arc that crosses the current band. */ min = max = arc[0].y; y = arc[1].y; if ( y < min ) min = y; if ( y > max ) max = y; y = arc[2].y; if ( y < min ) min = y; if ( y > max ) max = y; y = arc[3].y; if ( y < min ) min = y; if ( y > max ) max = y; if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < ras.min_ey ) goto Draw; for (;;) { /* Decide whether to split or draw. See `Rapid Termination */ /* Evaluation for Recursive Subdivision of Bezier Curves' by Thomas */ /* F. Hain, at */ /* http://www.cis.southalabama.edu/~hain/general/Publications/Bezier/Camera-ready%20CISST02%202.pdf */ { TPos dx, dy, dx_, dy_; TPos dx1, dy1, dx2, dy2; TPos L, s, s_limit; /* dx and dy are x and y components of the P0-P3 chord vector. */ dx = arc[3].x - arc[0].x; dy = arc[3].y - arc[0].y; /* L is an (under)estimate of the Euclidean distance P0-P3. */ /* */ /* If dx >= dy, then r = sqrt(dx^2 + dy^2) can be overestimated */ /* with least maximum error by */ /* */ /* r_upperbound = dx + (sqrt(2) - 1) * dy , */ /* */ /* where sqrt(2) - 1 can be (over)estimated by 107/256, giving an */ /* error of no more than 8.4%. */ /* */ /* Similarly, some elementary calculus shows that r can be */ /* underestimated with least maximum error by */ /* */ /* r_lowerbound = sqrt(2 + sqrt(2)) / 2 * dx */ /* + sqrt(2 - sqrt(2)) / 2 * dy . */ /* */ /* 236/256 and 97/256 are (under)estimates of the two algebraic */ /* numbers, giving an error of no more than 8.1%. */ dx_ = FT_ABS( dx ); dy_ = FT_ABS( dy ); /* This is the same as */ /* */ /* L = ( 236 * FT_MAX( dx_, dy_ ) */ /* + 97 * FT_MIN( dx_, dy_ ) ) >> 8; */ L = ( dx_ > dy_ ? 236 * dx_ + 97 * dy_ : 97 * dx_ + 236 * dy_ ) >> 8; /* Avoid possible arithmetic overflow below by splitting. */ if ( L > 32767 ) goto Split; /* Max deviation may be as much as (s/L) * 3/4 (if Hain's v = 1). */ s_limit = L * (TPos)( ONE_PIXEL / 6 ); /* s is L * the perpendicular distance from P1 to the line P0-P3. */ dx1 = arc[1].x - arc[0].x; dy1 = arc[1].y - arc[0].y; s = FT_ABS( dy * dx1 - dx * dy1 ); if ( s > s_limit ) goto Split; /* s is L * the perpendicular distance from P2 to the line P0-P3. */ dx2 = arc[2].x - arc[0].x; dy2 = arc[2].y - arc[0].y; s = FT_ABS( dy * dx2 - dx * dy2 ); if ( s > s_limit ) goto Split; /* Split super curvy segments where the off points are so far from the chord that the angles P0-P1-P3 or P0-P2-P3 become acute as detected by appropriate dot products. */ if ( dx1 * ( dx1 - dx ) + dy1 * ( dy1 - dy ) > 0 || dx2 * ( dx2 - dx ) + dy2 * ( dy2 - dy ) > 0 ) goto Split; /* No reason to split. */ goto Draw; } Split: gray_split_cubic( arc ); arc += 3; continue; Draw: gray_render_line( RAS_VAR_ arc[0].x, arc[0].y ); if ( arc == ras.bez_stack ) return; arc -= 3; } } static int gray_cubic_to( const FT_Vector* control1, const FT_Vector* control2, const FT_Vector* to, gray_PWorker worker ) { gray_render_cubic( RAS_VAR_ control1, control2, to ); return 0; } static void gray_hline( RAS_ARG_ TCoord x, TCoord y, TPos area, TCoord acount ) { int coverage; /* compute the coverage line's coverage, depending on the */ /* outline fill rule */ /* */ /* the coverage percentage is area/(PIXEL_BITS*PIXEL_BITS*2) */ /* */ coverage = (int)( area >> ( PIXEL_BITS * 2 + 1 - 8 ) ); /* use range 0..256 */ if ( coverage < 0 ) coverage = -coverage; if ( ras.outline.flags & FT_OUTLINE_EVEN_ODD_FILL ) { coverage &= 511; if ( coverage > 256 ) coverage = 512 - coverage; else if ( coverage == 256 ) coverage = 255; } else { /* normal non-zero winding rule */ if ( coverage >= 256 ) coverage = 255; } y += (TCoord)ras.min_ey; x += (TCoord)ras.min_ex; /* FT_Span.x is a 16-bit short, so limit our coordinates appropriately */ if ( x >= 32767 ) x = 32767; /* FT_Span.y is an integer, so limit our coordinates appropriately */ if ( y >= FT_INT_MAX ) y = FT_INT_MAX; if ( coverage ) { FT_Span* span; int count; /* see whether we can add this span to the current list */ count = ras.num_gray_spans; span = ras.gray_spans + count - 1; if ( count > 0 && ras.span_y == y && (int)span->x + span->len == (int)x && span->coverage == coverage ) { span->len = (unsigned short)( span->len + acount ); return; } if ( ras.span_y != y || count >= FT_MAX_GRAY_SPANS ) { if ( ras.render_span && count > 0 ) ras.render_span( ras.span_y, count, ras.gray_spans, ras.render_span_data ); #ifdef FT_DEBUG_LEVEL_TRACE if ( count > 0 ) { int n; FT_TRACE7(( "y = %3d ", ras.span_y )); span = ras.gray_spans; for ( n = 0; n < count; n++, span++ ) FT_TRACE7(( "[%d..%d]:%02x ", span->x, span->x + span->len - 1, span->coverage )); FT_TRACE7(( "\n" )); } #endif /* FT_DEBUG_LEVEL_TRACE */ ras.num_gray_spans = 0; ras.span_y = (int)y; span = ras.gray_spans; } else span++; /* add a gray span to the current list */ span->x = (short)x; span->len = (unsigned short)acount; span->coverage = (unsigned char)coverage; ras.num_gray_spans++; } } FT_DEFINE_OUTLINE_FUNCS( func_interface, (FT_Outline_MoveTo_Func) gray_move_to, (FT_Outline_LineTo_Func) gray_line_to, (FT_Outline_ConicTo_Func)gray_conic_to, (FT_Outline_CubicTo_Func)gray_cubic_to, 0, 0 ) static void gray_compute_cbox( RAS_ARG ) { FT_Outline* outline = &ras.outline; FT_Vector* vec = outline->points; FT_Vector* limit = vec + outline->n_points; if ( outline->n_points <= 0 ) { ras.min_ex = ras.max_ex = 0; ras.min_ey = ras.max_ey = 0; return; } ras.min_ex = ras.max_ex = vec->x; ras.min_ey = ras.max_ey = vec->y; vec++; for ( ; vec < limit; vec++ ) { TPos x = vec->x; TPos y = vec->y; if ( x < ras.min_ex ) ras.min_ex = x; if ( x > ras.max_ex ) ras.max_ex = x; if ( y < ras.min_ey ) ras.min_ey = y; if ( y > ras.max_ey ) ras.max_ey = y; } /* truncate the bounding box to integer pixels */ ras.min_ex = ras.min_ex >> 6; ras.min_ey = ras.min_ey >> 6; ras.max_ex = ( ras.max_ex + 63 ) >> 6; ras.max_ey = ( ras.max_ey + 63 ) >> 6; } static PCell gray_find_cell( RAS_ARG ) { PCell *pcell, cell; TPos x = ras.ex; if ( x > ras.count_ex ) x = ras.count_ex; pcell = &ras.ycells[ras.ey]; for (;;) { cell = *pcell; if ( cell == NULL || cell->x > x ) break; if ( cell->x == x ) goto Exit; pcell = &cell->next; } if ( ras.num_cells >= ras.max_cells ) ft_longjmp( ras.jump_buffer, 1 ); cell = ras.cells + ras.num_cells++; cell->x = x; cell->area = 0; cell->cover = 0; cell->next = *pcell; *pcell = cell; Exit: return cell; } static void gray_record_cell( RAS_ARG ) { if ( ras.area | ras.cover ) { PCell cell = gray_find_cell( RAS_VAR ); cell->area += ras.area; cell->cover += ras.cover; } } static int gray_convert_glyph_inner( RAS_ARG ) { volatile int error = 0; #ifdef FT_CONFIG_OPTION_PIC FT_Outline_Funcs func_interface; Init_Class_func_interface(&func_interface); #endif if ( ft_setjmp( ras.jump_buffer ) == 0 ) { error = FT_Outline_Decompose( &ras.outline, &func_interface, &ras ); if ( !ras.invalid ) gray_record_cell( RAS_VAR ); } else error = FT_THROW( Memory_Overflow ); return error; } static void gray_sweep( RAS_ARG_ const FT_Bitmap* target ) { int yindex; FT_UNUSED( target ); if ( ras.num_cells == 0 ) return; ras.num_gray_spans = 0; FT_TRACE7(( "gray_sweep: start\n" )); for ( yindex = 0; yindex < ras.ycount; yindex++ ) { PCell cell = ras.ycells[yindex]; TCoord cover = 0; TCoord x = 0; for ( ; cell != NULL; cell = cell->next ) { TPos area; if ( cell->x > x && cover != 0 ) gray_hline( RAS_VAR_ x, yindex, cover * ( ONE_PIXEL * 2 ), cell->x - x ); cover += cell->cover; area = cover * ( ONE_PIXEL * 2 ) - cell->area; if ( area != 0 && cell->x >= 0 ) gray_hline( RAS_VAR_ cell->x, yindex, area, 1 ); x = cell->x + 1; } if ( cover != 0 ) gray_hline( RAS_VAR_ x, yindex, cover * ( ONE_PIXEL * 2 ), ras.count_ex - x ); } if ( ras.render_span && ras.num_gray_spans > 0 ) ras.render_span( ras.span_y, ras.num_gray_spans, ras.gray_spans, ras.render_span_data ); #ifdef FT_DEBUG_LEVEL_TRACE if ( ras.num_gray_spans > 0 ) { FT_Span* span; int n; FT_TRACE7(( "y = %3d ", ras.span_y )); span = ras.gray_spans; for ( n = 0; n < ras.num_gray_spans; n++, span++ ) FT_TRACE7(( "[%d..%d]:%02x ", span->x, span->x + span->len - 1, span->coverage )); FT_TRACE7(( "\n" )); } FT_TRACE7(( "gray_sweep: end\n" )); #endif /* FT_DEBUG_LEVEL_TRACE */ } static int gray_convert_glyph( RAS_ARG ) { gray_TBand bands[40]; gray_TBand* volatile band; int volatile n, num_bands; TPos volatile min, max, max_y; FT_BBox* clip; /* Set up state in the raster object */ gray_compute_cbox( RAS_VAR ); /* clip to target bitmap, exit if nothing to do */ clip = &ras.clip_box; if ( ras.max_ex <= clip->xMin || ras.min_ex >= clip->xMax || ras.max_ey <= clip->yMin || ras.min_ey >= clip->yMax ) return 0; if ( ras.min_ex < clip->xMin ) ras.min_ex = clip->xMin; if ( ras.min_ey < clip->yMin ) ras.min_ey = clip->yMin; if ( ras.max_ex > clip->xMax ) ras.max_ex = clip->xMax; if ( ras.max_ey > clip->yMax ) ras.max_ey = clip->yMax; ras.count_ex = ras.max_ex - ras.min_ex; ras.count_ey = ras.max_ey - ras.min_ey; /* set up vertical bands */ num_bands = (int)( ( ras.max_ey - ras.min_ey ) / ras.band_size ); if ( num_bands == 0 ) num_bands = 1; if ( num_bands >= 39 ) num_bands = 39; ras.band_shoot = 0; min = ras.min_ey; max_y = ras.max_ey; for ( n = 0; n < num_bands; n++, min = max ) { max = min + ras.band_size; if ( n == num_bands - 1 || max > max_y ) max = max_y; bands[0].min = min; bands[0].max = max; band = bands; while ( band >= bands ) { TPos bottom, top, middle; int error; { PCell cells_max; int yindex; long cell_start, cell_end, cell_mod; ras.ycells = (PCell*)ras.buffer; ras.ycount = band->max - band->min; cell_start = sizeof ( PCell ) * ras.ycount; cell_mod = cell_start % sizeof ( TCell ); if ( cell_mod > 0 ) cell_start += sizeof ( TCell ) - cell_mod; cell_end = ras.buffer_size; cell_end -= cell_end % sizeof ( TCell ); cells_max = (PCell)( (char*)ras.buffer + cell_end ); ras.cells = (PCell)( (char*)ras.buffer + cell_start ); if ( ras.cells >= cells_max ) goto ReduceBands; ras.max_cells = cells_max - ras.cells; if ( ras.max_cells < 2 ) goto ReduceBands; for ( yindex = 0; yindex < ras.ycount; yindex++ ) ras.ycells[yindex] = NULL; } ras.num_cells = 0; ras.invalid = 1; ras.min_ey = band->min; ras.max_ey = band->max; ras.count_ey = band->max - band->min; error = gray_convert_glyph_inner( RAS_VAR ); if ( !error ) { gray_sweep( RAS_VAR_ &ras.target ); band--; continue; } else if ( error != FT_Err_Memory_Overflow ) return 1; ReduceBands: /* render pool overflow; we will reduce the render band by half */ bottom = band->min; top = band->max; middle = bottom + ( ( top - bottom ) >> 1 ); /* This is too complex for a single scanline; there must */ /* be some problems. */ if ( middle == bottom ) { #ifdef FT_DEBUG_LEVEL_TRACE FT_TRACE7(( "gray_convert_glyph: rotten glyph\n" )); #endif return 1; } if ( bottom-top >= ras.band_size ) ras.band_shoot++; band[1].min = bottom; band[1].max = middle; band[0].min = middle; band[0].max = top; band++; } } if ( ras.band_shoot > 8 && ras.band_size > 16 ) ras.band_size = ras.band_size / 2; return 0; } static int gray_raster_render( gray_PRaster raster, const FT_Raster_Params* params ) { const FT_Outline* outline = (const FT_Outline*)params->source; const FT_Bitmap* target_map = params->target; gray_PWorker worker; if ( !raster || !raster->buffer || !raster->buffer_size ) return FT_THROW( Invalid_Argument ); if ( !outline ) return FT_THROW( Invalid_Outline ); /* return immediately if the outline is empty */ if ( outline->n_points == 0 || outline->n_contours <= 0 ) return 0; if ( !outline->contours || !outline->points ) return FT_THROW( Invalid_Outline ); if ( outline->n_points != outline->contours[outline->n_contours - 1] + 1 ) return FT_THROW( Invalid_Outline ); worker = raster->worker; /* if direct mode is not set, we must have a target bitmap */ if ( !( params->flags & FT_RASTER_FLAG_DIRECT ) ) { if ( !target_map ) return FT_THROW( Invalid_Argument ); /* nothing to do */ if ( !target_map->width || !target_map->rows ) return 0; if ( !target_map->buffer ) return FT_THROW( Invalid_Argument ); } /* this version does not support monochrome rendering */ if ( !( params->flags & FT_RASTER_FLAG_AA ) ) return FT_THROW( Invalid_Mode ); /* compute clipping box */ if ( !( params->flags & FT_RASTER_FLAG_DIRECT ) ) { /* compute clip box from target pixmap */ ras.clip_box.xMin = 0; ras.clip_box.yMin = 0; ras.clip_box.xMax = target_map->width; ras.clip_box.yMax = target_map->rows; } else if ( params->flags & FT_RASTER_FLAG_CLIP ) ras.clip_box = params->clip_box; else { ras.clip_box.xMin = -32768L; ras.clip_box.yMin = -32768L; ras.clip_box.xMax = 32767L; ras.clip_box.yMax = 32767L; } gray_init_cells( RAS_VAR_ raster->buffer, raster->buffer_size ); ras.outline = *outline; ras.num_cells = 0; ras.invalid = 1; ras.band_size = raster->band_size; ras.num_gray_spans = 0; if ( params->flags & FT_RASTER_FLAG_DIRECT ) { ras.render_span = (FT_Raster_Span_Func)params->gray_spans; ras.render_span_data = params->user; } else { ras.target = *target_map; ras.render_span = (FT_Raster_Span_Func)gray_render_span; ras.render_span_data = &ras; } return gray_convert_glyph( RAS_VAR ); } FT_DEFINE_RASTER_FUNCS( ft_grays_raster, FT_GLYPH_FORMAT_OUTLINE, (FT_Raster_New_Func) gray_raster_new, (FT_Raster_Reset_Func) gray_raster_reset, (FT_Raster_Set_Mode_Func)0, (FT_Raster_Render_Func) gray_raster_render, (FT_Raster_Done_Func) gray_raster_done ) #ifndef FT_CONFIG_OPTION_PIC #define FT_GRAYS_RASTER_GET ft_grays_raster #else /* FT_CONFIG_OPTION_PIC */ typedef struct SmoothPIC_ { int ref_count; FT_Raster_Funcs ft_grays_raster; } SmoothPIC; #define GET_PIC( lib ) \ ( (SmoothPIC*)( (lib)->pic_container.smooth ) ) #define FT_GRAYS_RASTER_GET ( GET_PIC( library )->ft_grays_raster ) /* see ftspic.c for the implementation */ void ft_smooth_renderer_class_pic_free( FT_Library library ); void ft_smooth_lcd_renderer_class_pic_free( FT_Library library ); void ft_smooth_lcdv_renderer_class_pic_free( FT_Library library ); FT_Error ft_smooth_renderer_class_pic_init( FT_Library library ); FT_Error ft_smooth_lcd_renderer_class_pic_init( FT_Library library ); FT_Error ft_smooth_lcdv_renderer_class_pic_init( FT_Library library ); #endif /* FT_CONFIG_OPTION_PIC */ FT_DEFINE_RENDERER( ft_smooth_renderer_class, FT_MODULE_RENDERER, sizeof ( FT_RendererRec ), "smooth", 0x10000L, 0x20000L, 0, /* module specific interface */ (FT_Module_Constructor)ft_smooth_init, (FT_Module_Destructor) 0, (FT_Module_Requester) 0 , FT_GLYPH_FORMAT_OUTLINE, (FT_Renderer_RenderFunc) ft_smooth_render, (FT_Renderer_TransformFunc)ft_smooth_transform, (FT_Renderer_GetCBoxFunc) ft_smooth_get_cbox, (FT_Renderer_SetModeFunc) ft_smooth_set_mode, (FT_Raster_Funcs*) &FT_GRAYS_RASTER_GET ) // ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ #define AF_CJK_IS_TOP_BLUE( b ) \ ( (b)->properties & AF_BLUE_PROPERTY_CJK_TOP ) #define AF_CJK_IS_HORIZ_BLUE( b ) \ ( (b)->properties & AF_BLUE_PROPERTY_CJK_HORIZ ) #define AF_CJK_IS_FILLED_BLUE( b ) \ ( (b)->properties & AF_BLUE_PROPERTY_CJK_FILL ) #define AF_CJK_IS_RIGHT_BLUE AF_CJK_IS_TOP_BLUE #define AF_CJK_MAX_WIDTHS 16 enum { AF_CJK_BLUE_ACTIVE = 1 << 0, /* set if zone height is <= 3/4px */ AF_CJK_BLUE_TOP = 1 << 1, /* result of AF_CJK_IS_TOP_BLUE */ AF_CJK_BLUE_ADJUSTMENT = 1 << 2, /* used for scale adjustment */ /* optimization */ AF_CJK_BLUE_FLAG_MAX }; typedef struct AF_CJKBlueRec_ { AF_WidthRec ref; AF_WidthRec shoot; /* undershoot */ FT_UInt flags; } AF_CJKBlueRec, *AF_CJKBlue; typedef struct AF_CJKAxisRec_ { FT_Fixed scale; FT_Pos delta; FT_UInt width_count; /* number of used widths */ AF_WidthRec widths[AF_CJK_MAX_WIDTHS]; /* widths array */ FT_Pos edge_distance_threshold; /* used for creating edges */ FT_Pos standard_width; /* the default stem thickness */ FT_Bool extra_light; /* is standard width very light? */ /* used for horizontal metrics too for CJK */ FT_Bool control_overshoot; FT_UInt blue_count; AF_CJKBlueRec blues[AF_BLUE_STRINGSET_MAX]; FT_Fixed org_scale; FT_Pos org_delta; } AF_CJKAxisRec, *AF_CJKAxis; typedef struct AF_CJKMetricsRec_ { AF_StyleMetricsRec root; FT_UInt units_per_em; AF_CJKAxisRec axis[AF_DIMENSION_MAX]; } AF_CJKMetricsRec, *AF_CJKMetrics; FT_LOCAL_DEF( void ) af_cjk_metrics_init_widths( AF_CJKMetrics metrics, FT_Face face ) { /* scan the array of segments in each direction */ AF_GlyphHintsRec hints[1]; FT_TRACE5(( "\n" "cjk standard widths computation (style `%s')\n" "===================================================\n" "\n", af_style_names[metrics->root.style_class->style] )); af_glyph_hints_init( hints, face->memory ); metrics->axis[AF_DIMENSION_HORZ].width_count = 0; metrics->axis[AF_DIMENSION_VERT].width_count = 0; { FT_Error error; FT_ULong glyph_index; FT_Long y_offset; int dim; AF_CJKMetricsRec dummy[1]; AF_Scaler scaler = &dummy->root.scaler; #ifdef FT_CONFIG_OPTION_PIC AF_FaceGlobals globals = metrics->root.globals; #endif AF_StyleClass style_class = metrics->root.style_class; AF_ScriptClass script_class = AF_SCRIPT_CLASSES_GET [style_class->script]; FT_UInt32 standard_char; standard_char = script_class->standard_char1; af_get_char_index( &metrics->root, standard_char, &glyph_index, &y_offset ); if ( !glyph_index ) { if ( script_class->standard_char2 ) { standard_char = script_class->standard_char2; af_get_char_index( &metrics->root, standard_char, &glyph_index, &y_offset ); if ( !glyph_index ) { if ( script_class->standard_char3 ) { standard_char = script_class->standard_char3; af_get_char_index( &metrics->root, standard_char, &glyph_index, &y_offset ); if ( !glyph_index ) goto Exit; } else goto Exit; } } else goto Exit; } FT_TRACE5(( "standard character: U+%04lX (glyph index %d)\n", standard_char, glyph_index )); error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE ); if ( error || face->glyph->outline.n_points <= 0 ) goto Exit; FT_ZERO( dummy ); dummy->units_per_em = metrics->units_per_em; scaler->x_scale = 0x10000L; scaler->y_scale = 0x10000L; scaler->x_delta = 0; scaler->y_delta = 0; scaler->face = face; scaler->render_mode = FT_RENDER_MODE_NORMAL; scaler->flags = 0; af_glyph_hints_rescale( hints, (AF_StyleMetrics)dummy ); error = af_glyph_hints_reload( hints, &face->glyph->outline ); if ( error ) goto Exit; for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) { AF_CJKAxis axis = &metrics->axis[dim]; AF_AxisHints axhints = &hints->axis[dim]; AF_Segment seg, limit, link; FT_UInt num_widths = 0; error = af_latin_hints_compute_segments( hints, (AF_Dimension)dim ); if ( error ) goto Exit; af_latin_hints_link_segments( hints, (AF_Dimension)dim ); seg = axhints->segments; limit = seg + axhints->num_segments; for ( ; seg < limit; seg++ ) { link = seg->link; /* we only consider stem segments there! */ if ( link && link->link == seg && link > seg ) { FT_Pos dist; dist = seg->pos - link->pos; if ( dist < 0 ) dist = -dist; if ( num_widths < AF_CJK_MAX_WIDTHS ) axis->widths[num_widths++].org = dist; } } /* this also replaces multiple almost identical stem widths */ /* with a single one (the value 100 is heuristic) */ af_sort_and_quantize_widths( &num_widths, axis->widths, dummy->units_per_em / 100 ); axis->width_count = num_widths; } Exit: for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) { AF_CJKAxis axis = &metrics->axis[dim]; FT_Pos stdw; stdw = ( axis->width_count > 0 ) ? axis->widths[0].org : AF_LATIN_CONSTANT( metrics, 50 ); /* let's try 20% of the smallest width */ axis->edge_distance_threshold = stdw / 5; axis->standard_width = stdw; axis->extra_light = 0; #ifdef FT_DEBUG_LEVEL_TRACE { FT_UInt i; FT_TRACE5(( "%s widths:\n", dim == AF_DIMENSION_VERT ? "horizontal" : "vertical" )); FT_TRACE5(( " %d (standard)", axis->standard_width )); for ( i = 1; i < axis->width_count; i++ ) FT_TRACE5(( " %d", axis->widths[i].org )); FT_TRACE5(( "\n" )); } #endif } } FT_TRACE5(( "\n" )); af_glyph_hints_done( hints ); } /* Find all blue zones. */ static void af_cjk_metrics_init_blues( AF_CJKMetrics metrics, FT_Face face ) { FT_Pos fills[AF_BLUE_STRING_MAX_LEN]; FT_Pos flats[AF_BLUE_STRING_MAX_LEN]; FT_Int num_fills; FT_Int num_flats; AF_CJKBlue blue; FT_Error error; AF_CJKAxis axis; FT_Outline outline; AF_StyleClass sc = metrics->root.style_class; AF_Blue_Stringset bss = sc->blue_stringset; const AF_Blue_StringRec* bs = &af_blue_stringsets[bss]; #ifdef FT_DEBUG_LEVEL_TRACE FT_String* cjk_blue_name[4] = { (FT_String*)"bottom", /* -- , -- */ (FT_String*)"top", /* -- , TOP */ (FT_String*)"left", /* HORIZ, -- */ (FT_String*)"right" /* HORIZ, TOP */ }; FT_String* cjk_blue_type_name[2] = { (FT_String*)"unfilled", /* -- */ (FT_String*)"filled" /* FILL */ }; #endif /* we walk over the blue character strings as specified in the */ /* style's entry in the `af_blue_stringset' array, computing its */ /* extremum points (depending on the string properties) */ FT_TRACE5(( "cjk blue zones computation\n" "==========================\n" "\n" )); for ( ; bs->string != AF_BLUE_STRING_MAX; bs++ ) { const char* p = &af_blue_strings[bs->string]; FT_Pos* blue_ref; FT_Pos* blue_shoot; if ( AF_CJK_IS_HORIZ_BLUE( bs ) ) axis = &metrics->axis[AF_DIMENSION_HORZ]; else axis = &metrics->axis[AF_DIMENSION_VERT]; FT_TRACE5(( "blue zone %d:\n", axis->blue_count )); num_fills = 0; num_flats = 0; FT_TRACE5(( " cjk blue %s/%s\n", cjk_blue_name[AF_CJK_IS_HORIZ_BLUE( bs ) | AF_CJK_IS_TOP_BLUE( bs ) ], cjk_blue_type_name[!!AF_CJK_IS_FILLED_BLUE( bs )] )); while ( *p ) { FT_ULong ch; FT_ULong glyph_index; FT_Long y_offset; FT_Pos best_pos; /* same as points.y or points.x, resp. */ FT_Int best_point; FT_Vector* points; GET_UTF8_CHAR( ch, p ); /* load the character in the face -- skip unknown or empty ones */ af_get_char_index( &metrics->root, ch, &glyph_index, &y_offset ); if ( glyph_index == 0 ) { FT_TRACE5(( " U+%04lX unavailable\n", ch )); continue; } error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE ); outline = face->glyph->outline; if ( error || outline.n_points <= 0 ) { FT_TRACE5(( " U+%04lX contains no outlines\n", ch )); continue; } /* now compute min or max point indices and coordinates */ points = outline.points; best_point = -1; best_pos = 0; /* make compiler happy */ { FT_Int nn; FT_Int first = 0; FT_Int last = -1; for ( nn = 0; nn < outline.n_contours; first = last + 1, nn++ ) { FT_Int pp; last = outline.contours[nn]; /* Avoid single-point contours since they are never rasterized. */ /* In some fonts, they correspond to mark attachment points */ /* which are way outside of the glyph's real outline. */ if ( last <= first ) continue; if ( AF_CJK_IS_HORIZ_BLUE( bs ) ) { if ( AF_CJK_IS_RIGHT_BLUE( bs ) ) { for ( pp = first; pp <= last; pp++ ) if ( best_point < 0 || points[pp].x > best_pos ) { best_point = pp; best_pos = points[pp].x; } } else { for ( pp = first; pp <= last; pp++ ) if ( best_point < 0 || points[pp].x < best_pos ) { best_point = pp; best_pos = points[pp].x; } } } else { if ( AF_CJK_IS_TOP_BLUE( bs ) ) { for ( pp = first; pp <= last; pp++ ) if ( best_point < 0 || points[pp].y > best_pos ) { best_point = pp; best_pos = points[pp].y; } } else { for ( pp = first; pp <= last; pp++ ) if ( best_point < 0 || points[pp].y < best_pos ) { best_point = pp; best_pos = points[pp].y; } } } } FT_TRACE5(( " U+%04lX: best_pos = %5ld\n", ch, best_pos )); } if ( AF_CJK_IS_FILLED_BLUE( bs ) ) fills[num_fills++] = best_pos; else flats[num_flats++] = best_pos; } if ( num_flats == 0 && num_fills == 0 ) { /* * we couldn't find a single glyph to compute this blue zone, * we will simply ignore it then */ FT_TRACE5(( " empty\n" )); continue; } /* we have computed the contents of the `fill' and `flats' tables, */ /* now determine the reference position of the blue zone -- */ /* we simply take the median value after a simple sort */ af_sort_pos( num_flats, flats ); af_sort_pos( num_fills, fills ); blue = &axis->blues[axis->blue_count]; blue_ref = &blue->ref.org; blue_shoot = &blue->shoot.org; axis->blue_count++; if ( num_flats == 0 ) { *blue_ref = *blue_shoot = fills[num_fills / 2]; } else if ( num_fills == 0 ) { *blue_ref = *blue_shoot = flats[num_flats / 2]; } else { *blue_ref = fills[num_fills / 2]; *blue_shoot = flats[num_flats / 2]; } /* make sure blue_ref >= blue_shoot for top/right or */ /* vice versa for bottom/left */ if ( *blue_shoot != *blue_ref ) { FT_Pos ref = *blue_ref; FT_Pos shoot = *blue_shoot; FT_Bool under_ref = FT_BOOL( shoot < ref ); /* AF_CJK_IS_TOP_BLUE covers `right' and `top' */ if ( AF_CJK_IS_TOP_BLUE( bs ) ^ under_ref ) { *blue_ref = *blue_shoot = ( shoot + ref ) / 2; FT_TRACE5(( " [overshoot smaller than reference," " taking mean value]\n" )); } } blue->flags = 0; if ( AF_CJK_IS_TOP_BLUE( bs ) ) blue->flags |= AF_CJK_BLUE_TOP; FT_TRACE5(( " -> reference = %ld\n" " overshoot = %ld\n", *blue_ref, *blue_shoot )); } FT_TRACE5(( "\n" )); return; } /* Basically the Latin version with type AF_CJKMetrics for metrics. */ FT_LOCAL_DEF( void ) af_cjk_metrics_check_digits( AF_CJKMetrics metrics, FT_Face face ) { FT_UInt i; FT_Bool started = 0, same_width = 1; FT_Fixed advance, old_advance = 0; /* digit `0' is 0x30 in all supported charmaps */ for ( i = 0x30; i <= 0x39; i++ ) { FT_ULong glyph_index; FT_Long y_offset; af_get_char_index( &metrics->root, i, &glyph_index, &y_offset ); if ( glyph_index == 0 ) continue; if ( FT_Get_Advance( face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_IGNORE_TRANSFORM, &advance ) ) continue; if ( started ) { if ( advance != old_advance ) { same_width = 0; break; } } else { old_advance = advance; started = 1; } } metrics->root.digits_have_same_width = same_width; } FT_LOCAL_DEF( FT_Error ) af_cjk_metrics_init( AF_CJKMetrics metrics, FT_Face face ) { FT_CharMap oldmap = face->charmap; metrics->units_per_em = face->units_per_EM; if ( !FT_Select_Charmap( face, FT_ENCODING_UNICODE ) ) { af_cjk_metrics_init_widths( metrics, face ); af_cjk_metrics_init_blues( metrics, face ); af_cjk_metrics_check_digits( metrics, face ); } FT_Set_Charmap( face, oldmap ); return FT_Err_Ok; } static void af_cjk_metrics_scale_dim( AF_CJKMetrics metrics, AF_Scaler scaler, AF_Dimension dim ) { FT_Fixed scale; FT_Pos delta; AF_CJKAxis axis; FT_UInt nn; if ( dim == AF_DIMENSION_HORZ ) { scale = scaler->x_scale; delta = scaler->x_delta; } else { scale = scaler->y_scale; delta = scaler->y_delta; } axis = &metrics->axis[dim]; if ( axis->org_scale == scale && axis->org_delta == delta ) return; axis->org_scale = scale; axis->org_delta = delta; axis->scale = scale; axis->delta = delta; /* scale the blue zones */ for ( nn = 0; nn < axis->blue_count; nn++ ) { AF_CJKBlue blue = &axis->blues[nn]; FT_Pos dist; blue->ref.cur = FT_MulFix( blue->ref.org, scale ) + delta; blue->ref.fit = blue->ref.cur; blue->shoot.cur = FT_MulFix( blue->shoot.org, scale ) + delta; blue->shoot.fit = blue->shoot.cur; blue->flags &= ~AF_CJK_BLUE_ACTIVE; /* a blue zone is only active if it is less than 3/4 pixels tall */ dist = FT_MulFix( blue->ref.org - blue->shoot.org, scale ); if ( dist <= 48 && dist >= -48 ) { FT_Pos delta1, delta2; blue->ref.fit = FT_PIX_ROUND( blue->ref.cur ); /* shoot is under shoot for cjk */ delta1 = FT_DivFix( blue->ref.fit, scale ) - blue->shoot.org; delta2 = delta1; if ( delta1 < 0 ) delta2 = -delta2; delta2 = FT_MulFix( delta2, scale ); FT_TRACE5(( "delta: %d", delta1 )); if ( delta2 < 32 ) delta2 = 0; #if 0 else if ( delta2 < 64 ) delta2 = 32 + ( ( ( delta2 - 32 ) + 16 ) & ~31 ); #endif else delta2 = FT_PIX_ROUND( delta2 ); FT_TRACE5(( "/%d\n", delta2 )); if ( delta1 < 0 ) delta2 = -delta2; blue->shoot.fit = blue->ref.fit - delta2; FT_TRACE5(( ">> active cjk blue zone %c%d[%ld/%ld]:\n" " ref: cur=%.2f fit=%.2f\n" " shoot: cur=%.2f fit=%.2f\n", ( dim == AF_DIMENSION_HORZ ) ? 'H' : 'V', nn, blue->ref.org, blue->shoot.org, blue->ref.cur / 64.0, blue->ref.fit / 64.0, blue->shoot.cur / 64.0, blue->shoot.fit / 64.0 )); blue->flags |= AF_CJK_BLUE_ACTIVE; } } } /* Scale global values in both directions. */ FT_LOCAL_DEF( void ) af_cjk_metrics_scale( AF_CJKMetrics metrics, AF_Scaler scaler ) { /* we copy the whole structure since the x and y scaling values */ /* are not modified, contrary to e.g. the `latin' auto-hinter */ metrics->root.scaler = *scaler; af_cjk_metrics_scale_dim( metrics, scaler, AF_DIMENSION_HORZ ); af_cjk_metrics_scale_dim( metrics, scaler, AF_DIMENSION_VERT ); } static FT_Error af_cjk_hints_compute_segments( AF_GlyphHints hints, AF_Dimension dim ) { AF_AxisHints axis = &hints->axis[dim]; AF_Segment segments = axis->segments; AF_Segment segment_limit = segments + axis->num_segments; FT_Error error; AF_Segment seg; error = af_latin_hints_compute_segments( hints, dim ); if ( error ) return error; /* a segment is round if it doesn't have successive */ /* on-curve points. */ for ( seg = segments; seg < segment_limit; seg++ ) { AF_Point pt = seg->first; AF_Point last = seg->last; AF_Flags f0 = (AF_Flags)( pt->flags & AF_FLAG_CONTROL ); AF_Flags f1; seg->flags &= ~AF_EDGE_ROUND; for ( ; pt != last; f0 = f1 ) { pt = pt->next; f1 = (AF_Flags)( pt->flags & AF_FLAG_CONTROL ); if ( !f0 && !f1 ) break; if ( pt == last ) seg->flags |= AF_EDGE_ROUND; } } return FT_Err_Ok; } static void af_cjk_hints_link_segments( AF_GlyphHints hints, AF_Dimension dim ) { AF_AxisHints axis = &hints->axis[dim]; AF_Segment segments = axis->segments; AF_Segment segment_limit = segments + axis->num_segments; AF_Direction major_dir = axis->major_dir; AF_Segment seg1, seg2; FT_Pos len_threshold; FT_Pos dist_threshold; len_threshold = AF_LATIN_CONSTANT( hints->metrics, 8 ); dist_threshold = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale : hints->y_scale; dist_threshold = FT_DivFix( 64 * 3, dist_threshold ); /* now compare each segment to the others */ for ( seg1 = segments; seg1 < segment_limit; seg1++ ) { /* the fake segments are for metrics hinting only */ if ( seg1->first == seg1->last ) continue; if ( seg1->dir != major_dir ) continue; for ( seg2 = segments; seg2 < segment_limit; seg2++ ) if ( seg2 != seg1 && seg1->dir + seg2->dir == 0 ) { FT_Pos dist = seg2->pos - seg1->pos; if ( dist < 0 ) continue; { FT_Pos min = seg1->min_coord; FT_Pos max = seg1->max_coord; FT_Pos len; if ( min < seg2->min_coord ) min = seg2->min_coord; if ( max > seg2->max_coord ) max = seg2->max_coord; len = max - min; if ( len >= len_threshold ) { if ( dist * 8 < seg1->score * 9 && ( dist * 8 < seg1->score * 7 || seg1->len < len ) ) { seg1->score = dist; seg1->len = len; seg1->link = seg2; } if ( dist * 8 < seg2->score * 9 && ( dist * 8 < seg2->score * 7 || seg2->len < len ) ) { seg2->score = dist; seg2->len = len; seg2->link = seg1; } } } } } /* * now compute the `serif' segments * * In Hanzi, some strokes are wider on one or both of the ends. * We either identify the stems on the ends as serifs or remove * the linkage, depending on the length of the stems. * */ { AF_Segment link1, link2; for ( seg1 = segments; seg1 < segment_limit; seg1++ ) { link1 = seg1->link; if ( !link1 || link1->link != seg1 || link1->pos <= seg1->pos ) continue; if ( seg1->score >= dist_threshold ) continue; for ( seg2 = segments; seg2 < segment_limit; seg2++ ) { if ( seg2->pos > seg1->pos || seg1 == seg2 ) continue; link2 = seg2->link; if ( !link2 || link2->link != seg2 || link2->pos < link1->pos ) continue; if ( seg1->pos == seg2->pos && link1->pos == link2->pos ) continue; if ( seg2->score <= seg1->score || seg1->score * 4 <= seg2->score ) continue; /* seg2 < seg1 < link1 < link2 */ if ( seg1->len >= seg2->len * 3 ) { AF_Segment seg; for ( seg = segments; seg < segment_limit; seg++ ) { AF_Segment link = seg->link; if ( link == seg2 ) { seg->link = 0; seg->serif = link1; } else if ( link == link2 ) { seg->link = 0; seg->serif = seg1; } } } else { seg1->link = link1->link = 0; break; } } } } for ( seg1 = segments; seg1 < segment_limit; seg1++ ) { seg2 = seg1->link; if ( seg2 ) { seg2->num_linked++; if ( seg2->link != seg1 ) { seg1->link = 0; if ( seg2->score < dist_threshold || seg1->score < seg2->score * 4 ) seg1->serif = seg2->link; else seg2->num_linked--; } } } } #define AF_SEGMENT_LEN( seg ) ( (seg)->max_coord - (seg)->min_coord ) #define AF_SEGMENT_DIST( seg1, seg2 ) ( ( (seg1)->pos > (seg2)->pos ) \ ? (seg1)->pos - (seg2)->pos \ : (seg2)->pos - (seg1)->pos ) static FT_Error af_cjk_hints_compute_edges( AF_GlyphHints hints, AF_Dimension dim ) { AF_AxisHints axis = &hints->axis[dim]; FT_Error error = FT_Err_Ok; FT_Memory memory = hints->memory; AF_CJKAxis laxis = &((AF_CJKMetrics)hints->metrics)->axis[dim]; AF_Segment segments = axis->segments; AF_Segment segment_limit = segments + axis->num_segments; AF_Segment seg; FT_Fixed scale; FT_Pos edge_distance_threshold; axis->num_edges = 0; scale = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale : hints->y_scale; /*********************************************************************/ /* */ /* We begin by generating a sorted table of edges for the current */ /* direction. To do so, we simply scan each segment and try to find */ /* an edge in our table that corresponds to its position. */ /* */ /* If no edge is found, we create and insert a new edge in the */ /* sorted table. Otherwise, we simply add the segment to the edge's */ /* list which is then processed in the second step to compute the */ /* edge's properties. */ /* */ /* Note that the edges table is sorted along the segment/edge */ /* position. */ /* */ /*********************************************************************/ edge_distance_threshold = FT_MulFix( laxis->edge_distance_threshold, scale ); if ( edge_distance_threshold > 64 / 4 ) edge_distance_threshold = FT_DivFix( 64 / 4, scale ); else edge_distance_threshold = laxis->edge_distance_threshold; for ( seg = segments; seg < segment_limit; seg++ ) { AF_Edge found = NULL; FT_Pos best = 0xFFFFU; FT_Int ee; /* look for an edge corresponding to the segment */ for ( ee = 0; ee < axis->num_edges; ee++ ) { AF_Edge edge = axis->edges + ee; FT_Pos dist; if ( edge->dir != seg->dir ) continue; dist = seg->pos - edge->fpos; if ( dist < 0 ) dist = -dist; if ( dist < edge_distance_threshold && dist < best ) { AF_Segment link = seg->link; /* check whether all linked segments of the candidate edge */ /* can make a single edge. */ if ( link ) { AF_Segment seg1 = edge->first; FT_Pos dist2 = 0; do { AF_Segment link1 = seg1->link; if ( link1 ) { dist2 = AF_SEGMENT_DIST( link, link1 ); if ( dist2 >= edge_distance_threshold ) break; } } while ( ( seg1 = seg1->edge_next ) != edge->first ); if ( dist2 >= edge_distance_threshold ) continue; } best = dist; found = edge; } } if ( !found ) { AF_Edge edge; /* insert a new edge in the list and */ /* sort according to the position */ error = af_axis_hints_new_edge( axis, seg->pos, (AF_Direction)seg->dir, memory, &edge ); if ( error ) goto Exit; /* add the segment to the new edge's list */ FT_ZERO( edge ); edge->first = seg; edge->last = seg; edge->fpos = seg->pos; edge->opos = edge->pos = FT_MulFix( seg->pos, scale ); seg->edge_next = seg; edge->dir = seg->dir; } else { /* if an edge was found, simply add the segment to the edge's */ /* list */ seg->edge_next = found->first; found->last->edge_next = seg; found->last = seg; } } /******************************************************************/ /* */ /* Good, we now compute each edge's properties according to the */ /* segments found on its position. Basically, these are */ /* */ /* - the edge's main direction */ /* - stem edge, serif edge or both (which defaults to stem then) */ /* - rounded edge, straight or both (which defaults to straight) */ /* - link for edge */ /* */ /******************************************************************/ /* first of all, set the `edge' field in each segment -- this is */ /* required in order to compute edge links */ /* * Note that removing this loop and setting the `edge' field of each * segment directly in the code above slows down execution speed for * some reasons on platforms like the Sun. */ { AF_Edge edges = axis->edges; AF_Edge edge_limit = edges + axis->num_edges; AF_Edge edge; for ( edge = edges; edge < edge_limit; edge++ ) { seg = edge->first; if ( seg ) do { seg->edge = edge; seg = seg->edge_next; } while ( seg != edge->first ); } /* now compute each edge properties */ for ( edge = edges; edge < edge_limit; edge++ ) { FT_Int is_round = 0; /* does it contain round segments? */ FT_Int is_straight = 0; /* does it contain straight segments? */ seg = edge->first; do { FT_Bool is_serif; /* check for roundness of segment */ if ( seg->flags & AF_EDGE_ROUND ) is_round++; else is_straight++; /* check for links -- if seg->serif is set, then seg->link must */ /* be ignored */ is_serif = (FT_Bool)( seg->serif && seg->serif->edge != edge ); if ( seg->link || is_serif ) { AF_Edge edge2; AF_Segment seg2; edge2 = edge->link; seg2 = seg->link; if ( is_serif ) { seg2 = seg->serif; edge2 = edge->serif; } if ( edge2 ) { FT_Pos edge_delta; FT_Pos seg_delta; edge_delta = edge->fpos - edge2->fpos; if ( edge_delta < 0 ) edge_delta = -edge_delta; seg_delta = AF_SEGMENT_DIST( seg, seg2 ); if ( seg_delta < edge_delta ) edge2 = seg2->edge; } else edge2 = seg2->edge; if ( is_serif ) { edge->serif = edge2; edge2->flags |= AF_EDGE_SERIF; } else edge->link = edge2; } seg = seg->edge_next; } while ( seg != edge->first ); /* set the round/straight flags */ edge->flags = AF_EDGE_NORMAL; if ( is_round > 0 && is_round >= is_straight ) edge->flags |= AF_EDGE_ROUND; /* get rid of serifs if link is set */ /* XXX: This gets rid of many unpleasant artefacts! */ /* Example: the `c' in cour.pfa at size 13 */ if ( edge->serif && edge->link ) edge->serif = 0; } } Exit: return error; } static FT_Error af_cjk_hints_detect_features( AF_GlyphHints hints, AF_Dimension dim ) { FT_Error error; error = af_cjk_hints_compute_segments( hints, dim ); if ( !error ) { af_cjk_hints_link_segments( hints, dim ); error = af_cjk_hints_compute_edges( hints, dim ); } return error; } /* Compute all edges which lie within blue zones. */ FT_LOCAL_DEF( void ) af_cjk_hints_compute_blue_edges( AF_GlyphHints hints, AF_CJKMetrics metrics, AF_Dimension dim ) { AF_AxisHints axis = &hints->axis[dim]; AF_Edge edge = axis->edges; AF_Edge edge_limit = edge + axis->num_edges; AF_CJKAxis cjk = &metrics->axis[dim]; FT_Fixed scale = cjk->scale; FT_Pos best_dist0; /* initial threshold */ /* compute the initial threshold as a fraction of the EM size */ best_dist0 = FT_MulFix( metrics->units_per_em / 40, scale ); if ( best_dist0 > 64 / 2 ) /* maximum 1/2 pixel */ best_dist0 = 64 / 2; /* compute which blue zones are active, i.e. have their scaled */ /* size < 3/4 pixels */ /* If the distant between an edge and a blue zone is shorter than */ /* best_dist0, set the blue zone for the edge. Then search for */ /* the blue zone with the smallest best_dist to the edge. */ for ( ; edge < edge_limit; edge++ ) { FT_UInt bb; AF_Width best_blue = NULL; FT_Pos best_dist = best_dist0; for ( bb = 0; bb < cjk->blue_count; bb++ ) { AF_CJKBlue blue = cjk->blues + bb; FT_Bool is_top_right_blue, is_major_dir; /* skip inactive blue zones (i.e., those that are too small) */ if ( !( blue->flags & AF_CJK_BLUE_ACTIVE ) ) continue; /* if it is a top zone, check for right edges -- if it is a bottom */ /* zone, check for left edges */ /* */ /* of course, that's for TrueType */ is_top_right_blue = FT_BOOL( blue->flags & AF_CJK_BLUE_TOP ); is_major_dir = FT_BOOL( edge->dir == axis->major_dir ); /* if it is a top zone, the edge must be against the major */ /* direction; if it is a bottom zone, it must be in the major */ /* direction */ if ( is_top_right_blue ^ is_major_dir ) { FT_Pos dist; AF_Width compare; /* Compare the edge to the closest blue zone type */ if ( FT_ABS( edge->fpos - blue->ref.org ) > FT_ABS( edge->fpos - blue->shoot.org ) ) compare = &blue->shoot; else compare = &blue->ref; dist = edge->fpos - compare->org; if ( dist < 0 ) dist = -dist; dist = FT_MulFix( dist, scale ); if ( dist < best_dist ) { best_dist = dist; best_blue = compare; } } } if ( best_blue ) edge->blue_edge = best_blue; } } FT_LOCAL_DEF( FT_Error ) af_cjk_hints_init( AF_GlyphHints hints, AF_CJKMetrics metrics ) { FT_Render_Mode mode; FT_UInt32 scaler_flags, other_flags; af_glyph_hints_rescale( hints, (AF_StyleMetrics)metrics ); /* * correct x_scale and y_scale when needed, since they may have * been modified af_cjk_scale_dim above */ hints->x_scale = metrics->axis[AF_DIMENSION_HORZ].scale; hints->x_delta = metrics->axis[AF_DIMENSION_HORZ].delta; hints->y_scale = metrics->axis[AF_DIMENSION_VERT].scale; hints->y_delta = metrics->axis[AF_DIMENSION_VERT].delta; /* compute flags depending on render mode, etc. */ mode = metrics->root.scaler.render_mode; #ifdef AF_CONFIG_OPTION_USE_WARPER if ( mode == FT_RENDER_MODE_LCD || mode == FT_RENDER_MODE_LCD_V ) metrics->root.scaler.render_mode = mode = FT_RENDER_MODE_NORMAL; #endif scaler_flags = hints->scaler_flags; other_flags = 0; /* * We snap the width of vertical stems for the monochrome and * horizontal LCD rendering targets only. */ if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD ) other_flags |= AF_LATIN_HINTS_HORZ_SNAP; /* * We snap the width of horizontal stems for the monochrome and * vertical LCD rendering targets only. */ if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD_V ) other_flags |= AF_LATIN_HINTS_VERT_SNAP; /* * We adjust stems to full pixels only if we don't use the `light' mode. */ if ( mode != FT_RENDER_MODE_LIGHT ) other_flags |= AF_LATIN_HINTS_STEM_ADJUST; if ( mode == FT_RENDER_MODE_MONO ) other_flags |= AF_LATIN_HINTS_MONO; scaler_flags |= AF_SCALER_FLAG_NO_ADVANCE; hints->scaler_flags = scaler_flags; hints->other_flags = other_flags; return FT_Err_Ok; } static FT_Pos af_cjk_snap_width( AF_Width widths, FT_Int count, FT_Pos width ) { int n; FT_Pos best = 64 + 32 + 2; FT_Pos reference = width; FT_Pos scaled; for ( n = 0; n < count; n++ ) { FT_Pos w; FT_Pos dist; w = widths[n].cur; dist = width - w; if ( dist < 0 ) dist = -dist; if ( dist < best ) { best = dist; reference = w; } } scaled = FT_PIX_ROUND( reference ); if ( width >= reference ) { if ( width < scaled + 48 ) width = reference; } else { if ( width > scaled - 48 ) width = reference; } return width; } static FT_Pos af_cjk_compute_stem_width( AF_GlyphHints hints, AF_Dimension dim, FT_Pos width, AF_Edge_Flags base_flags, AF_Edge_Flags stem_flags ) { AF_CJKMetrics metrics = (AF_CJKMetrics)hints->metrics; AF_CJKAxis axis = &metrics->axis[dim]; FT_Pos dist = width; FT_Int sign = 0; FT_Bool vertical = FT_BOOL( dim == AF_DIMENSION_VERT ); FT_UNUSED( base_flags ); FT_UNUSED( stem_flags ); if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) ) return width; if ( dist < 0 ) { dist = -width; sign = 1; } if ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) || ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) ) { /* smooth hinting process: very lightly quantize the stem width */ if ( axis->width_count > 0 ) { if ( FT_ABS( dist - axis->widths[0].cur ) < 40 ) { dist = axis->widths[0].cur; if ( dist < 48 ) dist = 48; goto Done_Width; } } if ( dist < 54 ) dist += ( 54 - dist ) / 2 ; else if ( dist < 3 * 64 ) { FT_Pos delta; delta = dist & 63; dist &= -64; if ( delta < 10 ) dist += delta; else if ( delta < 22 ) dist += 10; else if ( delta < 42 ) dist += delta; else if ( delta < 54 ) dist += 54; else dist += delta; } } else { /* strong hinting process: snap the stem width to integer pixels */ dist = af_cjk_snap_width( axis->widths, axis->width_count, dist ); if ( vertical ) { /* in the case of vertical hinting, always round */ /* the stem heights to integer pixels */ if ( dist >= 64 ) dist = ( dist + 16 ) & ~63; else dist = 64; } else { if ( AF_LATIN_HINTS_DO_MONO( hints ) ) { /* monochrome horizontal hinting: snap widths to integer pixels */ /* with a different threshold */ if ( dist < 64 ) dist = 64; else dist = ( dist + 32 ) & ~63; } else { /* for horizontal anti-aliased hinting, we adopt a more subtle */ /* approach: we strengthen small stems, round stems whose size */ /* is between 1 and 2 pixels to an integer, otherwise nothing */ if ( dist < 48 ) dist = ( dist + 64 ) >> 1; else if ( dist < 128 ) dist = ( dist + 22 ) & ~63; else /* round otherwise to prevent color fringes in LCD mode */ dist = ( dist + 32 ) & ~63; } } } Done_Width: if ( sign ) dist = -dist; return dist; } static void af_cjk_align_linked_edge( AF_GlyphHints hints, AF_Dimension dim, AF_Edge base_edge, AF_Edge stem_edge ) { FT_Pos dist = stem_edge->opos - base_edge->opos; FT_Pos fitted_width = af_cjk_compute_stem_width( hints, dim, dist, (AF_Edge_Flags)base_edge->flags, (AF_Edge_Flags)stem_edge->flags ); stem_edge->pos = base_edge->pos + fitted_width; } #define AF_LIGHT_MODE_MAX_HORZ_GAP 9 #define AF_LIGHT_MODE_MAX_VERT_GAP 15 #define AF_LIGHT_MODE_MAX_DELTA_ABS 14 static FT_Pos af_hint_normal_stem( AF_GlyphHints hints, AF_Edge edge, AF_Edge edge2, FT_Pos anchor, AF_Dimension dim ) { FT_Pos org_len, cur_len, org_center; FT_Pos cur_pos1, cur_pos2; FT_Pos d_off1, u_off1, d_off2, u_off2, delta; FT_Pos offset; FT_Pos threshold = 64; if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) ) { if ( ( edge->flags & AF_EDGE_ROUND ) && ( edge2->flags & AF_EDGE_ROUND ) ) { if ( dim == AF_DIMENSION_VERT ) threshold = 64 - AF_LIGHT_MODE_MAX_HORZ_GAP; else threshold = 64 - AF_LIGHT_MODE_MAX_VERT_GAP; } else { if ( dim == AF_DIMENSION_VERT ) threshold = 64 - AF_LIGHT_MODE_MAX_HORZ_GAP / 3; else threshold = 64 - AF_LIGHT_MODE_MAX_VERT_GAP / 3; } } org_len = edge2->opos - edge->opos; cur_len = af_cjk_compute_stem_width( hints, dim, org_len, (AF_Edge_Flags)edge->flags, (AF_Edge_Flags)edge2->flags ); org_center = ( edge->opos + edge2->opos ) / 2 + anchor; cur_pos1 = org_center - cur_len / 2; cur_pos2 = cur_pos1 + cur_len; d_off1 = cur_pos1 - FT_PIX_FLOOR( cur_pos1 ); d_off2 = cur_pos2 - FT_PIX_FLOOR( cur_pos2 ); u_off1 = 64 - d_off1; u_off2 = 64 - d_off2; delta = 0; if ( d_off1 == 0 || d_off2 == 0 ) goto Exit; if ( cur_len <= threshold ) { if ( d_off2 < cur_len ) { if ( u_off1 <= d_off2 ) delta = u_off1; else delta = -d_off2; } goto Exit; } if ( threshold < 64 ) { if ( d_off1 >= threshold || u_off1 >= threshold || d_off2 >= threshold || u_off2 >= threshold ) goto Exit; } offset = cur_len & 63; if ( offset < 32 ) { if ( u_off1 <= offset || d_off2 <= offset ) goto Exit; } else offset = 64 - threshold; d_off1 = threshold - u_off1; u_off1 = u_off1 - offset; u_off2 = threshold - d_off2; d_off2 = d_off2 - offset; if ( d_off1 <= u_off1 ) u_off1 = -d_off1; if ( d_off2 <= u_off2 ) u_off2 = -d_off2; if ( FT_ABS( u_off1 ) <= FT_ABS( u_off2 ) ) delta = u_off1; else delta = u_off2; Exit: #if 1 if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) ) { if ( delta > AF_LIGHT_MODE_MAX_DELTA_ABS ) delta = AF_LIGHT_MODE_MAX_DELTA_ABS; else if ( delta < -AF_LIGHT_MODE_MAX_DELTA_ABS ) delta = -AF_LIGHT_MODE_MAX_DELTA_ABS; } #endif cur_pos1 += delta; if ( edge->opos < edge2->opos ) { edge->pos = cur_pos1; edge2->pos = cur_pos1 + cur_len; } else { edge->pos = cur_pos1 + cur_len; edge2->pos = cur_pos1; } return delta; } static void af_cjk_align_serif_edge( AF_GlyphHints hints, AF_Edge base, AF_Edge serif ) { FT_UNUSED( hints ); serif->pos = base->pos + ( serif->opos - base->opos ); } static void af_cjk_hint_edges( AF_GlyphHints hints, AF_Dimension dim ) { AF_AxisHints axis = &hints->axis[dim]; AF_Edge edges = axis->edges; AF_Edge edge_limit = edges + axis->num_edges; FT_PtrDist n_edges; AF_Edge edge; AF_Edge anchor = 0; FT_Pos delta = 0; FT_Int skipped = 0; FT_Bool has_last_stem = FALSE; FT_Pos last_stem_pos = 0; #ifdef FT_DEBUG_LEVEL_TRACE FT_UInt num_actions = 0; #endif FT_TRACE5(( "cjk %s edge hinting (style `%s')\n", dim == AF_DIMENSION_VERT ? "horizontal" : "vertical", af_style_names[hints->metrics->style_class->style] )); /* we begin by aligning all stems relative to the blue zone */ if ( AF_HINTS_DO_BLUES( hints ) ) { for ( edge = edges; edge < edge_limit; edge++ ) { AF_Width blue; AF_Edge edge1, edge2; if ( edge->flags & AF_EDGE_DONE ) continue; blue = edge->blue_edge; edge1 = NULL; edge2 = edge->link; if ( blue ) { edge1 = edge; } else if ( edge2 && edge2->blue_edge ) { blue = edge2->blue_edge; edge1 = edge2; edge2 = edge; } if ( !edge1 ) continue; #ifdef FT_DEBUG_LEVEL_TRACE FT_TRACE5(( " CJKBLUE: edge %d @%d (opos=%.2f) snapped to %.2f," " was %.2f\n", edge1 - edges, edge1->fpos, edge1->opos / 64.0, blue->fit / 64.0, edge1->pos / 64.0 )); num_actions++; #endif edge1->pos = blue->fit; edge1->flags |= AF_EDGE_DONE; if ( edge2 && !edge2->blue_edge ) { af_cjk_align_linked_edge( hints, dim, edge1, edge2 ); edge2->flags |= AF_EDGE_DONE; #ifdef FT_DEBUG_LEVEL_TRACE num_actions++; #endif } if ( !anchor ) anchor = edge; } } /* now we align all stem edges. */ for ( edge = edges; edge < edge_limit; edge++ ) { AF_Edge edge2; if ( edge->flags & AF_EDGE_DONE ) continue; /* skip all non-stem edges */ edge2 = edge->link; if ( !edge2 ) { skipped++; continue; } /* Some CJK characters have so many stems that * the hinter is likely to merge two adjacent ones. * To solve this problem, if either edge of a stem * is too close to the previous one, we avoid * aligning the two edges, but rather interpolate * their locations at the end of this function in * order to preserve the space between the stems. */ if ( has_last_stem && ( edge->pos < last_stem_pos + 64 || edge2->pos < last_stem_pos + 64 ) ) { skipped++; continue; } /* now align the stem */ /* this should not happen, but it's better to be safe */ if ( edge2->blue_edge ) { FT_TRACE5(( "ASSERTION FAILED for edge %d\n", edge2-edges )); af_cjk_align_linked_edge( hints, dim, edge2, edge ); edge->flags |= AF_EDGE_DONE; #ifdef FT_DEBUG_LEVEL_TRACE num_actions++; #endif continue; } if ( edge2 < edge ) { af_cjk_align_linked_edge( hints, dim, edge2, edge ); edge->flags |= AF_EDGE_DONE; #ifdef FT_DEBUG_LEVEL_TRACE num_actions++; #endif /* We rarely reaches here it seems; * usually the two edges belonging * to one stem are marked as DONE together */ has_last_stem = TRUE; last_stem_pos = edge->pos; continue; } if ( dim != AF_DIMENSION_VERT && !anchor ) { #if 0 if ( fixedpitch ) { AF_Edge left = edge; AF_Edge right = edge_limit - 1; AF_EdgeRec left1, left2, right1, right2; FT_Pos target, center1, center2; FT_Pos delta1, delta2, d1, d2; while ( right > left && !right->link ) right--; left1 = *left; left2 = *left->link; right1 = *right->link; right2 = *right; delta = ( ( ( hinter->pp2.x + 32 ) & -64 ) - hinter->pp2.x ) / 2; target = left->opos + ( right->opos - left->opos ) / 2 + delta - 16; delta1 = delta; delta1 += af_hint_normal_stem( hints, left, left->link, delta1, 0 ); if ( left->link != right ) af_hint_normal_stem( hints, right->link, right, delta1, 0 ); center1 = left->pos + ( right->pos - left->pos ) / 2; if ( center1 >= target ) delta2 = delta - 32; else delta2 = delta + 32; delta2 += af_hint_normal_stem( hints, &left1, &left2, delta2, 0 ); if ( delta1 != delta2 ) { if ( left->link != right ) af_hint_normal_stem( hints, &right1, &right2, delta2, 0 ); center2 = left1.pos + ( right2.pos - left1.pos ) / 2; d1 = center1 - target; d2 = center2 - target; if ( FT_ABS( d2 ) < FT_ABS( d1 ) ) { left->pos = left1.pos; left->link->pos = left2.pos; if ( left->link != right ) { right->link->pos = right1.pos; right->pos = right2.pos; } delta1 = delta2; } } delta = delta1; right->link->flags |= AF_EDGE_DONE; right->flags |= AF_EDGE_DONE; } else #endif /* 0 */ delta = af_hint_normal_stem( hints, edge, edge2, 0, AF_DIMENSION_HORZ ); } else af_hint_normal_stem( hints, edge, edge2, delta, dim ); #if 0 printf( "stem (%d,%d) adjusted (%.1f,%.1f)\n", edge - edges, edge2 - edges, ( edge->pos - edge->opos ) / 64.0, ( edge2->pos - edge2->opos ) / 64.0 ); #endif anchor = edge; edge->flags |= AF_EDGE_DONE; edge2->flags |= AF_EDGE_DONE; has_last_stem = TRUE; last_stem_pos = edge2->pos; } /* make sure that lowercase m's maintain their symmetry */ /* In general, lowercase m's have six vertical edges if they are sans */ /* serif, or twelve if they are with serifs. This implementation is */ /* based on that assumption, and seems to work very well with most */ /* faces. However, if for a certain face this assumption is not */ /* true, the m is just rendered like before. In addition, any stem */ /* correction will only be applied to symmetrical glyphs (even if the */ /* glyph is not an m), so the potential for unwanted distortion is */ /* relatively low. */ /* We don't handle horizontal edges since we can't easily assure that */ /* the third (lowest) stem aligns with the base line; it might end up */ /* one pixel higher or lower. */ n_edges = edge_limit - edges; if ( dim == AF_DIMENSION_HORZ && ( n_edges == 6 || n_edges == 12 ) ) { AF_Edge edge1, edge2, edge3; FT_Pos dist1, dist2, span; if ( n_edges == 6 ) { edge1 = edges; edge2 = edges + 2; edge3 = edges + 4; } else { edge1 = edges + 1; edge2 = edges + 5; edge3 = edges + 9; } dist1 = edge2->opos - edge1->opos; dist2 = edge3->opos - edge2->opos; span = dist1 - dist2; if ( span < 0 ) span = -span; if ( edge1->link == edge1 + 1 && edge2->link == edge2 + 1 && edge3->link == edge3 + 1 && span < 8 ) { delta = edge3->pos - ( 2 * edge2->pos - edge1->pos ); edge3->pos -= delta; if ( edge3->link ) edge3->link->pos -= delta; /* move the serifs along with the stem */ if ( n_edges == 12 ) { ( edges + 8 )->pos -= delta; ( edges + 11 )->pos -= delta; } edge3->flags |= AF_EDGE_DONE; if ( edge3->link ) edge3->link->flags |= AF_EDGE_DONE; } } if ( !skipped ) goto Exit; /* * now hint the remaining edges (serifs and single) in order * to complete our processing */ for ( edge = edges; edge < edge_limit; edge++ ) { if ( edge->flags & AF_EDGE_DONE ) continue; if ( edge->serif ) { af_cjk_align_serif_edge( hints, edge->serif, edge ); edge->flags |= AF_EDGE_DONE; skipped--; } } if ( !skipped ) goto Exit; for ( edge = edges; edge < edge_limit; edge++ ) { AF_Edge before, after; if ( edge->flags & AF_EDGE_DONE ) continue; before = after = edge; while ( --before >= edges ) if ( before->flags & AF_EDGE_DONE ) break; while ( ++after < edge_limit ) if ( after->flags & AF_EDGE_DONE ) break; if ( before >= edges || after < edge_limit ) { if ( before < edges ) af_cjk_align_serif_edge( hints, after, edge ); else if ( after >= edge_limit ) af_cjk_align_serif_edge( hints, before, edge ); else { if ( after->fpos == before->fpos ) edge->pos = before->pos; else edge->pos = before->pos + FT_MulDiv( edge->fpos - before->fpos, after->pos - before->pos, after->fpos - before->fpos ); } } } Exit: #ifdef FT_DEBUG_LEVEL_TRACE if ( !num_actions ) FT_TRACE5(( " (none)\n" )); FT_TRACE5(( "\n" )); #endif return; } static void af_cjk_align_edge_points( AF_GlyphHints hints, AF_Dimension dim ) { AF_AxisHints axis = & hints->axis[dim]; AF_Edge edges = axis->edges; AF_Edge edge_limit = edges + axis->num_edges; AF_Edge edge; FT_Bool snapping; snapping = FT_BOOL( ( dim == AF_DIMENSION_HORZ && AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) || ( dim == AF_DIMENSION_VERT && AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) ); for ( edge = edges; edge < edge_limit; edge++ ) { /* move the points of each segment */ /* in each edge to the edge's position */ AF_Segment seg = edge->first; if ( snapping ) { do { AF_Point point = seg->first; for (;;) { if ( dim == AF_DIMENSION_HORZ ) { point->x = edge->pos; point->flags |= AF_FLAG_TOUCH_X; } else { point->y = edge->pos; point->flags |= AF_FLAG_TOUCH_Y; } if ( point == seg->last ) break; point = point->next; } seg = seg->edge_next; } while ( seg != edge->first ); } else { FT_Pos delta = edge->pos - edge->opos; do { AF_Point point = seg->first; for (;;) { if ( dim == AF_DIMENSION_HORZ ) { point->x += delta; point->flags |= AF_FLAG_TOUCH_X; } else { point->y += delta; point->flags |= AF_FLAG_TOUCH_Y; } if ( point == seg->last ) break; point = point->next; } seg = seg->edge_next; } while ( seg != edge->first ); } } } FT_LOCAL_DEF( FT_Error ) af_cjk_hints_apply( AF_GlyphHints hints, FT_Outline* outline, AF_CJKMetrics metrics ) { FT_Error error; int dim; FT_UNUSED( metrics ); error = af_glyph_hints_reload( hints, outline ); if ( error ) goto Exit; /* analyze glyph outline */ if ( AF_HINTS_DO_HORIZONTAL( hints ) ) { error = af_cjk_hints_detect_features( hints, AF_DIMENSION_HORZ ); if ( error ) goto Exit; af_cjk_hints_compute_blue_edges( hints, metrics, AF_DIMENSION_HORZ ); } if ( AF_HINTS_DO_VERTICAL( hints ) ) { error = af_cjk_hints_detect_features( hints, AF_DIMENSION_VERT ); if ( error ) goto Exit; af_cjk_hints_compute_blue_edges( hints, metrics, AF_DIMENSION_VERT ); } /* grid-fit the outline */ for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) { if ( ( dim == AF_DIMENSION_HORZ && AF_HINTS_DO_HORIZONTAL( hints ) ) || ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_VERTICAL( hints ) ) ) { #ifdef AF_CONFIG_OPTION_USE_WARPER if ( dim == AF_DIMENSION_HORZ && metrics->root.scaler.render_mode == FT_RENDER_MODE_NORMAL ) { AF_WarperRec warper; FT_Fixed scale; FT_Pos delta; af_warper_compute( &warper, hints, (AF_Dimension)dim, &scale, &delta ); af_glyph_hints_scale_dim( hints, (AF_Dimension)dim, scale, delta ); continue; } #endif /* AF_CONFIG_OPTION_USE_WARPER */ af_cjk_hint_edges( hints, (AF_Dimension)dim ); af_cjk_align_edge_points( hints, (AF_Dimension)dim ); af_glyph_hints_align_strong_points( hints, (AF_Dimension)dim ); af_glyph_hints_align_weak_points( hints, (AF_Dimension)dim ); } } #if 0 af_glyph_hints_dump_points( hints ); af_glyph_hints_dump_segments( hints ); af_glyph_hints_dump_edges( hints ); #endif af_glyph_hints_save( hints, outline ); Exit: return error; } AF_DEFINE_WRITING_SYSTEM_CLASS( af_cjk_writing_system_class, AF_WRITING_SYSTEM_CJK, sizeof ( AF_CJKMetricsRec ), (AF_WritingSystem_InitMetricsFunc) af_cjk_metrics_init, (AF_WritingSystem_ScaleMetricsFunc)af_cjk_metrics_scale, (AF_WritingSystem_DoneMetricsFunc) NULL, (AF_WritingSystem_InitHintsFunc) af_cjk_hints_init, (AF_WritingSystem_ApplyHintsFunc) af_cjk_hints_apply ) // ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ static FT_Error af_indic_metrics_init( AF_CJKMetrics metrics, FT_Face face ) { /* skip blue zone init in CJK routines */ FT_CharMap oldmap = face->charmap; metrics->units_per_em = face->units_per_EM; if ( FT_Select_Charmap( face, FT_ENCODING_UNICODE ) ) face->charmap = NULL; else { af_cjk_metrics_init_widths( metrics, face ); #if 0 /* either need indic specific blue_chars[] or just skip blue zones */ af_cjk_metrics_init_blues( metrics, face, af_cjk_blue_chars ); #endif af_cjk_metrics_check_digits( metrics, face ); } FT_Set_Charmap( face, oldmap ); return FT_Err_Ok; } static void af_indic_metrics_scale( AF_CJKMetrics metrics, AF_Scaler scaler ) { /* use CJK routines */ af_cjk_metrics_scale( metrics, scaler ); } static FT_Error af_indic_hints_init( AF_GlyphHints hints, AF_CJKMetrics metrics ) { /* use CJK routines */ return af_cjk_hints_init( hints, metrics ); } static FT_Error af_indic_hints_apply( AF_GlyphHints hints, FT_Outline* outline, AF_CJKMetrics metrics ) { /* use CJK routines */ return af_cjk_hints_apply( hints, outline, metrics ); } AF_DEFINE_WRITING_SYSTEM_CLASS( af_indic_writing_system_class, AF_WRITING_SYSTEM_INDIC, sizeof ( AF_CJKMetricsRec ), (AF_WritingSystem_InitMetricsFunc) af_indic_metrics_init, (AF_WritingSystem_ScaleMetricsFunc)af_indic_metrics_scale, (AF_WritingSystem_DoneMetricsFunc) NULL, (AF_WritingSystem_InitHintsFunc) af_indic_hints_init, (AF_WritingSystem_ApplyHintsFunc) af_indic_hints_apply )