1/***************************************************************************/ 2/* */ 3/* sfdriver.c */ 4/* */ 5/* High-level SFNT driver interface (body). */ 6/* */ 7/* Copyright 1996-2017 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 <ft2build.h> 20#include FT_INTERNAL_DEBUG_H 21#include FT_INTERNAL_SFNT_H 22#include FT_INTERNAL_OBJECTS_H 23 24#include "sfdriver.h" 25#include "ttload.h" 26#include "sfobjs.h" 27#include "sfntpic.h" 28 29#include "sferrors.h" 30 31#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS 32#include "ttsbit.h" 33#endif 34 35#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES 36#include "ttpost.h" 37#endif 38 39#ifdef TT_CONFIG_OPTION_BDF 40#include "ttbdf.h" 41#include FT_SERVICE_BDF_H 42#endif 43 44#include "ttcmap.h" 45#include "ttkern.h" 46#include "ttmtx.h" 47 48#include FT_SERVICE_GLYPH_DICT_H 49#include FT_SERVICE_POSTSCRIPT_NAME_H 50#include FT_SERVICE_SFNT_H 51#include FT_SERVICE_TT_CMAP_H 52 53 54 /*************************************************************************/ 55 /* */ 56 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 57 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 58 /* messages during execution. */ 59 /* */ 60#undef FT_COMPONENT 61#define FT_COMPONENT trace_sfdriver 62 63 64 /* 65 * SFNT TABLE SERVICE 66 * 67 */ 68 69 static void* 70 get_sfnt_table( TT_Face face, 71 FT_Sfnt_Tag tag ) 72 { 73 void* table; 74 75 76 switch ( tag ) 77 { 78 case FT_SFNT_HEAD: 79 table = &face->header; 80 break; 81 82 case FT_SFNT_HHEA: 83 table = &face->horizontal; 84 break; 85 86 case FT_SFNT_VHEA: 87 table = face->vertical_info ? &face->vertical : NULL; 88 break; 89 90 case FT_SFNT_OS2: 91 table = ( face->os2.version == 0xFFFFU ) ? NULL : &face->os2; 92 break; 93 94 case FT_SFNT_POST: 95 table = &face->postscript; 96 break; 97 98 case FT_SFNT_MAXP: 99 table = &face->max_profile; 100 break; 101 102 case FT_SFNT_PCLT: 103 table = face->pclt.Version ? &face->pclt : NULL; 104 break; 105 106 default: 107 table = NULL; 108 } 109 110 return table; 111 } 112 113 114 static FT_Error 115 sfnt_table_info( TT_Face face, 116 FT_UInt idx, 117 FT_ULong *tag, 118 FT_ULong *offset, 119 FT_ULong *length ) 120 { 121 if ( !offset || !length ) 122 return FT_THROW( Invalid_Argument ); 123 124 if ( !tag ) 125 *length = face->num_tables; 126 else 127 { 128 if ( idx >= face->num_tables ) 129 return FT_THROW( Table_Missing ); 130 131 *tag = face->dir_tables[idx].Tag; 132 *offset = face->dir_tables[idx].Offset; 133 *length = face->dir_tables[idx].Length; 134 } 135 136 return FT_Err_Ok; 137 } 138 139 140 FT_DEFINE_SERVICE_SFNT_TABLEREC( 141 sfnt_service_sfnt_table, 142 143 (FT_SFNT_TableLoadFunc)tt_face_load_any, /* load_table */ 144 (FT_SFNT_TableGetFunc) get_sfnt_table, /* get_table */ 145 (FT_SFNT_TableInfoFunc)sfnt_table_info /* table_info */ 146 ) 147 148 149#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES 150 151 /* 152 * GLYPH DICT SERVICE 153 * 154 */ 155 156 static FT_Error 157 sfnt_get_glyph_name( FT_Face face, 158 FT_UInt glyph_index, 159 FT_Pointer buffer, 160 FT_UInt buffer_max ) 161 { 162 FT_String* gname; 163 FT_Error error; 164 165 166 error = tt_face_get_ps_name( (TT_Face)face, glyph_index, &gname ); 167 if ( !error ) 168 FT_STRCPYN( buffer, gname, buffer_max ); 169 170 return error; 171 } 172 173 174 static FT_UInt 175 sfnt_get_name_index( FT_Face face, 176 FT_String* glyph_name ) 177 { 178 TT_Face ttface = (TT_Face)face; 179 180 FT_UInt i, max_gid = FT_UINT_MAX; 181 182 183 if ( face->num_glyphs < 0 ) 184 return 0; 185 else if ( (FT_ULong)face->num_glyphs < FT_UINT_MAX ) 186 max_gid = (FT_UInt)face->num_glyphs; 187 else 188 FT_TRACE0(( "Ignore glyph names for invalid GID 0x%08x - 0x%08x\n", 189 FT_UINT_MAX, face->num_glyphs )); 190 191 for ( i = 0; i < max_gid; i++ ) 192 { 193 FT_String* gname; 194 FT_Error error = tt_face_get_ps_name( ttface, i, &gname ); 195 196 197 if ( error ) 198 continue; 199 200 if ( !ft_strcmp( glyph_name, gname ) ) 201 return i; 202 } 203 204 return 0; 205 } 206 207 208 FT_DEFINE_SERVICE_GLYPHDICTREC( 209 sfnt_service_glyph_dict, 210 211 (FT_GlyphDict_GetNameFunc) sfnt_get_glyph_name, /* get_name */ 212 (FT_GlyphDict_NameIndexFunc)sfnt_get_name_index /* name_index */ 213 ) 214 215#endif /* TT_CONFIG_OPTION_POSTSCRIPT_NAMES */ 216 217 218 /* 219 * POSTSCRIPT NAME SERVICE 220 * 221 */ 222 223 static const char* 224 sfnt_get_ps_name( TT_Face face ) 225 { 226 FT_Int n, found_win, found_apple; 227 const char* result = NULL; 228 229 230 /* shouldn't happen, but just in case to avoid memory leaks */ 231 if ( face->postscript_name ) 232 return face->postscript_name; 233 234 /* scan the name table to see whether we have a Postscript name here, */ 235 /* either in Macintosh or Windows platform encodings */ 236 found_win = -1; 237 found_apple = -1; 238 239 for ( n = 0; n < face->num_names; n++ ) 240 { 241 TT_Name name = face->name_table.names + n; 242 243 244 if ( name->nameID == 6 && name->stringLength > 0 ) 245 { 246 /* handling of PID/EID 3/0 and 3/1 is the same */ 247 if ( name->platformID == 3 && 248 ( name->encodingID == 1 || name->encodingID == 0 ) && 249 name->languageID == 0x409 ) 250 found_win = n; 251 252 if ( name->platformID == 1 && 253 name->encodingID == 0 && 254 name->languageID == 0 ) 255 found_apple = n; 256 } 257 } 258 259 if ( found_win != -1 ) 260 { 261 FT_Memory memory = face->root.memory; 262 TT_Name name = face->name_table.names + found_win; 263 FT_UInt len = name->stringLength / 2; 264 FT_Error error = FT_Err_Ok; 265 266 FT_UNUSED( error ); 267 268 269 if ( !FT_ALLOC( result, name->stringLength + 1 ) ) 270 { 271 FT_Stream stream = face->name_table.stream; 272 FT_String* r = (FT_String*)result; 273 FT_Char* p; 274 275 276 if ( FT_STREAM_SEEK( name->stringOffset ) || 277 FT_FRAME_ENTER( name->stringLength ) ) 278 { 279 FT_FREE( result ); 280 name->stringLength = 0; 281 name->stringOffset = 0; 282 FT_FREE( name->string ); 283 284 goto Exit; 285 } 286 287 p = (FT_Char*)stream->cursor; 288 289 for ( ; len > 0; len--, p += 2 ) 290 { 291 if ( p[0] == 0 && p[1] >= 32 ) 292 *r++ = p[1]; 293 } 294 *r = '\0'; 295 296 FT_FRAME_EXIT(); 297 } 298 goto Exit; 299 } 300 301 if ( found_apple != -1 ) 302 { 303 FT_Memory memory = face->root.memory; 304 TT_Name name = face->name_table.names + found_apple; 305 FT_UInt len = name->stringLength; 306 FT_Error error = FT_Err_Ok; 307 308 FT_UNUSED( error ); 309 310 311 if ( !FT_ALLOC( result, len + 1 ) ) 312 { 313 FT_Stream stream = face->name_table.stream; 314 315 316 if ( FT_STREAM_SEEK( name->stringOffset ) || 317 FT_STREAM_READ( result, len ) ) 318 { 319 name->stringOffset = 0; 320 name->stringLength = 0; 321 FT_FREE( name->string ); 322 FT_FREE( result ); 323 goto Exit; 324 } 325 ((char*)result)[len] = '\0'; 326 } 327 } 328 329 Exit: 330 face->postscript_name = result; 331 return result; 332 } 333 334 335 FT_DEFINE_SERVICE_PSFONTNAMEREC( 336 sfnt_service_ps_name, 337 338 (FT_PsName_GetFunc)sfnt_get_ps_name /* get_ps_font_name */ 339 ) 340 341 342 /* 343 * TT CMAP INFO 344 */ 345 FT_DEFINE_SERVICE_TTCMAPSREC( 346 tt_service_get_cmap_info, 347 348 (TT_CMap_Info_GetFunc)tt_get_cmap_info /* get_cmap_info */ 349 ) 350 351 352#ifdef TT_CONFIG_OPTION_BDF 353 354 static FT_Error 355 sfnt_get_charset_id( TT_Face face, 356 const char* *acharset_encoding, 357 const char* *acharset_registry ) 358 { 359 BDF_PropertyRec encoding, registry; 360 FT_Error error; 361 362 363 /* XXX: I don't know whether this is correct, since 364 * tt_face_find_bdf_prop only returns something correct if we have 365 * previously selected a size that is listed in the BDF table. 366 * Should we change the BDF table format to include single offsets 367 * for `CHARSET_REGISTRY' and `CHARSET_ENCODING'? 368 */ 369 error = tt_face_find_bdf_prop( face, "CHARSET_REGISTRY", ®istry ); 370 if ( !error ) 371 { 372 error = tt_face_find_bdf_prop( face, "CHARSET_ENCODING", &encoding ); 373 if ( !error ) 374 { 375 if ( registry.type == BDF_PROPERTY_TYPE_ATOM && 376 encoding.type == BDF_PROPERTY_TYPE_ATOM ) 377 { 378 *acharset_encoding = encoding.u.atom; 379 *acharset_registry = registry.u.atom; 380 } 381 else 382 error = FT_THROW( Invalid_Argument ); 383 } 384 } 385 386 return error; 387 } 388 389 390 FT_DEFINE_SERVICE_BDFRec( 391 sfnt_service_bdf, 392 393 (FT_BDF_GetCharsetIdFunc)sfnt_get_charset_id, /* get_charset_id */ 394 (FT_BDF_GetPropertyFunc) tt_face_find_bdf_prop /* get_property */ 395 ) 396 397 398#endif /* TT_CONFIG_OPTION_BDF */ 399 400 401 /* 402 * SERVICE LIST 403 */ 404 405#if defined TT_CONFIG_OPTION_POSTSCRIPT_NAMES && defined TT_CONFIG_OPTION_BDF 406 FT_DEFINE_SERVICEDESCREC5( 407 sfnt_services, 408 409 FT_SERVICE_ID_SFNT_TABLE, &SFNT_SERVICE_SFNT_TABLE_GET, 410 FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &SFNT_SERVICE_PS_NAME_GET, 411 FT_SERVICE_ID_GLYPH_DICT, &SFNT_SERVICE_GLYPH_DICT_GET, 412 FT_SERVICE_ID_BDF, &SFNT_SERVICE_BDF_GET, 413 FT_SERVICE_ID_TT_CMAP, &TT_SERVICE_CMAP_INFO_GET ) 414#elif defined TT_CONFIG_OPTION_POSTSCRIPT_NAMES 415 FT_DEFINE_SERVICEDESCREC4( 416 sfnt_services, 417 418 FT_SERVICE_ID_SFNT_TABLE, &SFNT_SERVICE_SFNT_TABLE_GET, 419 FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &SFNT_SERVICE_PS_NAME_GET, 420 FT_SERVICE_ID_GLYPH_DICT, &SFNT_SERVICE_GLYPH_DICT_GET, 421 FT_SERVICE_ID_TT_CMAP, &TT_SERVICE_CMAP_INFO_GET ) 422#elif defined TT_CONFIG_OPTION_BDF 423 FT_DEFINE_SERVICEDESCREC4( 424 sfnt_services, 425 426 FT_SERVICE_ID_SFNT_TABLE, &SFNT_SERVICE_SFNT_TABLE_GET, 427 FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &SFNT_SERVICE_PS_NAME_GET, 428 FT_SERVICE_ID_BDF, &SFNT_SERVICE_BDF_GET, 429 FT_SERVICE_ID_TT_CMAP, &TT_SERVICE_CMAP_INFO_GET ) 430#else 431 FT_DEFINE_SERVICEDESCREC3( 432 sfnt_services, 433 434 FT_SERVICE_ID_SFNT_TABLE, &SFNT_SERVICE_SFNT_TABLE_GET, 435 FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &SFNT_SERVICE_PS_NAME_GET, 436 FT_SERVICE_ID_TT_CMAP, &TT_SERVICE_CMAP_INFO_GET ) 437#endif 438 439 440 FT_CALLBACK_DEF( FT_Module_Interface ) 441 sfnt_get_interface( FT_Module module, 442 const char* module_interface ) 443 { 444 /* SFNT_SERVICES_GET dereferences `library' in PIC mode */ 445#ifdef FT_CONFIG_OPTION_PIC 446 FT_Library library; 447 448 449 if ( !module ) 450 return NULL; 451 library = module->library; 452 if ( !library ) 453 return NULL; 454#else 455 FT_UNUSED( module ); 456#endif 457 458 return ft_service_list_lookup( SFNT_SERVICES_GET, module_interface ); 459 } 460 461 462#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS 463#define PUT_EMBEDDED_BITMAPS( a ) a 464#else 465#define PUT_EMBEDDED_BITMAPS( a ) NULL 466#endif 467 468#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES 469#define PUT_PS_NAMES( a ) a 470#else 471#define PUT_PS_NAMES( a ) NULL 472#endif 473 474 FT_DEFINE_SFNT_INTERFACE( 475 sfnt_interface, 476 477 tt_face_goto_table, /* TT_Loader_GotoTableFunc goto_table */ 478 479 sfnt_init_face, /* TT_Init_Face_Func init_face */ 480 sfnt_load_face, /* TT_Load_Face_Func load_face */ 481 sfnt_done_face, /* TT_Done_Face_Func done_face */ 482 sfnt_get_interface, /* FT_Module_Requester get_interface */ 483 484 tt_face_load_any, /* TT_Load_Any_Func load_any */ 485 486 tt_face_load_head, /* TT_Load_Table_Func load_head */ 487 tt_face_load_hhea, /* TT_Load_Metrics_Func load_hhea */ 488 tt_face_load_cmap, /* TT_Load_Table_Func load_cmap */ 489 tt_face_load_maxp, /* TT_Load_Table_Func load_maxp */ 490 tt_face_load_os2, /* TT_Load_Table_Func load_os2 */ 491 tt_face_load_post, /* TT_Load_Table_Func load_post */ 492 493 tt_face_load_name, /* TT_Load_Table_Func load_name */ 494 tt_face_free_name, /* TT_Free_Table_Func free_name */ 495 496 tt_face_load_kern, /* TT_Load_Table_Func load_kern */ 497 tt_face_load_gasp, /* TT_Load_Table_Func load_gasp */ 498 tt_face_load_pclt, /* TT_Load_Table_Func load_init */ 499 500 /* see `ttload.h' */ 501 PUT_EMBEDDED_BITMAPS( tt_face_load_bhed ), 502 /* TT_Load_Table_Func load_bhed */ 503 PUT_EMBEDDED_BITMAPS( tt_face_load_sbit_image ), 504 /* TT_Load_SBit_Image_Func load_sbit_image */ 505 506 /* see `ttpost.h' */ 507 PUT_PS_NAMES( tt_face_get_ps_name ), 508 /* TT_Get_PS_Name_Func get_psname */ 509 PUT_PS_NAMES( tt_face_free_ps_names ), 510 /* TT_Free_Table_Func free_psnames */ 511 512 /* since version 2.1.8 */ 513 tt_face_get_kerning, /* TT_Face_GetKerningFunc get_kerning */ 514 515 /* since version 2.2 */ 516 tt_face_load_font_dir, /* TT_Load_Table_Func load_font_dir */ 517 tt_face_load_hmtx, /* TT_Load_Metrics_Func load_hmtx */ 518 519 /* see `ttsbit.h' and `sfnt.h' */ 520 PUT_EMBEDDED_BITMAPS( tt_face_load_sbit ), 521 /* TT_Load_Table_Func load_eblc */ 522 PUT_EMBEDDED_BITMAPS( tt_face_free_sbit ), 523 /* TT_Free_Table_Func free_eblc */ 524 525 PUT_EMBEDDED_BITMAPS( tt_face_set_sbit_strike ), 526 /* TT_Set_SBit_Strike_Func set_sbit_strike */ 527 PUT_EMBEDDED_BITMAPS( tt_face_load_strike_metrics ), 528 /* TT_Load_Strike_Metrics_Func load_strike_metrics */ 529 530 tt_face_get_metrics, /* TT_Get_Metrics_Func get_metrics */ 531 532 tt_face_get_name /* TT_Get_Name_Func get_name */ 533 ) 534 535 536 FT_DEFINE_MODULE( 537 sfnt_module_class, 538 539 0, /* not a font driver or renderer */ 540 sizeof ( FT_ModuleRec ), 541 542 "sfnt", /* driver name */ 543 0x10000L, /* driver version 1.0 */ 544 0x20000L, /* driver requires FreeType 2.0 or higher */ 545 546 (const void*)&SFNT_INTERFACE_GET, /* module specific interface */ 547 548 (FT_Module_Constructor)NULL, /* module_init */ 549 (FT_Module_Destructor) NULL, /* module_done */ 550 (FT_Module_Requester) sfnt_get_interface /* get_interface */ 551 ) 552 553 554/* END */ 555