1 /***************************************************************************/ 2 /* */ 3 /* t1cmap.c */ 4 /* */ 5 /* Type 1 character map 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 "t1cmap.h" 20 21 #include FT_INTERNAL_DEBUG_H 22 23 24 /*************************************************************************/ 25 /*************************************************************************/ 26 /***** *****/ 27 /***** TYPE1 STANDARD (AND EXPERT) ENCODING CMAPS *****/ 28 /***** *****/ 29 /*************************************************************************/ 30 /*************************************************************************/ 31 32 static void t1_cmap_std_init(T1_CMapStd cmap,FT_Int is_expert)33 t1_cmap_std_init( T1_CMapStd cmap, 34 FT_Int is_expert ) 35 { 36 T1_Face face = (T1_Face)FT_CMAP_FACE( cmap ); 37 PSNames_Service psnames = (PSNames_Service)face->psnames; 38 39 40 cmap->num_glyphs = face->type1.num_glyphs; 41 cmap->glyph_names = (const char* const*)face->type1.glyph_names; 42 cmap->sid_to_string = psnames->adobe_std_strings; 43 cmap->code_to_sid = is_expert ? psnames->adobe_expert_encoding 44 : psnames->adobe_std_encoding; 45 46 FT_ASSERT( cmap->code_to_sid != NULL ); 47 } 48 49 50 FT_CALLBACK_DEF( void ) t1_cmap_std_done(T1_CMapStd cmap)51 t1_cmap_std_done( T1_CMapStd cmap ) 52 { 53 cmap->num_glyphs = 0; 54 cmap->glyph_names = NULL; 55 cmap->sid_to_string = NULL; 56 cmap->code_to_sid = NULL; 57 } 58 59 60 FT_CALLBACK_DEF( FT_UInt ) t1_cmap_std_char_index(T1_CMapStd cmap,FT_UInt32 char_code)61 t1_cmap_std_char_index( T1_CMapStd cmap, 62 FT_UInt32 char_code ) 63 { 64 FT_UInt result = 0; 65 66 67 if ( char_code < 256 ) 68 { 69 FT_UInt code, n; 70 const char* glyph_name; 71 72 73 /* convert character code to Adobe SID string */ 74 code = cmap->code_to_sid[char_code]; 75 glyph_name = cmap->sid_to_string( code ); 76 77 /* look for the corresponding glyph name */ 78 for ( n = 0; n < cmap->num_glyphs; n++ ) 79 { 80 const char* gname = cmap->glyph_names[n]; 81 82 83 if ( gname && gname[0] == glyph_name[0] && 84 ft_strcmp( gname, glyph_name ) == 0 ) 85 { 86 result = n; 87 break; 88 } 89 } 90 } 91 92 return result; 93 } 94 95 96 FT_CALLBACK_DEF( FT_UInt ) t1_cmap_std_char_next(T1_CMapStd cmap,FT_UInt32 * pchar_code)97 t1_cmap_std_char_next( T1_CMapStd cmap, 98 FT_UInt32 *pchar_code ) 99 { 100 FT_UInt result = 0; 101 FT_UInt32 char_code = *pchar_code + 1; 102 103 104 while ( char_code < 256 ) 105 { 106 result = t1_cmap_std_char_index( cmap, char_code ); 107 if ( result != 0 ) 108 goto Exit; 109 110 char_code++; 111 } 112 char_code = 0; 113 114 Exit: 115 *pchar_code = char_code; 116 return result; 117 } 118 119 120 FT_CALLBACK_DEF( FT_Error ) t1_cmap_standard_init(T1_CMapStd cmap)121 t1_cmap_standard_init( T1_CMapStd cmap ) 122 { 123 t1_cmap_std_init( cmap, 0 ); 124 return 0; 125 } 126 127 128 FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec 129 t1_cmap_standard_class_rec = 130 { 131 sizeof ( T1_CMapStdRec ), 132 133 (FT_CMap_InitFunc) t1_cmap_standard_init, 134 (FT_CMap_DoneFunc) t1_cmap_std_done, 135 (FT_CMap_CharIndexFunc)t1_cmap_std_char_index, 136 (FT_CMap_CharNextFunc) t1_cmap_std_char_next 137 }; 138 139 140 FT_CALLBACK_DEF( FT_Error ) t1_cmap_expert_init(T1_CMapStd cmap)141 t1_cmap_expert_init( T1_CMapStd cmap ) 142 { 143 t1_cmap_std_init( cmap, 1 ); 144 return 0; 145 } 146 147 FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec 148 t1_cmap_expert_class_rec = 149 { 150 sizeof ( T1_CMapStdRec ), 151 152 (FT_CMap_InitFunc) t1_cmap_expert_init, 153 (FT_CMap_DoneFunc) t1_cmap_std_done, 154 (FT_CMap_CharIndexFunc)t1_cmap_std_char_index, 155 (FT_CMap_CharNextFunc) t1_cmap_std_char_next 156 }; 157 158 159 /*************************************************************************/ 160 /*************************************************************************/ 161 /***** *****/ 162 /***** TYPE1 CUSTOM ENCODING CMAP *****/ 163 /***** *****/ 164 /*************************************************************************/ 165 /*************************************************************************/ 166 167 168 FT_CALLBACK_DEF( FT_Error ) t1_cmap_custom_init(T1_CMapCustom cmap)169 t1_cmap_custom_init( T1_CMapCustom cmap ) 170 { 171 T1_Face face = (T1_Face)FT_CMAP_FACE( cmap ); 172 T1_Encoding encoding = &face->type1.encoding; 173 174 175 cmap->first = encoding->code_first; 176 cmap->count = (FT_UInt)( encoding->code_last - cmap->first + 1 ); 177 cmap->indices = encoding->char_index; 178 179 FT_ASSERT( cmap->indices != NULL ); 180 FT_ASSERT( encoding->code_first <= encoding->code_last ); 181 182 return 0; 183 } 184 185 186 FT_CALLBACK_DEF( void ) t1_cmap_custom_done(T1_CMapCustom cmap)187 t1_cmap_custom_done( T1_CMapCustom cmap ) 188 { 189 cmap->indices = NULL; 190 cmap->first = 0; 191 cmap->count = 0; 192 } 193 194 195 FT_CALLBACK_DEF( FT_UInt ) t1_cmap_custom_char_index(T1_CMapCustom cmap,FT_UInt32 char_code)196 t1_cmap_custom_char_index( T1_CMapCustom cmap, 197 FT_UInt32 char_code ) 198 { 199 FT_UInt result = 0; 200 201 202 if ( ( char_code >= cmap->first ) && 203 ( char_code < ( cmap->first + cmap->count ) ) ) 204 result = cmap->indices[char_code]; 205 206 return result; 207 } 208 209 210 FT_CALLBACK_DEF( FT_UInt ) t1_cmap_custom_char_next(T1_CMapCustom cmap,FT_UInt32 * pchar_code)211 t1_cmap_custom_char_next( T1_CMapCustom cmap, 212 FT_UInt32 *pchar_code ) 213 { 214 FT_UInt result = 0; 215 FT_UInt32 char_code = *pchar_code; 216 217 218 ++char_code; 219 220 if ( char_code < cmap->first ) 221 char_code = cmap->first; 222 223 for ( ; char_code < ( cmap->first + cmap->count ); char_code++ ) 224 { 225 result = cmap->indices[char_code]; 226 if ( result != 0 ) 227 goto Exit; 228 } 229 230 char_code = 0; 231 232 Exit: 233 *pchar_code = char_code; 234 return result; 235 } 236 237 238 FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec 239 t1_cmap_custom_class_rec = 240 { 241 sizeof ( T1_CMapCustomRec ), 242 243 (FT_CMap_InitFunc) t1_cmap_custom_init, 244 (FT_CMap_DoneFunc) t1_cmap_custom_done, 245 (FT_CMap_CharIndexFunc)t1_cmap_custom_char_index, 246 (FT_CMap_CharNextFunc) t1_cmap_custom_char_next 247 }; 248 249 250 /*************************************************************************/ 251 /*************************************************************************/ 252 /***** *****/ 253 /***** TYPE1 SYNTHETIC UNICODE ENCODING CMAP *****/ 254 /***** *****/ 255 /*************************************************************************/ 256 /*************************************************************************/ 257 258 FT_CALLBACK_DEF( FT_Int ) t1_cmap_uni_pair_compare(const void * pair1,const void * pair2)259 t1_cmap_uni_pair_compare( const void* pair1, 260 const void* pair2 ) 261 { 262 FT_UInt32 u1 = ((T1_CMapUniPair)pair1)->unicode; 263 FT_UInt32 u2 = ((T1_CMapUniPair)pair2)->unicode; 264 265 266 if ( u1 < u2 ) 267 return -1; 268 269 if ( u1 > u2 ) 270 return +1; 271 272 return 0; 273 } 274 275 276 FT_CALLBACK_DEF( FT_Error ) t1_cmap_unicode_init(T1_CMapUnicode cmap)277 t1_cmap_unicode_init( T1_CMapUnicode cmap ) 278 { 279 FT_Error error; 280 FT_UInt count; 281 T1_Face face = (T1_Face)FT_CMAP_FACE( cmap ); 282 FT_Memory memory = FT_FACE_MEMORY( face ); 283 PSNames_Service psnames = (PSNames_Service)face->psnames; 284 285 286 cmap->num_pairs = 0; 287 cmap->pairs = NULL; 288 289 count = face->type1.num_glyphs; 290 291 if ( !FT_NEW_ARRAY( cmap->pairs, count ) ) 292 { 293 FT_UInt n, new_count; 294 T1_CMapUniPair pair; 295 FT_UInt32 uni_code; 296 297 298 pair = cmap->pairs; 299 for ( n = 0; n < count; n++ ) 300 { 301 const char* gname = face->type1.glyph_names[n]; 302 303 304 /* build unsorted pair table by matching glyph names */ 305 if ( gname ) 306 { 307 uni_code = psnames->unicode_value( gname ); 308 309 if ( uni_code != 0 ) 310 { 311 pair->unicode = uni_code; 312 pair->gindex = n; 313 pair++; 314 } 315 } 316 } 317 318 new_count = (FT_UInt)( pair - cmap->pairs ); 319 if ( new_count == 0 ) 320 { 321 /* there are no unicode characters in here! */ 322 FT_FREE( cmap->pairs ); 323 error = FT_Err_Invalid_Argument; 324 } 325 else 326 { 327 /* re-allocate if the new array is much smaller than the original */ 328 /* one */ 329 if ( new_count != count && new_count < count / 2 ) 330 { 331 (void)FT_RENEW_ARRAY( cmap->pairs, count, new_count ); 332 error = 0; 333 } 334 335 /* sort the pairs table to allow efficient binary searches */ 336 ft_qsort( cmap->pairs, 337 new_count, 338 sizeof ( T1_CMapUniPairRec ), 339 t1_cmap_uni_pair_compare ); 340 341 cmap->num_pairs = new_count; 342 } 343 } 344 345 return error; 346 } 347 348 349 FT_CALLBACK_DEF( void ) t1_cmap_unicode_done(T1_CMapUnicode cmap)350 t1_cmap_unicode_done( T1_CMapUnicode cmap ) 351 { 352 FT_Face face = FT_CMAP_FACE(cmap); 353 FT_Memory memory = FT_FACE_MEMORY(face); 354 355 FT_FREE( cmap->pairs ); 356 cmap->num_pairs = 0; 357 } 358 359 360 FT_CALLBACK_DEF( FT_UInt ) t1_cmap_unicode_char_index(T1_CMapUnicode cmap,FT_UInt32 char_code)361 t1_cmap_unicode_char_index( T1_CMapUnicode cmap, 362 FT_UInt32 char_code ) 363 { 364 FT_UInt min = 0; 365 FT_UInt max = cmap->num_pairs; 366 FT_UInt mid; 367 T1_CMapUniPair pair; 368 369 370 while ( min < max ) 371 { 372 mid = min + ( max - min ) / 2; 373 pair = cmap->pairs + mid; 374 375 if ( pair->unicode == char_code ) 376 return pair->gindex; 377 378 if ( pair->unicode < char_code ) 379 min = mid + 1; 380 else 381 max = mid; 382 } 383 return 0; 384 } 385 386 387 FT_CALLBACK_DEF( FT_UInt ) t1_cmap_unicode_char_next(T1_CMapUnicode cmap,FT_UInt32 * pchar_code)388 t1_cmap_unicode_char_next( T1_CMapUnicode cmap, 389 FT_UInt32 *pchar_code ) 390 { 391 FT_UInt result = 0; 392 FT_UInt32 char_code = *pchar_code + 1; 393 394 395 Restart: 396 { 397 FT_UInt min = 0; 398 FT_UInt max = cmap->num_pairs; 399 FT_UInt mid; 400 T1_CMapUniPair pair; 401 402 403 while ( min < max ) 404 { 405 mid = min + ( ( max - min ) >> 1 ); 406 pair = cmap->pairs + mid; 407 408 if ( pair->unicode == char_code ) 409 { 410 result = pair->gindex; 411 if ( result != 0 ) 412 goto Exit; 413 414 char_code++; 415 goto Restart; 416 } 417 418 if ( pair->unicode < char_code ) 419 min = mid+1; 420 else 421 max = mid; 422 } 423 424 /* we didn't find it, but we have a pair just above it */ 425 char_code = 0; 426 427 if ( min < cmap->num_pairs ) 428 { 429 pair = cmap->pairs + min; 430 result = pair->gindex; 431 if ( result != 0 ) 432 char_code = pair->unicode; 433 } 434 } 435 436 Exit: 437 *pchar_code = char_code; 438 return result; 439 } 440 441 442 FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec 443 t1_cmap_unicode_class_rec = 444 { 445 sizeof ( T1_CMapUnicodeRec ), 446 447 (FT_CMap_InitFunc) t1_cmap_unicode_init, 448 (FT_CMap_DoneFunc) t1_cmap_unicode_done, 449 (FT_CMap_CharIndexFunc)t1_cmap_unicode_char_index, 450 (FT_CMap_CharNextFunc) t1_cmap_unicode_char_next 451 }; 452 453 454 /* END */ 455