diff --git a/ChangeLog b/ChangeLog index 478ccc3af..5ce1534db 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,48 @@ +2007-10-15 George Williams + + Add support for cmap type 14. + + * devel/ftoption.h, include/freetype/config/ftoption.h + (TT_CONFIG_CMAP_FORMAT_14): New macro. + + * include/freetype/internal/ftobjs.h (FT_CMap_CharVarIndexFunc, + FT_CMap_CharVarIsDefaultFunc, FT_CMap_VariantListFunc, + FT_CMap_CharVariantListFunc, FT_CMap_VariantCharListFunc): New + support function prototypes. + (FT_CMap_ClassRec): Add them. + Update all users. + + * include/freetype/ttnameid.h (TT_APPLE_ID_VARIANT_SELECTOR): New + macro. + + * include/freetype/freetype.h (FT_Get_Char_Variant_Index, + FT_Get_Char_Variant_IsDefault, FT_Get_Variant_Selectors, + FT_Get_Variants_Of_Char, FT_Get_Chars_Of_Variant): New API + functions. + + * src/base/ftobjs.c (find_variant_selector_charmap): New auxiliary + function. + (FT_Set_Charmap): Disallow cmaps of type 14. + (FT_Get_Char_Variant_Index, FT_Get_Char_Variant_IsDefault, + FT_Get_Variant_Selectors, FT_Get_Variants_Of_Char, + FT_Get_Chars_Of_Variant): New API functions. + + * src/sfnt/ttcmap.c (TT_PEEK_UINT24, TT_NEXT_UINT24): New macros. + + (TT_CMap14Rec, tt_cmap14_init, tt_cmap14_validate, + tt_cmap14_char_index, tt_cmap14_char_next, tt_cmap14_get_info, + tt_cmap14_char_map_def_binary, tt_cmap14_char_map_nondef_binary, + tt_cmap14_find_variant, tt_cmap14_char_var_index, + tt_cmap14_char_var_isdefault, tt_cmap14_variants, + tt_cmap14_char_variants, tt_cmap14_def_char_count, + tt_cmap14_get_def_chars, tt_cmap14_get_nondef_chars, + tt_cmap14_variant_chars, tt_cmap14_class_rec): New functions and + structures for cmap 14 support. + (tt_cmap_classes): Register tt_cmap14_class_rec. + (tt_face_build_cmaps): One more error message. + + * docs/CHANGES: Mention cmap 14 support. + 2007-10-01 Werner Lemberg * src/base/ftobjs.c (find_unicode_charmap): If search for a UCS-4 @@ -6,10 +51,10 @@ 2007-08-29 suzuki toshiya - * src/base/ftmac.c: Introduction of abstract "short" data types, - ResFileRefNum and ResID. These types were introduced for Copland, - then backported to MPW. The variables exchanged with FileManager - QuickDraw frameworks are redefined by these data types. Patch was + * src/base/ftmac.c: Introduction of abstract `short' data types, + ResFileRefNum and ResID. These types were introduced for Copland, + then backported to MPW. The variables exchanged with FileManager + QuickDraw frameworks are redefined by these data types. Patch was proposed by Sean McBride. * builds/mac/ftmac.c: Ditto. diff --git a/devel/ftoption.h b/devel/ftoption.h index 6cf1af236..3296421e3 100644 --- a/devel/ftoption.h +++ b/devel/ftoption.h @@ -436,6 +436,7 @@ FT_BEGIN_HEADER #define TT_CONFIG_CMAP_FORMAT_8 #define TT_CONFIG_CMAP_FORMAT_10 #define TT_CONFIG_CMAP_FORMAT_12 +#define TT_CONFIG_CMAP_FORMAT_14 /*************************************************************************/ diff --git a/docs/CHANGES b/docs/CHANGES index 7b98d5841..2c430cf78 100644 --- a/docs/CHANGES +++ b/docs/CHANGES @@ -1,6 +1,16 @@ CHANGES BETWEEN 2.3.6 and 2.3.5 + I. IMPORTANT BUG FIXES + + - Microsoft Unicode cmaps in TrueType fonts are now always + preferred over Apple cmaps. This is not a bug per se, but there + exist some buggy fonts created for MS which have broken Apple + cmaps. This affects only the automatic selection of FreeType; + it's always possible to manually select an Apple Unicode cmap if + desired. + + II. IMPORTANT CHANGES - The new function `FT_Get_CID_Registry_Ordering_Supplement' gives @@ -11,6 +21,9 @@ CHANGES BETWEEN 2.3.6 and 2.3.5 OpenType table (within the `otvalid' module). The `ftvalid' demo program has been extended accordingly. + - An API for cmap 14 support (for Unicode Variant Selectors, UVS) + has been contributed by George Williams. + ====================================================================== diff --git a/include/freetype/config/ftoption.h b/include/freetype/config/ftoption.h index 532848da7..242ec1115 100644 --- a/include/freetype/config/ftoption.h +++ b/include/freetype/config/ftoption.h @@ -436,6 +436,7 @@ FT_BEGIN_HEADER #define TT_CONFIG_CMAP_FORMAT_8 #define TT_CONFIG_CMAP_FORMAT_10 #define TT_CONFIG_CMAP_FORMAT_12 +#define TT_CONFIG_CMAP_FORMAT_14 /*************************************************************************/ diff --git a/include/freetype/freetype.h b/include/freetype/freetype.h index 53d3c0423..c4a183f26 100644 --- a/include/freetype/freetype.h +++ b/include/freetype/freetype.h @@ -2852,6 +2852,8 @@ FT_BEGIN_HEADER /* the face (i.e., if it is not listed in the `face->charmaps' */ /* table). */ /* */ + /* It also fails if a type 14 charmap is selected. */ + /* */ FT_EXPORT( FT_Error ) FT_Set_Charmap( FT_Face face, FT_CharMap charmap ); @@ -2990,6 +2992,162 @@ FT_BEGIN_HEADER FT_UInt *agindex ); + /*************************************************************************/ + /* */ + /* */ + /* FT_Get_Char_Variant_Index */ + /* */ + /* */ + /* Return the glyph index of a given character code as modified by */ + /* the variation selector. */ + /* */ + /* */ + /* face :: */ + /* A handle to the source face object. */ + /* */ + /* charcode :: */ + /* The character code point in Unicode. */ + /* */ + /* variantSelector :: */ + /* The Unicode code point of the variation selector. */ + /* */ + /* */ + /* The glyph index. 0 means either `undefined character code', or */ + /* `undefined selector code', or `no variation selector cmap */ + /* subtable', or `current CharMap is not Unicode'. */ + /* */ + /* */ + /* If you use FreeType to manipulate the contents of font files */ + /* directly, be aware that the glyph index returned by this function */ + /* doesn't always correspond to the internal indices used within */ + /* the file. This is done to ensure that value 0 always corresponds */ + /* to the `missing glyph'. */ + /* */ + /* */ + /* This function is only meaningful if: */ + /* a) the font has a variation selector cmap sub table */ + /* b) the current charmap has a Unicode encoding */ + /* */ + FT_EXPORT( FT_UInt ) + FT_Get_Char_Variant_Index( FT_Face face, + FT_ULong charcode, + FT_ULong variantSelector ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Get_Char_Variant_IsDefault */ + /* */ + /* */ + /* Check whether this variant of this Unicode character is the one to */ + /* be found in the `cmap'. */ + /* */ + /* */ + /* face :: */ + /* A handle to the source face object. */ + /* */ + /* charcode :: */ + /* The character codepoint in Unicode. */ + /* */ + /* variantSelector :: */ + /* The Unicode codepoint of the variation selector. */ + /* */ + /* */ + /* 1 if found in the standard (Unicode) cmap, 0 if found in the */ + /* variation selector cmap, or -1 if it is not a variant. */ + /* */ + /* */ + /* This function is only meaningful if the font has a variation */ + /* selector cmap subtable. */ + /* */ + FT_EXPORT( FT_Int ) + FT_Get_Char_Variant_IsDefault( FT_Face face, + FT_ULong charcode, + FT_ULong variantSelector ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Get_Variant_Selectors */ + /* */ + /* */ + /* Return a zero-terminated list of Unicode variant selectors found */ + /* in the font. */ + /* */ + /* */ + /* face :: A handle to the source face object. */ + /* */ + /* */ + /* A list of all the variant selector code points in the cmap */ + /* or NULL if there is no valid variant selector cmap subtable. */ + /* */ + /* */ + /* User is responsible for deallocating the returned list. */ + /* */ + FT_EXPORT( FT_UInt32* ) + FT_Get_Variant_Selectors( FT_Face face ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Get_Variants_Of_Char */ + /* */ + /* */ + /* Return a zero-terminated list of Unicode variant selectors found */ + /* for the specified character code. */ + /* */ + /* */ + /* face :: */ + /* A handle to the source face object. */ + /* */ + /* charcode :: */ + /* The character codepoint in Unicode. */ + /* */ + /* */ + /* A list of all the variant selector code points which are active */ + /* for the given character or NULL if there is no valid variant */ + /* selector cmap subtable (or if if this character has no variants). */ + /* */ + /* */ + /* User is responsible for deallocating the returned list. */ + /* */ + FT_EXPORT( FT_UInt32* ) + FT_Get_Variants_Of_Char( FT_Face face, + FT_ULong charcode ); + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Get_Chars_Of_Variant */ + /* */ + /* */ + /* Return a zero-terminated list of Unicode character codes found for */ + /* the specified variant selector. */ + /* */ + /* */ + /* face :: */ + /* A handle to the source face object. */ + /* */ + /* variantSelector :: */ + /* The variant selector code point in Unicode. */ + /* */ + /* */ + /* A list of all the code points which are specified by this selector */ + /* (both default and non-default codes are returned) or NULL if there */ + /* is no valid cmap or the variant selector is invalid. */ + /* */ + /* */ + /* User is responsible for deallocating the returned list. */ + /* */ + FT_EXPORT( FT_UInt32* ) + FT_Get_Chars_Of_Variant( FT_Face face, + FT_ULong variantSelector ); + + /*************************************************************************/ /* */ /* */ diff --git a/include/freetype/internal/ftobjs.h b/include/freetype/internal/ftobjs.h index 15b68d63f..3e604e540 100644 --- a/include/freetype/internal/ftobjs.h +++ b/include/freetype/internal/ftobjs.h @@ -160,6 +160,31 @@ FT_BEGIN_HEADER (*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_ { @@ -169,6 +194,15 @@ FT_BEGIN_HEADER 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; diff --git a/include/freetype/ttnameid.h b/include/freetype/ttnameid.h index b9acbdad1..7ee865596 100644 --- a/include/freetype/ttnameid.h +++ b/include/freetype/ttnameid.h @@ -108,13 +108,18 @@ FT_BEGIN_HEADER * * TT_APPLE_ID_UNICODE_32 :: * Unicode 3.1 and beyond, using UTF-32. + * + * TT_APPLE_ID_VARIANT_SELECTOR :: + * From Adobe, not Apple. Not a normal cmap. Specifies variations + * on a real cmap. */ -#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_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 */ /*********************************************************************** diff --git a/src/base/ftobjs.c b/src/base/ftobjs.c index 804ba549a..755270fac 100644 --- a/src/base/ftobjs.c +++ b/src/base/ftobjs.c @@ -964,6 +964,45 @@ } + /*************************************************************************/ + /* */ + /* */ + /* find_variant_selector_charmap */ + /* */ + /* */ + /* This function finds the variant selector charmap, if there is one. */ + /* There can only be one (platform=0, specific=5, format=14). */ + /* */ + static FT_CharMap + find_variant_selector_charmap( FT_Face face ) + { + FT_CharMap* first; + FT_CharMap* end; + FT_CharMap* cur; + + + /* caller should have already checked that `face' is valid */ + FT_ASSERT( face ); + + first = face->charmaps; + + if ( !first ) + return NULL; + + end = first + face->num_charmaps; /* points after the last one */ + + for ( cur = first; cur < end; ++cur ) + { + if ( cur[0]->platform_id == TT_PLATFORM_APPLE_UNICODE && + cur[0]->encoding_id == TT_APPLE_ID_VARIANT_SELECTOR && + FT_Get_CMap_Format( cur[0] ) == 14 ) + return cur[0]; + } + + return NULL; + } + + /*************************************************************************/ /* */ /* */ @@ -2631,6 +2670,8 @@ cur = face->charmaps; if ( !cur ) return FT_Err_Invalid_CharMap_Handle; + if ( FT_Get_CMap_Format( charmap ) == 14 ) + return FT_Err_Invalid_Argument; limit = cur + face->num_charmaps; @@ -2849,6 +2890,149 @@ } + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_UInt ) + FT_Get_Char_Variant_Index( 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 ); + + + result = vcmap->clazz->char_var_index( vcmap, ucmap, charcode, + variantSelector ); + } + } + + return result; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Int ) + FT_Get_Char_Variant_IsDefault( 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 ); + + + result = vcmap->clazz->char_var_default( vcmap, charcode, + variantSelector ); + } + } + + return result; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_UInt32* ) + FT_Get_Variant_Selectors( FT_Face face ) + { + FT_UInt32 *result = NULL; + + + if ( face ) + { + FT_CharMap charmap = find_variant_selector_charmap( face ); + + + if ( charmap != NULL ) + { + FT_CMap vcmap = FT_CMAP( charmap ); + FT_Memory memory = FT_FACE_MEMORY( face ); + + + result = vcmap->clazz->variant_list( vcmap, memory ); + } + } + + return result; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_UInt32* ) + FT_Get_Variants_Of_Char( 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 ); + + + result = vcmap->clazz->charvariant_list( vcmap, memory, charcode ); + } + } + return result; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_UInt32* ) + FT_Get_Chars_Of_Variant( 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 ); + + + result = vcmap->clazz->variantchar_list( vcmap, memory, + variantSelector ); + } + } + + return result; + } + + /* documentation is in freetype.h */ FT_EXPORT_DEF( FT_UInt ) diff --git a/src/bdf/bdfdrivr.c b/src/bdf/bdfdrivr.c index 74cc2f1b8..2a5767e2f 100644 --- a/src/bdf/bdfdrivr.c +++ b/src/bdf/bdfdrivr.c @@ -181,7 +181,9 @@ THE SOFTWARE. bdf_cmap_init, bdf_cmap_done, bdf_cmap_char_index, - bdf_cmap_char_next + bdf_cmap_char_next, + + NULL, NULL, NULL, NULL, NULL }; diff --git a/src/cff/cffcmap.c b/src/cff/cffcmap.c index fffc5fc55..578d048be 100644 --- a/src/cff/cffcmap.c +++ b/src/cff/cffcmap.c @@ -4,7 +4,7 @@ /* */ /* CFF character mapping table (cmap) support (body). */ /* */ -/* Copyright 2002, 2003, 2004, 2005, 2006 by */ +/* Copyright 2002, 2003, 2004, 2005, 2006, 2007 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -107,7 +107,9 @@ (FT_CMap_InitFunc) cff_cmap_encoding_init, (FT_CMap_DoneFunc) cff_cmap_encoding_done, (FT_CMap_CharIndexFunc)cff_cmap_encoding_char_index, - (FT_CMap_CharNextFunc) cff_cmap_encoding_char_next + (FT_CMap_CharNextFunc) cff_cmap_encoding_char_next, + + NULL, NULL, NULL, NULL, NULL }; @@ -213,7 +215,9 @@ (FT_CMap_InitFunc) cff_cmap_unicode_init, (FT_CMap_DoneFunc) cff_cmap_unicode_done, (FT_CMap_CharIndexFunc)cff_cmap_unicode_char_index, - (FT_CMap_CharNextFunc) cff_cmap_unicode_char_next + (FT_CMap_CharNextFunc) cff_cmap_unicode_char_next, + + NULL, NULL, NULL, NULL, NULL }; diff --git a/src/pcf/pcfdrivr.c b/src/pcf/pcfdrivr.c index c0f0e49ca..9cd330d73 100644 --- a/src/pcf/pcfdrivr.c +++ b/src/pcf/pcfdrivr.c @@ -2,7 +2,7 @@ FreeType font driver for pcf files - Copyright (C) 2000, 2001, 2002, 2003, 2004, 2006 by + Copyright (C) 2000, 2001, 2002, 2003, 2004, 2006, 2007 by Francesco Zappa Nardelli Permission is hereby granted, free of charge, to any person obtaining a copy @@ -187,7 +187,9 @@ THE SOFTWARE. pcf_cmap_init, pcf_cmap_done, pcf_cmap_char_index, - pcf_cmap_char_next + pcf_cmap_char_next, + + NULL, NULL, NULL, NULL, NULL }; diff --git a/src/pfr/pfrcmap.c b/src/pfr/pfrcmap.c index fe9eb69a9..d4656d1b5 100644 --- a/src/pfr/pfrcmap.c +++ b/src/pfr/pfrcmap.c @@ -158,7 +158,9 @@ (FT_CMap_InitFunc) pfr_cmap_init, (FT_CMap_DoneFunc) pfr_cmap_done, (FT_CMap_CharIndexFunc)pfr_cmap_char_index, - (FT_CMap_CharNextFunc) pfr_cmap_char_next + (FT_CMap_CharNextFunc) pfr_cmap_char_next, + + NULL, NULL, NULL, NULL, NULL }; diff --git a/src/psaux/t1cmap.c b/src/psaux/t1cmap.c index 293468696..67a23db56 100644 --- a/src/psaux/t1cmap.c +++ b/src/psaux/t1cmap.c @@ -4,7 +4,7 @@ /* */ /* Type 1 character map support (body). */ /* */ -/* Copyright 2002, 2003, 2006 by */ +/* Copyright 2002, 2003, 2006, 2007 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -135,7 +135,9 @@ (FT_CMap_InitFunc) t1_cmap_standard_init, (FT_CMap_DoneFunc) t1_cmap_std_done, (FT_CMap_CharIndexFunc)t1_cmap_std_char_index, - (FT_CMap_CharNextFunc) t1_cmap_std_char_next + (FT_CMap_CharNextFunc) t1_cmap_std_char_next, + + NULL, NULL, NULL, NULL, NULL }; @@ -154,7 +156,9 @@ (FT_CMap_InitFunc) t1_cmap_expert_init, (FT_CMap_DoneFunc) t1_cmap_std_done, (FT_CMap_CharIndexFunc)t1_cmap_std_char_index, - (FT_CMap_CharNextFunc) t1_cmap_std_char_next + (FT_CMap_CharNextFunc) t1_cmap_std_char_next, + + NULL, NULL, NULL, NULL, NULL }; @@ -245,7 +249,9 @@ (FT_CMap_InitFunc) t1_cmap_custom_init, (FT_CMap_DoneFunc) t1_cmap_custom_done, (FT_CMap_CharIndexFunc)t1_cmap_custom_char_index, - (FT_CMap_CharNextFunc) t1_cmap_custom_char_next + (FT_CMap_CharNextFunc) t1_cmap_custom_char_next, + + NULL, NULL, NULL, NULL, NULL }; @@ -326,7 +332,9 @@ (FT_CMap_InitFunc) t1_cmap_unicode_init, (FT_CMap_DoneFunc) t1_cmap_unicode_done, (FT_CMap_CharIndexFunc)t1_cmap_unicode_char_index, - (FT_CMap_CharNextFunc) t1_cmap_unicode_char_next + (FT_CMap_CharNextFunc) t1_cmap_unicode_char_next, + + NULL, NULL, NULL, NULL, NULL }; diff --git a/src/sfnt/ttcmap.c b/src/sfnt/ttcmap.c index 854d567d1..d0105d5fd 100644 --- a/src/sfnt/ttcmap.c +++ b/src/sfnt/ttcmap.c @@ -39,11 +39,13 @@ #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 @@ -171,7 +173,9 @@ (FT_CMap_InitFunc) tt_cmap_init, (FT_CMap_DoneFunc) NULL, (FT_CMap_CharIndexFunc)tt_cmap0_char_index, - (FT_CMap_CharNextFunc) tt_cmap0_char_next + (FT_CMap_CharNextFunc) tt_cmap0_char_next, + + NULL, NULL, NULL, NULL, NULL }, 0, (TT_CMap_ValidateFunc) tt_cmap0_validate, @@ -544,7 +548,9 @@ (FT_CMap_InitFunc) tt_cmap_init, (FT_CMap_DoneFunc) NULL, (FT_CMap_CharIndexFunc)tt_cmap2_char_index, - (FT_CMap_CharNextFunc) tt_cmap2_char_next + (FT_CMap_CharNextFunc) tt_cmap2_char_next, + + NULL, NULL, NULL, NULL, NULL }, 2, (TT_CMap_ValidateFunc) tt_cmap2_validate, @@ -1320,7 +1326,9 @@ (FT_CMap_InitFunc) tt_cmap4_init, (FT_CMap_DoneFunc) NULL, (FT_CMap_CharIndexFunc)tt_cmap4_char_index, - (FT_CMap_CharNextFunc) tt_cmap4_char_next + (FT_CMap_CharNextFunc) tt_cmap4_char_next, + + NULL, NULL, NULL, NULL, NULL }, 4, (TT_CMap_ValidateFunc) tt_cmap4_validate, @@ -1481,7 +1489,9 @@ (FT_CMap_InitFunc) tt_cmap_init, (FT_CMap_DoneFunc) NULL, (FT_CMap_CharIndexFunc)tt_cmap6_char_index, - (FT_CMap_CharNextFunc) tt_cmap6_char_next + (FT_CMap_CharNextFunc) tt_cmap6_char_next, + + NULL, NULL, NULL, NULL, NULL }, 6, (TT_CMap_ValidateFunc) tt_cmap6_validate, @@ -1735,7 +1745,9 @@ (FT_CMap_InitFunc) tt_cmap_init, (FT_CMap_DoneFunc) NULL, (FT_CMap_CharIndexFunc)tt_cmap8_char_index, - (FT_CMap_CharNextFunc) tt_cmap8_char_next + (FT_CMap_CharNextFunc) tt_cmap8_char_next, + + NULL, NULL, NULL, NULL, NULL }, 8, (TT_CMap_ValidateFunc) tt_cmap8_validate, @@ -1884,7 +1896,9 @@ (FT_CMap_InitFunc) tt_cmap_init, (FT_CMap_DoneFunc) NULL, (FT_CMap_CharIndexFunc)tt_cmap10_char_index, - (FT_CMap_CharNextFunc) tt_cmap10_char_next + (FT_CMap_CharNextFunc) tt_cmap10_char_next, + + NULL, NULL, NULL, NULL, NULL }, 10, (TT_CMap_ValidateFunc) tt_cmap10_validate, @@ -2201,17 +2215,712 @@ (FT_CMap_InitFunc) tt_cmap12_init, (FT_CMap_DoneFunc) NULL, (FT_CMap_CharIndexFunc)tt_cmap12_char_index, - (FT_CMap_CharNextFunc) tt_cmap12_char_next + (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 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; + + } TT_CMap14Rec, *TT_CMap14; + + + 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 ); + + return SFNT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap14_validate( FT_Byte* table, + FT_Validator valid ) + { + FT_Byte* p = table + 2; + FT_ULong length = TT_NEXT_ULONG( p ); + FT_ULong num_selectors = TT_NEXT_ULONG( p ); + + + if ( table + length > valid->limit || length < 10 + 11 * num_selectors ) + FT_INVALID_TOO_SHORT; + + /* check selectors, they must be in increasing order */ + { + FT_ULong n, varSel, defOff, nondefOff, last = 0; + + + for ( n = 0; n < num_selectors; n++ ) + { + varSel = TT_NEXT_UINT24( p ); + defOff = TT_NEXT_ULONG( p ); + nondefOff = TT_NEXT_ULONG( p ); + + if ( defOff >= length || nondefOff >= length ) + FT_INVALID_TOO_SHORT; + + if ( n > 0 && varSel <= last ) + FT_INVALID_DATA; + last = varSel; + + /* 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, base, cnt; + + + for ( i = 0; i < numRanges; ++i ) + { + base = TT_NEXT_UINT24( defp ); + cnt = FT_NEXT_BYTE( defp ); + + if ( base + cnt >= 0x110000UL ) /* end of Unicode */ + FT_INVALID_DATA; + + if ( i > 0 && base <= last ) + FT_INVALID_DATA; + last = base + cnt; + } + } + + /* 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, uni, gid; + + + for ( i = 0; i < numMappings; ++i ) + { + uni = TT_NEXT_UINT24( ndp ); + gid = TT_NEXT_USHORT( ndp ); + + if ( uni >= 0x110000UL ) /* end of Unicode */ + FT_INVALID_DATA; + + if ( i > 0 && uni <= last ) + FT_INVALID_DATA; + last = uni; + + if ( valid->level >= FT_VALIDATE_TIGHT && + gid >= TT_VALID_GLYPH_COUNT( valid ) ) + FT_INVALID_GLYPH_ID; + } + } + } + } + + return SFNT_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_UInt ) + 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 SFNT_Err_Ok; + } + + + static FT_UInt + tt_cmap14_char_map_def_binary( FT_Byte *base, + FT_UInt32 char_code ) + { + FT_Byte* p; + FT_UInt32 numRanges = TT_PEEK_ULONG( base ); + FT_UInt32 start, cnt; + FT_UInt32 max, min, mid; + + + if ( !numRanges ) + return FALSE; + + /* make compiler happy */ + mid = numRanges; + + min = 0; + max = numRanges; + + /* binary search */ + while ( min < max ) + { + mid = ( min + max ) >> 1; + p = base + 4 + 4 * mid; + + start = TT_NEXT_UINT24( p ); + 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_Byte* p; + FT_UInt32 numMappings = TT_PEEK_ULONG( base ); + FT_UInt32 uni, gid; + FT_UInt32 max, min, mid; + + + if ( !numMappings ) + return 0; + + /* make compiler happy */ + mid = numMappings; + + min = 0; + max = numMappings; + + /* binary search */ + while ( min < max ) + { + mid = ( min + max ) >> 1; + p = base + 4 + 5 * mid; + + uni = TT_NEXT_UINT24( p ); + gid = TT_NEXT_USHORT( p ); + + if ( char_code < uni ) + max = mid; + else if ( char_code > uni ) + min = mid + 1; + else + return gid; + } + + return 0; + } + + + static FT_Byte* + tt_cmap14_find_variant( FT_Byte *base, + FT_UInt32 variantCode ) + { + FT_Byte* p; + FT_UInt32 numVar = TT_PEEK_ULONG( base ); + FT_ULong varSel; + FT_UInt32 max, min, mid; + + + if ( !numVar ) + return NULL; + + /* make compiler happy */ + mid = numVar; + + min = 0; + max = numVar; + + /* binary search */ + while ( min < max ) + { + mid = ( min + max ) >> 1; + p = base + 4 + 11 * mid; + + 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_ULong charcode, + FT_ULong 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_NEXT_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_ULong charcode, + FT_ULong 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_Byte* p = cmap->data + 10; + FT_UInt32* ret; + FT_UInt i; + FT_Error error; + + + if ( FT_ALLOC( ret, + ( cmap14->num_selectors + 1 ) * sizeof ( FT_UInt32 ) ) ) + return NULL; + + for ( i = 0; i < cmap14->num_selectors; ++i ) + { + ret[i] = TT_NEXT_UINT24( p ); + p += 8; + } + ret[i] = 0; + + return ret; + } + + + FT_CALLBACK_DEF( FT_UInt32 * ) + tt_cmap14_char_variants( TT_CMap cmap, + FT_Memory memory, + FT_ULong charCode ) + { + TT_CMap14 cmap14 = (TT_CMap14) cmap; + FT_Byte* p = cmap->data + 10; + FT_UInt32 *ret; + FT_UInt i, j; + FT_UInt32 varSel; + FT_ULong defOff; + FT_ULong nondefOff; + FT_Error error; + + + if ( FT_ALLOC( ret, + ( cmap14->num_selectors + 1 ) * sizeof ( FT_UInt32 ) ) ) + return NULL; + + for ( i = j = 0; i < cmap14->num_selectors; ++i ) + { + varSel = TT_NEXT_UINT24( p ); + defOff = TT_NEXT_ULONG( p ); + 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 ) ) + ret[j++] = varSel; + } + ret[j] = 0; + + return ret; + } + + + static FT_UInt + tt_cmap14_def_char_count( FT_Byte *p ) + { + FT_UInt32 numRanges; + FT_UInt tot; + FT_UInt cnt; + FT_UInt i; + + + numRanges = TT_NEXT_ULONG( p ); + + tot = 0; + for ( i = 0; i < numRanges; ++i ) + { + p += 3; + cnt = FT_NEXT_BYTE( p ); + tot += cnt + 1; + } + + return tot; + } + + + static FT_UInt* + tt_cmap14_get_def_chars( FT_Byte *p, + FT_Memory memory ) + { + FT_UInt32 numRanges; + FT_UInt uni; + FT_UInt cnt; + FT_UInt i, j, k; + FT_UInt32 *ret; + FT_Error error; + + + cnt = tt_cmap14_def_char_count( p ); + numRanges = TT_NEXT_ULONG( p ); + + if ( FT_ALLOC( ret , ( cnt + 1 ) * sizeof ( FT_UInt32 ) ) ) + return NULL; + + for ( i = j = 0; i < numRanges; ++i ) + { + uni = TT_NEXT_UINT24( p ); + cnt = FT_NEXT_BYTE( p ); + + for ( k = 0; k <= cnt; ++k ) + ret[j++] = uni + k; + } + ret[j] = 0; + + return ret; + } + + + static FT_UInt* + tt_cmap14_get_nondef_chars( FT_Byte *p, + FT_Memory memory ) + { + FT_UInt32 numMappings; + FT_UInt i; + FT_UInt32 *ret; + FT_Error error; + + + numMappings = TT_NEXT_ULONG( p ); + + if ( FT_ALLOC( ret, ( numMappings + 1 ) * sizeof ( FT_UInt32 ) ) ) + return NULL; + + for ( i = 0; i < numMappings; ++i ) + { + ret[i] = 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_ULong variantSelector ) + { + FT_Byte *p = tt_cmap14_find_variant( cmap->data + 6, + variantSelector ); + FT_UInt32 *ret; + 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->data + nondefOff, memory ); + else if ( nondefOff == 0 ) + return tt_cmap14_get_def_chars( 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... */ + FT_UInt32 numRanges; + FT_UInt32 numMappings; + FT_UInt32 duni; + FT_UInt32 dcnt; + FT_UInt32 nuni; + FT_Byte* dp; + FT_UInt di, ni, k; + FT_Error error; + + + p = cmap->data + nondefOff; + dp = cmap->data + defOff; + + numMappings = TT_NEXT_ULONG( p ); + dcnt = tt_cmap14_def_char_count( dp ); + numRanges = TT_NEXT_ULONG( dp ); + + if ( numMappings == 0 ) + return tt_cmap14_get_def_chars( cmap->data + defOff, memory ); + if ( dcnt == 0 ) + return tt_cmap14_get_nondef_chars( cmap->data + nondefOff, memory ); + + if ( FT_ALLOC( ret, + ( dcnt + numMappings + 1 ) * sizeof ( FT_UInt32 ) ) ) + return NULL; + + duni = TT_NEXT_UINT24( dp ); + dcnt = FT_NEXT_BYTE( dp ); + di = 1; + nuni = 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 ) + { + duni = TT_NEXT_UINT24( dp ); + dcnt = FT_NEXT_BYTE( dp ); + } + else + break; + } + 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 ) + { + nuni = TT_NEXT_UINT24( p ); + p += 2; + } + else + break; + } + } + + 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++] = 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 = 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_CALLBACK_TABLE_DEF + const TT_CMap_ClassRec tt_cmap14_class_rec = + { + { + sizeof ( TT_CMap14Rec ), + + (FT_CMap_InitFunc) tt_cmap14_init, + (FT_CMap_DoneFunc) NULL, + (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_0 */ + + static const TT_CMap_Class tt_cmap_classes[] = { #ifdef TT_CONFIG_CMAP_FORMAT_0 @@ -2242,6 +2951,10 @@ &tt_cmap12_class_rec, #endif +#ifdef TT_CONFIG_CMAP_FORMAT_14 + &tt_cmap14_class_rec, +#endif + NULL, }; @@ -2318,6 +3031,10 @@ 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 ) ) { @@ -2334,6 +3051,12 @@ break; } } + + if ( *pclazz == NULL ) + { + FT_ERROR(( "tt_face_build_cmaps:" )); + FT_ERROR(( " unsupported cmap sub-table ignored!\n" )); + } } } diff --git a/src/winfonts/winfnt.c b/src/winfonts/winfnt.c index 4aa974410..a56fe6052 100644 --- a/src/winfonts/winfnt.c +++ b/src/winfonts/winfnt.c @@ -652,7 +652,9 @@ (FT_CMap_InitFunc) fnt_cmap_init, (FT_CMap_DoneFunc) NULL, (FT_CMap_CharIndexFunc)fnt_cmap_char_index, - (FT_CMap_CharNextFunc) fnt_cmap_char_next + (FT_CMap_CharNextFunc) fnt_cmap_char_next, + + NULL, NULL, NULL, NULL, NULL }; static FT_CMap_Class const fnt_cmap_class = &fnt_cmap_class_rec;