1 /**************************************************************************** 2 * 3 * winfnt.c 4 * 5 * FreeType font driver for Windows FNT/FON files 6 * 7 * Copyright (C) 1996-2023 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 <freetype/ftwinfnt.h> 22 #include <freetype/internal/ftdebug.h> 23 #include <freetype/internal/ftstream.h> 24 #include <freetype/internal/ftobjs.h> 25 #include <freetype/ttnameid.h> 26 27 #include "winfnt.h" 28 #include "fnterrs.h" 29 #include <freetype/internal/services/svwinfnt.h> 30 #include <freetype/internal/services/svfntfmt.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 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 = NULL; 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 { 221 FT_TRACE2(( " not a Windows FNT file\n" )); 222 error = FT_THROW( Unknown_File_Format ); 223 goto Exit; 224 } 225 226 /* check header */ 227 if ( header->version != 0x200 && 228 header->version != 0x300 ) 229 { 230 FT_TRACE2(( " not a Windows FNT file\n" )); 231 error = FT_THROW( Unknown_File_Format ); 232 goto Exit; 233 } 234 235 new_format = FT_BOOL( font->header.version == 0x300 ); 236 size = new_format ? 148 : 118; 237 238 if ( header->file_size < size ) 239 { 240 FT_TRACE2(( " not a Windows FNT file\n" )); 241 error = FT_THROW( Unknown_File_Format ); 242 goto Exit; 243 } 244 245 /* Version 2 doesn't have these fields */ 246 if ( header->version == 0x200 ) 247 { 248 header->flags = 0; 249 header->A_space = 0; 250 header->B_space = 0; 251 header->C_space = 0; 252 253 header->color_table_offset = 0; 254 } 255 256 if ( header->file_type & 1 ) 257 { 258 FT_TRACE2(( "[can't handle vector FNT fonts]\n" )); 259 error = FT_THROW( Unknown_File_Format ); 260 goto Exit; 261 } 262 263 /* this is a FNT file/table; extract its frame */ 264 if ( FT_STREAM_SEEK( font->offset ) || 265 FT_FRAME_EXTRACT( header->file_size, font->fnt_frame ) ) 266 goto Exit; 267 268 Exit: 269 return error; 270 } 271 272 273 static FT_Error fnt_face_get_dll_font(FNT_Face face,FT_Int face_instance_index)274 fnt_face_get_dll_font( FNT_Face face, 275 FT_Int face_instance_index ) 276 { 277 FT_Error error; 278 FT_Stream stream = FT_FACE( face )->stream; 279 FT_Memory memory = FT_FACE( face )->memory; 280 WinMZ_HeaderRec mz_header; 281 FT_Long face_index; 282 283 284 face->font = NULL; 285 286 face_index = FT_ABS( face_instance_index ) & 0xFFFF; 287 288 /* does it begin with an MZ header? */ 289 if ( FT_STREAM_SEEK( 0 ) || 290 FT_STREAM_READ_FIELDS( winmz_header_fields, &mz_header ) ) 291 { 292 error = FT_ERR( Unknown_File_Format ); 293 goto Exit; 294 } 295 296 error = FT_ERR( Unknown_File_Format ); 297 if ( mz_header.magic == WINFNT_MZ_MAGIC ) 298 { 299 /* yes, now look for an NE header in the file */ 300 WinNE_HeaderRec ne_header; 301 302 303 FT_TRACE2(( "MZ signature found\n" )); 304 305 if ( FT_STREAM_SEEK( mz_header.lfanew ) || 306 FT_STREAM_READ_FIELDS( winne_header_fields, &ne_header ) ) 307 goto Exit; 308 309 error = FT_ERR( Unknown_File_Format ); 310 if ( ne_header.magic == WINFNT_NE_MAGIC ) 311 { 312 /* good, now look into the resource table for each FNT resource */ 313 FT_ULong res_offset = mz_header.lfanew + 314 ne_header.resource_tab_offset; 315 FT_UShort size_shift; 316 FT_UShort font_count = 0; 317 FT_ULong font_offset = 0; 318 319 320 FT_TRACE2(( "NE signature found\n" )); 321 322 if ( FT_STREAM_SEEK( res_offset ) || 323 FT_FRAME_ENTER( ne_header.rname_tab_offset - 324 ne_header.resource_tab_offset ) ) 325 goto Exit; 326 327 size_shift = FT_GET_USHORT_LE(); 328 329 /* Microsoft's specification of the executable-file header format */ 330 /* for `New Executable' (NE) doesn't give a limit for the */ 331 /* alignment shift count; however, in 1985, the year of the */ 332 /* specification release, only 32bit values were supported, thus */ 333 /* anything larger than 16 doesn't make sense in general, given */ 334 /* that file offsets are 16bit values, shifted by the alignment */ 335 /* shift count */ 336 if ( size_shift > 16 ) 337 { 338 FT_TRACE2(( "invalid alignment shift count for resource data\n" )); 339 error = FT_THROW( Invalid_File_Format ); 340 goto Exit1; 341 } 342 343 344 for (;;) 345 { 346 FT_UShort type_id, count; 347 348 349 type_id = FT_GET_USHORT_LE(); 350 if ( !type_id ) 351 break; 352 353 count = FT_GET_USHORT_LE(); 354 355 FT_TRACE2(( type_id == 0x8007U ? "RT_FONTDIR count %hu\n" : 356 type_id == 0x8008U ? "RT_FONT count %hu\n" : "", 357 count )); 358 359 if ( type_id == 0x8008U ) 360 { 361 font_count = count; 362 font_offset = FT_STREAM_POS() + 4 + 363 (FT_ULong)( stream->cursor - stream->limit ); 364 break; 365 } 366 367 stream->cursor += 4 + count * 12; 368 } 369 370 FT_FRAME_EXIT(); 371 372 if ( !font_count || !font_offset ) 373 { 374 FT_TRACE2(( "this file doesn't contain any FNT resources\n" )); 375 error = FT_THROW( Invalid_File_Format ); 376 goto Exit; 377 } 378 379 /* loading `winfnt_header_fields' needs at least 118 bytes; */ 380 /* use this as a rough measure to check the expected font size */ 381 if ( font_count * 118UL > stream->size ) 382 { 383 FT_TRACE2(( "invalid number of faces\n" )); 384 error = FT_THROW( Invalid_File_Format ); 385 goto Exit; 386 } 387 388 face->root.num_faces = font_count; 389 390 if ( face_instance_index < 0 ) 391 goto Exit; 392 393 if ( face_index >= font_count ) 394 { 395 error = FT_THROW( Invalid_Argument ); 396 goto Exit; 397 } 398 399 if ( FT_NEW( face->font ) ) 400 goto Exit; 401 402 if ( FT_STREAM_SEEK( font_offset + (FT_ULong)face_index * 12 ) || 403 FT_FRAME_ENTER( 12 ) ) 404 goto Fail; 405 406 face->font->offset = (FT_ULong)FT_GET_USHORT_LE() << size_shift; 407 face->font->fnt_size = (FT_ULong)FT_GET_USHORT_LE() << size_shift; 408 409 stream->cursor += 8; 410 411 FT_FRAME_EXIT(); 412 413 error = fnt_font_load( face->font, stream ); 414 } 415 else if ( ne_header.magic == WINFNT_PE_MAGIC ) 416 { 417 WinPE32_HeaderRec pe32_header; 418 WinPE32_SectionRec pe32_section; 419 WinPE_RsrcDirRec root_dir, name_dir, lang_dir; 420 WinPE_RsrcDirEntryRec dir_entry1, dir_entry2, dir_entry3; 421 WinPE_RsrcDataEntryRec data_entry; 422 423 FT_ULong root_dir_offset, name_dir_offset, lang_dir_offset; 424 FT_UShort i, j, k; 425 426 427 FT_TRACE2(( "PE signature found\n" )); 428 429 if ( FT_STREAM_SEEK( mz_header.lfanew ) || 430 FT_STREAM_READ_FIELDS( winpe32_header_fields, &pe32_header ) ) 431 goto Exit; 432 433 FT_TRACE2(( "magic %04lx, machine %02x, number_of_sections %u, " 434 "size_of_optional_header %02x\n", 435 pe32_header.magic, pe32_header.machine, 436 pe32_header.number_of_sections, 437 pe32_header.size_of_optional_header )); 438 FT_TRACE2(( "magic32 %02x, rsrc_virtual_address %04lx, " 439 "rsrc_size %04lx\n", 440 pe32_header.magic32, pe32_header.rsrc_virtual_address, 441 pe32_header.rsrc_size )); 442 443 if ( pe32_header.magic != WINFNT_PE_MAGIC /* check full signature */ || 444 pe32_header.machine != 0x014C /* i386 */ || 445 pe32_header.size_of_optional_header != 0xE0 /* FIXME */ || 446 pe32_header.magic32 != 0x10B ) 447 { 448 FT_TRACE2(( "this file has an invalid PE header\n" )); 449 error = FT_THROW( Invalid_File_Format ); 450 goto Exit; 451 } 452 453 face->root.num_faces = 0; 454 455 for ( i = 0; i < pe32_header.number_of_sections; i++ ) 456 { 457 if ( FT_STREAM_READ_FIELDS( winpe32_section_fields, 458 &pe32_section ) ) 459 goto Exit; 460 461 FT_TRACE2(( "name %.8s, va %04lx, size %04lx, offset %04lx\n", 462 pe32_section.name, pe32_section.virtual_address, 463 pe32_section.size_of_raw_data, 464 pe32_section.pointer_to_raw_data )); 465 466 if ( pe32_header.rsrc_virtual_address == 467 pe32_section.virtual_address ) 468 goto Found_rsrc_section; 469 } 470 471 FT_TRACE2(( "this file doesn't contain any resources\n" )); 472 error = FT_THROW( Invalid_File_Format ); 473 goto Exit; 474 475 Found_rsrc_section: 476 FT_TRACE2(( "found resources section %.8s\n", pe32_section.name )); 477 478 if ( FT_STREAM_SEEK( pe32_section.pointer_to_raw_data ) || 479 FT_STREAM_READ_FIELDS( winpe_rsrc_dir_fields, &root_dir ) ) 480 goto Exit; 481 482 root_dir_offset = pe32_section.pointer_to_raw_data; 483 484 for ( i = 0; i < root_dir.number_of_named_entries + 485 root_dir.number_of_id_entries; i++ ) 486 { 487 if ( FT_STREAM_SEEK( root_dir_offset + 16 + i * 8 ) || 488 FT_STREAM_READ_FIELDS( winpe_rsrc_dir_entry_fields, 489 &dir_entry1 ) ) 490 goto Exit; 491 492 if ( !( dir_entry1.offset & 0x80000000UL ) /* DataIsDirectory */ ) 493 { 494 error = FT_THROW( Invalid_File_Format ); 495 goto Exit; 496 } 497 498 dir_entry1.offset &= ~0x80000000UL; 499 500 name_dir_offset = pe32_section.pointer_to_raw_data + 501 dir_entry1.offset; 502 503 if ( FT_STREAM_SEEK( pe32_section.pointer_to_raw_data + 504 dir_entry1.offset ) || 505 FT_STREAM_READ_FIELDS( winpe_rsrc_dir_fields, &name_dir ) ) 506 goto Exit; 507 508 for ( j = 0; j < name_dir.number_of_named_entries + 509 name_dir.number_of_id_entries; j++ ) 510 { 511 if ( FT_STREAM_SEEK( name_dir_offset + 16 + j * 8 ) || 512 FT_STREAM_READ_FIELDS( winpe_rsrc_dir_entry_fields, 513 &dir_entry2 ) ) 514 goto Exit; 515 516 if ( !( dir_entry2.offset & 0x80000000UL ) /* DataIsDirectory */ ) 517 { 518 error = FT_THROW( Invalid_File_Format ); 519 goto Exit; 520 } 521 522 dir_entry2.offset &= ~0x80000000UL; 523 524 lang_dir_offset = pe32_section.pointer_to_raw_data + 525 dir_entry2.offset; 526 527 if ( FT_STREAM_SEEK( pe32_section.pointer_to_raw_data + 528 dir_entry2.offset ) || 529 FT_STREAM_READ_FIELDS( winpe_rsrc_dir_fields, &lang_dir ) ) 530 goto Exit; 531 532 for ( k = 0; k < lang_dir.number_of_named_entries + 533 lang_dir.number_of_id_entries; k++ ) 534 { 535 if ( FT_STREAM_SEEK( lang_dir_offset + 16 + k * 8 ) || 536 FT_STREAM_READ_FIELDS( winpe_rsrc_dir_entry_fields, 537 &dir_entry3 ) ) 538 goto Exit; 539 540 if ( dir_entry2.offset & 0x80000000UL /* DataIsDirectory */ ) 541 { 542 error = FT_THROW( Invalid_File_Format ); 543 goto Exit; 544 } 545 546 if ( dir_entry1.name == 8 /* RT_FONT */ ) 547 { 548 if ( FT_STREAM_SEEK( root_dir_offset + dir_entry3.offset ) || 549 FT_STREAM_READ_FIELDS( winpe_rsrc_data_entry_fields, 550 &data_entry ) ) 551 goto Exit; 552 553 FT_TRACE2(( "found font #%lu, offset %04lx, " 554 "size %04lx, cp %lu\n", 555 dir_entry2.name, 556 pe32_section.pointer_to_raw_data + 557 data_entry.offset_to_data - 558 pe32_section.virtual_address, 559 data_entry.size, data_entry.code_page )); 560 561 if ( face_index == face->root.num_faces ) 562 { 563 if ( FT_NEW( face->font ) ) 564 goto Exit; 565 566 face->font->offset = pe32_section.pointer_to_raw_data + 567 data_entry.offset_to_data - 568 pe32_section.virtual_address; 569 face->font->fnt_size = data_entry.size; 570 571 error = fnt_font_load( face->font, stream ); 572 if ( error ) 573 { 574 FT_TRACE2(( "font #%lu load error 0x%x\n", 575 dir_entry2.name, error )); 576 goto Fail; 577 } 578 else 579 FT_TRACE2(( "font #%lu successfully loaded\n", 580 dir_entry2.name )); 581 } 582 583 face->root.num_faces++; 584 } 585 } 586 } 587 } 588 } 589 590 if ( !face->root.num_faces ) 591 { 592 FT_TRACE2(( "this file doesn't contain any RT_FONT resources\n" )); 593 error = FT_THROW( Invalid_File_Format ); 594 goto Exit; 595 } 596 597 if ( face_index >= face->root.num_faces ) 598 { 599 error = FT_THROW( Invalid_Argument ); 600 goto Exit; 601 } 602 } 603 604 Fail: 605 if ( error ) 606 fnt_font_done( face ); 607 608 Exit: 609 return error; 610 611 Exit1: 612 FT_FRAME_EXIT(); 613 goto Exit; 614 } 615 616 617 typedef struct FNT_CMapRec_ 618 { 619 FT_CMapRec cmap; 620 FT_UInt32 first; 621 FT_UInt32 count; 622 623 } FNT_CMapRec, *FNT_CMap; 624 625 626 static FT_Error fnt_cmap_init(FNT_CMap cmap,FT_Pointer pointer)627 fnt_cmap_init( FNT_CMap cmap, 628 FT_Pointer pointer ) 629 { 630 FNT_Face face = (FNT_Face)FT_CMAP_FACE( cmap ); 631 FNT_Font font = face->font; 632 633 FT_UNUSED( pointer ); 634 635 636 cmap->first = (FT_UInt32) font->header.first_char; 637 cmap->count = (FT_UInt32)( font->header.last_char - cmap->first + 1 ); 638 639 return 0; 640 } 641 642 643 static FT_UInt fnt_cmap_char_index(FNT_CMap cmap,FT_UInt32 char_code)644 fnt_cmap_char_index( FNT_CMap cmap, 645 FT_UInt32 char_code ) 646 { 647 FT_UInt gindex = 0; 648 649 650 char_code -= cmap->first; 651 if ( char_code < cmap->count ) 652 /* we artificially increase the glyph index; */ 653 /* FNT_Load_Glyph reverts to the right one */ 654 gindex = (FT_UInt)( char_code + 1 ); 655 return gindex; 656 } 657 658 659 static FT_UInt32 fnt_cmap_char_next(FNT_CMap cmap,FT_UInt32 * pchar_code)660 fnt_cmap_char_next( FNT_CMap cmap, 661 FT_UInt32 *pchar_code ) 662 { 663 FT_UInt gindex = 0; 664 FT_UInt32 result = 0; 665 FT_UInt32 char_code = *pchar_code + 1; 666 667 668 if ( char_code <= cmap->first ) 669 { 670 result = cmap->first; 671 gindex = 1; 672 } 673 else 674 { 675 char_code -= cmap->first; 676 if ( char_code < cmap->count ) 677 { 678 result = cmap->first + char_code; 679 gindex = (FT_UInt)( char_code + 1 ); 680 } 681 } 682 683 *pchar_code = result; 684 return gindex; 685 } 686 687 688 static const FT_CMap_ClassRec fnt_cmap_class_rec = 689 { 690 sizeof ( FNT_CMapRec ), 691 692 (FT_CMap_InitFunc) fnt_cmap_init, 693 (FT_CMap_DoneFunc) NULL, 694 (FT_CMap_CharIndexFunc)fnt_cmap_char_index, 695 (FT_CMap_CharNextFunc) fnt_cmap_char_next, 696 697 NULL, NULL, NULL, NULL, NULL 698 }; 699 700 static FT_CMap_Class const fnt_cmap_class = &fnt_cmap_class_rec; 701 702 703 static void FNT_Face_Done(FT_Face fntface)704 FNT_Face_Done( FT_Face fntface ) /* FNT_Face */ 705 { 706 FNT_Face face = (FNT_Face)fntface; 707 FT_Memory memory; 708 709 710 if ( !face ) 711 return; 712 713 memory = FT_FACE_MEMORY( face ); 714 715 fnt_font_done( face ); 716 717 FT_FREE( fntface->available_sizes ); 718 fntface->num_fixed_sizes = 0; 719 } 720 721 722 static FT_Error FNT_Face_Init(FT_Stream stream,FT_Face fntface,FT_Int face_instance_index,FT_Int num_params,FT_Parameter * params)723 FNT_Face_Init( FT_Stream stream, 724 FT_Face fntface, /* FNT_Face */ 725 FT_Int face_instance_index, 726 FT_Int num_params, 727 FT_Parameter* params ) 728 { 729 FNT_Face face = (FNT_Face)fntface; 730 FT_Error error; 731 FT_Memory memory = FT_FACE_MEMORY( face ); 732 FT_Int face_index; 733 734 FT_UNUSED( num_params ); 735 FT_UNUSED( params ); 736 737 738 FT_TRACE2(( "Windows FNT driver\n" )); 739 740 face_index = FT_ABS( face_instance_index ) & 0xFFFF; 741 742 /* try to load font from a DLL */ 743 error = fnt_face_get_dll_font( face, face_instance_index ); 744 if ( !error && face_instance_index < 0 ) 745 goto Exit; 746 747 if ( FT_ERR_EQ( error, Unknown_File_Format ) ) 748 { 749 /* this didn't work; try to load a single FNT font */ 750 FNT_Font font; 751 752 if ( FT_NEW( face->font ) ) 753 goto Exit; 754 755 fntface->num_faces = 1; 756 757 font = face->font; 758 font->offset = 0; 759 font->fnt_size = stream->size; 760 761 error = fnt_font_load( font, stream ); 762 763 if ( !error ) 764 { 765 if ( face_instance_index < 0 ) 766 goto Exit; 767 768 if ( face_index > 0 ) 769 error = FT_THROW( Invalid_Argument ); 770 } 771 } 772 773 if ( error ) 774 goto Fail; 775 776 /* sanity check */ 777 if ( !face->font->header.pixel_height ) 778 { 779 FT_TRACE2(( "invalid pixel height\n" )); 780 error = FT_THROW( Invalid_File_Format ); 781 goto Fail; 782 } 783 784 /* we now need to fill the root FT_Face fields */ 785 /* with relevant information */ 786 { 787 FT_Face root = FT_FACE( face ); 788 FNT_Font font = face->font; 789 FT_ULong family_size; 790 791 792 root->face_index = face_index; 793 794 root->face_flags |= FT_FACE_FLAG_FIXED_SIZES | 795 FT_FACE_FLAG_HORIZONTAL; 796 797 if ( font->header.avg_width == font->header.max_width ) 798 root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; 799 800 if ( font->header.italic ) 801 root->style_flags |= FT_STYLE_FLAG_ITALIC; 802 803 if ( font->header.weight >= 800 ) 804 root->style_flags |= FT_STYLE_FLAG_BOLD; 805 806 /* set up the `fixed_sizes' array */ 807 if ( FT_QNEW( root->available_sizes ) ) 808 goto Fail; 809 810 root->num_fixed_sizes = 1; 811 812 { 813 FT_Bitmap_Size* bsize = root->available_sizes; 814 FT_UShort x_res, y_res; 815 816 817 bsize->width = (FT_Short)font->header.avg_width; 818 bsize->height = (FT_Short)( font->header.pixel_height + 819 font->header.external_leading ); 820 bsize->size = font->header.nominal_point_size << 6; 821 822 x_res = font->header.horizontal_resolution; 823 if ( !x_res ) 824 x_res = 72; 825 826 y_res = font->header.vertical_resolution; 827 if ( !y_res ) 828 y_res = 72; 829 830 bsize->y_ppem = FT_MulDiv( bsize->size, y_res, 72 ); 831 bsize->y_ppem = FT_PIX_ROUND( bsize->y_ppem ); 832 833 /* 834 * this reads: 835 * 836 * the nominal height is larger than the bbox's height 837 * 838 * => nominal_point_size contains incorrect value; 839 * use pixel_height as the nominal height 840 */ 841 if ( bsize->y_ppem > ( font->header.pixel_height << 6 ) ) 842 { 843 FT_TRACE2(( "use pixel_height as the nominal height\n" )); 844 845 bsize->y_ppem = font->header.pixel_height << 6; 846 bsize->size = FT_MulDiv( bsize->y_ppem, 72, y_res ); 847 } 848 849 bsize->x_ppem = FT_MulDiv( bsize->size, x_res, 72 ); 850 bsize->x_ppem = FT_PIX_ROUND( bsize->x_ppem ); 851 } 852 853 { 854 FT_CharMapRec charmap; 855 856 857 charmap.encoding = FT_ENCODING_NONE; 858 /* initial platform/encoding should indicate unset status? */ 859 charmap.platform_id = TT_PLATFORM_APPLE_UNICODE; 860 charmap.encoding_id = TT_APPLE_ID_DEFAULT; 861 charmap.face = root; 862 863 if ( font->header.charset == FT_WinFNT_ID_MAC ) 864 { 865 charmap.encoding = FT_ENCODING_APPLE_ROMAN; 866 charmap.platform_id = TT_PLATFORM_MACINTOSH; 867 /* charmap.encoding_id = TT_MAC_ID_ROMAN; */ 868 } 869 870 error = FT_CMap_New( fnt_cmap_class, 871 NULL, 872 &charmap, 873 NULL ); 874 if ( error ) 875 goto Fail; 876 } 877 878 /* set up remaining flags */ 879 880 if ( font->header.last_char < font->header.first_char ) 881 { 882 FT_TRACE2(( "invalid number of glyphs\n" )); 883 error = FT_THROW( Invalid_File_Format ); 884 goto Fail; 885 } 886 887 /* reserve one slot for the .notdef glyph at index 0 */ 888 root->num_glyphs = font->header.last_char - 889 font->header.first_char + 1 + 1; 890 891 if ( font->header.face_name_offset >= font->header.file_size ) 892 { 893 FT_TRACE2(( "invalid family name offset\n" )); 894 error = FT_THROW( Invalid_File_Format ); 895 goto Fail; 896 } 897 family_size = font->header.file_size - font->header.face_name_offset; 898 /* Some broken fonts don't delimit the face name with a final */ 899 /* null byte -- the frame is erroneously one byte too small. */ 900 /* We thus allocate one more byte, setting it explicitly to */ 901 /* zero. */ 902 if ( FT_QALLOC( font->family_name, family_size + 1 ) ) 903 goto Fail; 904 905 FT_MEM_COPY( font->family_name, 906 font->fnt_frame + font->header.face_name_offset, 907 family_size ); 908 909 font->family_name[family_size] = '\0'; 910 911 /* shrink it to the actual length */ 912 if ( FT_QREALLOC( font->family_name, 913 family_size + 1, 914 ft_strlen( font->family_name ) + 1 ) ) 915 goto Fail; 916 917 root->family_name = font->family_name; 918 root->style_name = (char *)"Regular"; 919 920 if ( root->style_flags & FT_STYLE_FLAG_BOLD ) 921 { 922 if ( root->style_flags & FT_STYLE_FLAG_ITALIC ) 923 root->style_name = (char *)"Bold Italic"; 924 else 925 root->style_name = (char *)"Bold"; 926 } 927 else if ( root->style_flags & FT_STYLE_FLAG_ITALIC ) 928 root->style_name = (char *)"Italic"; 929 } 930 goto Exit; 931 932 Fail: 933 FNT_Face_Done( fntface ); 934 935 Exit: 936 return error; 937 } 938 939 940 static FT_Error FNT_Size_Select(FT_Size size,FT_ULong strike_index)941 FNT_Size_Select( FT_Size size, 942 FT_ULong strike_index ) 943 { 944 FNT_Face face = (FNT_Face)size->face; 945 FT_WinFNT_Header header = &face->font->header; 946 947 FT_UNUSED( strike_index ); 948 949 950 FT_Select_Metrics( size->face, 0 ); 951 952 size->metrics.ascender = header->ascent * 64; 953 size->metrics.descender = -( header->pixel_height - 954 header->ascent ) * 64; 955 size->metrics.max_advance = header->max_width * 64; 956 957 return FT_Err_Ok; 958 } 959 960 961 static FT_Error FNT_Size_Request(FT_Size size,FT_Size_Request req)962 FNT_Size_Request( FT_Size size, 963 FT_Size_Request req ) 964 { 965 FNT_Face face = (FNT_Face)size->face; 966 FT_WinFNT_Header header = &face->font->header; 967 FT_Bitmap_Size* bsize = size->face->available_sizes; 968 FT_Error error = FT_ERR( Invalid_Pixel_Size ); 969 FT_Long height; 970 971 972 height = FT_REQUEST_HEIGHT( req ); 973 height = ( height + 32 ) >> 6; 974 975 switch ( req->type ) 976 { 977 case FT_SIZE_REQUEST_TYPE_NOMINAL: 978 if ( height == ( ( bsize->y_ppem + 32 ) >> 6 ) ) 979 error = FT_Err_Ok; 980 break; 981 982 case FT_SIZE_REQUEST_TYPE_REAL_DIM: 983 if ( height == header->pixel_height ) 984 error = FT_Err_Ok; 985 break; 986 987 default: 988 error = FT_THROW( Unimplemented_Feature ); 989 break; 990 } 991 992 if ( error ) 993 return error; 994 else 995 return FNT_Size_Select( size, 0 ); 996 } 997 998 999 static FT_Error FNT_Load_Glyph(FT_GlyphSlot slot,FT_Size size,FT_UInt glyph_index,FT_Int32 load_flags)1000 FNT_Load_Glyph( FT_GlyphSlot slot, 1001 FT_Size size, 1002 FT_UInt glyph_index, 1003 FT_Int32 load_flags ) 1004 { 1005 FNT_Face face = (FNT_Face)FT_SIZE_FACE( size ); 1006 FNT_Font font; 1007 FT_Error error = FT_Err_Ok; 1008 FT_Byte* p; 1009 FT_UInt len; 1010 FT_Bitmap* bitmap = &slot->bitmap; 1011 FT_ULong offset; 1012 FT_Bool new_format; 1013 1014 1015 if ( !face ) 1016 { 1017 error = FT_THROW( Invalid_Face_Handle ); 1018 goto Exit; 1019 } 1020 1021 font = face->font; 1022 1023 if ( !font || 1024 glyph_index >= (FT_UInt)( FT_FACE( face )->num_glyphs ) ) 1025 { 1026 error = FT_THROW( Invalid_Argument ); 1027 goto Exit; 1028 } 1029 1030 FT_TRACE1(( "FNT_Load_Glyph: glyph index %d\n", glyph_index )); 1031 1032 if ( glyph_index > 0 ) 1033 glyph_index--; /* revert to real index */ 1034 else 1035 glyph_index = font->header.default_char; /* the `.notdef' glyph */ 1036 1037 new_format = FT_BOOL( font->header.version == 0x300 ); 1038 len = new_format ? 6 : 4; 1039 1040 /* get glyph width and offset */ 1041 offset = ( new_format ? 148 : 118 ) + len * glyph_index; 1042 1043 if ( offset >= font->header.file_size - 2 - ( new_format ? 4 : 2 ) ) 1044 { 1045 FT_TRACE2(( "invalid FNT offset\n" )); 1046 error = FT_THROW( Invalid_File_Format ); 1047 goto Exit; 1048 } 1049 1050 p = font->fnt_frame + offset; 1051 1052 bitmap->width = FT_NEXT_USHORT_LE( p ); 1053 1054 /* jump to glyph entry */ 1055 if ( new_format ) 1056 offset = FT_NEXT_ULONG_LE( p ); 1057 else 1058 offset = FT_NEXT_USHORT_LE( p ); 1059 1060 if ( offset >= font->header.file_size ) 1061 { 1062 FT_TRACE2(( "invalid FNT offset\n" )); 1063 error = FT_THROW( Invalid_File_Format ); 1064 goto Exit; 1065 } 1066 1067 bitmap->rows = font->header.pixel_height; 1068 bitmap->pixel_mode = FT_PIXEL_MODE_MONO; 1069 1070 slot->bitmap_left = 0; 1071 slot->bitmap_top = font->header.ascent; 1072 slot->format = FT_GLYPH_FORMAT_BITMAP; 1073 1074 /* now set up metrics */ 1075 slot->metrics.width = (FT_Pos)( bitmap->width << 6 ); 1076 slot->metrics.height = (FT_Pos)( bitmap->rows << 6 ); 1077 slot->metrics.horiAdvance = (FT_Pos)( bitmap->width << 6 ); 1078 slot->metrics.horiBearingX = 0; 1079 slot->metrics.horiBearingY = slot->bitmap_top << 6; 1080 1081 ft_synthesize_vertical_metrics( &slot->metrics, 1082 (FT_Pos)( bitmap->rows << 6 ) ); 1083 1084 if ( load_flags & FT_LOAD_BITMAP_METRICS_ONLY ) 1085 goto Exit; 1086 1087 /* jump to glyph data */ 1088 p = font->fnt_frame + /* font->header.bits_offset */ + offset; 1089 1090 /* allocate and build bitmap */ 1091 { 1092 FT_Memory memory = FT_FACE_MEMORY( slot->face ); 1093 FT_UInt pitch = ( bitmap->width + 7 ) >> 3; 1094 FT_Byte* column; 1095 FT_Byte* write; 1096 1097 1098 bitmap->pitch = (int)pitch; 1099 if ( !pitch || 1100 offset + pitch * bitmap->rows > font->header.file_size ) 1101 { 1102 FT_TRACE2(( "invalid bitmap width\n" )); 1103 error = FT_THROW( Invalid_File_Format ); 1104 goto Exit; 1105 } 1106 1107 /* note: since glyphs are stored in columns and not in rows we */ 1108 /* can't use ft_glyphslot_set_bitmap */ 1109 if ( FT_QALLOC_MULT( bitmap->buffer, bitmap->rows, pitch ) ) 1110 goto Exit; 1111 1112 column = (FT_Byte*)bitmap->buffer; 1113 1114 for ( ; pitch > 0; pitch--, column++ ) 1115 { 1116 FT_Byte* limit = p + bitmap->rows; 1117 1118 1119 for ( write = column; p < limit; p++, write += bitmap->pitch ) 1120 *write = *p; 1121 } 1122 1123 slot->internal->flags = FT_GLYPH_OWN_BITMAP; 1124 } 1125 1126 Exit: 1127 return error; 1128 } 1129 1130 1131 static FT_Error winfnt_get_header(FT_Face face,FT_WinFNT_HeaderRec * aheader)1132 winfnt_get_header( FT_Face face, 1133 FT_WinFNT_HeaderRec *aheader ) 1134 { 1135 FNT_Font font = ((FNT_Face)face)->font; 1136 1137 1138 *aheader = font->header; 1139 1140 return 0; 1141 } 1142 1143 1144 static const FT_Service_WinFntRec winfnt_service_rec = 1145 { 1146 winfnt_get_header /* get_header */ 1147 }; 1148 1149 /* 1150 * SERVICE LIST 1151 * 1152 */ 1153 1154 static const FT_ServiceDescRec winfnt_services[] = 1155 { 1156 { FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_WINFNT }, 1157 { FT_SERVICE_ID_WINFNT, &winfnt_service_rec }, 1158 { NULL, NULL } 1159 }; 1160 1161 1162 static FT_Module_Interface winfnt_get_service(FT_Module module,const FT_String * service_id)1163 winfnt_get_service( FT_Module module, 1164 const FT_String* service_id ) 1165 { 1166 FT_UNUSED( module ); 1167 1168 return ft_service_list_lookup( winfnt_services, service_id ); 1169 } 1170 1171 1172 1173 1174 FT_CALLBACK_TABLE_DEF 1175 const FT_Driver_ClassRec winfnt_driver_class = 1176 { 1177 { 1178 FT_MODULE_FONT_DRIVER | 1179 FT_MODULE_DRIVER_NO_OUTLINES, 1180 sizeof ( FT_DriverRec ), 1181 1182 "winfonts", 1183 0x10000L, 1184 0x20000L, 1185 1186 NULL, /* module-specific interface */ 1187 1188 NULL, /* FT_Module_Constructor module_init */ 1189 NULL, /* FT_Module_Destructor module_done */ 1190 winfnt_get_service /* FT_Module_Requester get_interface */ 1191 }, 1192 1193 sizeof ( FNT_FaceRec ), 1194 sizeof ( FT_SizeRec ), 1195 sizeof ( FT_GlyphSlotRec ), 1196 1197 FNT_Face_Init, /* FT_Face_InitFunc init_face */ 1198 FNT_Face_Done, /* FT_Face_DoneFunc done_face */ 1199 NULL, /* FT_Size_InitFunc init_size */ 1200 NULL, /* FT_Size_DoneFunc done_size */ 1201 NULL, /* FT_Slot_InitFunc init_slot */ 1202 NULL, /* FT_Slot_DoneFunc done_slot */ 1203 1204 FNT_Load_Glyph, /* FT_Slot_LoadFunc load_glyph */ 1205 1206 NULL, /* FT_Face_GetKerningFunc get_kerning */ 1207 NULL, /* FT_Face_AttachFunc attach_file */ 1208 NULL, /* FT_Face_GetAdvancesFunc get_advances */ 1209 1210 FNT_Size_Request, /* FT_Size_RequestFunc request_size */ 1211 FNT_Size_Select /* FT_Size_SelectFunc select_size */ 1212 }; 1213 1214 1215 /* END */ 1216