📄 font_freetype2.c
字号:
/* * Freetype 2 driver for Microwindows * * Originally written by Koninklijke Philips Electronics N.V. * * (Loosly) Based on the FreeType 1.x driver, font_freetype.c. * * Portions contributed by Koninklijke Philips Electronics N.V. * These portions are Copyright 2002 Koninklijke Philips Electronics * N.V. All Rights Reserved. These portions are licensed under the * terms of the Mozilla Public License, version 1.1, or, at your * option, the GNU General Public License version 2.0. Please see * the file "ChangeLog" for documentation regarding these * contributions. *//* * Note on FreeType versions: * 2.0.9 - worked (not tested recently) * 2.1.0 - not tested * 2.1.1 - worked (switch CONFIG_OPTION_USE_CMAPS off if your fonts are * rejected as invalid). * 2.1.2 - avoid this release. Rotations were the wrong way. There is * no way to test for this and correct it, because this version of * the library mis-reports the version number as 2.1.1. * 2.1.3 - works. *//*#define NDEBUG*/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <assert.h>#include <string.h>#include <dirent.h>#include "device.h"#include "devfont.h"#if (UNIX | DOS_DJGPP)#define strcmpi strcasecmp#endif/* temp extern decls*/extern MWPIXELVAL gr_foreground;extern MWPIXELVAL gr_background;extern MWBOOL gr_usebg;/* * Enable the Freetype 2 font cache. Only applicable if * FreeType 2 itself is enabled. * * It is STRONGLY recommended that you turn this option on, * as to will give a HUGE speed boost. If you are using many * Microwindows font objects, this can also save memory (since * there is a single cache with a fixed size shared across * the system, but the memory use without caching is * proportional to the number of MWFREETYPE2FONT objects). * * FIXME: This option should be in the config file. */#define HAVE_FREETYPE_2_CACHE 1/* * Enable the Freetype 2 character map cache. Only applicable if * FreeType 2 itself is enabled, and HAVE_FREETYPE_2_CACHE is also * enabled. * * It is recommended that you turn this option on if you are * using FreeType 2.1.1 or later, as it should give a small * speed boost. (With earlier releases, this should work but * might actually slow down rendering slightly - the cache was * much slower before FreeType 2.1.1.) * * FIXME: This option should be in the config file. */#define HAVE_FREETYPE_2_CMAP_CACHE 0/* **************************************************************************//* FreeType 2.x *//* **************************************************************************/#include <ft2build.h>#include FT_FREETYPE_H#include FT_TRIGONOMETRY_H#include FT_GLYPH_H#if HAVE_FREETYPE_2_CACHE# include FT_CACHE_H# include FT_CACHE_SMALL_BITMAPS_H# if HAVE_FREETYPE_2_CMAP_CACHE# include FT_CACHE_CHARMAP_H# endif#endif/* Checking FreeType version numbers *//** * Change a major.minor.patch version number into a single number, which * is much simpler to compare. * * If the paramaters are compile-time constants, then the result is also * a compile-time constant (and so can be used in #if statements). * * @param major Version number part * @param minor Version number part * @param patch Version number part * @return Single version number */#define SIMPLIFY_VERSION_NUMBER(major,minor,patch) \ ((major)*0x01000000UL + (minor)*0x01000UL + (patch)*0x01UL)/** * The FreeType version number, in simplified format. */#define FREETYPE_VERSION_NUMBER_SIMPLE \ SIMPLIFY_VERSION_NUMBER(FREETYPE_MAJOR,FREETYPE_MINOR,FREETYPE_PATCH)/** * TRUE if the FreeType version number is equal to or greater than the * specified version. * * If the paramaters are compile-time constants, then the result is also * a compile-time constant (and so can be used in #if statements). * * @param major Version number part * @param minor Version number part * @param patch Version number part * @return Single version number */#define HAVE_FREETYPE_VERSION_AFTER_OR_EQUAL(major,minor,patch) \ (FREETYPE_VERSION_NUMBER_SIMPLE >= SIMPLIFY_VERSION_NUMBER(major,minor,patch))#ifndef FREETYPE_FONT_DIR/** * The default Freetype font directory. */#define FREETYPE_FONT_DIR "/usr/local/microwin/fonts"#endif/** * The Freetype 2 font directory. */char *freetype2_font_dir;typedef struct freetype2_fontdata_ freetype2_fontdata;struct freetype2_fontdata_{ int isBuffer; union { char *filename; struct { unsigned char *data; unsigned length; } buffer; } data; int refcount; /* Currently only used for buffers, not files */#if HAVE_FREETYPE_2_CACHE freetype2_fontdata *next;#endif};struct MWFREETYPE2FONT_STRUCT{ PMWFONTPROCS fontprocs; /* common hdr */ MWCOORD fontsize; int fontrotation; int fontattr; /* freetype stuff */ char *filename; /* NULL if buffered */ freetype2_fontdata *faceid; /* only used if HAVE_FREETYPE_2_CACHE or buffered. */#if HAVE_FREETYPE_2_CACHE#if HAVE_FREETYPE_VERSION_AFTER_OR_EQUAL(2,1,3) FTC_ImageTypeRec imagedesc;#else FTC_ImageDesc imagedesc;#endif#if HAVE_FREETYPE_2_CMAP_CACHE FTC_CMapDescRec cmapdesc;#endif#else FT_Face face;#endif FT_Matrix matrix;};static MWBOOL freetype2_getfontinfo(PMWFONT pfont, PMWFONTINFO pfontinfo);static void freetype2_gettextsize(PMWFONT pfont, const void *text, int cc, MWTEXTFLAGS flags, MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase);static void freetype2_destroyfont(PMWFONT pfont);static void freetype2_drawtext(PMWFONT pfont, PSD psd, MWCOORD x, MWCOORD y, const void *text, int cc, MWTEXTFLAGS flags);static void freetype2_setfontsize(PMWFONT pfont, MWCOORD fontsize);static void freetype2_setfontrotation(PMWFONT pfont, int tenthdegrees);static void freetype2_setfontattr(PMWFONT pfont, int setflags, int clrflags);static PMWFONT freetype2_duplicate(PMWFONT psrcfont, MWCOORD fontsize);/** * The virtual method table for FreeType 2 fonts (i.e. class MWFREETYPE2FONT). */static MWFONTPROCS freetype2_procs = { MWTF_UC16, /* routines expect unicode 16 */ freetype2_getfontinfo, freetype2_gettextsize, NULL, /* gettextbits */ freetype2_destroyfont, freetype2_drawtext, freetype2_setfontsize, freetype2_setfontrotation, freetype2_setfontattr, freetype2_duplicate,};static PMWFREETYPE2FONTfreetype2_createfont_internal(freetype2_fontdata * faceid, char *filename, MWCOORD height);/** * The freetype library instance - a singleton. */static FT_Library freetype2_library = NULL;#if HAVE_FREETYPE_2_CACHE/** * The Freetype 2 cache subsystem requires a 1-1 mapping * between "void *" pointers and actual font files. The * only almost-sane way to do this is to have a linked list * of font file names, and use pointers to the entries * in that array. Font names are added to the list the * first time the font is used, and never removed. */static freetype2_fontdata *freetype2_fonts = NULL;/** * The FreeType 2 cache. */static FTC_Manager freetype2_cache_manager;/** * The FreeType 2 cache for glyph bitmaps. */static FTC_SBitCache freetype2_cache_sbit;#if HAVE_FREETYPE_2_CMAP_CACHE/** * The FreeType 2 cache for charater->glyph mappings. */static FTC_CMapCache freetype2_cache_cmap;#endif#if HAVE_FREETYPE_2_CMAP_CACHE/** * Look up a glyph index from a character code. * There are two implementations of this macro, which one is used * depends on the setting of HAVE_FREETYPE_2_CMAP_CACHE * * @param pf_ The Microwindows font * @param face_ The equivalent FreeType 2 font * @param ch_ The character to look up * @return The glyph index. */#define LOOKUP_CHAR(pf_,face_,ch_) \ (FTC_CMapCache_Lookup(freetype2_cache_cmap, \ &((pf_)->cmapdesc), \ (ch_)))#else#define LOOKUP_CHAR(pf_,face_,ch_) \ (FT_Get_Char_Index((face_), (ch_)))#endif/** * The FreeType 2 sbit cache does not support bitmaps >256x256. * For fonts up to and including the following height, use the cache. * For larger fonts, do it the slow way. * * Note: Should probably detect this using the maximum ascent and * maximum descent values. FIXME. */#define FREETYPE2_CACHE_FONT_SIZE_LIMIT 100/** * Test if a font can use the FreeType 2 cache. * * To use the cache, there must be no rotation, and the font must be * small enough for the bitmaps to be supported (i.e. it must be under * FREETYPE2_CACHE_FONT_SIZE_LIMIT). */#define CAN_USE_FT2_CACHE(pf_) \ (((pf_)->fontrotation == 0) && \ ((pf_)->fontsize < FREETYPE2_CACHE_FONT_SIZE_LIMIT))/** * Called from the FreeType 2 cache to load a font file. * * @param face_id The font ID. This is a pointer to a freetype2_fontdata structure. * @param library the FreeType library instance. * @param request_data FIXME * @param aface FIXME */static FT_Errorfreetype2_face_requester(FTC_FaceID face_id, FT_Library library, FT_Pointer request_data, FT_Face * aface){ freetype2_fontdata *fontdata = (freetype2_fontdata *) face_id; // simple typecast assert(fontdata); if (fontdata->isBuffer) { unsigned char * buffer = fontdata->data.buffer.data; unsigned length = fontdata->data.buffer.length; /* DPRINTF("Font magic = '%c%c%c%c', len = %u @ freetype2_face_requester\n", (char)buffer[0], (char)buffer[1], (char)buffer[2], (char)buffer[3], length); */ assert(buffer); return FT_New_Memory_Face(library, buffer, length, 0, aface); } else { char * filename = fontdata->data.filename; /* DPRINTF("Loading font from file '%s' @ freetype2_face_requester\n", filename); */ assert(filename); return FT_New_Face(library, filename, 0, aface); }}#endif/** * Initialize the FreeType 2 driver. If successful, this is a one-time * operation. Subsequent calls will do nothing, successfully. * * @param psd Unused. * @return 0 on error, nonzero on success. */intfreetype2_init(PSD psd){ FT_Error err; if (freetype2_library != NULL) { return 1; } if ((freetype2_font_dir = getenv("MWFONTS")) == NULL) { freetype2_font_dir = FREETYPE_FONT_DIR; } /* Init freetype library */ err = FT_Init_FreeType(&freetype2_library); if (err != FT_Err_Ok) { freetype2_library = NULL; EPRINTF("Error 0x%x initializing FreeType 2\n", err); return 0; }#if HAVE_FREETYPE_2_CACHE /* initialize cache manager */ err = FTC_Manager_New(freetype2_library, 3, /* Faces */ 5, /* Sizes */ 512 * 1024, /* Bytes - 512K */ &freetype2_face_requester, NULL, &freetype2_cache_manager); if (err != FT_Err_Ok) { EPRINTF("Error 0x%x initializing FreeType 2 cache system\n", err); freetype2_cache_manager = NULL; FT_Done_FreeType(freetype2_library); freetype2_library = NULL; return 0; } err = FTC_SBitCache_New(freetype2_cache_manager, &freetype2_cache_sbit); if (err != FT_Err_Ok) { EPRINTF("Error 0x%x initializing FreeType 2 sbit cache system\n", err); freetype2_cache_sbit = NULL; FTC_Manager_Done(freetype2_cache_manager); freetype2_cache_manager = NULL; FT_Done_FreeType(freetype2_library); freetype2_library = NULL; return 0; }#if HAVE_FREETYPE_2_CMAP_CACHE err = FTC_CMapCache_New(freetype2_cache_manager, &freetype2_cache_cmap); if (err != FT_Err_Ok) { EPRINTF("Error 0x%x initializing FreeType 2 cmap cache system\n", err); freetype2_cache_cmap = NULL; // FIXME: Should we free the SBit cache here? freetype2_cache_sbit = NULL; FTC_Manager_Done(freetype2_cache_manager); freetype2_cache_manager = NULL; FT_Done_FreeType(freetype2_library); freetype2_library = NULL; return 0; }#endif#endif return 1;}/** * Create a font from a disk file. * * @param name The font file name or path. If no directory is specified, * freetype2_font_dir will be prepended. If no extension is * specified, ".ttf" will be added. * @param height The height of the font, in pixels. * @param attr The font attributes - a bitmask. * @return The new font, or NULL on error. */PMWFREETYPE2FONTfreetype2_createfont(const char *name, MWCOORD height, int attr){ PMWFREETYPE2FONT pf; char *p; char *fontname; freetype2_fontdata *faceid = NULL;#if HAVE_FREETYPE_2_CACHE int first_time = 0;#endif /* Initialization */ if (freetype2_library == NULL) { /* Init freetype library */ if (!freetype2_init(NULL)) { return NULL; } } fontname = malloc(6 + strlen(name) + strlen(freetype2_font_dir)); if (fontname == NULL) return NULL; /* check for pathname prefix */ if (strchr(name, '/') != NULL) { strcpy(fontname, name); } else { strcpy(fontname, freetype2_font_dir); strcat(fontname, "/"); strcat(fontname, name); } /* check for extension */ if ((p = strrchr(fontname, '.')) == NULL || ((strcmpi(p, ".ttf") != 0) && (strcmpi(p, ".pfr") != 0))) { strcat(fontname, ".ttf"); }#if HAVE_FREETYPE_2_CACHE faceid = freetype2_fonts; while ( (faceid != NULL) && (0 != strcmpi(faceid->data.filename, fontname)) ) { faceid = faceid->next; } if (faceid == NULL) { /* Not found in list, so add it. */ DPRINTF("Nano-X-Freetype2: Adding new font: %s\n", fontname); faceid = (freetype2_fontdata *) calloc(sizeof(*faceid), 1); if (faceid == NULL) { free(fontname); return NULL; } /* faceid->isBuffer = 0; - implied by calloc */ faceid->data.filename = fontname; /* Add to font list. */ faceid->next = freetype2_fonts; freetype2_fonts = faceid; /* Set a special flag. If we can't load the font, * we want to destroy the faceid. */ first_time = 1; } else { free(fontname); } fontname = faceid->data.filename;#else faceid = NULL;#endif pf = freetype2_createfont_internal(faceid, fontname, height); if (!pf) {#if HAVE_FREETYPE_2_CACHE if (first_time) { assert(freetype2_fonts == faceid); freetype2_fonts = faceid->next; free(fontname); free(faceid); }#else free(fontname);#endif return NULL; } GdSetFontAttr((PMWFONT) pf, attr, 0); return pf;}/** * Create a font from a memory buffer. * * @param buffer The font data. This will be copied by this function. * @param length The length of the font data. * @param height The height of the font, in pixels. * @return The new font, or NULL on error. */PMWFREETYPE2FONTfreetype2_createfontfrombuffer(const unsigned char *buffer, unsigned length, MWCOORD height){ PMWFREETYPE2FONT pf; freetype2_fontdata *faceid = NULL; unsigned char *buffercopy; assert(buffer); /* Initialization */ if (freetype2_library == NULL) { /* Init freetype library */ if (!freetype2_init(NULL)) { return NULL; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -