URL
https://opencores.org/ocsvn/openrisc/openrisc/trunk
Subversion Repositories openrisc
[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [services/] [gfx/] [mw/] [v2_0/] [src/] [engine/] [devfont.c] - Rev 365
Go to most recent revision | Compare with Previous | Blame | View Log
/* * Copyright (c) 2000 Greg Haerr <greg@censoft.com> * T1lib Adobe type1 routines contributed by Vidar Hokstad * Freetype TrueType routines contributed by Martin Jolicoeur * Han Zi Ku routines contributed by Tanghao and Jauming * * Device-independent font and text drawing routines * * These routines do the necessary range checking, clipping, and cursor * overwriting checks, and then call the lower level device dependent * routines to actually do the drawing. The lower level routines are * only called when it is known that all the pixels to be drawn are * within the device area and are visible. */ /*#define NDEBUG*/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include <string.h> #include "device.h" #if (UNIX | DOS_DJGPP) #define strcmpi strcasecmp #endif #if HAVE_T1LIB_SUPPORT #include <t1lib.h> #define T1LIB_USE_AA_HIGH typedef struct { PMWFONTPROCS fontprocs; /* common hdr*/ MWCOORD fontsize; int fontrotation; int fontattr; int fontid; /* t1lib stuff*/ } MWT1LIBFONT, *PMWT1LIBFONT; static int t1lib_init(PSD psd); static PMWT1LIBFONT t1lib_createfont(const char *name, MWCOORD height,int attr); static void t1lib_drawtext(PMWFONT pfont, PSD psd, MWCOORD x, MWCOORD y, const void *text, int cc, int flags); static MWBOOL t1lib_getfontinfo(PMWFONT pfont, PMWFONTINFO pfontinfo); static void t1lib_gettextsize(PMWFONT pfont, const void *text, int cc, MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase); static void t1lib_destroyfont(PMWFONT pfont); /* handling routines for MWT1LIBFONT*/ static MWFONTPROCS t1lib_procs = { MWTF_ASCII, /* routines expect ascii*/ t1lib_getfontinfo, t1lib_gettextsize, NULL, /* gettextbits*/ t1lib_destroyfont, t1lib_drawtext, NULL, /* setfontsize*/ NULL, /* setfontrotation*/ NULL, /* setfontattr*/ }; #endif #ifdef T1LIB_USE_AA_HIGH typedef unsigned long OUTPIXELVAL; #else typedef MWPIXELVAL OUTPIXELVAL; #endif #if HAVE_FREETYPE_SUPPORT #include <freetype/freetype.h> #include <freetype/ftxkern.h> #include <freetype/ftnameid.h> #include <freetype/ftxcmap.h> #include <freetype/ftxwidth.h> #include <math.h> #ifndef FREETYPE_FONT_DIR #define FREETYPE_FONT_DIR "/usr/local/microwin/fonts" #endif #if TT_FREETYPE_MAJOR != 1 | TT_FREETYPE_MINOR < 3 #error "You must link with freetype lib version 1.3.x +, and not freetype 2. \ Download it at http://www.freetype.org or http://microwindows.org" #endif typedef struct { 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, *PMWFREETYPEFONT; static int freetype_init(PSD psd); static 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, 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, int 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*/ }; static TT_Engine engine; /* THE ONLY freetype engine */ #endif /* HAVE_FREETYPE_SUPPORT*/ #if HAVE_HZK_SUPPORT /* * 12x12 and 16x16 ascii and chinese fonts * Big5 and GB2312 encodings supported */ #define MAX_PATH 256 typedef struct { int width; int height; int size; unsigned long use_count; char * pFont; char file[MAX_PATH + 1]; } HZKFONT; static int use_big5=1; static HZKFONT CFont[2]; /* font cache*/ static HZKFONT AFont[2]; /* font cache*/ /* jmt: moved inside MWHZKFONT*/ static int afont_width = 8; static int cfont_width = 16; static int font_height = 16; static char *afont_address; static char *cfont_address; typedef struct { PMWFONTPROCS fontprocs; /* common hdr*/ MWCOORD fontsize; int fontrotation; int fontattr; HZKFONT CFont; /* hzkfont stuff */ HZKFONT AFont; int afont_width; int cfont_width; int font_height; char *afont_address; char *cfont_address; } MWHZKFONT, *PMWHZKFONT; static int hzk_init(PSD psd); static PMWHZKFONT hzk_createfont(const char *name, MWCOORD height,int fontattr); static MWBOOL hzk_getfontinfo(PMWFONT pfont, PMWFONTINFO pfontinfo); static void hzk_gettextsize(PMWFONT pfont, const void *text, int cc, MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase); #if 0 static void hzk_gettextbits(PMWFONT pfont, int ch, IMAGEBITS *retmap, MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase); static void hzk_setfontrotation(PMWFONT pfont, int tenthdegrees); #endif static void hzk_destroyfont(PMWFONT pfont); static void hzk_drawtext(PMWFONT pfont, PSD psd, MWCOORD x, MWCOORD y, const void *text, int cc, int flags); static void hzk_setfontsize(PMWFONT pfont, MWCOORD fontsize); /* handling routines for MWHZKFONT*/ static MWFONTPROCS hzk_procs = { MWTF_ASCII, /* routines expect ASCII*/ hzk_getfontinfo, hzk_gettextsize, NULL, /* hzk_gettextbits*/ hzk_destroyfont, hzk_drawtext, hzk_setfontsize, NULL, /* setfontrotation*/ NULL, /* setfontattr*/ }; static int UC16_to_GB(const unsigned char *uc16, int cc, unsigned char *ascii); #endif /* HAVE_HZK_SUPPORT*/ static PMWFONT gr_pfont; /* current font*/ /* temp extern decls*/ extern MWPIXELVAL gr_foreground; extern MWPIXELVAL gr_background; extern MWBOOL gr_usebg; static int utf8_to_utf16(const unsigned char *utf8, int cc, unsigned short *unicode16); #if FONTMAPPER /* entry point for font selection*/ int select_font(const PMWLOGFONT plogfont, char *physname); #endif /* * Set the font for future calls. */ PMWFONT GdSetFont(PMWFONT pfont) { PMWFONT oldfont = gr_pfont; gr_pfont = pfont; return oldfont; } /* * Select a font, based on various parameters. * If plogfont is specified, name and height parms are ignored * and instead used from MWLOGFONT. * * If height is 0, return builtin font from passed name. * Otherwise find builtin font best match based on height. */ PMWFONT GdCreateFont(PSD psd, const char *name, MWCOORD height, const PMWLOGFONT plogfont) { int i; int fontht; int fontno; int fontclass; int fontattr = 0; PMWFONT pfont; PMWCOREFONT pf = psd->builtin_fonts; MWFONTINFO fontinfo; MWSCREENINFO scrinfo; char fontname[128]; GdGetScreenInfo(psd, &scrinfo); /* if plogfont not specified, use name and height*/ if (!plogfont) { if (!name) name = MWFONT_SYSTEM_VAR; strcpy(fontname, name); fontclass = MWLF_CLASS_ANY; } else { #if FONTMAPPER /* otherwise, use MWLOGFONT name and height*/ fontclass = select_font(plogfont, fontname); #else if (!name) name = MWFONT_SYSTEM_VAR; strcpy(fontname, name); fontclass = MWLF_CLASS_ANY; #endif height = plogfont->lfHeight; if (plogfont->lfUnderline) fontattr = MWTF_UNDERLINE; } height = abs(height); if (!fontclass) goto first; /* use builtin screen fonts, FONT_xxx, if height is 0 */ if (height == 0 || fontclass == MWLF_CLASS_ANY || fontclass == MWLF_CLASS_BUILTIN) { for(i = 0; i < scrinfo.fonts; ++i) { if(!strcmpi(pf[i].name, fontname)) { pf[i].fontsize = pf[i].cfont->height; pf[i].fontattr = fontattr; return (PMWFONT)&pf[i]; } } /* return first builtin font*/ if (height == 0 || fontclass == MWLF_CLASS_BUILTIN) goto first; } #if HAVE_HZK_SUPPORT /* Make sure the library is initialized */ if (hzk_init(psd)) { pfont = (PMWFONT)hzk_createfont(name, height, fontattr); if(pfont) return pfont; fprintf(stderr, "hzk_createfont: %s not found\n", name); } #endif #if HAVE_FREETYPE_SUPPORT if (fontclass == MWLF_CLASS_ANY || fontclass == MWLF_CLASS_FREETYPE) { if (freetype_init(psd)) { /* auto antialias for height > 14 for kaffe*/ if (plogfont && plogfont->lfHeight > 14 && plogfont->lfQuality) fontattr |= MWTF_ANTIALIAS; pfont = (PMWFONT)freetype_createfont(fontname, height, fontattr); if(pfont) { /* temp kaffe kluge*/ pfont->fontattr |= FS_FREETYPE; return pfont; } DPRINTF("freetype_createfont: %s,%d not found\n", fontname, height); } } #endif #if HAVE_T1LIB_SUPPORT if (fontclass == MWLF_CLASS_ANY || fontclass == MWLF_CLASS_T1LIB) { if (t1lib_init(psd)) { pfont = (PMWFONT)t1lib_createfont(fontname, height, fontattr); if(pfont) return pfont; DPRINTF("t1lib_createfont: %s,%d not found\n", fontname, height); } } #endif /* find builtin font closest in height*/ if(height != 0) { fontno = 0; height = abs(height); fontht = MAX_MWCOORD; for(i = 0; i < scrinfo.fonts; ++i) { pfont = (PMWFONT)&pf[i]; GdGetFontInfo(pfont, &fontinfo); if(fontht > abs(height-fontinfo.height)) { fontno = i; fontht = abs(height-fontinfo.height); } } pf[fontno].fontsize = pf[fontno].cfont->height; pf[fontno].fontattr = fontattr; return (PMWFONT)&pf[fontno]; } first: /* Return first builtin font*/ pf->fontsize = pf->cfont->height; pf->fontattr = fontattr; return (PMWFONT)&pf[0]; } /* Set the font size for the passed font*/ MWCOORD GdSetFontSize(PMWFONT pfont, MWCOORD fontsize) { MWCOORD oldfontsize = pfont->fontsize; pfont->fontsize = fontsize; if (pfont->fontprocs->SetFontSize) pfont->fontprocs->SetFontSize(pfont, fontsize); return oldfontsize; } /* Set the font rotation angle in tenths of degrees for the passed font*/ int GdSetFontRotation(PMWFONT pfont, int tenthdegrees) { MWCOORD oldrotation = pfont->fontrotation; pfont->fontrotation = tenthdegrees; if (pfont->fontprocs->SetFontRotation) pfont->fontprocs->SetFontRotation(pfont, tenthdegrees); return oldrotation; } /* * Set/reset font attributes (MWTF_KERNING, MWTF_ANTIALIAS) * for the passed font. */ int GdSetFontAttr(PMWFONT pfont, int setflags, int clrflags) { MWCOORD oldattr = pfont->fontattr; pfont->fontattr &= ~clrflags; pfont->fontattr |= setflags; if (pfont->fontprocs->SetFontAttr) pfont->fontprocs->SetFontAttr(pfont, setflags, clrflags); return oldattr; } /* Unload and deallocate font*/ void GdDestroyFont(PMWFONT pfont) { if (pfont->fontprocs->DestroyFont) pfont->fontprocs->DestroyFont(pfont); } /* Return information about a specified font*/ MWBOOL GdGetFontInfo(PMWFONT pfont, PMWFONTINFO pfontinfo) { if(!pfont || !pfont->fontprocs->GetFontInfo) return FALSE; return pfont->fontprocs->GetFontInfo(pfont, pfontinfo); } /* * Convert from one encoding to another * Input cc and returned cc is character count, not bytes * Return < 0 on error or can't translate */ int GdConvertEncoding(const void *istr, int iflags, int cc, void *ostr, int oflags) { const unsigned char *istr8; const unsigned short *istr16; const unsigned long *istr32; unsigned char *ostr8; unsigned short *ostr16; unsigned long *ostr32; unsigned int ch; int icc; unsigned short buf16[512]; iflags &= MWTF_PACKMASK; oflags &= MWTF_PACKMASK; /* allow -1 for len with ascii*/ if(cc == -1 && (iflags == MWTF_ASCII)) cc = strlen((char *)istr); /* first check for utf8 input encoding*/ if(iflags == MWTF_UTF8) { /* we've only got uc16 now so convert to uc16...*/ cc = utf8_to_utf16((unsigned char *)istr, cc, oflags==MWTF_UC16?(unsigned short*) ostr: buf16); if(oflags == MWTF_UC16 || cc < 0) return cc; /* will decode again to requested format (probably ascii)*/ iflags = MWTF_UC16; istr = buf16; } #if HAVE_HZK_SUPPORT if(iflags == MWTF_UC16 && oflags == MWTF_ASCII) { /* only support uc16 convert to ascii now...*/ cc = UC16_to_GB( istr, cc, ostr); return cc; } #endif icc = cc; istr8 = istr; istr16 = istr; istr32 = istr; ostr8 = ostr; ostr16 = ostr; ostr32 = ostr; /* Convert between formats. Note that there's no error * checking here yet. */ while(--icc >= 0) { switch(iflags) { default: ch = *istr8++; break; case MWTF_UC16: ch = *istr16++; break; case MWTF_UC32: ch = *istr32++; } switch(oflags) { default: *ostr8++ = (unsigned char)ch; break; case MWTF_UC16: *ostr16++ = (unsigned short)ch; break; case MWTF_UC32: *ostr32++ = ch; } } return cc; } /* Get the width and height of passed text string in the passed font*/ void GdGetTextSize(PMWFONT pfont, const void *str, int cc, MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase, int flags) { const void * text; unsigned long buf[256]; int defencoding = pfont->fontprocs->encoding; /* convert encoding if required*/ if((flags & MWTF_PACKMASK) != defencoding) { cc = GdConvertEncoding(str, flags, cc, buf, defencoding); flags &= ~MWTF_PACKMASK; flags |= defencoding; text = buf; } else text = str; if(cc == -1 && (flags & MWTF_PACKMASK) == MWTF_ASCII) cc = strlen((char *)str); if(cc <= 0 || !pfont->fontprocs->GetTextSize) { *pwidth = *pheight = *pbase = 0; return; } /* calc height and width of string*/ pfont->fontprocs->GetTextSize(pfont, text, cc, pwidth, pheight, pbase); } /* Draw a text string at a specifed coordinates in the foreground color * (and possibly the background color), applying clipping if necessary. * The background color is only drawn if the gr_usebg flag is set. * Use the current font. */ void GdText(PSD psd, MWCOORD x, MWCOORD y, const void *str, int cc, int flags) { const void * text; unsigned long buf[256]; int defencoding = gr_pfont->fontprocs->encoding; /* convert encoding if required*/ if((flags & MWTF_PACKMASK) != defencoding) { cc = GdConvertEncoding(str, flags, cc, buf, defencoding); flags &= ~MWTF_PACKMASK; flags |= defencoding; text = buf; } else text = str; if(cc == -1 && (flags & MWTF_PACKMASK) == MWTF_ASCII) cc = strlen((char *)str); if(cc <= 0 || !gr_pfont->fontprocs->DrawText) return; /* draw text string*/ gr_pfont->fontprocs->DrawText(gr_pfont, psd, x, y, text, cc, flags); } /* * Draw ascii text using COREFONT type font. */ void corefont_drawtext(PMWFONT pfont, PSD psd, MWCOORD x, MWCOORD y, const void *text, int cc, int flags) { const unsigned char *str = text; MWCOORD width; /* width of text area */ MWCOORD height; /* height of text area */ MWCOORD base; /* baseline of text*/ MWCOORD startx, starty; /* bitmap for characters */ MWIMAGEBITS bitmap[MAX_CHAR_HEIGHT*MAX_CHAR_WIDTH/MWIMAGE_BITSPERIMAGE]; pfont->fontprocs->GetTextSize(pfont, str, cc, &width, &height, &base); if(flags & MWTF_BASELINE) y -= base; else if(flags & MWTF_BOTTOM) y -= (height - 1); startx = x; starty = y + base; switch (GdClipArea(psd, x, y, x + width - 1, y + height - 1)) { case CLIP_VISIBLE: /* * For size considerations, there's no low-level text * draw, so we've got to draw all text * with per-point clipping for the time being if (gr_usebg) psd->FillRect(psd, x, y, x + width - 1, y + height - 1, gr_background); psd->DrawText(psd, x, y, str, cc, gr_foreground, pfont); GdFixCursor(psd); return; */ break; case CLIP_INVISIBLE: return; } /* Get the bitmap for each character individually, and then display * them using clipping for each one. */ while (--cc >= 0 && x < psd->xvirtres) { unsigned int ch = *str++; #if HAVE_BIG5_SUPPORT /* chinese big5 decoding*/ if (ch >= 0xA1 && ch <= 0xF9 && cc >= 1 && ((*str >= 0x40 && *str <= 0x7E) || (*str >= 0xA1 && *str <= 0xFE)) ) { ch = (ch << 8) | *str++; --cc; } #endif #if HAVE_GB2312_SUPPORT /* chinese gb2312 decoding*/ if (ch >= 0xA1 && ch < 0xF8 && cc >= 1 && *str >= 0xA1 && *str < 0xFF) { ch = (ch << 8) | *str++; --cc; } #endif #if HAVE_KSC5601_SUPPORT /* Korean KSC5601 decoding */ if (ch >= 0xA1 && ch <= 0xFE && cc >= 1 && (*str >= 0xA1 && *str <= 0xFE)) { ch = (ch << 8) | *str++; --cc; } #endif pfont->fontprocs->GetTextBits(pfont, ch, bitmap, &width, &height, &base); /* note: change to bitmap*/ GdBitmap(psd, x, y, width, height, bitmap); x += width; } if (pfont->fontattr & MWTF_UNDERLINE) GdLine(psd, startx, starty, x, starty, FALSE); GdFixCursor(psd); } #if HAVE_T1LIB_SUPPORT | HAVE_FREETYPE_SUPPORT /* * Produce blend table from src and dst based on passed alpha table * Used because we don't quite yet have GdArea with alphablending, * so we pre-blend fg/bg colors for fade effect. */ static void alphablend(PSD psd, OUTPIXELVAL *out, MWPIXELVAL src, MWPIXELVAL dst, unsigned char *alpha, int count) { unsigned int a, d; unsigned char r, g, b; MWCOLORVAL palsrc, paldst; extern MWPALENTRY gr_palette[256]; while (--count >= 0) { a = *alpha++; #define BITS(pixel,shift,mask) (((pixel)>>shift)&(mask)) if(a == 0) *out++ = dst; else if(a == 255) *out++ = src; else switch(psd->pixtype) { case MWPF_TRUECOLOR0888: case MWPF_TRUECOLOR888: d = BITS(dst, 16, 0xff); r = (unsigned char)(((BITS(src, 16, 0xff) - d)*a)>>8) + d; d = BITS(dst, 8, 0xff); g = (unsigned char)(((BITS(src, 8, 0xff) - d)*a)>>8) + d; d = BITS(dst, 0, 0xff); b = (unsigned char)(((BITS(src, 0, 0xff) - d)*a)>>8) + d; *out++ = (r << 16) | (g << 8) | b; break; case MWPF_TRUECOLOR565: d = BITS(dst, 11, 0x1f); r = (unsigned char)(((BITS(src, 11, 0x1f) - d)*a)>>8) + d; d = BITS(dst, 5, 0x3f); g = (unsigned char)(((BITS(src, 5, 0x3f) - d)*a)>>8) + d; d = BITS(dst, 0, 0x1f); b = (unsigned char)(((BITS(src, 0, 0x1f) - d)*a)>>8) + d; *out++ = (r << 11) | (g << 5) | b; break; case MWPF_TRUECOLOR555: d = BITS(dst, 10, 0x1f); r = (unsigned char)(((BITS(src, 10, 0x1f) - d)*a)>>8) + d; d = BITS(dst, 5, 0x1f); g = (unsigned char)(((BITS(src, 5, 0x1f) - d)*a)>>8) + d; d = BITS(dst, 0, 0x1f); b = (unsigned char)(((BITS(src, 0, 0x1f) - d)*a)>>8) + d; *out++ = (r << 10) | (g << 5) | b; break; case MWPF_TRUECOLOR332: d = BITS(dst, 5, 0x07); r = (unsigned char)(((BITS(src, 5, 0x07) - d)*a)>>8) + d; d = BITS(dst, 2, 0x07); g = (unsigned char)(((BITS(src, 2, 0x07) - d)*a)>>8) + d; d = BITS(dst, 0, 0x03); b = (unsigned char)(((BITS(src, 0, 0x03) - d)*a)>>8) + d; *out++ = (r << 5) | (g << 2) | b; break; case MWPF_PALETTE: /* reverse lookup palette entry for blend ;-)*/ palsrc = GETPALENTRY(gr_palette, src); paldst = GETPALENTRY(gr_palette, dst); d = REDVALUE(paldst); r = (unsigned char)(((REDVALUE(palsrc) - d)*a)>>8) + d; d = GREENVALUE(paldst); g = (unsigned char)(((GREENVALUE(palsrc) - d)*a)>>8) + d; d = BLUEVALUE(paldst); b = (unsigned char)(((BLUEVALUE(palsrc) - d)*a)>>8) + d; *out++ = GdFindNearestColor(gr_palette, (int)psd->ncolors, MWRGB(r, g, b)); break; } } } #endif /*HAVE_T1LIB_SUPPORT | HAVE_FREETYPE_SUPPORT*/ #if HAVE_T1LIB_SUPPORT /* contributed by Vidar Hokstad*/ static int t1lib_init(PSD psd) { char **encoding; static int inited = 0; if (inited) return 1; T1_SetBitmapPad(8); if (!T1_InitLib(0)) return 0; /* set default Latin1 encoding*/ encoding = T1_LoadEncoding("IsoLatin1.enc"); T1_SetDefaultEncoding(encoding); #ifdef T1LIB_USE_AA_HIGH T1_AASetLevel(T1_AA_HIGH); #else T1_AASetLevel(T1_AA_LOW); #endif #if 0 /* kluge: this is required if 16bpp drawarea driver is used*/ if(psd->bpp == 16) T1_AASetBitsPerPixel(16); else #endif T1_AASetBitsPerPixel(sizeof(MWPIXELVAL)*8); inited = 1; return 1; } static PMWT1LIBFONT t1lib_createfont(const char *name, MWCOORD height, int attr) { PMWT1LIBFONT pf; int id; char * p; char buf[256]; /* match name against t1 font id's from t1 font database*/ for(id=0; id<T1_Get_no_fonts(); ++id) { strncpy(buf, T1_GetFontFileName(id), sizeof(buf)); /* remove extension*/ for(p=buf; *p; ++p) { if(*p == '.') { *p = 0; break; } } if(!strcmpi(name, buf)) { /* allocate font structure*/ pf = (PMWT1LIBFONT)calloc(sizeof(MWT1LIBFONT), 1); if (!pf) return NULL; pf->fontprocs = &t1lib_procs; GdSetFontSize((PMWFONT)pf, height); GdSetFontRotation((PMWFONT)pf, 0); GdSetFontAttr((PMWFONT)pf, attr, 0); pf->fontid = id; return pf; } } return NULL; } /* * Draw ascii text string using T1LIB type font */ static void t1lib_drawtext(PMWFONT pfont, PSD psd, MWCOORD x, MWCOORD y, const void *text, int cc, int flags) { PMWT1LIBFONT pf = (PMWT1LIBFONT)pfont; const unsigned char *str = text; MWCOORD width; /* width of text area */ MWCOORD height; /* height of text area */ MWCOORD underliney; GLYPH * g; /* T1lib glyph structure. Memory handling by T1lib */ #ifdef T1LIB_USE_AA_HIGH OUTPIXELVAL gvals[17]; /* Blending array for antialiasing. The steeper the values increase * near the end, the sharper the characters look, but also more jagged */ static unsigned char blend[17] = { 0x00, 0x00, 0x04, 0x0c, 0x10, 0x14, 0x18, 0x20, 0x30, 0x38, 0x40, 0x50, 0x70, 0x80, 0xa0, 0xc0, 0xff }; #else OUTPIXELVAL gvals[5]; static unsigned char blend[5] = { 0x00, 0x44, 0x88, 0xcc, 0xff }; #endif /* Check if we should throw out some fonts */ if (pf->fontattr&MWTF_ANTIALIAS) { #ifdef T1LIB_USE_AA_HIGH alphablend(psd, gvals, gr_foreground, gr_background, blend, 17); T1_AAHSetGrayValues(gvals); #else alphablend(psd, gvals, gr_foreground, gr_background, blend, 5); T1_AASetGrayValues(gvals[0],gvals[1],gvals[2],gvals[3],gvals[4]); #endif g = T1_AASetString(pf->fontid,(char *)str,cc,0, (pf->fontattr&MWTF_KERNING)? T1_KERNING: 0, pf->fontsize * 1.0, 0); if (g && g->bits) { /*MWPIXELVAL save = gr_background;*/ width = g->metrics.rightSideBearing - g->metrics.leftSideBearing; height = g->metrics.ascent - g->metrics.descent; if(flags & MWTF_BASELINE) y -= g->metrics.ascent; else if(flags & MWTF_BOTTOM) y -= (height - 1); underliney = y + g->metrics.ascent; /* FIXME: Looks damn ugly if usebg is false. * Will be handled when using alphablending in GdArea... */ /* clipping handled in GdArea*/ /*FIXME kluge for transparency*/ /*gr_background = gr_foreground + 1;*/ /*gr_usebg = 0;*/ GdArea(psd,x,y, width, height, g->bits, MWPF_PIXELVAL); /*gr_background = save;*/ if (pf->fontattr & MWTF_UNDERLINE) GdLine(psd, x, underliney, x+width, underliney, FALSE); } } else { /* Do non-aa drawing */ g = T1_SetString(pf->fontid,(char *)str,cc,0, (pf->fontattr&MWTF_KERNING)? T1_KERNING: 0, pf->fontsize * 1.0, 0); if (g && g->bits) { unsigned char * b; int xoff; int maxy; int xmod; /* I'm sure this sorry excuse for a bitmap rendering routine can * be optimized quite a bit ;) */ width = g->metrics.rightSideBearing - g->metrics.leftSideBearing; height = g->metrics.ascent - g->metrics.descent; if(flags & MWTF_BASELINE) y -= g->metrics.ascent; else if(flags & MWTF_BOTTOM) y -= (height - 1); underliney = y + g->metrics.ascent; b = g->bits; maxy = y + height; /* if ((x + width) > psd->xvirtres) { xmod = (x + width - psd->xvirtres + 7) >> 3; width = width + x + width - psd->xvirtres; } else xmod = 0; */ xmod = 0; while (y < maxy) { unsigned char data; xoff = 0; while (xoff < width ) { if (!(xoff % 8)) { data = *b; b++; } if (GdClipPoint(psd, x+xoff,y)) { if (gr_usebg) { psd->DrawPixel(psd,x+xoff,y, data & (1 << (xoff % 8)) ? gr_foreground : gr_background); } else if (data & (1 << (xoff % 8))) { psd->DrawPixel(psd,x+xoff,y, gr_foreground); } } xoff++; } b += xmod; y++; } if (pf->fontattr & MWTF_UNDERLINE) GdLine(psd, x, underliney, x+xoff, underliney, FALSE); } } if (g && g->bits) { /* Save some memory */ free(g->bits); g->bits = 0; /* Make sure T1lib doesnt try to free it again */ } GdFixCursor(psd); } static MWBOOL t1lib_getfontinfo(PMWFONT pfont, PMWFONTINFO pfontinfo) { int i; MWCOORD width, height, baseline; /* FIXME, guess all sizes*/ GdGetTextSize(pfont, "A", 1, &width, &height, &baseline, MWTF_ASCII); pfontinfo->height = height; pfontinfo->maxwidth = width; pfontinfo->baseline = 0; pfontinfo->firstchar = 32; pfontinfo->lastchar = 255; pfontinfo->fixed = TRUE; for(i=0; i<256; ++i) pfontinfo->widths[i] = width; return TRUE; } /* Get the width and height of passed text string in the current font*/ static void t1lib_gettextsize(PMWFONT pfont, const void *text, int cc, MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase) { PMWT1LIBFONT pf = (PMWT1LIBFONT)pfont; const unsigned char * str = text; GLYPH * g; g = T1_SetString(pf->fontid, (char *)str, cc, 0, (pf->fontattr&MWTF_KERNING)? T1_KERNING: 0, pf->fontsize * 1.0, 0); *pwidth = g->metrics.rightSideBearing - g->metrics.leftSideBearing; *pheight = g->metrics.ascent - g->metrics.descent; if(g && g->bits) { free(g->bits); g->bits = 0; } #if 0 BBox b; /* FIXME. Something is *VERY* wrong here */ b = T1_GetStringBBox(pf->fontid, str, cc, 0, (pf->fontattr&MWTF_KERNING)?T1_KERNING:0); DPRINTF("b.urx = %d, b.llx = %d\n",b.urx, b.llx); DPRINTF("b.ury = %d, b.lly = %d\n",b.ury, b.lly); *pwidth = (b.urx - b.llx); *pheight = (b.lly - b.ury); #endif } static void t1lib_destroyfont(PMWFONT pfont) { PMWT1LIBFONT pf = (PMWT1LIBFONT)pfont; T1_DeleteAllSizes(pf->fontid); free(pf); } #endif /* HAVE_T1LIB_SUPPORT*/ #if HAVE_FREETYPE_SUPPORT static OUTPIXELVAL gray_palette[5]; static int freetype_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; } static PMWFREETYPEFONT freetype_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 int compute_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_UShort Get_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 void drawchar(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 void freetype_drawtext(PMWFONT pfont, PSD psd, MWCOORD ax, MWCOORD ay, const void *text, int cc, int 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; /* Kerning point syndrome avoidance */ if (pf->last_pen_pos > x) x = pf->last_pen_pos; pf->last_pen_pos = x; } pf->last_glyph_code = curchar; } if (pf->fontattr & MWTF_UNDERLINE) GdLine(psd, startx, starty, x, y, FALSE); } /* * Return information about a specified font. */ static MWBOOL freetype_getfontinfo(PMWFONT pfont, PMWFONTINFO pfontinfo) { int i; PMWFREETYPEFONT pf = (PMWFREETYPEFONT)pfont; TT_Face_Properties properties; TT_Instance_Metrics imetrics; TT_UShort last_glyph_index; TT_Get_Face_Properties (pf->face, &properties); TT_Get_Instance_Metrics(pf->instance, &imetrics); /* Fill up the fields */ pfontinfo->height = (((properties.horizontal->Ascender * \ imetrics.y_scale)/ 0x10000) >> 6) - (((properties.horizontal->Descender * \ imetrics.y_scale)/ 0x10000) >> 6); pfontinfo->maxwidth = ((properties.horizontal->xMax_Extent * \ imetrics.x_scale)/ 0x10000) >> 6; pfontinfo->baseline = ((properties.horizontal->Ascender * \ imetrics.y_scale)/ 0x10000) >> 6; pfontinfo->firstchar = TT_CharMap_First(pf->char_map, NULL); pfontinfo->lastchar = TT_CharMap_Last(pf->char_map, NULL); pfontinfo->fixed = properties.postscript->isFixedPitch; last_glyph_index = properties.num_Glyphs > 255 ? 255: properties.num_Glyphs-1; /* Doesn't work ... don't know why ....*/ #if 0 if (TT_Get_Face_Widths( pf->face, 0, last_glyph_index, widths, NULL ) != TT_Err_Ok) { return TRUE; } for(i=0; i<=last_glyph_index; i++) DPRINTF("widths[%d]: %d\n", i, widths[i]); #endif /* Get glyphs widths */ for(i=0; i<=last_glyph_index; i++) pfontinfo->widths[i] = Get_Glyph_Width(pf, i); #if 0 DPRINTF("x_ppem: %d\ny_ppem: %d\nx_scale: %d\ny_scale: %d\n\ x_resolution: %d\ny_resolution: %d\n", imetrics.x_ppem, imetrics.y_ppem, imetrics.x_scale, \ imetrics.y_scale, imetrics.x_resolution, imetrics.y_resolution); DPRINTF("Ascender: %d\nDescender: %d\nxMax_Extent: %d\n\ Mac Style Say Italic?: %d\nMac Style Say Bold?: %d\n\ sTypoAscender: %d\nsTypoDescender: %d\nusWinAscent: %d\n\ usWinDescent: %d\nusFirstCharIndex: %d\nusLastCharIndex: %d\n\ OS2 Say Italic?: %d\nOS2 Say Bold?: %d\nOS2 Say monospaced?: %d\n\ Postscript Say monospaced?: %d\n",\ properties.horizontal->Ascender, properties.horizontal->Descender, properties.horizontal->xMax_Extent, (properties.header->Mac_Style & 0x2)?1:0, (properties.header->Mac_Style & 0x1)?1:0, properties.os2->sTypoAscender, properties.os2->sTypoDescender, properties.os2->usWinAscent, properties.os2->usWinDescent, properties.os2->usFirstCharIndex, properties.os2->usLastCharIndex, (properties.os2->fsSelection & 0x1)?1:0, (properties.os2->fsSelection & 0x20)?1:0, properties.postscript->isFixedPitch, (properties.os2->panose[3] == 9)?1:0); #endif return TRUE; } static void freetype_gettextsize(PMWFONT pfont, const void *text, int cc, MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase) { PMWFREETYPEFONT pf = (PMWFREETYPEFONT)pfont; const unsigned short * str = text; TT_F26Dot6 x = 0; int i; TT_UShort curchar; TT_Glyph_Metrics metrics; TT_Face_Properties properties; TT_Instance_Metrics imetrics; TT_Get_Face_Properties (pf->face, &properties); TT_Get_Instance_Metrics(pf->instance, &imetrics); pf->last_glyph_code = -1; /* reset kerning*/ pf->last_pen_pos = -32767; 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_SCALE_GLYPH|TTLOAD_HINT_GLYPH) != TT_Err_Ok) continue; TT_Get_Glyph_Metrics (pf->glyph, &metrics); if ((pf->fontattr&MWTF_KERNING) && pf->can_kern) { x += compute_kernval(pf, curchar) / 64; } x += metrics.advance / 64; /* Kerning point syndrome avoidance */ if (pf->last_pen_pos > x) x = pf->last_pen_pos; pf->last_pen_pos = x; pf->last_glyph_code = curchar; } *pwidth = x; *pheight = (((properties.horizontal->Ascender * imetrics.y_scale)/ 0x10000) >> 6) - (((properties.horizontal->Descender * imetrics.y_scale)/ 0x10000) >> 6); /* FIXME: is it what's required ?? */ *pbase = (((-properties.horizontal->Descender) * imetrics.y_scale)/ 0x10000) >> 6; } static void freetype_destroyfont(PMWFONT pfont) { PMWFREETYPEFONT pf = (PMWFREETYPEFONT)pfont; TT_Close_Face(pf->face); free(pf); } static void freetype_setfontsize(PMWFONT pfont, MWCOORD fontsize) { PMWFREETYPEFONT pf = (PMWFREETYPEFONT)pfont; pf->fontsize = fontsize; /* We want real pixel sizes ... not points ...*/ TT_Set_Instance_PixelSizes( pf->instance, pf->fontsize, pf->fontsize, pf->fontsize * 64 ); #if 0 /* set charsize (convert to points for freetype)*/ TT_Set_Instance_CharSize (pf->instance, ((pf->fontsize * 72 + 96/2) / 96) * 64); #endif } static void freetype_setfontrotation(PMWFONT pfont, int tenthdegrees) { PMWFREETYPEFONT pf = (PMWFREETYPEFONT)pfont; float angle; pf->fontrotation = tenthdegrees; /* Build the rotation matrix with the given angle */ TT_Set_Instance_Transform_Flags (pf->instance, TRUE, FALSE); angle = pf->fontrotation * M_PI / 1800; pf->matrix.yy = (TT_Fixed) (cos (angle) * (1 << 16)); pf->matrix.yx = (TT_Fixed) (sin (angle) * (1 << 16)); pf->matrix.xx = pf->matrix.yy; pf->matrix.xy = -pf->matrix.yx; } #endif /* HAVE_FREETYPE_SUPPORT*/ /* UTF-8 to UTF-16 conversion. Surrogates are handeled properly, e.g. * a single 4-byte UTF-8 character is encoded into a surrogate pair. * On the other hand, if the UTF-8 string contains surrogate values, this * is considered an error and returned as such. * * The destination array must be able to hold as many Unicode-16 characters * as there are ASCII characters in the UTF-8 string. This in case all UTF-8 * characters are ASCII characters. No more will be needed. * * Copyright (c) 2000 Morten Rolland, Screen Media */ static int utf8_to_utf16(const unsigned char *utf8, int cc, unsigned short *unicode16) { int count = 0; unsigned char c0, c1; unsigned long scalar; while(--cc >= 0) { c0 = *utf8++; /*DPRINTF("Trying: %02x\n",c0);*/ if ( c0 < 0x80 ) { /* Plain ASCII character, simple translation :-) */ *unicode16++ = c0; count++; continue; } if ( (c0 & 0xc0) == 0x80 ) /* Illegal; starts with 10xxxxxx */ return -1; /* c0 must be 11xxxxxx if we get here => at least 2 bytes */ scalar = c0; if(--cc < 0) return -1; c1 = *utf8++; /*DPRINTF("c1=%02x\n",c1);*/ if ( (c1 & 0xc0) != 0x80 ) /* Bad byte */ return -1; scalar <<= 6; scalar |= (c1 & 0x3f); if ( !(c0 & 0x20) ) { /* Two bytes UTF-8 */ if ( scalar < 0x80 ) return -1; /* Overlong encoding */ *unicode16++ = scalar & 0x7ff; count++; continue; } /* c0 must be 111xxxxx if we get here => at least 3 bytes */ if(--cc < 0) return -1; c1 = *utf8++; /*DPRINTF("c1=%02x\n",c1);*/ if ( (c1 & 0xc0) != 0x80 ) /* Bad byte */ return -1; scalar <<= 6; scalar |= (c1 & 0x3f); if ( !(c0 & 0x10) ) { /*DPRINTF("####\n");*/ /* Three bytes UTF-8 */ if ( scalar < 0x800 ) return -1; /* Overlong encoding */ if ( scalar >= 0xd800 && scalar < 0xe000 ) return -1; /* UTF-16 high/low halfs */ *unicode16++ = scalar & 0xffff; count++; continue; } /* c0 must be 1111xxxx if we get here => at least 4 bytes */ c1 = *utf8++; if(--cc < 0) return -1; /*DPRINTF("c1=%02x\n",c1);*/ if ( (c1 & 0xc0) != 0x80 ) /* Bad byte */ return -1; scalar <<= 6; scalar |= (c1 & 0x3f); if ( !(c0 & 0x08) ) { /* Four bytes UTF-8, needs encoding as surrogates */ if ( scalar < 0x10000 ) return -1; /* Overlong encoding */ scalar -= 0x10000; *unicode16++ = ((scalar >> 10) & 0x3ff) + 0xd800; *unicode16++ = (scalar & 0x3ff) + 0xdc00; count += 2; continue; } return -1; /* No support for more than four byte UTF-8 */ } return count; } #if HAVE_HZK_SUPPORT /* UniCode-16 (MWTF_UC16) to GB(MWTF_ASCII) Chinese Characters conversion. * a single 2-byte UC16 character is encoded into a surrogate pair. * return -1 ,if error; * The destination array must be able to hold as many * as there are Unicode-16 characters. * * Copyright (c) 2000 Tang Hao (TownHall)(tang_hao@263.net). */ static int UC16_to_GB(const unsigned char *uc16, int cc, unsigned char *ascii) { FILE* fp; char buffer[256]; unsigned char *uc16p; int i=0,j=0, k; unsigned char *filebuffer; unsigned short *uc16pp,*table; unsigned short uc16px; int length=31504; if (use_big5) length=54840; uc16p=(unsigned char *) uc16; uc16pp=(unsigned short *) uc16; strcpy(buffer,HZK_FONT_DIR); if (use_big5) strcat(buffer,"/BG2UBG.KU"); else strcat(buffer,"/UGB2GB.KU"); if(!(fp = fopen(buffer, "rb"))) { fprintf (stderr, "Error.\nThe %s file can not be found!\n",buffer); return -1; } filebuffer= (unsigned char *)malloc ( length); if(fread(filebuffer, sizeof(char),length, fp) < length) { fprintf (stderr, "Error in reading ugb2gb.ku file!\n"); fclose(fp); return -1; } fclose(fp); if (use_big5) { table=(unsigned short *)filebuffer; while(1) { if(j>=cc) { ascii[i]=0; break; } uc16px=*uc16pp; if((uc16px)<=0x00ff) { ascii[i]=(char)(*uc16pp); i++; } else { ascii[i]=0xa1; ascii[i+1]=0x40; for (k=0; k<13710; k++) { if (*(table+(k*2+1))==(uc16px)) { ascii[i]=(char)((*(table+(k*2)) & 0xff00) >> 8); ascii[i+1]=(char)(*(table+(k*2)) & 0x00ff); break; } } i+=2; } uc16pp++; j++; } } else { while(1) { if(j>=cc) { ascii[i]=0; break; } if((*((uc16p)+j)==0)&&(*((uc16p)+j+1)==0)) { ascii[i]=0; break; } else { if(*((uc16p)+j+1)==0) { ascii[i]=*((uc16p)+j); i++; j+=2; } else { /* to find the place of unicode charater .¶þ·Ö·¨Æ¥Åä*/ { int p1=0,p2=length-4,p; unsigned int c1,c2,c,d; c1=((unsigned int )filebuffer[p1])*0x100+(filebuffer[p1+1]); c2=((unsigned int )filebuffer[p2])*0x100+(filebuffer[p2+1]); d=((unsigned int )*((uc16p)+j))*0x100+*((uc16p)+j+1); if(c1==d) { ascii[i]=filebuffer[p1+2]; ascii[i+1]=filebuffer[p1+3]; goto findit; } if(c2==d) { ascii[i]=filebuffer[p2+2]; ascii[i+1]=filebuffer[p2+3]; goto findit; } while(1) { p=(((p2-p1)/2+p1)>>2)<<2; c=((unsigned int )filebuffer[p])*0x100+(filebuffer[p+1]); if(d==c) /* find it*/ { ascii[i]=filebuffer[p+2]; ascii[i+1]=filebuffer[p+3]; break; } else if(p2<=p1+4) /* can't find.*/ { ascii[i]='.'; /* ((uc16p)+j);*/ ascii[i+1]='.'; /* ((uc16p)+j+1);*/ break; } else if(d<c) { p2=p; c2=c; } else { p1=p; c1=c; } } } findit: i+=2; j+=2; } } } } free(filebuffer); return i; } /************************** functions definition ******************************/ static int hzk_id( PMWHZKFONT pf ) { switch(pf->font_height) { case 12: return 0; case 16: default: return 1; } } /* This function get Chinese font info from etc file.*/ static MWBOOL GetCFontInfo( PMWHZKFONT pf ) { int charset; if (use_big5) charset=(13094+408); else charset=8178; CFont[hzk_id(pf)].width = pf->cfont_width; pf->CFont.width = pf->cfont_width; CFont[hzk_id(pf)].height = pf->font_height; pf->CFont.height = pf->font_height; CFont[hzk_id(pf)].size = ((pf->CFont.width + 7) / 8) * pf->CFont.height * charset; pf->CFont.size = ((pf->CFont.width + 7) / 8) * pf->CFont.height * charset; if(pf->CFont.size < charset * 8) return FALSE; strcpy(CFont[hzk_id(pf)].file,HZK_FONT_DIR); strcpy(pf->CFont.file,HZK_FONT_DIR); if(pf->font_height==16) { strcat(CFont[hzk_id(pf)].file,"/hzk16"); strcat(pf->CFont.file,"/hzk16"); } else { strcat(CFont[hzk_id(pf)].file,"/hzk12"); strcat(pf->CFont.file,"/hzk12"); } if (use_big5) { CFont[hzk_id(pf)].file[strlen(pf->CFont.file)-3]+=use_big5; pf->CFont.file[strlen(pf->CFont.file)-3]+=use_big5; } return TRUE; } /* This function get ASCII font info from etc file.*/ static MWBOOL GetAFontInfo( PMWHZKFONT pf ) { AFont[hzk_id(pf)].width = pf->afont_width; pf->AFont.width = pf->afont_width; AFont[hzk_id(pf)].height = pf->font_height; pf->AFont.height = pf->font_height; AFont[hzk_id(pf)].size = ((pf->AFont.width + 7) / 8) * pf->AFont.height * 255; pf->AFont.size = ((pf->AFont.width + 7) / 8) * pf->AFont.height * 255; if(pf->AFont.size < 255 * 8) return FALSE; strcpy(AFont[hzk_id(pf)].file,HZK_FONT_DIR); strcpy(pf->AFont.file,HZK_FONT_DIR); if(pf->font_height==16) { strcat(AFont[hzk_id(pf)].file,"/asc16"); strcat(pf->AFont.file,"/asc16"); } else { strcat(AFont[hzk_id(pf)].file,"/asc12"); strcat(pf->AFont.file,"/asc12"); } return TRUE; } /* This function load system font into memory.*/ static MWBOOL LoadFont( PMWHZKFONT pf ) { FILE* fp; if(!GetCFontInfo(pf)) { fprintf (stderr, "Get Chinese HZK font info failure!\n"); return FALSE; } if(CFont[hzk_id(pf)].pFont == NULL) /* check font cache*/ { /* Allocate system memory for Chinese font.*/ if( !(CFont[hzk_id(pf)].pFont = (char *)malloc(pf->CFont.size)) ) { fprintf (stderr, "Allocate memory for Chinese HZK font failure.\n"); return FALSE; } /* Open font file and read information to the system memory.*/ fprintf (stderr, "Loading Chinese HZK font from file(%s)..." ,pf->CFont.file); if(!(fp = fopen(CFont[hzk_id(pf)].file, "rb"))) { fprintf (stderr, "Error.\nThe Chinese HZK font file can not be found!\n"); return FALSE; } if(fread(CFont[hzk_id(pf)].pFont, sizeof(char), pf->CFont.size, fp) < pf->CFont.size) { fprintf (stderr, "Error in reading Chinese HZK font file!\n"); fclose(fp); return FALSE; } fclose(fp); CFont[hzk_id(pf)].use_count=0; fprintf (stderr, "done.\n" ); } cfont_address = CFont[hzk_id(pf)].pFont; pf->cfont_address = CFont[hzk_id(pf)].pFont; pf->CFont.pFont = CFont[hzk_id(pf)].pFont; CFont[hzk_id(pf)].use_count++; if(!GetAFontInfo(pf)) { fprintf (stderr, "Get ASCII HZK font info failure!\n"); return FALSE; } if(AFont[hzk_id(pf)].pFont == NULL) /* check font cache*/ { /* Allocate system memory for ASCII font.*/ if( !(AFont[hzk_id(pf)].pFont = (char *)malloc(pf->AFont.size)) ) { fprintf (stderr, "Allocate memory for ASCII HZK font failure.\n"); free(CFont[hzk_id(pf)].pFont); CFont[hzk_id(pf)].pFont = NULL; return FALSE; } /* Load ASCII font information to the near memory.*/ fprintf (stderr, "Loading ASCII HZK font..." ); if(!(fp = fopen(AFont[hzk_id(pf)].file, "rb"))) { fprintf (stderr, "Error.\nThe ASCII HZK font file can not be found!\n"); return FALSE; } if(fread(AFont[hzk_id(pf)].pFont, sizeof(char), pf->AFont.size, fp) < pf->AFont.size) { fprintf (stderr, "Error in reading ASCII HZK font file!\n"); fclose(fp); return FALSE; } fclose(fp); AFont[hzk_id(pf)].use_count=0; fprintf (stderr, "done.\n" ); } afont_address = AFont[hzk_id(pf)].pFont; pf->afont_address = AFont[hzk_id(pf)].pFont; pf->AFont.pFont = AFont[hzk_id(pf)].pFont; AFont[hzk_id(pf)].use_count++; return TRUE; } /* This function unload system font from memory.*/ static void UnloadFont( PMWHZKFONT pf ) { CFont[hzk_id(pf)].use_count--; AFont[hzk_id(pf)].use_count--; if (!CFont[hzk_id(pf)].use_count) { free(pf->CFont.pFont); free(pf->AFont.pFont); CFont[hzk_id(pf)].pFont = NULL; AFont[hzk_id(pf)].pFont = NULL; } } static int hzk_init(PSD psd) { /* FIXME: *.KU file should be opened and * read in here...*/ return 1; } static PMWHZKFONT hzk_createfont(const char *name, MWCOORD height, int attr) { PMWHZKFONT pf; if(strcmp(name,"HZKFONT")!=0 && strcmp(name,"HZXFONT")!=0) return FALSE; /*printf("hzk_createfont(%s,%d)\n",name,height);*/ use_big5=name[2]-'K'; /* allocate font structure*/ pf = (PMWHZKFONT)calloc(sizeof(MWHZKFONT), 1); if (!pf) return NULL; pf->fontprocs = &hzk_procs; pf->fontsize=height; #if 0 GdSetFontSize((PMWFONT)pf, height); #endif GdSetFontRotation((PMWFONT)pf, 0); GdSetFontAttr((PMWFONT)pf, attr, 0); if(height==12) { afont_width = 6; cfont_width = 12; font_height = 12; pf->afont_width = 6; pf->cfont_width = 12; pf->font_height = 12; } else { afont_width = 8; cfont_width = 16; font_height = 16; pf->afont_width = 8; pf->cfont_width = 16; pf->font_height = 16; } /* Load the font library to the system memory.*/ if(!LoadFont(pf)) return FALSE; return pf; } int IsBig5(int i) { if ((i>=0xa140 && i<=0xa3bf) || /* a140-a3bf(!a3e0) */ (i>=0xa440 && i<=0xc67e) || /* a440-c67e */ (i>=0xc6a1 && i<=0xc8d3) || /* c6a1-c8d3(!c8fe) */ (i>=0xc940 && i<=0xf9fe)) /* c940-f9fe */ return 1; else return 0; } /* * following several function is used in hzk_drawtext */ static int getnextchar(char* s, unsigned char* cc) { if( s[0] == '\0') return 0; cc[0] = (unsigned char)(*s); cc[1] = (unsigned char)(*(s + 1)); if (use_big5) { if( IsBig5( (int) ( (cc[0] << 8) + cc[1]) ) ) return 1; } else { if( ((unsigned char)cc[0] > 0xa0) && ((unsigned char)cc[1] > 0xa0) ) return 1; } cc[1] = '\0'; return 1; } static void expandcchar(PMWHZKFONT pf, int bg, int fg, unsigned char* c, MWPIXELVAL* bitmap) { int i=0; int c1, c2, seq; int x,y; unsigned char *font; int b = 0; /* keep gcc happy with b = 0 - MW */ int pixelsize; pixelsize=sizeof(MWPIXELVAL); c1 = c[0]; c2 = c[1]; if (use_big5) { seq=0; /* ladd=loby-(if(loby<127)?64:98)*/ c2-=(c2<127?64:98); /* hadd=(hiby-164)*157*/ if (c1>=0xa4) /* standard font*/ { seq=(((c1-164)*157)+c2); if (seq>=5809) seq-=408; } /* hadd=(hiby-161)*157*/ if (c1<=0xa3) /* special font*/ seq=(((c1-161)*157)+c2)+13094; } else seq=((c1 - 161)*94 + c2 - 161); font = pf->cfont_address + ((seq) * (pf->font_height * ((pf->cfont_width + 7) / 8))); for (y = 0; y < pf->font_height; y++) for (x = 0; x < pf->cfont_width; x++) { if (x % 8 == 0) b = *font++; if (b & (128 >> (x % 8))) /* pixel */ bitmap[i++]=fg; else bitmap[i++]=bg; } } static void expandchar(PMWHZKFONT pf, int bg, int fg, int c, MWPIXELVAL* bitmap) { int i=0; int x,y; unsigned char *font; int pixelsize; int b = 0; /* keep gcc happy with b = 0 - MW */ pixelsize=sizeof(MWPIXELVAL); font = pf->afont_address + c * (pf->font_height * ((pf->afont_width + 7) / 8)); for (y = 0; y < pf->font_height; y++) for (x = 0; x < pf->afont_width; x++) { if (x % 8 == 0) b = *font++; if (b & (128 >> (x % 8))) /* pixel */ bitmap[i++]=fg; else bitmap[i++]=bg; } } /* * Draw ASCII text string using HZK type font */ static void hzk_drawtext(PMWFONT pfont, PSD psd, MWCOORD ax, MWCOORD ay, const void *text, int cc, int flags) { PMWHZKFONT pf=(PMWHZKFONT)pfont; unsigned char c[2]; MWPIXELVAL *bitmap; unsigned char s1[3]; char *s,*sbegin; s=(char *)text; if(cc==1) { s1[0]=*((unsigned char*)text); s1[1]=0x0; s1[2]=0x0; s=s1; } sbegin=s; bitmap = (MWPIXELVAL *)ALLOCA(pf->cfont_width * pf->font_height * sizeof(MWPIXELVAL)); while( getnextchar(s, c) ) { if( c[1] != '\0') { expandcchar(pf, gr_background,gr_foreground, c, bitmap); /* Now draw the bitmap ... */ if (flags&MWTF_TOP) GdArea(psd,ax, ay, pf->cfont_width, pf->font_height, bitmap, MWPF_PIXELVAL); else GdArea(psd,ax, ay-pf->font_height+2, pf->cfont_width, pf->font_height, bitmap, MWPF_PIXELVAL); s += 2; ax += pf->cfont_width; } else { expandchar(pf, gr_background,gr_foreground, c[0], bitmap); /* Now draw the bitmap ... */ if (flags&MWTF_TOP) GdArea(psd,ax, ay, pf->afont_width, pf->font_height, bitmap, MWPF_PIXELVAL); else GdArea(psd,ax, ay-pf->font_height+2, pf->afont_width, pf->font_height, bitmap, MWPF_PIXELVAL); s += 1; ax += pf->afont_width; } if(s>=sbegin+cc)break; } FREEA(bitmap); } /* * Return information about a specified font. */ static MWBOOL hzk_getfontinfo(PMWFONT pfont, PMWFONTINFO pfontinfo) { PMWHZKFONT pf=(PMWHZKFONT)pfont; int i; pfontinfo->height = pf->font_height; pfontinfo->maxwidth = pf->cfont_width; pfontinfo->baseline = pf->font_height-2; pfontinfo->firstchar = 0; pfontinfo->lastchar = 0; pfontinfo->fixed = TRUE; for(i=0; i<=256; i++) pfontinfo->widths[i] = pf->afont_width; return TRUE; } static void hzk_gettextsize(PMWFONT pfont, const void *text, int cc, MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase) { PMWHZKFONT pf=(PMWHZKFONT)pfont; unsigned char c[2]; char *s,*sbegin; unsigned char s1[3]; int ax=0; s=(char *)text; if(cc==0) { *pwidth = 0; *pheight = pf->font_height; *pbase = pf->font_height-2; } if(cc==1) { s1[0]=*((unsigned char*)text); s1[1]=0x0; s1[2]=0x0; s=s1; } sbegin=s; while( getnextchar(s, c) ) { if( c[1] != '\0') { s += 2; ax += pf->cfont_width; } else { s += 1; ax += pf->afont_width; } if(s>=sbegin+cc) { /*fprintf(stderr,"s=%x,sbegin=%x,cc=%x\n",s,sbegin,cc);*/ break; } } /*fprintf(stderr,"ax=%d,\n",ax);*/ *pwidth = ax; *pheight = pf->font_height; *pbase = pf->font_height-2; } static void hzk_destroyfont(PMWFONT pfont) { PMWHZKFONT pf=(PMWHZKFONT)pfont; UnloadFont(pf); free(pf); } static void hzk_setfontsize(PMWFONT pfont, MWCOORD fontsize) { PMWHZKFONT pf=(PMWHZKFONT)pfont; /* jmt: hzk_setfontsize not supported*/ /* & pf->fontsize can't be changed*/ /* because of hzk_id() :p*/ pf->fontsize=pf->font_height; } #endif /* HAVE_HZK_SUPPORT*/ /* FIXME: this routine should work for all font renderers...*/ int GdGetTextSizeEx(PMWFONT pfont, const void *str, int cc,int nMaxExtent, int* lpnFit, int* alpDx,MWCOORD *pwidth,MWCOORD *pheight, MWCOORD *pbase, int flags) { #ifdef HAVE_FREETYPE_SUPPORT unsigned short buf[256]; unsigned short* text; PMWFREETYPEFONT pf = (PMWFREETYPEFONT)pfont; int defencoding = pf->fontprocs->encoding; int x = 0; int i; TT_UShort curchar; TT_Glyph_Metrics metrics; TT_Face_Properties properties; TT_Instance_Metrics imetrics; if ((cc<0)||(!str)) { *pwidth = *pheight = *pbase = 0; return 0; } /* convert encoding if required*/ if((flags & MWTF_PACKMASK) != defencoding) { cc = GdConvertEncoding(str, flags, cc, buf, defencoding); flags &= ~MWTF_PACKMASK; flags |= defencoding; text=buf; } else text =(unsigned short*)str; if(cc <= 0) { *pwidth = *pheight = *pbase = 0; return 0; } TT_Get_Face_Properties (pf->face, &properties); TT_Get_Instance_Metrics(pf->instance, &imetrics); pf->last_glyph_code = -1; /* reset kerning*/ pf->last_pen_pos = -32767; if (lpnFit) *lpnFit=-1; for (i = 0; i < cc; i++) { curchar = TT_Char_Index (pf->char_map,text[i]); if (TT_Load_Glyph (pf->instance, pf->glyph, curchar, TTLOAD_SCALE_GLYPH|TTLOAD_HINT_GLYPH) != TT_Err_Ok) { fprintf(stderr, "Unable to load glyph with index=%d\n",curchar); return 0; } TT_Get_Glyph_Metrics (pf->glyph, &metrics); if ((pf->fontattr&MWTF_KERNING) && pf->can_kern) { x += compute_kernval(pf, curchar) / 64; } x += metrics.advance / 64; if((lpnFit)&&(alpDx)) { if (x<=nMaxExtent) alpDx[i]=x; else if (*lpnFit==-1) (*lpnFit)=i; } /* Kerning point syndrome avoidance */ if (pf->last_pen_pos > x) x = pf->last_pen_pos; pf->last_pen_pos = x; pf->last_glyph_code = curchar; } if ((lpnFit)&&(*lpnFit==-1)) *lpnFit=cc; *pwidth = x; *pheight = (((properties.horizontal->Ascender * imetrics.y_scale)/ 0x10000) >> 6) - (((properties.horizontal->Descender * imetrics.y_scale)/ 0x10000) >> 6); /* FIXME: is it what's required ??*/ if (pbase) *pbase = (((-properties.horizontal->Descender) * imetrics.y_scale)/ 0x10000) >> 6; return 1; #else /* HAVE_FREETYPE_SUPPORT*/ *pwidth = *pheight = *pbase = 0; return 0; #endif } #ifdef HAVE_FREETYPE_SUPPORT #include <dirent.h> /* * This function is taken almost verbatim from ftdump.c from * the freetype library (version 1.3.1) */ static char * tt_lookup_name(TT_Face face) { TT_Face_Properties prop; unsigned short i, n; unsigned short platform, encoding, language, id; char *string; char *name_buffer; unsigned short string_len; int j, found; int index = 4; /* I dont know why as yet.. */ int name_len; TT_Get_Face_Properties(face, &prop); n = prop.num_Names; for ( i = 0; i < n; i++ ) { TT_Get_Name_ID( face, i, &platform, &encoding, &language, &id ); TT_Get_Name_String( face, i, &string, &string_len ); if (id == index ) { /* The following code was inspired from Mark Leisher's */ /* ttf2bdf package */ found = 0; /* Try to find a Microsoft English name */ if ( platform == 3 ) for ( j = 1; j >= 0; j-- ) if ( encoding == j ) /* Microsoft ? */ if ( (language & 0x3FF) == 0x009 ) { /* English language */ found = 1; break; } if ( !found && platform == 0 && language == 0 ) found = 1; /* Found a Unicode Name. */ if ( found ) { if ( string_len > 512 ) string_len = 512; name_len = 0; name_buffer = (char*)malloc((string_len / 2) + 1); for ( i = 1; i < string_len; i += 2 ) name_buffer[name_len++] = string[i]; name_buffer[name_len] = '\0'; return name_buffer; } } } /* Not found */ return NULL; } static char * get_tt_name(char *p) { TT_Face face; char *ret; /*printf("Trying to open: %s!\n",p);*/ if (TT_Open_Face(engine, p, &face) != TT_Err_Ok) { fprintf(stderr, "Error opening font: %s\n", p); return NULL; } ret = tt_lookup_name(face); TT_Close_Face(face); return ret; } void GdFreeFontList(MWFONTLIST ***fonts, int n) { int i; MWFONTLIST *g, **list = *fonts; for (i = 0; i < n; i++) { g = list[i]; if(g) { if(g->mwname) free(g->mwname); if(g->ttname) free(g->ttname); free(g); } } free(list); *fonts = 0; } void GdGetFontList(MWFONTLIST ***fonts, int *numfonts) { DIR *dir; struct dirent *dent; char *p, *ftmp; int pl, idx = 0; MWFONTLIST **list; if (TT_Err_Ok != TT_Init_FreeType(&engine)) { fprintf(stderr, "Unable to initialize freetype\n"); *numfonts = -1; return ; } dir = opendir(FREETYPE_FONT_DIR); if (dir <= 0) { fprintf(stderr, "Error opening font directory\n"); *numfonts = -1; return ; } /* get the number of strings we need to allocate */ while ((dent = readdir(dir)) != NULL) { p = strrchr(dent->d_name, '.'); if (strcasecmp(p, ".ttf") == 0) idx++; } *numfonts = idx; rewinddir(dir); /* allocate strings */ list = (MWFONTLIST**)malloc(idx * sizeof(MWFONTLIST*)); for (pl = 0; pl < idx; pl++) list[pl] = (MWFONTLIST*)malloc(sizeof(MWFONTLIST)); *fonts = list; idx = 0; while ((dent = readdir(dir)) != NULL) { /* check extension */ p = strrchr(dent->d_name, '.'); if (strcasecmp(p, ".ttf") == 0) { /* get full path */ p = 0; pl = strlen(FREETYPE_FONT_DIR) + strlen(dent->d_name) * sizeof(char) + 2; p = (char*)malloc(pl); p = (char*)memset(p, '\0', pl); p = (char*)strcat(p, FREETYPE_FONT_DIR); p = (char*)strcat(p, "/"); p = (char*)strcat(p, dent->d_name); if((ftmp = get_tt_name(p)) != NULL) { list[idx]->ttname = ftmp; list[idx]->mwname = malloc(strlen(dent->d_name) + 1); list[idx]->mwname = strcpy(list[idx]->mwname, dent->d_name); idx++; } free(p); } } closedir(dir); } #else /* !HAVE_FREETYPE_SUPPORT*/ void GdFreeFontList(MWFONTLIST ***fonts, int n) { } void GdGetFontList(MWFONTLIST ***fonts, int *numfonts) { *numfonts = -1; } #endif /* !HAVE_FREETYPE_SUPPORT*/
Go to most recent revision | Compare with Previous | Blame | View Log