1 /***************************************************************************/ 2 /* */ 3 /* winfnt.c */ 4 /* */ 5 /* FreeType font driver for Windows FNT/FON files */ 6 /* */ 7 /* Copyright 1996-2001, 2002, 2003, 2004, 2006, 2007, 2008 by */ 8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */ 9 /* Copyright 2003 Huw D M Davies for Codeweavers */ 10 /* Copyright 2007 Dmitry Timoshkov for Codeweavers */ 11 /* */ 12 /* This file is part of the FreeType project, and may only be used, */ 13 /* modified, and distributed under the terms of the FreeType project */ 14 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ 15 /* this file you indicate that you have read the license and */ 16 /* understand and accept it fully. */ 17 /* */ 18 /***************************************************************************/ 19 20 21 #include <ft2build.h> 22 #include FT_WINFONTS_H 23 #include FT_INTERNAL_DEBUG_H 24 #include FT_INTERNAL_STREAM_H 25 #include FT_INTERNAL_OBJECTS_H 26 27 #include "winfnt.h" 28 #include "fnterrs.h" 29 #include FT_SERVICE_WINFNT_H 30 #include FT_SERVICE_XFREE86_NAME_H 31 32 /*************************************************************************/ 33 /* */ 34 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 35 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 36 /* messages during execution. */ 37 /* */ 38 #undef FT_COMPONENT 39 #define FT_COMPONENT trace_winfnt 40 41 42 static const FT_Frame_Field winmz_header_fields[] = 43 { 44 #undef FT_STRUCTURE 45 #define FT_STRUCTURE WinMZ_HeaderRec 46 47 FT_FRAME_START( 64 ), 48 FT_FRAME_USHORT_LE ( magic ), 49 FT_FRAME_SKIP_BYTES( 29 * 2 ), 50 FT_FRAME_ULONG_LE ( lfanew ), 51 FT_FRAME_END 52 }; 53 54 static const FT_Frame_Field winne_header_fields[] = 55 { 56 #undef FT_STRUCTURE 57 #define FT_STRUCTURE WinNE_HeaderRec 58 59 FT_FRAME_START( 40 ), 60 FT_FRAME_USHORT_LE ( magic ), 61 FT_FRAME_SKIP_BYTES( 34 ), 62 FT_FRAME_USHORT_LE ( resource_tab_offset ), 63 FT_FRAME_USHORT_LE ( rname_tab_offset ), 64 FT_FRAME_END 65 }; 66 67 static const FT_Frame_Field winpe32_header_fields[] = 68 { 69 #undef FT_STRUCTURE 70 #define FT_STRUCTURE WinPE32_HeaderRec 71 72 FT_FRAME_START( 248 ), 73 FT_FRAME_ULONG_LE ( magic ), /* PE00 */ 74 FT_FRAME_USHORT_LE ( machine ), /* 0x014c - i386 */ 75 FT_FRAME_USHORT_LE ( number_of_sections ), 76 FT_FRAME_SKIP_BYTES( 12 ), 77 FT_FRAME_USHORT_LE ( size_of_optional_header ), 78 FT_FRAME_SKIP_BYTES( 2 ), 79 FT_FRAME_USHORT_LE ( magic32 ), /* 0x10b */ 80 FT_FRAME_SKIP_BYTES( 110 ), 81 FT_FRAME_ULONG_LE ( rsrc_virtual_address ), 82 FT_FRAME_ULONG_LE ( rsrc_size ), 83 FT_FRAME_SKIP_BYTES( 104 ), 84 FT_FRAME_END 85 }; 86 87 static const FT_Frame_Field winpe32_section_fields[] = 88 { 89 #undef FT_STRUCTURE 90 #define FT_STRUCTURE WinPE32_SectionRec 91 92 FT_FRAME_START( 40 ), 93 FT_FRAME_BYTES ( name, 8 ), 94 FT_FRAME_SKIP_BYTES( 4 ), 95 FT_FRAME_ULONG_LE ( virtual_address ), 96 FT_FRAME_ULONG_LE ( size_of_raw_data ), 97 FT_FRAME_ULONG_LE ( pointer_to_raw_data ), 98 FT_FRAME_SKIP_BYTES( 16 ), 99 FT_FRAME_END 100 }; 101 102 static const FT_Frame_Field winpe_rsrc_dir_fields[] = 103 { 104 #undef FT_STRUCTURE 105 #define FT_STRUCTURE WinPE_RsrcDirRec 106 107 FT_FRAME_START( 16 ), 108 FT_FRAME_ULONG_LE ( characteristics ), 109 FT_FRAME_ULONG_LE ( time_date_stamp ), 110 FT_FRAME_USHORT_LE( major_version ), 111 FT_FRAME_USHORT_LE( minor_version ), 112 FT_FRAME_USHORT_LE( number_of_named_entries ), 113 FT_FRAME_USHORT_LE( number_of_id_entries ), 114 FT_FRAME_END 115 }; 116 117 static const FT_Frame_Field winpe_rsrc_dir_entry_fields[] = 118 { 119 #undef FT_STRUCTURE 120 #define FT_STRUCTURE WinPE_RsrcDirEntryRec 121 122 FT_FRAME_START( 8 ), 123 FT_FRAME_ULONG_LE( name ), 124 FT_FRAME_ULONG_LE( offset ), 125 FT_FRAME_END 126 }; 127 128 static const FT_Frame_Field winpe_rsrc_data_entry_fields[] = 129 { 130 #undef FT_STRUCTURE 131 #define FT_STRUCTURE WinPE_RsrcDataEntryRec 132 133 FT_FRAME_START( 16 ), 134 FT_FRAME_ULONG_LE( offset_to_data ), 135 FT_FRAME_ULONG_LE( size ), 136 FT_FRAME_ULONG_LE( code_page ), 137 FT_FRAME_ULONG_LE( reserved ), 138 FT_FRAME_END 139 }; 140 141 static const FT_Frame_Field winfnt_header_fields[] = 142 { 143 #undef FT_STRUCTURE 144 #define FT_STRUCTURE FT_WinFNT_HeaderRec 145 146 FT_FRAME_START( 148 ), 147 FT_FRAME_USHORT_LE( version ), 148 FT_FRAME_ULONG_LE ( file_size ), 149 FT_FRAME_BYTES ( copyright, 60 ), 150 FT_FRAME_USHORT_LE( file_type ), 151 FT_FRAME_USHORT_LE( nominal_point_size ), 152 FT_FRAME_USHORT_LE( vertical_resolution ), 153 FT_FRAME_USHORT_LE( horizontal_resolution ), 154 FT_FRAME_USHORT_LE( ascent ), 155 FT_FRAME_USHORT_LE( internal_leading ), 156 FT_FRAME_USHORT_LE( external_leading ), 157 FT_FRAME_BYTE ( italic ), 158 FT_FRAME_BYTE ( underline ), 159 FT_FRAME_BYTE ( strike_out ), 160 FT_FRAME_USHORT_LE( weight ), 161 FT_FRAME_BYTE ( charset ), 162 FT_FRAME_USHORT_LE( pixel_width ), 163 FT_FRAME_USHORT_LE( pixel_height ), 164 FT_FRAME_BYTE ( pitch_and_family ), 165 FT_FRAME_USHORT_LE( avg_width ), 166 FT_FRAME_USHORT_LE( max_width ), 167 FT_FRAME_BYTE ( first_char ), 168 FT_FRAME_BYTE ( last_char ), 169 FT_FRAME_BYTE ( default_char ), 170 FT_FRAME_BYTE ( break_char ), 171 FT_FRAME_USHORT_LE( bytes_per_row ), 172 FT_FRAME_ULONG_LE ( device_offset ), 173 FT_FRAME_ULONG_LE ( face_name_offset ), 174 FT_FRAME_ULONG_LE ( bits_pointer ), 175 FT_FRAME_ULONG_LE ( bits_offset ), 176 FT_FRAME_BYTE ( reserved ), 177 FT_FRAME_ULONG_LE ( flags ), 178 FT_FRAME_USHORT_LE( A_space ), 179 FT_FRAME_USHORT_LE( B_space ), 180 FT_FRAME_USHORT_LE( C_space ), 181 FT_FRAME_ULONG_LE ( color_table_offset ), 182 FT_FRAME_BYTES ( reserved1, 16 ), 183 FT_FRAME_END 184 }; 185 186 187 static void fnt_font_done(FNT_Face face)188 fnt_font_done( FNT_Face face ) 189 { 190 FT_Memory memory = FT_FACE( face )->memory; 191 FT_Stream stream = FT_FACE( face )->stream; 192 FNT_Font font = face->font; 193 194 195 if ( !font ) 196 return; 197 198 if ( font->fnt_frame ) 199 FT_FRAME_RELEASE( font->fnt_frame ); 200 FT_FREE( font->family_name ); 201 202 FT_FREE( font ); 203 face->font = 0; 204 } 205 206 207 static FT_Error fnt_font_load(FNT_Font font,FT_Stream stream)208 fnt_font_load( FNT_Font font, 209 FT_Stream stream ) 210 { 211 FT_Error error; 212 FT_WinFNT_Header header = &font->header; 213 FT_Bool new_format; 214 FT_UInt size; 215 216 217 /* first of all, read the FNT header */ 218 if ( FT_STREAM_SEEK( font->offset ) || 219 FT_STREAM_READ_FIELDS( winfnt_header_fields, header ) ) 220 goto Exit; 221 222 /* check header */ 223 if ( header->version != 0x200 && 224 header->version != 0x300 ) 225 { 226 FT_TRACE2(( "[not a valid FNT file]\n" )); 227 error = FNT_Err_Unknown_File_Format; 228 goto Exit; 229 } 230 231 new_format = FT_BOOL( font->header.version == 0x300 ); 232 size = new_format ? 148 : 118; 233 234 if ( header->file_size < size ) 235 { 236 FT_TRACE2(( "[not a valid FNT file]\n" )); 237 error = FNT_Err_Unknown_File_Format; 238 goto Exit; 239 } 240 241 /* Version 2 doesn't have these fields */ 242 if ( header->version == 0x200 ) 243 { 244 header->flags = 0; 245 header->A_space = 0; 246 header->B_space = 0; 247 header->C_space = 0; 248 249 header->color_table_offset = 0; 250 } 251 252 if ( header->file_type & 1 ) 253 { 254 FT_TRACE2(( "[can't handle vector FNT fonts]\n" )); 255 error = FNT_Err_Unknown_File_Format; 256 goto Exit; 257 } 258 259 /* this is a FNT file/table; extract its frame */ 260 if ( FT_STREAM_SEEK( font->offset ) || 261 FT_FRAME_EXTRACT( header->file_size, font->fnt_frame ) ) 262 goto Exit; 263 264 Exit: 265 return error; 266 } 267 268 269 static FT_Error fnt_face_get_dll_font(FNT_Face face,FT_Int face_index)270 fnt_face_get_dll_font( FNT_Face face, 271 FT_Int face_index ) 272 { 273 FT_Error error; 274 FT_Stream stream = FT_FACE( face )->stream; 275 FT_Memory memory = FT_FACE( face )->memory; 276 WinMZ_HeaderRec mz_header; 277 278 279 face->font = 0; 280 281 /* does it begin with an MZ header? */ 282 if ( FT_STREAM_SEEK( 0 ) || 283 FT_STREAM_READ_FIELDS( winmz_header_fields, &mz_header ) ) 284 goto Exit; 285 286 error = FNT_Err_Unknown_File_Format; 287 if ( mz_header.magic == WINFNT_MZ_MAGIC ) 288 { 289 /* yes, now look for an NE header in the file */ 290 WinNE_HeaderRec ne_header; 291 292 293 FT_TRACE2(( "MZ signature found\n" )); 294 295 if ( FT_STREAM_SEEK( mz_header.lfanew ) || 296 FT_STREAM_READ_FIELDS( winne_header_fields, &ne_header ) ) 297 goto Exit; 298 299 error = FNT_Err_Unknown_File_Format; 300 if ( ne_header.magic == WINFNT_NE_MAGIC ) 301 { 302 /* good, now look into the resource table for each FNT resource */ 303 FT_ULong res_offset = mz_header.lfanew + 304 ne_header.resource_tab_offset; 305 FT_UShort size_shift; 306 FT_UShort font_count = 0; 307 FT_ULong font_offset = 0; 308 309 310 FT_TRACE2(( "NE signature found\n" )); 311 312 if ( FT_STREAM_SEEK( res_offset ) || 313 FT_FRAME_ENTER( ne_header.rname_tab_offset - 314 ne_header.resource_tab_offset ) ) 315 goto Exit; 316 317 size_shift = FT_GET_USHORT_LE(); 318 319 for (;;) 320 { 321 FT_UShort type_id, count; 322 323 324 type_id = FT_GET_USHORT_LE(); 325 if ( !type_id ) 326 break; 327 328 count = FT_GET_USHORT_LE(); 329 330 if ( type_id == 0x8008U ) 331 { 332 font_count = count; 333 font_offset = (FT_ULong)( FT_STREAM_POS() + 4 + 334 ( stream->cursor - stream->limit ) ); 335 break; 336 } 337 338 stream->cursor += 4 + count * 12; 339 } 340 341 FT_FRAME_EXIT(); 342 343 if ( !font_count || !font_offset ) 344 { 345 FT_TRACE2(( "this file doesn't contain any FNT resources!\n" )); 346 error = FNT_Err_Invalid_File_Format; 347 goto Exit; 348 } 349 350 /* loading `winfnt_header_fields' needs at least 118 bytes; */ 351 /* use this as a rough measure to check the expected font size */ 352 if ( font_count * 118UL > stream->size ) 353 { 354 FT_TRACE2(( "invalid number of faces\n" )); 355 error = FNT_Err_Invalid_File_Format; 356 goto Exit; 357 } 358 359 face->root.num_faces = font_count; 360 361 if ( face_index >= font_count ) 362 { 363 error = FNT_Err_Invalid_Argument; 364 goto Exit; 365 } 366 else if ( face_index < 0 ) 367 goto Exit; 368 369 if ( FT_NEW( face->font ) ) 370 goto Exit; 371 372 if ( FT_STREAM_SEEK( font_offset + face_index * 12 ) || 373 FT_FRAME_ENTER( 12 ) ) 374 goto Fail; 375 376 face->font->offset = (FT_ULong)FT_GET_USHORT_LE() << size_shift; 377 face->font->fnt_size = (FT_ULong)FT_GET_USHORT_LE() << size_shift; 378 379 stream->cursor += 8; 380 381 FT_FRAME_EXIT(); 382 383 error = fnt_font_load( face->font, stream ); 384 } 385 else if ( ne_header.magic == WINFNT_PE_MAGIC ) 386 { 387 WinPE32_HeaderRec pe32_header; 388 WinPE32_SectionRec pe32_section; 389 WinPE_RsrcDirRec root_dir, name_dir, lang_dir; 390 WinPE_RsrcDirEntryRec dir_entry1, dir_entry2, dir_entry3; 391 WinPE_RsrcDataEntryRec data_entry; 392 393 FT_Long root_dir_offset, name_dir_offset, lang_dir_offset; 394 FT_UShort i, j, k; 395 396 397 FT_TRACE2(( "PE signature found\n" )); 398 399 if ( FT_STREAM_SEEK( mz_header.lfanew ) || 400 FT_STREAM_READ_FIELDS( winpe32_header_fields, &pe32_header ) ) 401 goto Exit; 402 403 FT_TRACE2(( "magic %04lx, machine %02x, number_of_sections %u, " 404 "size_of_optional_header %02x\n" 405 "magic32 %02x, rsrc_virtual_address %04lx, " 406 "rsrc_size %04lx\n", 407 pe32_header.magic, pe32_header.machine, 408 pe32_header.number_of_sections, 409 pe32_header.size_of_optional_header, 410 pe32_header.magic32, pe32_header.rsrc_virtual_address, 411 pe32_header.rsrc_size )); 412 413 if ( pe32_header.magic != WINFNT_PE_MAGIC /* check full signature */ || 414 pe32_header.machine != 0x014c /* i386 */ || 415 pe32_header.size_of_optional_header != 0xe0 /* FIXME */ || 416 pe32_header.magic32 != 0x10b ) 417 { 418 FT_TRACE2(( "this file has an invalid PE header\n" )); 419 error = FNT_Err_Invalid_File_Format; 420 goto Exit; 421 } 422 423 face->root.num_faces = 0; 424 425 for ( i = 0; i < pe32_header.number_of_sections; i++ ) 426 { 427 if ( FT_STREAM_READ_FIELDS( winpe32_section_fields, 428 &pe32_section ) ) 429 goto Exit; 430 431 FT_TRACE2(( "name %.8s, va %04lx, size %04lx, offset %04lx\n", 432 pe32_section.name, pe32_section.virtual_address, 433 pe32_section.size_of_raw_data, 434 pe32_section.pointer_to_raw_data )); 435 436 if ( pe32_header.rsrc_virtual_address == 437 pe32_section.virtual_address ) 438 goto Found_rsrc_section; 439 } 440 441 FT_TRACE2(( "this file doesn't contain any resources\n" )); 442 error = FNT_Err_Invalid_File_Format; 443 goto Exit; 444 445 Found_rsrc_section: 446 FT_TRACE2(( "found resources section %.8s\n", pe32_section.name )); 447 448 if ( FT_STREAM_SEEK( pe32_section.pointer_to_raw_data ) || 449 FT_STREAM_READ_FIELDS( winpe_rsrc_dir_fields, &root_dir ) ) 450 goto Exit; 451 452 root_dir_offset = pe32_section.pointer_to_raw_data; 453 454 for ( i = 0; i < root_dir.number_of_named_entries + 455 root_dir.number_of_id_entries; i++ ) 456 { 457 if ( FT_STREAM_SEEK( root_dir_offset + 16 + i * 8 ) || 458 FT_STREAM_READ_FIELDS( winpe_rsrc_dir_entry_fields, 459 &dir_entry1 ) ) 460 goto Exit; 461 462 if ( !(dir_entry1.offset & 0x80000000UL ) /* DataIsDirectory */ ) 463 { 464 error = FNT_Err_Invalid_File_Format; 465 goto Exit; 466 } 467 468 dir_entry1.offset &= ~0x80000000UL; 469 470 name_dir_offset = pe32_section.pointer_to_raw_data + 471 dir_entry1.offset; 472 473 if ( FT_STREAM_SEEK( pe32_section.pointer_to_raw_data + 474 dir_entry1.offset ) || 475 FT_STREAM_READ_FIELDS( winpe_rsrc_dir_fields, &name_dir ) ) 476 goto Exit; 477 478 for ( j = 0; j < name_dir.number_of_named_entries + 479 name_dir.number_of_id_entries; j++ ) 480 { 481 if ( FT_STREAM_SEEK( name_dir_offset + 16 + j * 8 ) || 482 FT_STREAM_READ_FIELDS( winpe_rsrc_dir_entry_fields, 483 &dir_entry2 ) ) 484 goto Exit; 485 486 if ( !(dir_entry2.offset & 0x80000000UL ) /* DataIsDirectory */ ) 487 { 488 error = FNT_Err_Invalid_File_Format; 489 goto Exit; 490 } 491 492 dir_entry2.offset &= ~0x80000000UL; 493 494 lang_dir_offset = pe32_section.pointer_to_raw_data + 495 dir_entry2.offset; 496 497 if ( FT_STREAM_SEEK( pe32_section.pointer_to_raw_data + 498 dir_entry2.offset ) || 499 FT_STREAM_READ_FIELDS( winpe_rsrc_dir_fields, &lang_dir ) ) 500 goto Exit; 501 502 for ( k = 0; k < lang_dir.number_of_named_entries + 503 lang_dir.number_of_id_entries; k++ ) 504 { 505 if ( FT_STREAM_SEEK( lang_dir_offset + 16 + k * 8 ) || 506 FT_STREAM_READ_FIELDS( winpe_rsrc_dir_entry_fields, 507 &dir_entry3 ) ) 508 goto Exit; 509 510 if ( dir_entry2.offset & 0x80000000UL /* DataIsDirectory */ ) 511 { 512 error = FNT_Err_Invalid_File_Format; 513 goto Exit; 514 } 515 516 if ( dir_entry1.name == 8 /* RT_FONT */ ) 517 { 518 if ( FT_STREAM_SEEK( root_dir_offset + dir_entry3.offset ) || 519 FT_STREAM_READ_FIELDS( winpe_rsrc_data_entry_fields, 520 &data_entry ) ) 521 goto Exit; 522 523 FT_TRACE2(( "found font #%lu, offset %04lx, " 524 "size %04lx, cp %lu\n", 525 dir_entry2.name, 526 pe32_section.pointer_to_raw_data + 527 data_entry.offset_to_data - 528 pe32_section.virtual_address, 529 data_entry.size, data_entry.code_page )); 530 531 if ( face_index == face->root.num_faces ) 532 { 533 if ( FT_NEW( face->font ) ) 534 goto Exit; 535 536 face->font->offset = pe32_section.pointer_to_raw_data + 537 data_entry.offset_to_data - 538 pe32_section.virtual_address; 539 face->font->fnt_size = data_entry.size; 540 541 error = fnt_font_load( face->font, stream ); 542 if ( error ) 543 { 544 FT_TRACE2(( "font #%lu load error %d\n", 545 dir_entry2.name, error )); 546 goto Fail; 547 } 548 else 549 FT_TRACE2(( "font #%lu successfully loaded\n", 550 dir_entry2.name )); 551 } 552 553 face->root.num_faces++; 554 } 555 } 556 } 557 } 558 } 559 560 if ( !face->root.num_faces ) 561 { 562 FT_TRACE2(( "this file doesn't contain any RT_FONT resources\n" )); 563 error = FNT_Err_Invalid_File_Format; 564 goto Exit; 565 } 566 567 if ( face_index >= face->root.num_faces ) 568 { 569 error = FNT_Err_Invalid_Argument; 570 goto Exit; 571 } 572 } 573 574 Fail: 575 if ( error ) 576 fnt_font_done( face ); 577 578 Exit: 579 return error; 580 } 581 582 583 typedef struct FNT_CMapRec_ 584 { 585 FT_CMapRec cmap; 586 FT_UInt32 first; 587 FT_UInt32 count; 588 589 } FNT_CMapRec, *FNT_CMap; 590 591 592 static FT_Error fnt_cmap_init(FNT_CMap cmap)593 fnt_cmap_init( FNT_CMap cmap ) 594 { 595 FNT_Face face = (FNT_Face)FT_CMAP_FACE( cmap ); 596 FNT_Font font = face->font; 597 598 599 cmap->first = (FT_UInt32) font->header.first_char; 600 cmap->count = (FT_UInt32)( font->header.last_char - cmap->first + 1 ); 601 602 return 0; 603 } 604 605 606 static FT_UInt fnt_cmap_char_index(FNT_CMap cmap,FT_UInt32 char_code)607 fnt_cmap_char_index( FNT_CMap cmap, 608 FT_UInt32 char_code ) 609 { 610 FT_UInt gindex = 0; 611 612 613 char_code -= cmap->first; 614 if ( char_code < cmap->count ) 615 /* we artificially increase the glyph index; */ 616 /* FNT_Load_Glyph reverts to the right one */ 617 gindex = (FT_UInt)( char_code + 1 ); 618 return gindex; 619 } 620 621 622 static FT_UInt fnt_cmap_char_next(FNT_CMap cmap,FT_UInt32 * pchar_code)623 fnt_cmap_char_next( FNT_CMap cmap, 624 FT_UInt32 *pchar_code ) 625 { 626 FT_UInt gindex = 0; 627 FT_UInt32 result = 0; 628 FT_UInt32 char_code = *pchar_code + 1; 629 630 631 if ( char_code <= cmap->first ) 632 { 633 result = cmap->first; 634 gindex = 1; 635 } 636 else 637 { 638 char_code -= cmap->first; 639 if ( char_code < cmap->count ) 640 { 641 result = cmap->first + char_code; 642 gindex = (FT_UInt)( char_code + 1 ); 643 } 644 } 645 646 *pchar_code = result; 647 return gindex; 648 } 649 650 651 static const FT_CMap_ClassRec fnt_cmap_class_rec = 652 { 653 sizeof ( FNT_CMapRec ), 654 655 (FT_CMap_InitFunc) fnt_cmap_init, 656 (FT_CMap_DoneFunc) NULL, 657 (FT_CMap_CharIndexFunc)fnt_cmap_char_index, 658 (FT_CMap_CharNextFunc) fnt_cmap_char_next, 659 660 NULL, NULL, NULL, NULL, NULL 661 }; 662 663 static FT_CMap_Class const fnt_cmap_class = &fnt_cmap_class_rec; 664 665 666 static void FNT_Face_Done(FNT_Face face)667 FNT_Face_Done( FNT_Face face ) 668 { 669 FT_Memory memory; 670 671 672 if ( !face ) 673 return; 674 675 memory = FT_FACE_MEMORY( face ); 676 677 fnt_font_done( face ); 678 679 FT_FREE( face->root.available_sizes ); 680 face->root.num_fixed_sizes = 0; 681 } 682 683 684 static FT_Error FNT_Face_Init(FT_Stream stream,FNT_Face face,FT_Int face_index,FT_Int num_params,FT_Parameter * params)685 FNT_Face_Init( FT_Stream stream, 686 FNT_Face face, 687 FT_Int face_index, 688 FT_Int num_params, 689 FT_Parameter* params ) 690 { 691 FT_Error error; 692 FT_Memory memory = FT_FACE_MEMORY( face ); 693 694 FT_UNUSED( num_params ); 695 FT_UNUSED( params ); 696 697 698 /* try to load font from a DLL */ 699 error = fnt_face_get_dll_font( face, face_index ); 700 if ( !error && face_index < 0 ) 701 goto Exit; 702 703 if ( error == FNT_Err_Unknown_File_Format ) 704 { 705 /* this didn't work; try to load a single FNT font */ 706 FNT_Font font; 707 708 if ( FT_NEW( face->font ) ) 709 goto Exit; 710 711 face->root.num_faces = 1; 712 713 font = face->font; 714 font->offset = 0; 715 font->fnt_size = stream->size; 716 717 error = fnt_font_load( font, stream ); 718 719 if ( !error ) 720 { 721 if ( face_index > 0 ) 722 error = FNT_Err_Invalid_Argument; 723 else if ( face_index < 0 ) 724 goto Exit; 725 } 726 } 727 728 if ( error ) 729 goto Fail; 730 731 /* we now need to fill the root FT_Face fields */ 732 /* with relevant information */ 733 { 734 FT_Face root = FT_FACE( face ); 735 FNT_Font font = face->font; 736 FT_PtrDist family_size; 737 738 739 root->face_index = face_index; 740 741 root->face_flags = FT_FACE_FLAG_FIXED_SIZES | 742 FT_FACE_FLAG_HORIZONTAL; 743 744 if ( font->header.avg_width == font->header.max_width ) 745 root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; 746 747 if ( font->header.italic ) 748 root->style_flags |= FT_STYLE_FLAG_ITALIC; 749 750 if ( font->header.weight >= 800 ) 751 root->style_flags |= FT_STYLE_FLAG_BOLD; 752 753 /* set up the `fixed_sizes' array */ 754 if ( FT_NEW_ARRAY( root->available_sizes, 1 ) ) 755 goto Fail; 756 757 root->num_fixed_sizes = 1; 758 759 { 760 FT_Bitmap_Size* bsize = root->available_sizes; 761 FT_UShort x_res, y_res; 762 763 764 bsize->width = font->header.avg_width; 765 bsize->height = (FT_Short)( 766 font->header.pixel_height + font->header.external_leading ); 767 bsize->size = font->header.nominal_point_size << 6; 768 769 x_res = font->header.horizontal_resolution; 770 if ( !x_res ) 771 x_res = 72; 772 773 y_res = font->header.vertical_resolution; 774 if ( !y_res ) 775 y_res = 72; 776 777 bsize->y_ppem = FT_MulDiv( bsize->size, y_res, 72 ); 778 bsize->y_ppem = FT_PIX_ROUND( bsize->y_ppem ); 779 780 /* 781 * this reads: 782 * 783 * the nominal height is larger than the bbox's height 784 * 785 * => nominal_point_size contains incorrect value; 786 * use pixel_height as the nominal height 787 */ 788 if ( bsize->y_ppem > ( font->header.pixel_height << 6 ) ) 789 { 790 FT_TRACE2(( "use pixel_height as the nominal height\n" )); 791 792 bsize->y_ppem = font->header.pixel_height << 6; 793 bsize->size = FT_MulDiv( bsize->y_ppem, 72, y_res ); 794 } 795 796 bsize->x_ppem = FT_MulDiv( bsize->size, x_res, 72 ); 797 bsize->x_ppem = FT_PIX_ROUND( bsize->x_ppem ); 798 } 799 800 { 801 FT_CharMapRec charmap; 802 803 804 charmap.encoding = FT_ENCODING_NONE; 805 charmap.platform_id = 0; 806 charmap.encoding_id = 0; 807 charmap.face = root; 808 809 if ( font->header.charset == FT_WinFNT_ID_MAC ) 810 { 811 charmap.encoding = FT_ENCODING_APPLE_ROMAN; 812 charmap.platform_id = 1; 813 /* charmap.encoding_id = 0; */ 814 } 815 816 error = FT_CMap_New( fnt_cmap_class, 817 NULL, 818 &charmap, 819 NULL ); 820 if ( error ) 821 goto Fail; 822 823 /* Select default charmap */ 824 if ( root->num_charmaps ) 825 root->charmap = root->charmaps[0]; 826 } 827 828 /* setup remaining flags */ 829 830 /* reserve one slot for the .notdef glyph at index 0 */ 831 root->num_glyphs = font->header.last_char - 832 font->header.first_char + 1 + 1; 833 834 if ( font->header.face_name_offset >= font->header.file_size ) 835 { 836 FT_TRACE2(( "invalid family name offset!\n" )); 837 error = FNT_Err_Invalid_File_Format; 838 goto Fail; 839 } 840 family_size = font->header.file_size - font->header.face_name_offset; 841 /* Some broken fonts don't delimit the face name with a final */ 842 /* NULL byte -- the frame is erroneously one byte too small. */ 843 /* We thus allocate one more byte, setting it explicitly to */ 844 /* zero. */ 845 if ( FT_ALLOC( font->family_name, family_size + 1 ) ) 846 goto Fail; 847 848 FT_MEM_COPY( font->family_name, 849 font->fnt_frame + font->header.face_name_offset, 850 family_size ); 851 852 font->family_name[family_size] = '\0'; 853 854 if ( FT_REALLOC( font->family_name, 855 family_size, 856 ft_strlen( font->family_name ) + 1 ) ) 857 goto Fail; 858 859 root->family_name = font->family_name; 860 root->style_name = (char *)"Regular"; 861 862 if ( root->style_flags & FT_STYLE_FLAG_BOLD ) 863 { 864 if ( root->style_flags & FT_STYLE_FLAG_ITALIC ) 865 root->style_name = (char *)"Bold Italic"; 866 else 867 root->style_name = (char *)"Bold"; 868 } 869 else if ( root->style_flags & FT_STYLE_FLAG_ITALIC ) 870 root->style_name = (char *)"Italic"; 871 } 872 goto Exit; 873 874 Fail: 875 FNT_Face_Done( face ); 876 877 Exit: 878 return error; 879 } 880 881 882 static FT_Error FNT_Size_Select(FT_Size size)883 FNT_Size_Select( FT_Size size ) 884 { 885 FNT_Face face = (FNT_Face)size->face; 886 FT_WinFNT_Header header = &face->font->header; 887 888 889 FT_Select_Metrics( size->face, 0 ); 890 891 size->metrics.ascender = header->ascent * 64; 892 size->metrics.descender = -( header->pixel_height - 893 header->ascent ) * 64; 894 size->metrics.max_advance = header->max_width * 64; 895 896 return FNT_Err_Ok; 897 } 898 899 900 static FT_Error FNT_Size_Request(FT_Size size,FT_Size_Request req)901 FNT_Size_Request( FT_Size size, 902 FT_Size_Request req ) 903 { 904 FNT_Face face = (FNT_Face)size->face; 905 FT_WinFNT_Header header = &face->font->header; 906 FT_Bitmap_Size* bsize = size->face->available_sizes; 907 FT_Error error = FNT_Err_Invalid_Pixel_Size; 908 FT_Long height; 909 910 911 height = FT_REQUEST_HEIGHT( req ); 912 height = ( height + 32 ) >> 6; 913 914 switch ( req->type ) 915 { 916 case FT_SIZE_REQUEST_TYPE_NOMINAL: 917 if ( height == ( ( bsize->y_ppem + 32 ) >> 6 ) ) 918 error = FNT_Err_Ok; 919 break; 920 921 case FT_SIZE_REQUEST_TYPE_REAL_DIM: 922 if ( height == header->pixel_height ) 923 error = FNT_Err_Ok; 924 break; 925 926 default: 927 error = FNT_Err_Unimplemented_Feature; 928 break; 929 } 930 931 if ( error ) 932 return error; 933 else 934 return FNT_Size_Select( size ); 935 } 936 937 938 static FT_Error FNT_Load_Glyph(FT_GlyphSlot slot,FT_Size size,FT_UInt glyph_index,FT_Int32 load_flags)939 FNT_Load_Glyph( FT_GlyphSlot slot, 940 FT_Size size, 941 FT_UInt glyph_index, 942 FT_Int32 load_flags ) 943 { 944 FNT_Face face = (FNT_Face)FT_SIZE_FACE( size ); 945 FNT_Font font = face->font; 946 FT_Error error = FNT_Err_Ok; 947 FT_Byte* p; 948 FT_Int len; 949 FT_Bitmap* bitmap = &slot->bitmap; 950 FT_ULong offset; 951 FT_Bool new_format; 952 953 FT_UNUSED( load_flags ); 954 955 956 if ( !face || !font || 957 glyph_index >= (FT_UInt)( FT_FACE( face )->num_glyphs ) ) 958 { 959 error = FNT_Err_Invalid_Argument; 960 goto Exit; 961 } 962 963 if ( glyph_index > 0 ) 964 glyph_index--; /* revert to real index */ 965 else 966 glyph_index = font->header.default_char; /* the .notdef glyph */ 967 968 new_format = FT_BOOL( font->header.version == 0x300 ); 969 len = new_format ? 6 : 4; 970 971 /* jump to glyph entry */ 972 p = font->fnt_frame + ( new_format ? 148 : 118 ) + len * glyph_index; 973 974 bitmap->width = FT_NEXT_SHORT_LE( p ); 975 976 if ( new_format ) 977 offset = FT_NEXT_ULONG_LE( p ); 978 else 979 offset = FT_NEXT_USHORT_LE( p ); 980 981 if ( offset >= font->header.file_size ) 982 { 983 FT_TRACE2(( "invalid FNT offset!\n" )); 984 error = FNT_Err_Invalid_File_Format; 985 goto Exit; 986 } 987 988 /* jump to glyph data */ 989 p = font->fnt_frame + /* font->header.bits_offset */ + offset; 990 991 /* allocate and build bitmap */ 992 { 993 FT_Memory memory = FT_FACE_MEMORY( slot->face ); 994 FT_Int pitch = ( bitmap->width + 7 ) >> 3; 995 FT_Byte* column; 996 FT_Byte* write; 997 998 999 bitmap->pitch = pitch; 1000 bitmap->rows = font->header.pixel_height; 1001 bitmap->pixel_mode = FT_PIXEL_MODE_MONO; 1002 1003 if ( offset + pitch * bitmap->rows >= font->header.file_size ) 1004 { 1005 FT_TRACE2(( "invalid bitmap width\n" )); 1006 error = FNT_Err_Invalid_File_Format; 1007 goto Exit; 1008 } 1009 1010 /* note: since glyphs are stored in columns and not in rows we */ 1011 /* can't use ft_glyphslot_set_bitmap */ 1012 if ( FT_ALLOC_MULT( bitmap->buffer, pitch, bitmap->rows ) ) 1013 goto Exit; 1014 1015 column = (FT_Byte*)bitmap->buffer; 1016 1017 for ( ; pitch > 0; pitch--, column++ ) 1018 { 1019 FT_Byte* limit = p + bitmap->rows; 1020 1021 1022 for ( write = column; p < limit; p++, write += bitmap->pitch ) 1023 *write = *p; 1024 } 1025 } 1026 1027 slot->internal->flags = FT_GLYPH_OWN_BITMAP; 1028 slot->bitmap_left = 0; 1029 slot->bitmap_top = font->header.ascent; 1030 slot->format = FT_GLYPH_FORMAT_BITMAP; 1031 1032 /* now set up metrics */ 1033 slot->metrics.width = bitmap->width << 6; 1034 slot->metrics.height = bitmap->rows << 6; 1035 slot->metrics.horiAdvance = bitmap->width << 6; 1036 slot->metrics.horiBearingX = 0; 1037 slot->metrics.horiBearingY = slot->bitmap_top << 6; 1038 1039 ft_synthesize_vertical_metrics( &slot->metrics, 1040 bitmap->rows << 6 ); 1041 1042 Exit: 1043 return error; 1044 } 1045 1046 1047 static FT_Error winfnt_get_header(FT_Face face,FT_WinFNT_HeaderRec * aheader)1048 winfnt_get_header( FT_Face face, 1049 FT_WinFNT_HeaderRec *aheader ) 1050 { 1051 FNT_Font font = ((FNT_Face)face)->font; 1052 1053 1054 *aheader = font->header; 1055 1056 return 0; 1057 } 1058 1059 1060 static const FT_Service_WinFntRec winfnt_service_rec = 1061 { 1062 winfnt_get_header 1063 }; 1064 1065 /* 1066 * SERVICE LIST 1067 * 1068 */ 1069 1070 static const FT_ServiceDescRec winfnt_services[] = 1071 { 1072 { FT_SERVICE_ID_XF86_NAME, FT_XF86_FORMAT_WINFNT }, 1073 { FT_SERVICE_ID_WINFNT, &winfnt_service_rec }, 1074 { NULL, NULL } 1075 }; 1076 1077 1078 static FT_Module_Interface winfnt_get_service(FT_Driver driver,const FT_String * service_id)1079 winfnt_get_service( FT_Driver driver, 1080 const FT_String* service_id ) 1081 { 1082 FT_UNUSED( driver ); 1083 1084 return ft_service_list_lookup( winfnt_services, service_id ); 1085 } 1086 1087 1088 1089 1090 FT_CALLBACK_TABLE_DEF 1091 const FT_Driver_ClassRec winfnt_driver_class = 1092 { 1093 { 1094 FT_MODULE_FONT_DRIVER | 1095 FT_MODULE_DRIVER_NO_OUTLINES, 1096 sizeof ( FT_DriverRec ), 1097 1098 "winfonts", 1099 0x10000L, 1100 0x20000L, 1101 1102 0, 1103 1104 (FT_Module_Constructor)0, 1105 (FT_Module_Destructor) 0, 1106 (FT_Module_Requester) winfnt_get_service 1107 }, 1108 1109 sizeof( FNT_FaceRec ), 1110 sizeof( FT_SizeRec ), 1111 sizeof( FT_GlyphSlotRec ), 1112 1113 (FT_Face_InitFunc) FNT_Face_Init, 1114 (FT_Face_DoneFunc) FNT_Face_Done, 1115 (FT_Size_InitFunc) 0, 1116 (FT_Size_DoneFunc) 0, 1117 (FT_Slot_InitFunc) 0, 1118 (FT_Slot_DoneFunc) 0, 1119 1120 #ifdef FT_CONFIG_OPTION_OLD_INTERNALS 1121 ft_stub_set_char_sizes, 1122 ft_stub_set_pixel_sizes, 1123 #endif 1124 (FT_Slot_LoadFunc) FNT_Load_Glyph, 1125 1126 (FT_Face_GetKerningFunc) 0, 1127 (FT_Face_AttachFunc) 0, 1128 (FT_Face_GetAdvancesFunc) 0, 1129 1130 (FT_Size_RequestFunc) FNT_Size_Request, 1131 (FT_Size_SelectFunc) FNT_Size_Select 1132 }; 1133 1134 1135 /* END */ 1136