📄 font_freetype.c
字号:
/* * Copyright (c) 2000, 2002, 2003 Greg Haerr <greg@censoft.com> * Portions Copyright (c) 2002 by Koninklijke Philips Electronics N.V. * * Freetype TrueType routines originally contributed by Martin Jolicoeur * Heavily modified by Greg Haerr *//*#define NDEBUG*/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <math.h>#include <dirent.h>#include <freetype/freetype.h>#include <freetype/ftxkern.h>#include <freetype/ftnameid.h>#include <freetype/ftxcmap.h>#include <freetype/ftxwidth.h>#include "device.h"#include "devfont.h"#if TT_FREETYPE_MAJOR != 1 || TT_FREETYPE_MINOR < 3#error "You must link with freetype lib version 1.3.x +, and not freetype 2."#endiftypedef struct MWFREETYPEFONT { PMWFONTPROCS fontprocs; /* common hdr*/ MWCOORD fontsize; int fontrotation; int fontattr; TT_Face face; /* freetype stuff*/ TT_Instance instance; TT_CharMap char_map; TT_Kerning directory; TT_Matrix matrix; TT_Glyph glyph; MWBOOL can_kern; short last_glyph_code; short last_pen_pos;} MWFREETYPEFONT;int freetype_init(PSD psd);PMWFREETYPEFONT freetype_createfont(const char *name, MWCOORD height, int attr);static MWBOOL freetype_getfontinfo(PMWFONT pfont, PMWFONTINFO pfontinfo);static void freetype_gettextsize(PMWFONT pfont, const void *text, int cc, MWTEXTFLAGS flags, MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase);static void freetype_destroyfont(PMWFONT pfont);static void freetype_drawtext(PMWFONT pfont, PSD psd, MWCOORD x, MWCOORD y, const void *text, int cc, MWTEXTFLAGS flags);static void freetype_setfontsize(PMWFONT pfont, MWCOORD fontsize);static void freetype_setfontrotation(PMWFONT pfont, int tenthdegrees); /* handling routines for MWFREETYPEFONT*/static MWFONTPROCS freetype_procs = { MWTF_UC16, /* routines expect unicode 16*/ freetype_getfontinfo, freetype_gettextsize, NULL, /* gettextbits*/ freetype_destroyfont, freetype_drawtext, freetype_setfontsize, freetype_setfontrotation, NULL, /* setfontattr*/ NULL, /* duplicate not yet implemented */};static TT_Engine engine; /* THE ONLY freetype engine */static OUTPIXELVAL gray_palette[5];/* temp extern decls*/extern MWPIXELVAL gr_foreground;extern MWPIXELVAL gr_background;extern MWBOOL gr_usebg;intfreetype_init(PSD psd){ static int inited = 0; if (inited) return 1; /* Init freetype library */ if (TT_Init_FreeType (&engine) != TT_Err_Ok) { return 0; } /* Init kerning extension */ if (TT_Init_Kerning_Extension (engine) != TT_Err_Ok) return 0; inited = 1; return 1;}PMWFREETYPEFONTfreetype_createfont(const char *name, MWCOORD height, int attr){ PMWFREETYPEFONT pf; unsigned short i, n; unsigned short platform, encoding; TT_Face_Properties properties; char * p; char fontname[128]; /* check for pathname prefix*/ if (strchr(name, '/') != NULL) strcpy(fontname, name); else { strcpy(fontname, FREETYPE_FONT_DIR); strcat(fontname, "/"); strcat(fontname, name); } /* check for extension*/ if ((p = strrchr(fontname, '.')) == NULL || strcmp(p, ".ttf") != 0) { strcat(fontname, ".ttf"); } /* allocate font structure*/ pf = (PMWFREETYPEFONT)calloc(sizeof(MWFREETYPEFONT), 1); if (!pf) return NULL; pf->fontprocs = &freetype_procs; /* Load face */ if (TT_Open_Face (engine, fontname, &pf->face) != TT_Err_Ok) goto out; /* Load first kerning table */ pf->can_kern = TRUE; if (TT_Load_Kerning_Table (pf->face, 0) != TT_Err_Ok) pf->can_kern = FALSE; else { if (TT_Get_Kerning_Directory (pf->face, &pf->directory) != TT_Err_Ok) pf->can_kern = FALSE; else { /* Support only version 0 kerning table ... */ if ((pf->directory.version != 0) || (pf->directory.nTables <= 0) || (pf->directory.tables->loaded != 1) || (pf->directory.tables->version != 0) || (pf->directory.tables->t.kern0.nPairs <= 0)) pf->can_kern = FALSE; } } /* get face properties and allocate preload arrays */ TT_Get_Face_Properties (pf->face, &properties);#if 0 /* * Use header information for ascent and descent * to compute scaled ascent/descent for current font height. */ h = properties.os2->sTypoAscender - properties.os2->sTypoDescender + properties.os2->sTypoLineGap; ascent = properties.os2->sTypoAscender + properties.os2->sTypoLineGap/2; pf->ascent = (ascent * height + h/2) / h; pf->descent = height - pf->ascent;#endif /* Create a glyph container */ if (TT_New_Glyph (pf->face, &pf->glyph) != TT_Err_Ok) goto out; /* create instance */ if (TT_New_Instance (pf->face, &pf->instance) != TT_Err_Ok) goto out; /* Set the instance resolution */ if (TT_Set_Instance_Resolutions (pf->instance, 96, 96) != TT_Err_Ok) goto out; /* Look for a Unicode charmap: Windows flavor of Apple flavor only */ n = properties.num_CharMaps; for (i = 0; i < n; i++) { TT_Get_CharMap_ID (pf->face, i, &platform, &encoding); if (((platform == TT_PLATFORM_MICROSOFT) && (encoding == TT_MS_ID_UNICODE_CS)) || ((platform == TT_PLATFORM_APPLE_UNICODE) && (encoding == TT_APPLE_ID_DEFAULT))) { TT_Get_CharMap (pf->face, i, &pf->char_map); i = n + 1; } } if (i == n) { DPRINTF("freetype_createfont: no unicode map table\n"); goto out; } GdSetFontSize((PMWFONT)pf, height); GdSetFontRotation((PMWFONT)pf, 0); GdSetFontAttr((PMWFONT)pf, attr, 0); return pf;out: free(pf); return NULL;}static intcompute_kernval(PMWFREETYPEFONT pf, short current_glyph_code){ int i = 0; int kernval; int nPairs = pf->directory.tables->t.kern0.nPairs; TT_Kern_0_Pair *pair = pf->directory.tables->t.kern0.pairs; if (pf->last_glyph_code != -1) { while ((pair->left != pf->last_glyph_code) && (pair->right != current_glyph_code)) { pair++; i++; if (i == nPairs) break; } if (i == nPairs) kernval = 0; else /* We round the value (hence the +32) */ kernval = (pair->value + 32) & -64; } else kernval = 0; return kernval;}static TT_UShortGet_Glyph_Width(PMWFREETYPEFONT pf, TT_UShort glyph_index){ TT_Glyph_Metrics metrics; if (TT_Load_Glyph ( pf->instance, pf->glyph, TT_Char_Index (pf->char_map,glyph_index), TTLOAD_SCALE_GLYPH|TTLOAD_HINT_GLYPH) != TT_Err_Ok) { /* Try to load default glyph: index 0 */ if (TT_Load_Glyph ( pf->instance, pf->glyph, 0, TTLOAD_SCALE_GLYPH|TTLOAD_HINT_GLYPH) != TT_Err_Ok) return 0; } TT_Get_Glyph_Metrics (pf->glyph, &metrics); return((metrics.advance & 0xFFFFFFC0) >> 6);}/* Render a single glyph*/static voiddrawchar(PMWFREETYPEFONT pf, PSD psd, TT_Glyph glyph, int x_offset, int y_offset){ TT_F26Dot6 xmin, ymin, xmax, ymax, x, y, z; unsigned char *src, *srcptr; MWPIXELVAL *dst, *dstptr; MWPIXELVAL *bitmap; int size, width, height; TT_Outline outline; TT_BBox bbox; TT_Raster_Map Raster; TT_Error error; /*MWPIXELVAL save;*/ /* we begin by grid-fitting the bounding box */ TT_Get_Glyph_Outline (pf->glyph, &outline); TT_Get_Outline_BBox (&outline, &bbox); xmin = (bbox.xMin & -64) >> 6; ymin = (bbox.yMin & -64) >> 6; xmax = ((bbox.xMax + 63) & -64) >> 6; ymax = ((bbox.yMax + 63) & -64) >> 6; width = xmax - xmin; height = ymax - ymin; size = width * height; /* now re-allocate the raster bitmap */ Raster.rows = height; Raster.width = width; if (pf->fontattr&MWTF_ANTIALIAS) Raster.cols = (Raster.width + 3) & -4; /* pad to 32-bits */ else Raster.cols = (Raster.width + 7) & -8; /* pad to 64-bits ??? */ Raster.flow = TT_Flow_Up; Raster.size = Raster.rows * Raster.cols; Raster.bitmap = malloc (Raster.size); memset (Raster.bitmap, 0, Raster.size); /* now render the glyph in the small pixmap */ /* IMPORTANT NOTE: the offset parameters passed to the function */ /* TT_Get_Glyph_Bitmap() must be integer pixel values, i.e., */ /* multiples of 64. HINTING WILL BE RUINED IF THIS ISN'T THE CASE! */ /* This is why we _did_ grid-fit the bounding box, especially xmin */ /* and ymin. */ if (!(pf->fontattr&MWTF_ANTIALIAS)) error = TT_Get_Glyph_Bitmap (pf->glyph, &Raster, -xmin * 64, -ymin * 64); else error = TT_Get_Glyph_Pixmap (pf->glyph, &Raster, -xmin * 64, -ymin * 64); if (error) { free (Raster.bitmap); return; } bitmap = malloc (size * sizeof (MWPIXELVAL)); memset (bitmap, 0, size * sizeof (MWPIXELVAL)); src = (char *) Raster.bitmap; dst = bitmap + (size - width); for (y = ymin; y < ymax; y++) { srcptr = src; dstptr = dst; for (x = xmin; x < xmax; x++) { if (pf->fontattr&MWTF_ANTIALIAS) *dstptr++ = gray_palette[(int) *srcptr]; else { for(z=0; z <= ((xmax-x-1) < 7 ? (xmax-x-1) : 7); z++) { *dstptr++ = ((*srcptr << z) & 0x80)? gr_foreground: gr_background; } x += 7; } srcptr++; } src += Raster.cols; dst -= width; } /* FIXME - must clear background upstairs if not gr_usebg*/ /* FIXME: GdArea problem if fg == bg*/ /*save = gr_background;*/ /*gr_background = gr_foreground + 1;*/ /* Now draw the bitmap ... */ GdArea(psd, x_offset + xmin, y_offset - (ymin + height), width, height, bitmap, MWPF_PIXELVAL); /*gr_background = save;*/ free (bitmap); free (Raster.bitmap);}/* * Draw unicode 16 text string using FREETYPE type font */static voidfreetype_drawtext(PMWFONT pfont, PSD psd, MWCOORD ax, MWCOORD ay, const void *text, int cc, MWTEXTFLAGS flags){ PMWFREETYPEFONT pf = (PMWFREETYPEFONT)pfont; const unsigned short * str = text; TT_F26Dot6 x = ax, y = ay; TT_Pos vec_x, vec_y; int i; TT_F26Dot6 startx, starty; TT_Outline outline; TT_UShort curchar; TT_Glyph_Metrics metrics; TT_Face_Properties properties; TT_Instance_Metrics imetrics; TT_F26Dot6 ascent, descent; static unsigned char blend[5] = { 0x00, 0x44, 0x88, 0xcc, 0xff }; static unsigned char virtual_palette[5] = { 0, 1, 2, 3, 4 }; pf->last_glyph_code = -1; /* reset kerning*/ pf->last_pen_pos = -32767; /* * Compute instance ascent & descent values * in fractional units (1/64th pixel) */ TT_Get_Face_Properties (pf->face, &properties); TT_Get_Instance_Metrics(pf->instance, &imetrics); ascent = ((properties.horizontal->Ascender * imetrics.y_scale)/0x10000); descent = ((properties.horizontal->Descender*imetrics.y_scale)/0x10000); /* * Offset the starting point if necessary, * FreeType always aligns at baseline */ if (flags&MWTF_BOTTOM) { vec_x = 0; vec_y = descent; TT_Transform_Vector(&vec_x, &vec_y,&pf->matrix); x -= vec_x / 64; y += vec_y / 64; } else if (flags&MWTF_TOP) { vec_x = 0; vec_y = ascent; TT_Transform_Vector(&vec_x, &vec_y,&pf->matrix); x -= vec_x / 64; y += vec_y / 64; } /* Set the "graylevels" */ if (pf->fontattr&MWTF_ANTIALIAS) { TT_Set_Raster_Gray_Palette (engine, virtual_palette); alphablend(psd, gray_palette, gr_foreground, gr_background, blend, 5); } startx = x; starty = y; for (i = 0; i < cc; i++) { curchar = TT_Char_Index (pf->char_map, str[i]); if (TT_Load_Glyph (pf->instance, pf->glyph, curchar, TTLOAD_DEFAULT) != TT_Err_Ok) continue; if (pf->fontrotation) { TT_Get_Glyph_Outline (pf->glyph, &outline); TT_Transform_Outline (&outline, &pf->matrix); } TT_Get_Glyph_Metrics (pf->glyph, &metrics); if ((pf->fontattr&MWTF_KERNING) && pf->can_kern) { if (pf->fontrotation) { vec_x = compute_kernval(pf, curchar); vec_y = 0; TT_Transform_Vector(&vec_x, &vec_y,&pf->matrix); x += vec_x / 64; y -= vec_y / 64; } else x += compute_kernval(pf, curchar) / 64; } drawchar(pf, psd, pf->glyph, x, y); if (pf->fontrotation) { vec_x = metrics.advance; vec_y = 0; TT_Transform_Vector (&vec_x, &vec_y, &pf->matrix); x += vec_x / 64; y -= vec_y / 64; } else { x += metrics.advance / 64;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -