From ab9cc277c2d695b2d253610d9867256aa2a3ad8f Mon Sep 17 00:00:00 2001 From: David Turner Date: Fri, 7 Jul 2000 19:46:01 +0000 Subject: [PATCH] added Windows FNT/FON font driver --- src/winfonts/module.mk | 6 + src/winfonts/rules.mk | 71 ++++++ src/winfonts/winfnt.c | 566 +++++++++++++++++++++++++++++++++++++++++ src/winfonts/winfnt.h | 146 +++++++++++ 4 files changed, 789 insertions(+) create mode 100644 src/winfonts/module.mk create mode 100644 src/winfonts/rules.mk create mode 100644 src/winfonts/winfnt.c create mode 100644 src/winfonts/winfnt.h diff --git a/src/winfonts/module.mk b/src/winfonts/module.mk new file mode 100644 index 000000000..5c12eb6ee --- /dev/null +++ b/src/winfonts/module.mk @@ -0,0 +1,6 @@ +make_module_list: add_windows_driver + +add_windows_driver: + $(OPEN_DRIVER)winfnt_driver_class$(CLOSE_DRIVER) + $(ECHO_DRIVER)winfnt $(ECHO_DRIVER_DESC)Windows bitmap fonts with extension *.fnt or *.fon$(ECHO_DRIVER_DONE) + diff --git a/src/winfonts/rules.mk b/src/winfonts/rules.mk new file mode 100644 index 000000000..ce4134375 --- /dev/null +++ b/src/winfonts/rules.mk @@ -0,0 +1,71 @@ +# +# FreeType 2 Windows FNT/FON driver configuration rules +# + + +# Copyright 1996-2000 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# Windows driver directory +# +FNT_DIR := $(SRC_)winfonts +FNT_DIR_ := $(FNT_DIR)$(SEP) + + +# additional include flags used when compiling the driver +# +FNT_INCLUDE := $(FNT_DIR) + +# compilation flags for the driver +# +FNT_CFLAGS := $(FNT_INCLUDE:%=$I%) +FNT_COMPILE := $(FT_COMPILE) $(FNT_CFLAGS) + + +# Windows driver sources (i.e., C files) +# +FNT_DRV_SRC := $(FNT_DIR_)winfnt.c + +# Windows driver headers +# +FNT_DRV_H := $(FNT_DRV_SRC:%.c=%.h) + + +# Windows driver object(s) +# +# FNT_DRV_OBJ_M is used during `multi' builds +# FNT_DRV_OBJ_S is used during `single' builds +# +FNT_DRV_OBJ_M := $(FNT_DRV_SRC:$(FNT_DIR_)%.c=$(OBJ_)%.$O) +FNT_DRV_OBJ_S := $(OBJ_)winfnt.$O + +# Windows driver source file for single build +# +FNT_DRV_SRC_S := $(FNT_DIR_)winfnt.c + + +# Windows driver - single object +# +$(FNT_DRV_OBJ_S): $(FNT_DRV_SRC_S) $(FNT_DRV_SRC) $(FREETYPE_H) $(FNT_DRV_H) + $(FNT_COMPILE) $T$@ $(FNT_DRV_SRC_S) + + +# Windows driver - multiple objects +# +$(OBJ_)%.$O: $(FNT_DIR_)%.c $(FREETYPE_H) $(FNT_DRV_H) + $(FNT_COMPILE) $T$@ $< + + +# update main driver object lists +# +DRV_OBJS_S += $(FNT_DRV_OBJ_S) +DRV_OBJS_M += $(FNT_DRV_OBJ_M) + +# EOF diff --git a/src/winfonts/winfnt.c b/src/winfonts/winfnt.c new file mode 100644 index 000000000..28e83c47d --- /dev/null +++ b/src/winfonts/winfnt.c @@ -0,0 +1,566 @@ +/***************************************************************************/ +/* */ +/* winfnt.c */ +/* */ +/* FreeType font driver for Windows FNT/FON files */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used */ +/* modified and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + +#include +#include +#include +#include +#include + +#undef FT_COMPONENT +#define FT_COMPONENT trace_ttobjs + + static const FT_Frame_Field winmz_header_fields[] = + { FT_FRAME_START( 64 ), + FT_FRAME_USHORT_LE ( WinMZ_Header, magic ), + FT_FRAME_SKIP_BYTES( 29*2 ), + FT_FRAME_ULONG_LE ( WinMZ_Header, lfanew ), + FT_FRAME_END }; + + static const FT_Frame_Field winne_header_fields[] = + { FT_FRAME_START( 40 ), + FT_FRAME_USHORT_LE( WinNE_Header, magic ), + FT_FRAME_SKIP_BYTES( 34 ), + FT_FRAME_USHORT_LE( WinNE_Header, resource_tab_offset ), + FT_FRAME_USHORT_LE( WinNE_Header, rname_tab_offset ), + FT_FRAME_END }; + + + static const FT_Frame_Field winfnt_header_fields[] = + { FT_FRAME_START( 134 ), + FT_FRAME_USHORT_LE( WinFNT_Header, version ), + FT_FRAME_ULONG_LE ( WinFNT_Header, file_size ), + FT_FRAME_BYTES ( WinFNT_Header, copyright, 60 ), + FT_FRAME_USHORT_LE( WinFNT_Header, file_type ), + FT_FRAME_USHORT_LE( WinFNT_Header, nominal_point_size ), + FT_FRAME_USHORT_LE( WinFNT_Header, vertical_resolution ), + FT_FRAME_USHORT_LE( WinFNT_Header, horizontal_resolution ), + FT_FRAME_USHORT_LE( WinFNT_Header, ascent ), + FT_FRAME_USHORT_LE( WinFNT_Header, internal_leading ), + FT_FRAME_USHORT_LE( WinFNT_Header, external_leading ), + FT_FRAME_BYTE ( WinFNT_Header, italic ), + FT_FRAME_BYTE ( WinFNT_Header, underline ), + FT_FRAME_BYTE ( WinFNT_Header, strike_out ), + FT_FRAME_USHORT_LE( WinFNT_Header, weight ), + FT_FRAME_BYTE ( WinFNT_Header, charset ), + FT_FRAME_USHORT_LE( WinFNT_Header, pixel_width ), + FT_FRAME_USHORT_LE( WinFNT_Header, pixel_height ), + FT_FRAME_BYTE ( WinFNT_Header, pitch_and_family ), + FT_FRAME_USHORT_LE( WinFNT_Header, avg_width ), + FT_FRAME_USHORT_LE( WinFNT_Header, max_width ), + FT_FRAME_BYTE ( WinFNT_Header, first_char ), + FT_FRAME_BYTE ( WinFNT_Header, last_char ), + FT_FRAME_BYTE ( WinFNT_Header, default_char ), + FT_FRAME_BYTE ( WinFNT_Header, break_char ), + FT_FRAME_USHORT_LE( WinFNT_Header, bytes_per_row ), + FT_FRAME_ULONG_LE ( WinFNT_Header, device_offset ), + FT_FRAME_ULONG_LE ( WinFNT_Header, face_name_offset ), + FT_FRAME_ULONG_LE ( WinFNT_Header, bits_pointer ), + FT_FRAME_ULONG_LE ( WinFNT_Header, bits_offset ), + FT_FRAME_BYTE ( WinFNT_Header, reserved ), + FT_FRAME_ULONG_LE ( WinFNT_Header, flags ), + FT_FRAME_USHORT_LE( WinFNT_Header, A_space ), + FT_FRAME_USHORT_LE( WinFNT_Header, B_space ), + FT_FRAME_USHORT_LE( WinFNT_Header, C_space ), + FT_FRAME_USHORT_LE( WinFNT_Header, color_table_offset ), + FT_FRAME_BYTES ( WinFNT_Header, reserved, 4 ), + + FT_FRAME_END }; + + + static + void fnt_done_font( FT_Stream stream, + FNT_Font* font ) + { + if (font->fnt_frame) + RELEASE_Frame( font->fnt_frame ); + + font->fnt_size = 0; + font->fnt_frame = 0; + } + + + static + FT_Error fnt_load_font( FT_Stream stream, + FNT_Font* font ) + { + FT_Error error; + WinFNT_Header* header = &font->header; + + /* first of all, read the FNT header */ + if ( FILE_Seek ( font->offset ) || + READ_Fields( winfnt_header_fields, header ) ) + goto Exit; + + /* check header */ + if ( header->version != 0x200 && + header->version != 0x300 ) + { + FT_TRACE2(( "not a valid FNT file\n" )); + error = FT_Err_Unknown_File_Format; + goto Exit; + } + + if ( header->file_type & 1 ) + { + FT_TRACE2(( "can't handle vector FNT fonts\n" )); + error = FT_Err_Unknown_File_Format; + goto Exit; + } + + /* small fixup. some fonts have the "pixel_width" field set to 0 */ + if ( header->pixel_width == 0 ) + header->pixel_width = header->pixel_height; + + /* this is a FNT file/table, we now extract its frame */ + if ( FILE_Seek( font->offset ) || + EXTRACT_Frame( header->file_size, font->fnt_frame ) ) + goto Exit; + + Exit: + return error; + } + + + + static + void fnt_done_fonts( FNT_Face face ) + { + FT_Memory memory = FT_FACE(face)->memory; + FT_Stream stream = FT_FACE(face)->stream; + FNT_Font* cur = face->fonts; + FNT_Font* limit = cur + face->num_fonts; + + for ( ; cur < limit; cur++ ) + fnt_done_font( stream, cur ); + + FREE( face->fonts ); + face->num_fonts = 0; + } + + + + static + FT_Error fnt_get_dll_fonts( FNT_Face face ) + { + FT_Error error; + FT_Stream stream = FT_FACE(face)->stream; + FT_Memory memory = FT_FACE(face)->memory; + WinMZ_Header mz_header; + + face->fonts = 0; + face->num_fonts = 0; + + /* does it begin with a MZ header ?? */ + if ( FILE_Seek( 0 ) || + READ_Fields( winmz_header_fields, &mz_header ) ) + goto Exit; + + if ( mz_header.magic == WINFNT_MZ_MAGIC ) + { + /* yes, now look for a NE header in the file */ + WinNE_Header ne_header; + + if ( FILE_Seek( mz_header.lfanew ) || + READ_Fields( winne_header_fields, &ne_header ) ) + goto Exit; + + if ( ne_header.magic == WINFNT_NE_MAGIC ) + { + /* good, now look in the resource table for each FNT resource */ + FT_ULong res_offset = mz_header.lfanew + ne_header.resource_tab_offset; + + FT_UShort size_shift; + FT_UShort font_count = 0; + FT_ULong font_offset = 0; + + if ( FILE_Seek( res_offset ) || + ACCESS_Frame( ne_header.rname_tab_offset - + ne_header.resource_tab_offset ) ) + goto Exit; + + size_shift = GET_UShortLE(); + + for (;;) + { + FT_UShort type_id, count; + + type_id = GET_UShortLE(); + if (!type_id) + break; + + count = GET_UShortLE(); + + if (type_id == 0x8008) + { + font_count = count; + font_offset = FILE_Pos() + 4 + (stream->cursor - stream->limit); + break; + } + + stream->cursor += 4 + count*12; + } + FORGET_Frame(); + + if ( !font_count || !font_offset ) + { + FT_TRACE2(( "This file doesn't contain any FNT resource !!\n" )); + error = FT_Err_Unknown_File_Format; + goto Exit; + } + + if ( FILE_Seek( font_offset ) || + ALLOC_ARRAY( face->fonts, font_count, FNT_Font ) ) + goto Exit; + + face->num_fonts = font_count; + + if ( ACCESS_Frame( (FT_Long)font_count * 12 ) ) + goto Exit; + + /* now read the offset and position of each FNT font */ + { + FNT_Font* cur = face->fonts; + FNT_Font* limit = cur + font_count; + + for ( ; cur < limit; cur++ ) + { + cur->offset = (FT_ULong)GET_UShortLE() << size_shift; + cur->fnt_size = (FT_ULong)GET_UShortLE() << size_shift; + cur->size_shift = size_shift; + stream->cursor += 8; + } + } + FORGET_Frame(); + + /* finally, try to load each font there */ + { + FNT_Font* cur = face->fonts; + FNT_Font* limit = cur + font_count; + + for ( ; cur < limit; cur++ ) + { + error = fnt_load_font( stream, cur ); + if (error) goto Fail; + } + } + } + } + + Fail: + if (error) + fnt_done_fonts( face ); + + Exit: + return error; + } + + + + static + void FNT_Done_Face( FNT_Face face ) + { + FT_Memory memory = FT_FACE_MEMORY(face); + + fnt_done_fonts(face); + + FREE( face->root.available_sizes ); + face->root.num_fixed_sizes = 0; + } + + + + static + FT_Error FNT_Init_Face( FT_Stream stream, + FNT_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + FT_Error error; + FT_Memory memory = FT_FACE_MEMORY(face); + + FT_UNUSED(num_params); + FT_UNUSED(params); + FT_UNUSED(face_index); + + /* try to load several fonts from a DLL */ + error = fnt_get_dll_fonts( face ); + if (error) + { + /* this didn't work, now try to load a single FNT font */ + FT_Memory memory = FT_FACE_MEMORY(face); + FNT_Font* font; + + if ( ALLOC( face->fonts, sizeof(*face->fonts) ) ) + goto Exit; + + face->num_fonts = 1; + font = face->fonts; + + font->offset = 0; + font->fnt_size = stream->size; + + error = fnt_load_font( stream, font ); + if (error) + goto Fail; + } + + /* all right, one or more fonts were loaded, we now need to */ + /* fill the root FT_Face fields with relevant information.. */ + { + FT_Face root = FT_FACE(face); + FNT_Font* fonts = face->fonts; + FNT_Font* limit = fonts + face->num_fonts; + FNT_Font* cur; + + root->num_faces = 1; + root->face_flags = FT_FACE_FLAG_FIXED_SIZES | + FT_FACE_FLAG_HORIZONTAL; + + if ( fonts->header.avg_width == fonts->header.max_width ) + root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; + + if ( fonts->header.italic ) + root->style_flags |= FT_STYLE_FLAG_ITALIC; + + if ( fonts->header.weight >= 800 ) + root->style_flags |= FT_STYLE_FLAG_BOLD; + + /* Setup the "fixed_sizes" array */ + if ( ALLOC_ARRAY( root->available_sizes, face->num_fonts, FT_Bitmap_Size ) ) + goto Fail; + + root->num_fixed_sizes = face->num_fonts; + + { + FT_Bitmap_Size* size = root->available_sizes; + + for ( cur = fonts; cur < limit; cur++, size++ ) + { + size->width = cur->header.pixel_width; + size->height = cur->header.pixel_height; + } + } + + /* Setup the "charmaps" array */ + root->charmaps = &face->charmap_handle; + root->num_charmaps = 1; + + face->charmap.encoding = ft_encoding_unicode; + face->charmap.platform_id = 3; + face->charmap.encoding_id = 1; + face->charmap.face = root; + + face->charmap_handle = &face->charmap; + + root->charmap = face->charmap_handle; + + /* setup remaining flags */ + root->num_glyphs = fonts->header.last_char - fonts->header.first_char + 1; + + root->family_name = (FT_String*)fonts->fnt_frame + fonts->header.face_name_offset; + root->style_name = "Regular"; + if (root->style_flags & FT_STYLE_FLAG_BOLD) + { + if (root->style_flags & FT_STYLE_FLAG_ITALIC) + root->style_name = "Bold Italic"; + else + root->style_name = "Bold"; + } + else if (root->style_flags & FT_STYLE_FLAG_ITALIC) + root->style_name = "Italic"; + } + + + Fail: + if (error) + FNT_Done_Face( face ); + + Exit: + return error; + } + + + + static + FT_Error FNT_Set_Pixel_Size( FNT_Size size ) + { + /* look up a font corresponding to the current pixel size */ + FNT_Face face = (FNT_Face)FT_SIZE_FACE(size); + FNT_Font* cur = face->fonts; + FNT_Font* limit = cur + face->num_fonts; + + size->font = 0; + for ( ; cur < limit; cur++ ) + { + /* we only compare the character height, as fonts used some strange */ + /* values.. */ + if ( cur->header.pixel_height == size->root.metrics.y_ppem ) + { + size->font = cur; + break; + } + } + + return (size->font ? FT_Err_Ok : FT_Err_Invalid_Argument); + } + + + static + FT_UInt FNT_Get_Char_Index( FT_CharMap charmap, + FT_ULong char_code ) + { + FT_UInt result = char_code; + + if (charmap) + { + FNT_Font* font = ((FNT_Face)charmap->face)->fonts; + FT_UInt first = font->header.first_char; + FT_UInt count = font->header.last_char - first + 1; + + char_code -= first; + if (char_code < count) + result = char_code; + else + result = font->header.default_char - first; + } + return result; + } + + + + static + FT_Error FNT_Load_Glyph( FT_GlyphSlot slot, + FNT_Size size, + FT_UInt glyph_index, + FT_Int load_flags ) + { + FNT_Font* font = size->font; + FT_Error error = 0; + FT_Byte* p; + FT_Int len; + FT_Bitmap* bitmap = &slot->bitmap; + FT_ULong offset; + FT_Bool new_format; + + FT_UNUSED(slot); + FT_UNUSED(load_flags); + + if (!font) + { + error = FT_Err_Invalid_Argument; + goto Exit; + } + + new_format = font->header.version == 0x300; + len = new_format ? 6 : 4; + + /* jump to glyph entry */ + p = font->fnt_frame + 118 + len*glyph_index; + + bitmap->width = NEXT_ShortLE(p); + + if (new_format) + offset = NEXT_ULongLE(p); + else + offset = NEXT_UShortLE(p); + + /* jump to glyph data */ + p = font->fnt_frame + /* font->header.bits_offset */ + offset; + + /* allocate and build bitmap */ + { + FT_Memory memory = FT_FACE_MEMORY(slot->face); + FT_Int pitch = (bitmap->width+7) >> 3; + FT_Byte* column; + FT_Byte* write; + + bitmap->pitch = pitch; + bitmap->rows = font->header.pixel_height; + bitmap->pixel_mode = ft_pixel_mode_mono; + + if ( ALLOC( bitmap->buffer, pitch * bitmap->rows ) ) + goto Exit; + + + column = (FT_Byte*)bitmap->buffer; + + for ( ; pitch > 0; pitch--, column++ ) + { + FT_Byte* limit = p + bitmap->rows; + + for ( write = column; p < limit; p++, write += bitmap->pitch ) + write[0] = p[0]; + } + } + + slot->flags = ft_glyph_own_bitmap; + slot->bitmap_left = 0; + slot->bitmap_top = font->header.ascent; + slot->format = ft_glyph_format_bitmap; + + /* now set up metrics */ + slot->metrics.horiAdvance = bitmap->width << 6; + slot->metrics.horiBearingX = 0; + slot->metrics.horiBearingY = slot->bitmap_top << 6; + + slot->linearHoriAdvance = (FT_Fixed)bitmap->width << 16; + + Exit: + return error; + } + + const FT_Driver_Class winfnt_driver_class = + { + { + ft_module_font_driver, + sizeof( FT_DriverRec ), + + "winfonts", + 0x10000, + 0x20000, + + 0, + + (FT_Module_Constructor) 0, + (FT_Module_Destructor) 0, + (FT_Module_Requester) 0 + }, + + sizeof( FNT_FaceRec ), + sizeof( FNT_SizeRec ), + sizeof( FT_GlyphSlotRec ), + + (FTDriver_initFace) FNT_Init_Face, + (FTDriver_doneFace) FNT_Done_Face, + (FTDriver_initSize) 0, + (FTDriver_doneSize) 0, + (FTDriver_initGlyphSlot)0, + (FTDriver_doneGlyphSlot)0, + + (FTDriver_setCharSizes) FNT_Set_Pixel_Size, + (FTDriver_setPixelSizes)FNT_Set_Pixel_Size, + + (FTDriver_loadGlyph) FNT_Load_Glyph, + (FTDriver_getCharIndex) FNT_Get_Char_Index, + + (FTDriver_getKerning) 0, + (FTDriver_attachFile) 0, + (FTDriver_getAdvances) 0 + }; + diff --git a/src/winfonts/winfnt.h b/src/winfonts/winfnt.h new file mode 100644 index 000000000..9a606b752 --- /dev/null +++ b/src/winfonts/winfnt.h @@ -0,0 +1,146 @@ +/***************************************************************************/ +/* */ +/* winfnt.h */ +/* */ +/* FreeType font driver for Windows FNT/FON files */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used */ +/* modified and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + +#ifndef WINFNT_H +#define WINFNT_H + +#include + + typedef struct WinMZ_Header_ + { + FT_UShort magic; + /* skipped content */ + FT_UShort lfanew; + + } WinMZ_Header; + + + + typedef struct WinNE_Header_ + { + FT_UShort magic; + /* skipped content */ + FT_UShort resource_tab_offset; + FT_UShort rname_tab_offset; + + } WinNE_Header; + + + + typedef struct WinNameInfo_ + { + FT_UShort offset; + FT_UShort length; + FT_UShort flags; + FT_UShort id; + FT_UShort handle; + FT_UShort usage; + + } WinNameInfo; + + + typedef struct WinResourceInfo_ + { + FT_UShort type_id; + FT_UShort count; + + } WinResourceInfo; + +#define WINFNT_MZ_MAGIC 0x5A4D +#define WINFNT_NE_MAGIC 0x454E + + + typedef struct WinFNT_Header_ + { + FT_UShort version; + FT_ULong file_size; + FT_Byte copyright[60]; + FT_UShort file_type; + FT_UShort nominal_point_size; + FT_UShort vertical_resolution; + FT_UShort horizontal_resolution; + FT_UShort ascent; + FT_UShort internal_leading; + FT_UShort external_leading; + FT_Byte italic; + FT_Byte underline; + FT_Byte strike_out; + FT_UShort weight; + FT_Byte charset; + FT_UShort pixel_width; + FT_UShort pixel_height; + FT_Byte pitch_and_family; + FT_UShort avg_width; + FT_UShort max_width; + FT_Byte first_char; + FT_Byte last_char; + FT_Byte default_char; + FT_Byte break_char; + FT_UShort bytes_per_row; + FT_ULong device_offset; + FT_ULong face_name_offset; + FT_ULong bits_pointer; + FT_ULong bits_offset; + FT_Byte reserved; + FT_ULong flags; + FT_UShort A_space; + FT_UShort B_space; + FT_UShort C_space; + FT_UShort color_table_offset; + FT_Byte reserved2[4]; + + } WinFNT_Header; + + + typedef struct FNT_Font_ + { + FT_ULong offset; + FT_Int size_shift; + + WinFNT_Header header; + + FT_Byte* fnt_frame; + FT_ULong fnt_size; + + } FNT_Font; + + + typedef struct FNT_SizeRec_ + { + FT_SizeRec root; + FNT_Font* font; + + } FNT_SizeRec, *FNT_Size; + + + + typedef struct FNT_FaceRec_ + { + FT_FaceRec root; + + FT_UInt num_fonts; + FNT_Font* fonts; + + FT_CharMap charmap_handle; + FT_CharMapRec charmap; /* a single charmap per face */ + + } FNT_FaceRec, *FNT_Face; + + + FT_EXPORT_VAR(const FT_Driver_Class) winfnt_driver_class; + +#endif /* WINFNT_H */