Mercurial > flash_v2
diff packages/services/gfx/mw/current/src/engine/devfont.caching.c @ 208:e0c0827131d1 ecos
Merge from eCos master repository on 2002-05-20-20:11:54-BST
| author | jlarmour |
|---|---|
| date | Mon, 20 May 2002 22:19:26 +0000 |
| parents | |
| children | e1afd37f2f1d |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/packages/services/gfx/mw/current/src/engine/devfont.caching.c @@ -0,0 +1,2921 @@ +/* + * 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> + +/************/ + +typedef struct xTT_Glyph_Cache_ { + + TT_Error error; + TT_Glyph glyph; + TT_UShort index; + TT_UShort flags; + + struct xTT_Glyph_Cache_ * l; + struct xTT_Glyph_Cache_ * r; + +} xTT_Glyph_Cache; + +typedef struct xTT_Instance_Object_ { + + TT_Face face; + TT_Instance instance; + + xTT_Glyph_Cache * head; + +} xTT_Instance_Object; + +typedef struct xTT_Instance_ { + + xTT_Instance_Object * instance; + +} xTT_Instance; + +typedef struct xTT_Outline_Object_ { + + TT_Outline outline; + TT_BBox bbox; + +} xTT_Outline_Object; + +typedef struct xTT_Outline_ { + + xTT_Outline_Object * outline; + +} xTT_Outline; + +typedef struct xTT_Glyph_Object_ { + + TT_Glyph * glyph; + + xTT_Outline_Object outline; + +} xTT_Glyph_Object; + +typedef struct xTT_Glyph_ { + + xTT_Glyph_Object * glyph; + +} xTT_Glyph; + +TT_Error +xTT_Glyph_Cache_Find ( xTT_Instance instance, + xTT_Glyph glyph, + TT_UShort glyphIndex, + TT_UShort loadFlags ) +{ + xTT_Glyph_Cache * node; + xTT_Glyph_Cache ** inode = &instance.instance->head; + + int miss = 0; + + while ( 1 ) + { + if (*inode == 0) + { + miss = 1; + + node = *inode = calloc(1,sizeof(**inode)); + + if (node == 0) + return TT_Err_Out_Of_Memory; + + node->error = TT_New_Glyph(instance.instance->face,&(node->glyph)); + + if (node->error == 0) + node->error = TT_Load_Glyph(instance.instance->instance, + node->glyph, + (node->index = glyphIndex), + (node->flags = loadFlags)); + + if (node->error != 0) + TT_Done_Glyph(node->glyph); + } + else + { + node = *inode; + } + + if (glyphIndex < node->index) + inode = &node->l; + else if (glyphIndex > node->index) + inode = &node->r; + else if (loadFlags < node->flags) + inode = &node->l; + else if (loadFlags > node->flags) + inode = &node->r; + else + { + static int count [] = { 0, 0 }; + ++count[miss]; + printf("\r(%s | hit %d | miss %d)",__TIME__,count[0],count[1]); + glyph.glyph->glyph = &node->glyph; + return node->error; + } + } +} + +void +xTT_Glyph_Cache_Free ( xTT_Glyph_Cache ** pnode ) +{ + xTT_Glyph_Cache * node; + + if (pnode == 0) + return; + + node = *pnode; + + if (node == 0) + return; + + if (node->l) + xTT_Glyph_Cache_Free(&node->l); + + if (node->r) + xTT_Glyph_Cache_Free(&node->r); + + TT_Done_Glyph(node->glyph); + free(node); + + *pnode = 0; +} + +TT_Error +xTT_New_Instance ( TT_Face face, + xTT_Instance * instance ) +{ + instance->instance = calloc(1,sizeof(*instance->instance)); + if (instance->instance == 0) + return TT_Err_Out_Of_Memory; + + instance->instance->face = face; + instance->instance->head = 0; + + return TT_New_Instance(face,&instance->instance->instance); +} + +TT_Error +xTT_Done_Instance ( xTT_Instance instance ) +{ + TT_Error error; + + xTT_Glyph_Cache_Free(&instance.instance->head); + error = TT_Done_Instance(instance.instance->instance); + + free(instance.instance); + + return error; +} + +TT_Error +xTT_Get_Instance_Metrics ( xTT_Instance instance, + TT_Instance_Metrics * imetrics ) +{ + return TT_Get_Instance_Metrics(instance.instance->instance,imetrics); +} + +TT_Error +xTT_Set_Instance_CharSize ( xTT_Instance instance, + TT_F26Dot6 charsize ) +{ + xTT_Glyph_Cache_Free(&instance.instance->head); + return TT_Set_Instance_CharSize(instance.instance->instance,charsize); +} + +TT_Error +xTT_Set_Instance_PixelSizes ( xTT_Instance instance, + TT_UShort pixelWidth, + TT_UShort pixelHeight, + TT_F26Dot6 pointSize ) +{ + xTT_Glyph_Cache_Free(&instance.instance->head); + return TT_Set_Instance_PixelSizes(instance.instance->instance, + pixelWidth, + pixelHeight, + pointSize); +} + +TT_Error +xTT_Set_Instance_Transform_Flags ( xTT_Instance instance, + TT_Bool rotated, + TT_Bool stretched ) +{ + xTT_Glyph_Cache_Free(&instance.instance->head); + return TT_Set_Instance_Resolutions(instance.instance->instance, + rotated, + stretched); +} + +TT_Error +xTT_Set_Instance_Resolutions ( xTT_Instance instance, + TT_UShort xResolution, + TT_UShort yResolution ) +{ + xTT_Glyph_Cache_Free(&instance.instance->head); + return TT_Set_Instance_Resolutions(instance.instance->instance, + xResolution, + yResolution); +} + +TT_Error +xTT_New_Glyph ( TT_Face face, + xTT_Glyph * glyph ) +{ + glyph->glyph = calloc(1,sizeof(*glyph->glyph)); + if (glyph->glyph == 0) + return TT_Err_Out_Of_Memory; + return 0; +} + +TT_Error +xTT_Done_Glyph ( xTT_Glyph glyph ) +{ + free(glyph.glyph); + return 0; +} + +TT_Error +xTT_Load_Glyph ( xTT_Instance instance, + xTT_Glyph glyph, + TT_UShort glyphIndex, + TT_UShort loadFlags ) +{ + TT_Error error; + error = xTT_Glyph_Cache_Find(instance,glyph,glyphIndex,loadFlags); + TT_Get_Glyph_Outline(*glyph.glyph->glyph, + &glyph.glyph->outline.outline); + TT_Get_Outline_BBox(&glyph.glyph->outline.outline, + &glyph.glyph->outline.bbox); + return error; +} + +TT_Error +xTT_Get_Glyph_Metrics ( xTT_Glyph glyph, + TT_Glyph_Metrics * metrics ) +{ + return TT_Get_Glyph_Metrics(*glyph.glyph->glyph,metrics); +} + +TT_Error +xTT_Get_Glyph_Outline ( xTT_Glyph glyph, + xTT_Outline * outline ) +{ + outline->outline = &glyph.glyph->outline; + return 0; +} + +TT_Error +xTT_Get_Outline_BBox ( xTT_Outline * outline, + TT_BBox * bbox ) +{ + *bbox = outline->outline->bbox; + return 0; +} + +void +xTT_Transform_Outline ( xTT_Outline * outline, + TT_Matrix * matrix ) +{ + TT_Transform_Outline(&outline->outline->outline,matrix); + TT_Get_Outline_BBox(&outline->outline->outline, + &outline->outline->bbox); +} + +TT_Error +xTT_Get_Glyph_Bitmap ( xTT_Glyph glyph, + TT_Raster_Map * bitmap, + TT_F26Dot6 xOffset, + TT_F26Dot6 yOffset ) +{ + return TT_Get_Glyph_Bitmap(*glyph.glyph->glyph, + bitmap, + xOffset, + yOffset); +} + +TT_Error +xTT_Get_Glyph_Pixmap ( xTT_Glyph glyph, + TT_Raster_Map * pixmap, + TT_F26Dot6 xOffset, + TT_F26Dot6 yOffset ) +{ + return TT_Get_Glyph_Pixmap(*glyph.glyph->glyph, + pixmap, + xOffset, + yOffset); +} + +#ifndef xTT_ALIAS +#define xTT_ALIAS 1 +#endif + +#if xTT_ALIAS + +#define TT_Instance xTT_Instance +#define TT_Outline xTT_Outline +#define TT_Glyph xTT_Glyph + +#define TT_New_Instance xTT_New_Instance +#define TT_Done_Instance xTT_Done_Instance + +#define TT_Get_Instance_Metrics xTT_Get_Instance_Metrics +#define TT_Set_Instance_CharSize xTT_Set_Instance_CharSize +#define TT_Set_Instance_PixelSizes xTT_Set_Instance_PixelSizes +#define TT_Set_Instance_Transform_Flags xTT_Set_Instance_Transform_Flags +#define TT_Set_Instance_Resolutions xTT_Set_Instance_Resolutions + +#define TT_New_Glyph xTT_New_Glyph +#define TT_Done_Glyph xTT_Done_Glyph + +#define TT_Load_Glyph xTT_Load_Glyph +#define TT_Get_Glyph_Metrics xTT_Get_Glyph_Metrics +#define TT_Get_Glyph_Outline xTT_Get_Glyph_Outline +#define TT_Get_Glyph_Bitmap xTT_Get_Glyph_Bitmap +#define TT_Get_Glyph_Pixmap xTT_Get_Glyph_Pixmap + +#define TT_Get_Outline_BBox xTT_Get_Outline_BBox +#define TT_Transform_Outline xTT_Transform_Outline + +#endif + +/************/ + +#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 + +#ifndef MWFREETYPEFONT_CACHE +#define MWFREETYPEFONT_CACHE 1 +#endif + +#if MWFREETYPEFONT_CACHE + +#ifndef MWFREETYPEFONT_CACHEBITMAP +#define MWFREETYPEFONT_CACHEBITMAP 1 +#endif + +typedef struct mwfreetypefontcache { + unsigned curchar; + void * buffer; +#if MWFREETYPEFONT_CACHEBITMAP + MWPIXELVAL fg; + MWPIXELVAL bg; + MWBOOL usebg; + void * bitmap; +#endif + struct mwfreetypefontcache * l; + struct mwfreetypefontcache * r; +} MWFREETYPEFONTCACHE; + +#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; + +#if MWFREETYPEFONT_CACHE + MWFREETYPEFONTCACHE * glyph_cache; +#endif + +} 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); +/*static void hzk_gettextbits(PMWFONT pfont, int ch, IMAGEBITS *retmap, + MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase);*/ +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); +/*static void hzk_setfontrotation(PMWFONT pfont, int tenthdegrees);*/ + +/* 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; + printf("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 + 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) +{ + static int inited = 0; + + if (inited) + return 1; + + T1_SetBitmapPad(8); + if (!T1_InitLib(0)) + return 0; +#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); +} + +static MWFREETYPEFONTCACHE * +find_cache_glyph ( PMWFREETYPEFONT pf, unsigned curchar ) +{ + MWFREETYPEFONTCACHE ** inode = &pf->glyph_cache; + + while (1) + { + if (*inode == 0) + { + *inode = calloc(sizeof(MWFREETYPEFONTCACHE),1); + (*inode)->curchar = curchar; + } + + if (curchar < (*inode)->curchar) + inode = &(*inode)->l; + else if (curchar > (*inode)->curchar) + inode = &(*inode)->r; + else + return *inode; + } +} + +static void +free_cache_glyph ( MWFREETYPEFONTCACHE * node ) +{ + if (node->l != 0) + free_cache_glyph(node->l); + + if (node->r != 0) + free_cache_glyph(node->r); + + free(node); +} + +/* Render a single glyph*/ +static void +drawchar(PMWFREETYPEFONT pf, PSD psd, unsigned curchar, 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;*/ + MWFREETYPEFONTCACHE * cache; + + /* 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 ??? */ + + cache = find_cache_glyph(pf,curchar); + /* SDR: if cache is 0 here, something really really bad happened */ + + Raster.flow = TT_Flow_Up; + Raster.size = Raster.rows * Raster.cols; + Raster.bitmap = cache->buffer; + + if (Raster.bitmap == 0) + { + 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; + } + + cache->buffer = Raster.bitmap; + } + +#if MWFREETYPEFONT_CACHEBITMAP + if ((memcmp(&gr_foreground,&cache->fg,sizeof(gr_foreground)) != 0) || + (memcmp(&gr_background,&cache->bg,sizeof(gr_background)) != 0) || + (gr_usebg != cache->usebg)) + { + if (cache->bitmap) + { + free(cache->bitmap); + cache->bitmap = 0; + } + } + + bitmap = cache->bitmap; +#else + bitmap = 0; +#endif + + if (bitmap == 0) + { + 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; + } +#if MWFREETYPEFONT_CACHEBITMAP + cache->fg = gr_foreground; + cache->bg = gr_background; + cache->usebg = gr_usebg; + cache->bitmap = bitmap; +#endif + } + + /* Now draw the bitmap ... */ + GdArea(psd, x_offset + xmin, y_offset - (ymin + height), width, height, + bitmap, MWPF_PIXELVAL); + +#if !MWFREETYPEFONT_CACHEBITMAP + free(bitmap); +#endif +} + +/* + * 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, curchar, 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); + + /*----------*/ + + if (pf->glyph_cache != 0) + free_cache_glyph(pf->glyph_cache); + + /*----------*/ + + 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; + /*GdSetFontSize((PMWFONT)pf, height);*/ + 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)break; + /* fprintf(stderr,"s=%x,sbegin=%x,cc=%x\n",s,sbegin,cc);*/ + + } +/* 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*/ + /*jmt: & pf->fontsize can't be changed*/ + /*jmt: 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) + { + printf("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 +}
