1 /***************************************************************************/ 2 /* */ 3 /* winfnt.c */ 4 /* */ 5 /* FreeType font driver for Windows FNT/FON files */ 6 /* */ 7 /* Copyright 1996-2001, 2002 by */ 8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */ 9 /* */ 10 /* This file is part of the FreeType project, and may only be used, */ 11 /* modified, and distributed under the terms of the FreeType project */ 12 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ 13 /* this file you indicate that you have read the license and */ 14 /* understand and accept it fully. */ 15 /* */ 16 /***************************************************************************/ 17 18 19 #include <ft2build.h> 20 #include FT_INTERNAL_DEBUG_H 21 #include FT_INTERNAL_STREAM_H 22 #include FT_INTERNAL_OBJECTS_H 23 #include FT_INTERNAL_FNT_TYPES_H 24 25 #include "winfnt.h" 26 27 #include "fnterrs.h" 28 29 30 /*************************************************************************/ 31 /* */ 32 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 33 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 34 /* messages during execution. */ 35 /* */ 36 #undef FT_COMPONENT 37 #define FT_COMPONENT trace_winfnt 38 39 40 static 41 const FT_Frame_Field winmz_header_fields[] = 42 { 43 #undef FT_STRUCTURE 44 #define FT_STRUCTURE WinMZ_HeaderRec 45 46 FT_FRAME_START( 64 ), 47 FT_FRAME_USHORT_LE ( magic ), 48 FT_FRAME_SKIP_BYTES( 29 * 2 ), 49 FT_FRAME_ULONG_LE ( lfanew ), 50 FT_FRAME_END 51 }; 52 53 static 54 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 68 const FT_Frame_Field winfnt_header_fields[] = 69 { 70 #undef FT_STRUCTURE 71 #define FT_STRUCTURE WinFNT_HeaderRec 72 73 FT_FRAME_START( 134 ), 74 FT_FRAME_USHORT_LE( version ), 75 FT_FRAME_ULONG_LE ( file_size ), 76 FT_FRAME_BYTES ( copyright, 60 ), 77 FT_FRAME_USHORT_LE( file_type ), 78 FT_FRAME_USHORT_LE( nominal_point_size ), 79 FT_FRAME_USHORT_LE( vertical_resolution ), 80 FT_FRAME_USHORT_LE( horizontal_resolution ), 81 FT_FRAME_USHORT_LE( ascent ), 82 FT_FRAME_USHORT_LE( internal_leading ), 83 FT_FRAME_USHORT_LE( external_leading ), 84 FT_FRAME_BYTE ( italic ), 85 FT_FRAME_BYTE ( underline ), 86 FT_FRAME_BYTE ( strike_out ), 87 FT_FRAME_USHORT_LE( weight ), 88 FT_FRAME_BYTE ( charset ), 89 FT_FRAME_USHORT_LE( pixel_width ), 90 FT_FRAME_USHORT_LE( pixel_height ), 91 FT_FRAME_BYTE ( pitch_and_family ), 92 FT_FRAME_USHORT_LE( avg_width ), 93 FT_FRAME_USHORT_LE( max_width ), 94 FT_FRAME_BYTE ( first_char ), 95 FT_FRAME_BYTE ( last_char ), 96 FT_FRAME_BYTE ( default_char ), 97 FT_FRAME_BYTE ( break_char ), 98 FT_FRAME_USHORT_LE( bytes_per_row ), 99 FT_FRAME_ULONG_LE ( device_offset ), 100 FT_FRAME_ULONG_LE ( face_name_offset ), 101 FT_FRAME_ULONG_LE ( bits_pointer ), 102 FT_FRAME_ULONG_LE ( bits_offset ), 103 FT_FRAME_BYTE ( reserved ), 104 FT_FRAME_ULONG_LE ( flags ), 105 FT_FRAME_USHORT_LE( A_space ), 106 FT_FRAME_USHORT_LE( B_space ), 107 FT_FRAME_USHORT_LE( C_space ), 108 FT_FRAME_USHORT_LE( color_table_offset ), 109 FT_FRAME_BYTES ( reserved, 4 ), 110 FT_FRAME_END 111 }; 112 113 114 static void fnt_font_done(FNT_Font font,FT_Stream stream)115 fnt_font_done( FNT_Font font, 116 FT_Stream stream ) 117 { 118 if ( font->fnt_frame ) 119 FT_FRAME_RELEASE( font->fnt_frame ); 120 121 font->fnt_size = 0; 122 font->fnt_frame = 0; 123 } 124 125 126 static FT_Error fnt_font_load(FNT_Font font,FT_Stream stream)127 fnt_font_load( FNT_Font font, 128 FT_Stream stream ) 129 { 130 FT_Error error; 131 WinFNT_Header header = &font->header; 132 133 134 /* first of all, read the FNT header */ 135 if ( FT_STREAM_SEEK( font->offset ) || 136 FT_STREAM_READ_FIELDS( winfnt_header_fields, header ) ) 137 goto Exit; 138 139 /* check header */ 140 if ( header->version != 0x200 && 141 header->version != 0x300 ) 142 { 143 FT_TRACE2(( "[not a valid FNT file]\n" )); 144 error = FNT_Err_Unknown_File_Format; 145 goto Exit; 146 } 147 148 if ( header->file_type & 1 ) 149 { 150 FT_TRACE2(( "[can't handle vector FNT fonts]\n" )); 151 error = FNT_Err_Unknown_File_Format; 152 goto Exit; 153 } 154 155 /* small fixup -- some fonts have the `pixel_width' field set to 0 */ 156 if ( header->pixel_width == 0 ) 157 header->pixel_width = header->pixel_height; 158 159 /* this is a FNT file/table, we now extract its frame */ 160 if ( FT_STREAM_SEEK( font->offset ) || 161 FT_FRAME_EXTRACT( header->file_size, font->fnt_frame ) ) 162 goto Exit; 163 164 Exit: 165 return error; 166 } 167 168 169 static void fnt_face_done_fonts(FNT_Face face)170 fnt_face_done_fonts( FNT_Face face ) 171 { 172 FT_Memory memory = FT_FACE( face )->memory; 173 FT_Stream stream = FT_FACE( face )->stream; 174 FNT_Font cur = face->fonts; 175 FNT_Font limit = cur + face->num_fonts; 176 177 178 for ( ; cur < limit; cur++ ) 179 fnt_font_done( cur, stream ); 180 181 FT_FREE( face->fonts ); 182 face->num_fonts = 0; 183 } 184 185 186 static FT_Error fnt_face_get_dll_fonts(FNT_Face face)187 fnt_face_get_dll_fonts( FNT_Face face ) 188 { 189 FT_Error error; 190 FT_Stream stream = FT_FACE( face )->stream; 191 FT_Memory memory = FT_FACE( face )->memory; 192 WinMZ_HeaderRec mz_header; 193 194 195 face->fonts = 0; 196 face->num_fonts = 0; 197 198 /* does it begin with a MZ header? */ 199 if ( FT_STREAM_SEEK( 0 ) || 200 FT_STREAM_READ_FIELDS( winmz_header_fields, &mz_header ) ) 201 goto Exit; 202 203 error = FNT_Err_Unknown_File_Format; 204 if ( mz_header.magic == WINFNT_MZ_MAGIC ) 205 { 206 /* yes, now look for a NE header in the file */ 207 WinNE_HeaderRec ne_header; 208 209 210 if ( FT_STREAM_SEEK( mz_header.lfanew ) || 211 FT_STREAM_READ_FIELDS( winne_header_fields, &ne_header ) ) 212 goto Exit; 213 214 error = FNT_Err_Unknown_File_Format; 215 if ( ne_header.magic == WINFNT_NE_MAGIC ) 216 { 217 /* good, now look in the resource table for each FNT resource */ 218 FT_ULong res_offset = mz_header.lfanew + 219 ne_header.resource_tab_offset; 220 221 FT_UShort size_shift; 222 FT_UShort font_count = 0; 223 FT_ULong font_offset = 0; 224 225 226 if ( FT_STREAM_SEEK( res_offset ) || 227 FT_FRAME_ENTER( ne_header.rname_tab_offset - 228 ne_header.resource_tab_offset ) ) 229 goto Exit; 230 231 size_shift = FT_GET_USHORT_LE(); 232 233 for (;;) 234 { 235 FT_UShort type_id, count; 236 237 238 type_id = FT_GET_USHORT_LE(); 239 if ( !type_id ) 240 break; 241 242 count = FT_GET_USHORT_LE(); 243 244 if ( type_id == 0x8008 ) 245 { 246 font_count = count; 247 font_offset = (FT_ULong)( FT_STREAM_POS() + 4 + 248 ( stream->cursor - stream->limit ) ); 249 break; 250 } 251 252 stream->cursor += 4 + count * 12; 253 } 254 FT_FRAME_EXIT(); 255 256 if ( !font_count || !font_offset ) 257 { 258 FT_TRACE2(( "this file doesn't contain any FNT resources!\n" )); 259 error = FNT_Err_Unknown_File_Format; 260 goto Exit; 261 } 262 263 if ( FT_STREAM_SEEK( font_offset ) || 264 FT_NEW_ARRAY( face->fonts, font_count ) ) 265 goto Exit; 266 267 face->num_fonts = font_count; 268 269 if ( FT_FRAME_ENTER( (FT_Long)font_count * 12 ) ) 270 goto Exit; 271 272 /* now read the offset and position of each FNT font */ 273 { 274 FNT_Font cur = face->fonts; 275 FNT_Font limit = cur + font_count; 276 277 278 for ( ; cur < limit; cur++ ) 279 { 280 cur->offset = (FT_ULong)FT_GET_USHORT_LE() << size_shift; 281 cur->fnt_size = (FT_ULong)FT_GET_USHORT_LE() << size_shift; 282 cur->size_shift = size_shift; 283 stream->cursor += 8; 284 } 285 } 286 FT_FRAME_EXIT(); 287 288 /* finally, try to load each font there */ 289 { 290 FNT_Font cur = face->fonts; 291 FNT_Font limit = cur + font_count; 292 293 294 for ( ; cur < limit; cur++ ) 295 { 296 error = fnt_font_load( cur, stream ); 297 if ( error ) 298 goto Fail; 299 } 300 } 301 } 302 } 303 304 Fail: 305 if ( error ) 306 fnt_face_done_fonts( face ); 307 308 Exit: 309 return error; 310 } 311 312 313 314 typedef struct FNT_CMapRec_ 315 { 316 FT_CMapRec cmap; 317 FT_UInt32 first; 318 FT_UInt32 count; 319 320 } FNT_CMapRec, *FNT_CMap; 321 322 323 static FT_Error fnt_cmap_init(FNT_CMap cmap)324 fnt_cmap_init( FNT_CMap cmap ) 325 { 326 FNT_Face face = (FNT_Face)FT_CMAP_FACE( cmap ); 327 FNT_Font font = face->fonts; 328 329 330 cmap->first = (FT_UInt32) font->header.first_char; 331 cmap->count = (FT_UInt32)( font->header.last_char - cmap->first + 1 ); 332 333 return 0; 334 } 335 336 337 static FT_UInt fnt_cmap_char_index(FNT_CMap cmap,FT_UInt32 char_code)338 fnt_cmap_char_index( FNT_CMap cmap, 339 FT_UInt32 char_code ) 340 { 341 FT_UInt gindex = 0; 342 343 344 char_code -= cmap->first; 345 if ( char_code < cmap->count ) 346 gindex = char_code + 1; 347 348 return gindex; 349 } 350 351 352 static FT_UInt fnt_cmap_char_next(FNT_CMap cmap,FT_UInt32 * pchar_code)353 fnt_cmap_char_next( FNT_CMap cmap, 354 FT_UInt32 *pchar_code ) 355 { 356 FT_UInt gindex = 0; 357 FT_UInt32 result = 0; 358 FT_UInt32 char_code = *pchar_code + 1; 359 360 361 if ( char_code <= cmap->first ) 362 { 363 result = cmap->first; 364 gindex = 1; 365 } 366 else 367 { 368 char_code -= cmap->first; 369 if ( char_code < cmap->count ) 370 { 371 result = cmap->first + char_code; 372 gindex = char_code + 1; 373 } 374 } 375 376 *pchar_code = result; 377 return gindex; 378 } 379 380 381 static FT_CMap_ClassRec fnt_cmap_class_rec = 382 { 383 sizeof ( FNT_CMapRec ), 384 385 (FT_CMap_InitFunc) fnt_cmap_init, 386 (FT_CMap_DoneFunc) NULL, 387 (FT_CMap_CharIndexFunc)fnt_cmap_char_index, 388 (FT_CMap_CharNextFunc) fnt_cmap_char_next 389 }; 390 391 static FT_CMap_Class fnt_cmap_class = &fnt_cmap_class_rec; 392 393 394 395 static void FNT_Face_Done(FNT_Face face)396 FNT_Face_Done( FNT_Face face ) 397 { 398 FT_Memory memory = FT_FACE_MEMORY( face ); 399 400 401 fnt_face_done_fonts( face ); 402 403 FT_FREE( face->root.available_sizes ); 404 face->root.num_fixed_sizes = 0; 405 } 406 407 408 static FT_Error FNT_Face_Init(FT_Stream stream,FNT_Face face,FT_Int face_index,FT_Int num_params,FT_Parameter * params)409 FNT_Face_Init( FT_Stream stream, 410 FNT_Face face, 411 FT_Int face_index, 412 FT_Int num_params, 413 FT_Parameter* params ) 414 { 415 FT_Error error; 416 FT_Memory memory = FT_FACE_MEMORY( face ); 417 418 FT_UNUSED( num_params ); 419 FT_UNUSED( params ); 420 FT_UNUSED( face_index ); 421 422 423 /* try to load several fonts from a DLL */ 424 error = fnt_face_get_dll_fonts( face ); 425 if ( error ) 426 { 427 /* this didn't work, now try to load a single FNT font */ 428 FNT_Font font; 429 430 431 if ( FT_NEW( face->fonts ) ) 432 goto Exit; 433 434 face->num_fonts = 1; 435 font = face->fonts; 436 437 font->offset = 0; 438 font->fnt_size = stream->size; 439 440 error = fnt_font_load( font, stream ); 441 if ( error ) 442 goto Fail; 443 } 444 445 /* all right, one or more fonts were loaded; we now need to */ 446 /* fill the root FT_Face fields with relevant information */ 447 { 448 FT_Face root = FT_FACE( face ); 449 FNT_Font fonts = face->fonts; 450 FNT_Font limit = fonts + face->num_fonts; 451 FNT_Font cur; 452 453 454 root->num_faces = 1; 455 root->face_flags = FT_FACE_FLAG_FIXED_SIZES | 456 FT_FACE_FLAG_HORIZONTAL; 457 458 if ( fonts->header.avg_width == fonts->header.max_width ) 459 root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; 460 461 if ( fonts->header.italic ) 462 root->style_flags |= FT_STYLE_FLAG_ITALIC; 463 464 if ( fonts->header.weight >= 800 ) 465 root->style_flags |= FT_STYLE_FLAG_BOLD; 466 467 /* Setup the `fixed_sizes' array */ 468 if ( FT_NEW_ARRAY( root->available_sizes, face->num_fonts ) ) 469 goto Fail; 470 471 root->num_fixed_sizes = face->num_fonts; 472 473 { 474 FT_Bitmap_Size* size = root->available_sizes; 475 476 477 for ( cur = fonts; cur < limit; cur++, size++ ) 478 { 479 size->width = cur->header.pixel_width; 480 size->height = cur->header.pixel_height; 481 } 482 } 483 484 { 485 FT_CharMapRec charmap; 486 487 charmap.encoding = FT_ENCODING_UNICODE; 488 charmap.platform_id = 3; 489 charmap.encoding_id = 1; 490 charmap.face = root; 491 492 error = FT_CMap_New( fnt_cmap_class, 493 NULL, 494 &charmap, 495 NULL ); 496 if ( error ) 497 goto Fail; 498 499 /* Select default charmap */ 500 if ( root->num_charmaps ) 501 root->charmap = root->charmaps[0]; 502 } 503 504 /* setup remaining flags */ 505 root->num_glyphs = fonts->header.last_char - 506 fonts->header.first_char + 1; 507 508 root->family_name = (FT_String*)fonts->fnt_frame + 509 fonts->header.face_name_offset; 510 root->style_name = (char *)"Regular"; 511 512 if ( root->style_flags & FT_STYLE_FLAG_BOLD ) 513 { 514 if ( root->style_flags & FT_STYLE_FLAG_ITALIC ) 515 root->style_name = (char *)"Bold Italic"; 516 else 517 root->style_name = (char *)"Bold"; 518 } 519 else if ( root->style_flags & FT_STYLE_FLAG_ITALIC ) 520 root->style_name = (char *)"Italic"; 521 } 522 523 Fail: 524 if ( error ) 525 FNT_Face_Done( face ); 526 527 Exit: 528 return error; 529 } 530 531 532 static FT_Error FNT_Size_Set_Pixels(FNT_Size size)533 FNT_Size_Set_Pixels( FNT_Size size ) 534 { 535 /* look up a font corresponding to the current pixel size */ 536 FNT_Face face = (FNT_Face)FT_SIZE_FACE( size ); 537 FNT_Font cur = face->fonts; 538 FNT_Font limit = cur + face->num_fonts; 539 540 541 size->font = 0; 542 for ( ; cur < limit; cur++ ) 543 { 544 /* we only compare the character height, as fonts used some strange */ 545 /* values */ 546 if ( cur->header.pixel_height == size->root.metrics.y_ppem ) 547 { 548 size->font = cur; 549 550 size->root.metrics.ascender = cur->header.ascent * 64; 551 size->root.metrics.descender = ( cur->header.pixel_height - 552 cur->header.ascent ) * 64; 553 size->root.metrics.height = cur->header.pixel_height * 64; 554 break; 555 } 556 } 557 558 return ( size->font ? FNT_Err_Ok : FNT_Err_Invalid_Pixel_Size ); 559 } 560 561 562 static FT_Error FNT_Load_Glyph(FT_GlyphSlot slot,FNT_Size size,FT_UInt glyph_index,FT_Int32 load_flags)563 FNT_Load_Glyph( FT_GlyphSlot slot, 564 FNT_Size size, 565 FT_UInt glyph_index, 566 FT_Int32 load_flags ) 567 { 568 FNT_Font font = size->font; 569 FT_Error error = 0; 570 FT_Byte* p; 571 FT_Int len; 572 FT_Bitmap* bitmap = &slot->bitmap; 573 FT_ULong offset; 574 FT_Bool new_format; 575 576 FT_UNUSED( slot ); 577 FT_UNUSED( load_flags ); 578 579 580 if ( !font ) 581 { 582 error = FNT_Err_Invalid_Argument; 583 goto Exit; 584 } 585 586 if ( glyph_index > 0 ) 587 glyph_index--; 588 else 589 glyph_index = font->header.default_char - font->header.first_char; 590 591 new_format = FT_BOOL( font->header.version == 0x300 ); 592 len = new_format ? 6 : 4; 593 594 /* jump to glyph entry */ 595 p = font->fnt_frame + 118 + len * glyph_index; 596 597 bitmap->width = FT_NEXT_SHORT_LE( p ); 598 599 if ( new_format ) 600 offset = FT_NEXT_ULONG_LE( p ); 601 else 602 offset = FT_NEXT_USHORT_LE( p ); 603 604 /* jump to glyph data */ 605 p = font->fnt_frame + /* font->header.bits_offset */ + offset; 606 607 /* allocate and build bitmap */ 608 { 609 FT_Memory memory = FT_FACE_MEMORY( slot->face ); 610 FT_Int pitch = ( bitmap->width + 7 ) >> 3; 611 FT_Byte* column; 612 FT_Byte* write; 613 614 615 bitmap->pitch = pitch; 616 bitmap->rows = font->header.pixel_height; 617 bitmap->pixel_mode = FT_PIXEL_MODE_MONO; 618 619 if ( FT_ALLOC( bitmap->buffer, pitch * bitmap->rows ) ) 620 goto Exit; 621 622 column = (FT_Byte*)bitmap->buffer; 623 624 for ( ; pitch > 0; pitch--, column++ ) 625 { 626 FT_Byte* limit = p + bitmap->rows; 627 628 629 for ( write = column; p < limit; p++, write += bitmap->pitch ) 630 write[0] = p[0]; 631 } 632 } 633 634 slot->flags = FT_GLYPH_OWN_BITMAP; 635 slot->bitmap_left = 0; 636 slot->bitmap_top = font->header.ascent; 637 slot->format = FT_GLYPH_FORMAT_BITMAP; 638 639 /* now set up metrics */ 640 slot->metrics.horiAdvance = bitmap->width << 6; 641 slot->metrics.horiBearingX = 0; 642 slot->metrics.horiBearingY = slot->bitmap_top << 6; 643 644 slot->linearHoriAdvance = (FT_Fixed)bitmap->width << 16; 645 slot->format = FT_GLYPH_FORMAT_BITMAP; 646 647 Exit: 648 return error; 649 } 650 651 652 FT_CALLBACK_TABLE_DEF 653 const FT_Driver_ClassRec winfnt_driver_class = 654 { 655 { 656 ft_module_font_driver, 657 sizeof ( FT_DriverRec ), 658 659 "winfonts", 660 0x10000L, 661 0x20000L, 662 663 0, 664 665 (FT_Module_Constructor)0, 666 (FT_Module_Destructor) 0, 667 (FT_Module_Requester) 0 668 }, 669 670 sizeof( FNT_FaceRec ), 671 sizeof( FNT_SizeRec ), 672 sizeof( FT_GlyphSlotRec ), 673 674 (FT_Face_InitFunc) FNT_Face_Init, 675 (FT_Face_DoneFunc) FNT_Face_Done, 676 (FT_Size_InitFunc) 0, 677 (FT_Size_DoneFunc) 0, 678 (FT_Slot_InitFunc) 0, 679 (FT_Slot_DoneFunc) 0, 680 681 (FT_Size_ResetPointsFunc) FNT_Size_Set_Pixels, 682 (FT_Size_ResetPixelsFunc) FNT_Size_Set_Pixels, 683 (FT_Slot_LoadFunc) FNT_Load_Glyph, 684 685 (FT_Face_GetKerningFunc) 0, 686 (FT_Face_AttachFunc) 0, 687 (FT_Face_GetAdvancesFunc) 0 688 }; 689 690 691 /* END */ 692