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(FT_CMap cmap,FT_Pointer pointer)627 fnt_cmap_init( FT_CMap cmap, /* FNT_CMap */ 628 FT_Pointer pointer ) 629 { 630 FNT_CMap fntcmap = (FNT_CMap)cmap; 631 FNT_Face face = (FNT_Face)FT_CMAP_FACE( cmap ); 632 FNT_Font font = face->font; 633 634 FT_UNUSED( pointer ); 635 636 637 fntcmap->first = (FT_UInt32)font->header.first_char; 638 fntcmap->count = (FT_UInt32)( font->header.last_char - 639 fntcmap->first + 1 ); 640 641 return 0; 642 } 643 644 645 static FT_UInt fnt_cmap_char_index(FT_CMap cmap,FT_UInt32 char_code)646 fnt_cmap_char_index( FT_CMap cmap, /* FNT_CMap */ 647 FT_UInt32 char_code ) 648 { 649 FNT_CMap fntcmap = (FNT_CMap)cmap; 650 FT_UInt gindex = 0; 651 652 653 char_code -= fntcmap->first; 654 if ( char_code < fntcmap->count ) 655 /* we artificially increase the glyph index; */ 656 /* FNT_Load_Glyph reverts to the right one */ 657 gindex = (FT_UInt)( char_code + 1 ); 658 return gindex; 659 } 660 661 662 static FT_UInt fnt_cmap_char_next(FT_CMap cmap,FT_UInt32 * pchar_code)663 fnt_cmap_char_next( FT_CMap cmap, /* FNT_CMap */ 664 FT_UInt32 *pchar_code ) 665 { 666 FNT_CMap fntcmap = (FNT_CMap)cmap; 667 FT_UInt gindex = 0; 668 FT_UInt32 result = 0; 669 FT_UInt32 char_code = *pchar_code + 1; 670 671 672 if ( char_code <= fntcmap->first ) 673 { 674 result = fntcmap->first; 675 gindex = 1; 676 } 677 else 678 { 679 char_code -= fntcmap->first; 680 if ( char_code < fntcmap->count ) 681 { 682 result = fntcmap->first + char_code; 683 gindex = (FT_UInt)( char_code + 1 ); 684 } 685 } 686 687 *pchar_code = result; 688 return gindex; 689 } 690 691 692 static const FT_CMap_ClassRec fnt_cmap_class_rec = 693 { 694 sizeof ( FNT_CMapRec ), 695 696 (FT_CMap_InitFunc) fnt_cmap_init, 697 (FT_CMap_DoneFunc) NULL, 698 (FT_CMap_CharIndexFunc)fnt_cmap_char_index, 699 (FT_CMap_CharNextFunc) fnt_cmap_char_next, 700 701 NULL, NULL, NULL, NULL, NULL 702 }; 703 704 static FT_CMap_Class const fnt_cmap_class = &fnt_cmap_class_rec; 705 706 707 static void FNT_Face_Done(FT_Face fntface)708 FNT_Face_Done( FT_Face fntface ) /* FNT_Face */ 709 { 710 FNT_Face face = (FNT_Face)fntface; 711 FT_Memory memory; 712 713 714 if ( !face ) 715 return; 716 717 memory = FT_FACE_MEMORY( face ); 718 719 fnt_font_done( face ); 720 721 FT_FREE( fntface->available_sizes ); 722 fntface->num_fixed_sizes = 0; 723 } 724 725 726 static FT_Error FNT_Face_Init(FT_Stream stream,FT_Face fntface,FT_Int face_instance_index,FT_Int num_params,FT_Parameter * params)727 FNT_Face_Init( FT_Stream stream, 728 FT_Face fntface, /* FNT_Face */ 729 FT_Int face_instance_index, 730 FT_Int num_params, 731 FT_Parameter* params ) 732 { 733 FNT_Face face = (FNT_Face)fntface; 734 FT_Error error; 735 FT_Memory memory = FT_FACE_MEMORY( face ); 736 FT_Int face_index; 737 738 FT_UNUSED( num_params ); 739 FT_UNUSED( params ); 740 741 742 FT_TRACE2(( "Windows FNT driver\n" )); 743 744 face_index = FT_ABS( face_instance_index ) & 0xFFFF; 745 746 /* try to load font from a DLL */ 747 error = fnt_face_get_dll_font( face, face_instance_index ); 748 if ( !error && face_instance_index < 0 ) 749 goto Exit; 750 751 if ( FT_ERR_EQ( error, Unknown_File_Format ) ) 752 { 753 /* this didn't work; try to load a single FNT font */ 754 FNT_Font font; 755 756 if ( FT_NEW( face->font ) ) 757 goto Exit; 758 759 fntface->num_faces = 1; 760 761 font = face->font; 762 font->offset = 0; 763 font->fnt_size = stream->size; 764 765 error = fnt_font_load( font, stream ); 766 767 if ( !error ) 768 { 769 if ( face_instance_index < 0 ) 770 goto Exit; 771 772 if ( face_index > 0 ) 773 error = FT_THROW( Invalid_Argument ); 774 } 775 } 776 777 if ( error ) 778 goto Fail; 779 780 /* sanity check */ 781 if ( !face->font->header.pixel_height ) 782 { 783 FT_TRACE2(( "invalid pixel height\n" )); 784 error = FT_THROW( Invalid_File_Format ); 785 goto Fail; 786 } 787 788 /* we now need to fill the root FT_Face fields */ 789 /* with relevant information */ 790 { 791 FT_Face root = FT_FACE( face ); 792 FNT_Font font = face->font; 793 FT_ULong family_size; 794 795 796 root->face_index = face_index; 797 798 root->face_flags |= FT_FACE_FLAG_FIXED_SIZES | 799 FT_FACE_FLAG_HORIZONTAL; 800 801 if ( font->header.avg_width == font->header.max_width ) 802 root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; 803 804 if ( font->header.italic ) 805 root->style_flags |= FT_STYLE_FLAG_ITALIC; 806 807 if ( font->header.weight >= 800 ) 808 root->style_flags |= FT_STYLE_FLAG_BOLD; 809 810 /* set up the `fixed_sizes' array */ 811 if ( FT_QNEW( root->available_sizes ) ) 812 goto Fail; 813 814 root->num_fixed_sizes = 1; 815 816 { 817 FT_Bitmap_Size* bsize = root->available_sizes; 818 FT_UShort x_res, y_res; 819 820 821 bsize->width = (FT_Short)font->header.avg_width; 822 bsize->height = (FT_Short)( font->header.pixel_height + 823 font->header.external_leading ); 824 bsize->size = font->header.nominal_point_size << 6; 825 826 x_res = font->header.horizontal_resolution; 827 if ( !x_res ) 828 x_res = 72; 829 830 y_res = font->header.vertical_resolution; 831 if ( !y_res ) 832 y_res = 72; 833 834 bsize->y_ppem = FT_MulDiv( bsize->size, y_res, 72 ); 835 bsize->y_ppem = FT_PIX_ROUND( bsize->y_ppem ); 836 837 /* 838 * this reads: 839 * 840 * the nominal height is larger than the bbox's height 841 * 842 * => nominal_point_size contains incorrect value; 843 * use pixel_height as the nominal height 844 */ 845 if ( bsize->y_ppem > ( font->header.pixel_height << 6 ) ) 846 { 847 FT_TRACE2(( "use pixel_height as the nominal height\n" )); 848 849 bsize->y_ppem = font->header.pixel_height << 6; 850 bsize->size = FT_MulDiv( bsize->y_ppem, 72, y_res ); 851 } 852 853 bsize->x_ppem = FT_MulDiv( bsize->size, x_res, 72 ); 854 bsize->x_ppem = FT_PIX_ROUND( bsize->x_ppem ); 855 } 856 857 { 858 FT_CharMapRec charmap; 859 860 861 charmap.encoding = FT_ENCODING_NONE; 862 /* initial platform/encoding should indicate unset status? */ 863 charmap.platform_id = TT_PLATFORM_APPLE_UNICODE; 864 charmap.encoding_id = TT_APPLE_ID_DEFAULT; 865 charmap.face = root; 866 867 if ( font->header.charset == FT_WinFNT_ID_MAC ) 868 { 869 charmap.encoding = FT_ENCODING_APPLE_ROMAN; 870 charmap.platform_id = TT_PLATFORM_MACINTOSH; 871 /* charmap.encoding_id = TT_MAC_ID_ROMAN; */ 872 } 873 874 error = FT_CMap_New( fnt_cmap_class, 875 NULL, 876 &charmap, 877 NULL ); 878 if ( error ) 879 goto Fail; 880 } 881 882 /* set up remaining flags */ 883 884 if ( font->header.last_char < font->header.first_char ) 885 { 886 FT_TRACE2(( "invalid number of glyphs\n" )); 887 error = FT_THROW( Invalid_File_Format ); 888 goto Fail; 889 } 890 891 /* reserve one slot for the .notdef glyph at index 0 */ 892 root->num_glyphs = font->header.last_char - 893 font->header.first_char + 1 + 1; 894 895 if ( font->header.face_name_offset >= font->header.file_size ) 896 { 897 FT_TRACE2(( "invalid family name offset\n" )); 898 error = FT_THROW( Invalid_File_Format ); 899 goto Fail; 900 } 901 family_size = font->header.file_size - font->header.face_name_offset; 902 /* Some broken fonts don't delimit the face name with a final */ 903 /* null byte -- the frame is erroneously one byte too small. */ 904 /* We thus allocate one more byte, setting it explicitly to */ 905 /* zero. */ 906 if ( FT_QALLOC( font->family_name, family_size + 1 ) ) 907 goto Fail; 908 909 FT_MEM_COPY( font->family_name, 910 font->fnt_frame + font->header.face_name_offset, 911 family_size ); 912 913 font->family_name[family_size] = '\0'; 914 915 /* shrink it to the actual length */ 916 if ( FT_QREALLOC( font->family_name, 917 family_size + 1, 918 ft_strlen( font->family_name ) + 1 ) ) 919 goto Fail; 920 921 root->family_name = font->family_name; 922 root->style_name = (char *)"Regular"; 923 924 if ( root->style_flags & FT_STYLE_FLAG_BOLD ) 925 { 926 if ( root->style_flags & FT_STYLE_FLAG_ITALIC ) 927 root->style_name = (char *)"Bold Italic"; 928 else 929 root->style_name = (char *)"Bold"; 930 } 931 else if ( root->style_flags & FT_STYLE_FLAG_ITALIC ) 932 root->style_name = (char *)"Italic"; 933 } 934 goto Exit; 935 936 Fail: 937 FNT_Face_Done( fntface ); 938 939 Exit: 940 return error; 941 } 942 943 944 static FT_Error FNT_Size_Select(FT_Size size,FT_ULong strike_index)945 FNT_Size_Select( FT_Size size, 946 FT_ULong strike_index ) 947 { 948 FNT_Face face = (FNT_Face)size->face; 949 FT_WinFNT_Header header = &face->font->header; 950 951 FT_UNUSED( strike_index ); 952 953 954 FT_Select_Metrics( size->face, 0 ); 955 956 size->metrics.ascender = header->ascent * 64; 957 size->metrics.descender = -( header->pixel_height - 958 header->ascent ) * 64; 959 size->metrics.max_advance = header->max_width * 64; 960 961 return FT_Err_Ok; 962 } 963 964 965 static FT_Error FNT_Size_Request(FT_Size size,FT_Size_Request req)966 FNT_Size_Request( FT_Size size, 967 FT_Size_Request req ) 968 { 969 FNT_Face face = (FNT_Face)size->face; 970 FT_WinFNT_Header header = &face->font->header; 971 FT_Bitmap_Size* bsize = size->face->available_sizes; 972 FT_Error error = FT_ERR( Invalid_Pixel_Size ); 973 FT_Long height; 974 975 976 height = FT_REQUEST_HEIGHT( req ); 977 height = ( height + 32 ) >> 6; 978 979 switch ( req->type ) 980 { 981 case FT_SIZE_REQUEST_TYPE_NOMINAL: 982 if ( height == ( ( bsize->y_ppem + 32 ) >> 6 ) ) 983 error = FT_Err_Ok; 984 break; 985 986 case FT_SIZE_REQUEST_TYPE_REAL_DIM: 987 if ( height == header->pixel_height ) 988 error = FT_Err_Ok; 989 break; 990 991 default: 992 error = FT_THROW( Unimplemented_Feature ); 993 break; 994 } 995 996 if ( error ) 997 return error; 998 else 999 return FNT_Size_Select( size, 0 ); 1000 } 1001 1002 1003 static FT_Error FNT_Load_Glyph(FT_GlyphSlot slot,FT_Size size,FT_UInt glyph_index,FT_Int32 load_flags)1004 FNT_Load_Glyph( FT_GlyphSlot slot, 1005 FT_Size size, 1006 FT_UInt glyph_index, 1007 FT_Int32 load_flags ) 1008 { 1009 FNT_Face face = (FNT_Face)FT_SIZE_FACE( size ); 1010 FNT_Font font; 1011 FT_Error error = FT_Err_Ok; 1012 FT_Byte* p; 1013 FT_UInt len; 1014 FT_Bitmap* bitmap = &slot->bitmap; 1015 FT_ULong offset; 1016 FT_Bool new_format; 1017 1018 1019 if ( !face ) 1020 { 1021 error = FT_THROW( Invalid_Face_Handle ); 1022 goto Exit; 1023 } 1024 1025 font = face->font; 1026 1027 if ( !font || 1028 glyph_index >= (FT_UInt)( FT_FACE( face )->num_glyphs ) ) 1029 { 1030 error = FT_THROW( Invalid_Argument ); 1031 goto Exit; 1032 } 1033 1034 FT_TRACE1(( "FNT_Load_Glyph: glyph index %d\n", glyph_index )); 1035 1036 if ( glyph_index > 0 ) 1037 glyph_index--; /* revert to real index */ 1038 else 1039 glyph_index = font->header.default_char; /* the `.notdef' glyph */ 1040 1041 new_format = FT_BOOL( font->header.version == 0x300 ); 1042 len = new_format ? 6 : 4; 1043 1044 /* get glyph width and offset */ 1045 offset = ( new_format ? 148 : 118 ) + len * glyph_index; 1046 1047 if ( offset >= font->header.file_size - 2 - ( new_format ? 4 : 2 ) ) 1048 { 1049 FT_TRACE2(( "invalid FNT offset\n" )); 1050 error = FT_THROW( Invalid_File_Format ); 1051 goto Exit; 1052 } 1053 1054 p = font->fnt_frame + offset; 1055 1056 bitmap->width = FT_NEXT_USHORT_LE( p ); 1057 1058 /* jump to glyph entry */ 1059 if ( new_format ) 1060 offset = FT_NEXT_ULONG_LE( p ); 1061 else 1062 offset = FT_NEXT_USHORT_LE( p ); 1063 1064 if ( offset >= font->header.file_size ) 1065 { 1066 FT_TRACE2(( "invalid FNT offset\n" )); 1067 error = FT_THROW( Invalid_File_Format ); 1068 goto Exit; 1069 } 1070 1071 bitmap->rows = font->header.pixel_height; 1072 bitmap->pixel_mode = FT_PIXEL_MODE_MONO; 1073 1074 slot->bitmap_left = 0; 1075 slot->bitmap_top = font->header.ascent; 1076 slot->format = FT_GLYPH_FORMAT_BITMAP; 1077 1078 /* now set up metrics */ 1079 slot->metrics.width = (FT_Pos)( bitmap->width << 6 ); 1080 slot->metrics.height = (FT_Pos)( bitmap->rows << 6 ); 1081 slot->metrics.horiAdvance = (FT_Pos)( bitmap->width << 6 ); 1082 slot->metrics.horiBearingX = 0; 1083 slot->metrics.horiBearingY = slot->bitmap_top << 6; 1084 1085 ft_synthesize_vertical_metrics( &slot->metrics, 1086 (FT_Pos)( bitmap->rows << 6 ) ); 1087 1088 if ( load_flags & FT_LOAD_BITMAP_METRICS_ONLY ) 1089 goto Exit; 1090 1091 /* jump to glyph data */ 1092 p = font->fnt_frame + /* font->header.bits_offset */ + offset; 1093 1094 /* allocate and build bitmap */ 1095 { 1096 FT_Memory memory = FT_FACE_MEMORY( slot->face ); 1097 FT_UInt pitch = ( bitmap->width + 7 ) >> 3; 1098 FT_Byte* column; 1099 FT_Byte* write; 1100 1101 1102 bitmap->pitch = (int)pitch; 1103 if ( !pitch || 1104 offset + pitch * bitmap->rows > font->header.file_size ) 1105 { 1106 FT_TRACE2(( "invalid bitmap width\n" )); 1107 error = FT_THROW( Invalid_File_Format ); 1108 goto Exit; 1109 } 1110 1111 /* note: since glyphs are stored in columns and not in rows we */ 1112 /* can't use ft_glyphslot_set_bitmap */ 1113 if ( FT_QALLOC_MULT( bitmap->buffer, bitmap->rows, pitch ) ) 1114 goto Exit; 1115 1116 column = (FT_Byte*)bitmap->buffer; 1117 1118 for ( ; pitch > 0; pitch--, column++ ) 1119 { 1120 FT_Byte* limit = p + bitmap->rows; 1121 1122 1123 for ( write = column; p < limit; p++, write += bitmap->pitch ) 1124 *write = *p; 1125 } 1126 1127 slot->internal->flags = FT_GLYPH_OWN_BITMAP; 1128 } 1129 1130 Exit: 1131 return error; 1132 } 1133 1134 1135 static FT_Error winfnt_get_header(FT_Face face,FT_WinFNT_HeaderRec * aheader)1136 winfnt_get_header( FT_Face face, 1137 FT_WinFNT_HeaderRec *aheader ) 1138 { 1139 FNT_Font font = ((FNT_Face)face)->font; 1140 1141 1142 *aheader = font->header; 1143 1144 return 0; 1145 } 1146 1147 1148 static const FT_Service_WinFntRec winfnt_service_rec = 1149 { 1150 winfnt_get_header /* get_header */ 1151 }; 1152 1153 /* 1154 * SERVICE LIST 1155 * 1156 */ 1157 1158 static const FT_ServiceDescRec winfnt_services[] = 1159 { 1160 { FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_WINFNT }, 1161 { FT_SERVICE_ID_WINFNT, &winfnt_service_rec }, 1162 { NULL, NULL } 1163 }; 1164 1165 1166 static FT_Module_Interface winfnt_get_service(FT_Module module,const FT_String * service_id)1167 winfnt_get_service( FT_Module module, 1168 const FT_String* service_id ) 1169 { 1170 FT_UNUSED( module ); 1171 1172 return ft_service_list_lookup( winfnt_services, service_id ); 1173 } 1174 1175 1176 1177 1178 FT_CALLBACK_TABLE_DEF 1179 const FT_Driver_ClassRec winfnt_driver_class = 1180 { 1181 { 1182 FT_MODULE_FONT_DRIVER | 1183 FT_MODULE_DRIVER_NO_OUTLINES, 1184 sizeof ( FT_DriverRec ), 1185 1186 "winfonts", 1187 0x10000L, 1188 0x20000L, 1189 1190 NULL, /* module-specific interface */ 1191 1192 NULL, /* FT_Module_Constructor module_init */ 1193 NULL, /* FT_Module_Destructor module_done */ 1194 winfnt_get_service /* FT_Module_Requester get_interface */ 1195 }, 1196 1197 sizeof ( FNT_FaceRec ), 1198 sizeof ( FT_SizeRec ), 1199 sizeof ( FT_GlyphSlotRec ), 1200 1201 FNT_Face_Init, /* FT_Face_InitFunc init_face */ 1202 FNT_Face_Done, /* FT_Face_DoneFunc done_face */ 1203 NULL, /* FT_Size_InitFunc init_size */ 1204 NULL, /* FT_Size_DoneFunc done_size */ 1205 NULL, /* FT_Slot_InitFunc init_slot */ 1206 NULL, /* FT_Slot_DoneFunc done_slot */ 1207 1208 FNT_Load_Glyph, /* FT_Slot_LoadFunc load_glyph */ 1209 1210 NULL, /* FT_Face_GetKerningFunc get_kerning */ 1211 NULL, /* FT_Face_AttachFunc attach_file */ 1212 NULL, /* FT_Face_GetAdvancesFunc get_advances */ 1213 1214 FNT_Size_Request, /* FT_Size_RequestFunc request_size */ 1215 FNT_Size_Select /* FT_Size_SelectFunc select_size */ 1216 }; 1217 1218 1219 /* END */ 1220