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