1 /***************************************************************************/ 2 /* */ 3 /* cffcmap.c */ 4 /* */ 5 /* CFF character mapping table (cmap) support (body). */ 6 /* */ 7 /* Copyright 2002 by */ 8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */ 9 /* */ 10 /* This file is part of the FreeType project, and may only be used, */ 11 /* modified, and distributed under the terms of the FreeType project */ 12 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ 13 /* this file you indicate that you have read the license and */ 14 /* understand and accept it fully. */ 15 /* */ 16 /***************************************************************************/ 17 18 19 #include "cffcmap.h" 20 #include "cffload.h" 21 22 23 /*************************************************************************/ 24 /*************************************************************************/ 25 /***** *****/ 26 /***** CFF STANDARD (AND EXPERT) ENCODING CMAPS *****/ 27 /***** *****/ 28 /*************************************************************************/ 29 /*************************************************************************/ 30 31 FT_CALLBACK_DEF( FT_Error ) cff_cmap_encoding_init(CFF_CMapStd cmap)32 cff_cmap_encoding_init( CFF_CMapStd cmap ) 33 { 34 TT_Face face = (TT_Face)FT_CMAP_FACE( cmap ); 35 CFF_Font cff = (CFF_Font)face->extra.data; 36 CFF_Encoding encoding = &cff->encoding; 37 38 39 cmap->count = encoding->count; 40 cmap->gids = encoding->codes; 41 42 return 0; 43 } 44 45 46 FT_CALLBACK_DEF( void ) cff_cmap_encoding_done(CFF_CMapStd cmap)47 cff_cmap_encoding_done( CFF_CMapStd cmap ) 48 { 49 cmap->count = 0; 50 cmap->gids = NULL; 51 } 52 53 54 FT_CALLBACK_DEF( FT_UInt ) cff_cmap_encoding_char_index(CFF_CMapStd cmap,FT_UInt32 char_code)55 cff_cmap_encoding_char_index( CFF_CMapStd cmap, 56 FT_UInt32 char_code ) 57 { 58 FT_UInt result = 0; 59 60 61 if ( char_code < cmap->count ) 62 result = cmap->gids[char_code]; 63 64 return result; 65 } 66 67 68 FT_CALLBACK_DEF( FT_UInt ) cff_cmap_encoding_char_next(CFF_CMapStd cmap,FT_UInt32 * pchar_code)69 cff_cmap_encoding_char_next( CFF_CMapStd cmap, 70 FT_UInt32 *pchar_code ) 71 { 72 FT_UInt result = 0; 73 FT_UInt32 char_code = *pchar_code; 74 75 76 *pchar_code = 0; 77 78 if ( char_code < cmap->count ) 79 { 80 FT_UInt code = (FT_UInt)(char_code + 1); 81 82 83 for (;;) 84 { 85 if ( code >= cmap->count ) 86 break; 87 88 result = cmap->gids[code]; 89 if ( result != 0 ) 90 { 91 *pchar_code = code; 92 break; 93 } 94 95 code++; 96 } 97 } 98 return result; 99 } 100 101 102 FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec 103 cff_cmap_encoding_class_rec = 104 { 105 sizeof ( CFF_CMapStdRec ), 106 107 (FT_CMap_InitFunc) cff_cmap_encoding_init, 108 (FT_CMap_DoneFunc) cff_cmap_encoding_done, 109 (FT_CMap_CharIndexFunc)cff_cmap_encoding_char_index, 110 (FT_CMap_CharNextFunc) cff_cmap_encoding_char_next 111 }; 112 113 114 /*************************************************************************/ 115 /*************************************************************************/ 116 /***** *****/ 117 /***** CFF SYNTHETIC UNICODE ENCODING CMAP *****/ 118 /***** *****/ 119 /*************************************************************************/ 120 /*************************************************************************/ 121 122 FT_CALLBACK_DEF( FT_Int ) cff_cmap_uni_pair_compare(const void * pair1,const void * pair2)123 cff_cmap_uni_pair_compare( const void* pair1, 124 const void* pair2 ) 125 { 126 FT_UInt32 u1 = ((CFF_CMapUniPair)pair1)->unicode; 127 FT_UInt32 u2 = ((CFF_CMapUniPair)pair2)->unicode; 128 129 130 if ( u1 < u2 ) 131 return -1; 132 133 if ( u1 > u2 ) 134 return +1; 135 136 return 0; 137 } 138 139 140 FT_CALLBACK_DEF( FT_Error ) cff_cmap_unicode_init(CFF_CMapUnicode cmap)141 cff_cmap_unicode_init( CFF_CMapUnicode cmap ) 142 { 143 FT_Error error; 144 FT_UInt count; 145 TT_Face face = (TT_Face)FT_CMAP_FACE( cmap ); 146 FT_Memory memory = FT_FACE_MEMORY( face ); 147 CFF_Font cff = (CFF_Font)face->extra.data; 148 CFF_Charset charset = &cff->charset; 149 PSNames_Service psnames = (PSNames_Service)cff->psnames; 150 151 152 cmap->num_pairs = 0; 153 cmap->pairs = NULL; 154 155 count = (FT_UInt)face->root.num_glyphs; 156 157 if ( !FT_NEW_ARRAY( cmap->pairs, count ) ) 158 { 159 FT_UInt n, new_count; 160 CFF_CMapUniPair pair; 161 FT_UInt32 uni_code; 162 163 164 pair = cmap->pairs; 165 for ( n = 0; n < count; n++ ) 166 { 167 FT_UInt sid = charset->sids[n]; 168 const char* gname; 169 170 171 gname = cff_index_get_sid_string( &cff->string_index, sid, psnames ); 172 173 /* build unsorted pair table by matching glyph names */ 174 if ( gname ) 175 { 176 uni_code = psnames->unicode_value( gname ); 177 178 if ( uni_code != 0 ) 179 { 180 pair->unicode = uni_code; 181 pair->gindex = n; 182 pair++; 183 } 184 185 FT_FREE( gname ); 186 } 187 } 188 189 new_count = (FT_UInt)( pair - cmap->pairs ); 190 if ( new_count == 0 ) 191 { 192 /* there are no unicode characters in here! */ 193 FT_FREE( cmap->pairs ); 194 error = FT_Err_Invalid_Argument; 195 } 196 else 197 { 198 /* re-allocate if the new array is much smaller than the original */ 199 /* one */ 200 if ( new_count != count && new_count < count / 2 ) 201 { 202 (void)FT_RENEW_ARRAY( cmap->pairs, count, new_count ); 203 error = 0; 204 } 205 206 /* sort the pairs table to allow efficient binary searches */ 207 ft_qsort( cmap->pairs, 208 new_count, 209 sizeof ( CFF_CMapUniPairRec ), 210 cff_cmap_uni_pair_compare ); 211 212 cmap->num_pairs = new_count; 213 } 214 } 215 216 return error; 217 } 218 219 220 FT_CALLBACK_DEF( void ) cff_cmap_unicode_done(CFF_CMapUnicode cmap)221 cff_cmap_unicode_done( CFF_CMapUnicode cmap ) 222 { 223 FT_Face face = FT_CMAP_FACE( cmap ); 224 FT_Memory memory = FT_FACE_MEMORY( face ); 225 226 227 FT_FREE( cmap->pairs ); 228 cmap->num_pairs = 0; 229 } 230 231 232 FT_CALLBACK_DEF( FT_UInt ) cff_cmap_unicode_char_index(CFF_CMapUnicode cmap,FT_UInt32 char_code)233 cff_cmap_unicode_char_index( CFF_CMapUnicode cmap, 234 FT_UInt32 char_code ) 235 { 236 FT_UInt min = 0; 237 FT_UInt max = cmap->num_pairs; 238 FT_UInt mid; 239 CFF_CMapUniPair pair; 240 241 242 while ( min < max ) 243 { 244 mid = min + ( max - min ) / 2; 245 pair = cmap->pairs + mid; 246 247 if ( pair->unicode == char_code ) 248 return pair->gindex; 249 250 if ( pair->unicode < char_code ) 251 min = mid + 1; 252 else 253 max = mid; 254 } 255 return 0; 256 } 257 258 259 FT_CALLBACK_DEF( FT_UInt ) cff_cmap_unicode_char_next(CFF_CMapUnicode cmap,FT_UInt32 * pchar_code)260 cff_cmap_unicode_char_next( CFF_CMapUnicode cmap, 261 FT_UInt32 *pchar_code ) 262 { 263 FT_UInt result = 0; 264 FT_UInt32 char_code = *pchar_code + 1; 265 266 267 Restart: 268 { 269 FT_UInt min = 0; 270 FT_UInt max = cmap->num_pairs; 271 FT_UInt mid; 272 CFF_CMapUniPair pair; 273 274 275 while ( min < max ) 276 { 277 mid = min + ( ( max - min ) >> 1 ); 278 pair = cmap->pairs + mid; 279 280 if ( pair->unicode == char_code ) 281 { 282 result = pair->gindex; 283 if ( result != 0 ) 284 goto Exit; 285 286 char_code++; 287 goto Restart; 288 } 289 290 if ( pair->unicode < char_code ) 291 min = mid+1; 292 else 293 max = mid; 294 } 295 296 /* we didn't find it, but we have a pair just above it */ 297 char_code = 0; 298 299 if ( min < cmap->num_pairs ) 300 { 301 pair = cmap->pairs + min; 302 result = pair->gindex; 303 if ( result != 0 ) 304 char_code = pair->unicode; 305 } 306 } 307 308 Exit: 309 *pchar_code = char_code; 310 return result; 311 } 312 313 314 FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec 315 cff_cmap_unicode_class_rec = 316 { 317 sizeof ( CFF_CMapUnicodeRec ), 318 319 (FT_CMap_InitFunc) cff_cmap_unicode_init, 320 (FT_CMap_DoneFunc) cff_cmap_unicode_done, 321 (FT_CMap_CharIndexFunc)cff_cmap_unicode_char_index, 322 (FT_CMap_CharNextFunc) cff_cmap_unicode_char_next 323 }; 324 325 326 /* END */ 327