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