Mercurial > ecos
comparison packages/services/gfx/mw/current/src/engine/devfont.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 |
comparison
equal
deleted
inserted
replaced
| 207:74c807ddde34 | 208:e0c0827131d1 |
|---|---|
| 1 /* | |
| 2 * Copyright (c) 2000 Greg Haerr <greg@censoft.com> | |
| 3 * T1lib Adobe type1 routines contributed by Vidar Hokstad | |
| 4 * Freetype TrueType routines contributed by Martin Jolicoeur | |
| 5 * Han Zi Ku routines contributed by Tanghao and Jauming | |
| 6 * | |
| 7 * Device-independent font and text drawing routines | |
| 8 * | |
| 9 * These routines do the necessary range checking, clipping, and cursor | |
| 10 * overwriting checks, and then call the lower level device dependent | |
| 11 * routines to actually do the drawing. The lower level routines are | |
| 12 * only called when it is known that all the pixels to be drawn are | |
| 13 * within the device area and are visible. | |
| 14 */ | |
| 15 /*#define NDEBUG*/ | |
| 16 #include <stdio.h> | |
| 17 #include <stdlib.h> | |
| 18 #include <string.h> | |
| 19 #include <assert.h> | |
| 20 #include <string.h> | |
| 21 | |
| 22 #include "device.h" | |
| 23 #if (UNIX | DOS_DJGPP) | |
| 24 #define strcmpi strcasecmp | |
| 25 #endif | |
| 26 | |
| 27 #if HAVE_T1LIB_SUPPORT | |
| 28 #include <t1lib.h> | |
| 29 #define T1LIB_USE_AA_HIGH | |
| 30 | |
| 31 typedef struct { | |
| 32 PMWFONTPROCS fontprocs; /* common hdr*/ | |
| 33 MWCOORD fontsize; | |
| 34 int fontrotation; | |
| 35 int fontattr; | |
| 36 | |
| 37 int fontid; /* t1lib stuff*/ | |
| 38 } MWT1LIBFONT, *PMWT1LIBFONT; | |
| 39 | |
| 40 static int t1lib_init(PSD psd); | |
| 41 static PMWT1LIBFONT t1lib_createfont(const char *name, MWCOORD height,int attr); | |
| 42 static void t1lib_drawtext(PMWFONT pfont, PSD psd, MWCOORD x, MWCOORD y, | |
| 43 const void *text, int cc, int flags); | |
| 44 static MWBOOL t1lib_getfontinfo(PMWFONT pfont, PMWFONTINFO pfontinfo); | |
| 45 static void t1lib_gettextsize(PMWFONT pfont, const void *text, int cc, | |
| 46 MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase); | |
| 47 static void t1lib_destroyfont(PMWFONT pfont); | |
| 48 | |
| 49 /* handling routines for MWT1LIBFONT*/ | |
| 50 static MWFONTPROCS t1lib_procs = { | |
| 51 MWTF_ASCII, /* routines expect ascii*/ | |
| 52 t1lib_getfontinfo, | |
| 53 t1lib_gettextsize, | |
| 54 NULL, /* gettextbits*/ | |
| 55 t1lib_destroyfont, | |
| 56 t1lib_drawtext, | |
| 57 NULL, /* setfontsize*/ | |
| 58 NULL, /* setfontrotation*/ | |
| 59 NULL, /* setfontattr*/ | |
| 60 }; | |
| 61 #endif | |
| 62 | |
| 63 #ifdef T1LIB_USE_AA_HIGH | |
| 64 typedef unsigned long OUTPIXELVAL; | |
| 65 #else | |
| 66 typedef MWPIXELVAL OUTPIXELVAL; | |
| 67 #endif | |
| 68 | |
| 69 #if HAVE_FREETYPE_SUPPORT | |
| 70 #include <freetype/freetype.h> | |
| 71 #include <freetype/ftxkern.h> | |
| 72 #include <freetype/ftnameid.h> | |
| 73 #include <freetype/ftxcmap.h> | |
| 74 #include <freetype/ftxwidth.h> | |
| 75 #include <math.h> | |
| 76 | |
| 77 #ifndef FREETYPE_FONT_DIR | |
| 78 #define FREETYPE_FONT_DIR "/usr/local/microwin/fonts" | |
| 79 #endif | |
| 80 | |
| 81 #if TT_FREETYPE_MAJOR != 1 | TT_FREETYPE_MINOR < 3 | |
| 82 #error "You must link with freetype lib version 1.3.x +, and not freetype 2. \ | |
| 83 Download it at http://www.freetype.org or http://microwindows.org" | |
| 84 #endif | |
| 85 | |
| 86 typedef struct { | |
| 87 PMWFONTPROCS fontprocs; /* common hdr*/ | |
| 88 MWCOORD fontsize; | |
| 89 int fontrotation; | |
| 90 int fontattr; | |
| 91 | |
| 92 TT_Face face; /* freetype stuff*/ | |
| 93 TT_Instance instance; | |
| 94 TT_CharMap char_map; | |
| 95 TT_Kerning directory; | |
| 96 TT_Matrix matrix; | |
| 97 TT_Glyph glyph; | |
| 98 MWBOOL can_kern; | |
| 99 short last_glyph_code; | |
| 100 short last_pen_pos; | |
| 101 } MWFREETYPEFONT, *PMWFREETYPEFONT; | |
| 102 | |
| 103 static int freetype_init(PSD psd); | |
| 104 static PMWFREETYPEFONT freetype_createfont(const char *name, MWCOORD height, | |
| 105 int attr); | |
| 106 static MWBOOL freetype_getfontinfo(PMWFONT pfont, PMWFONTINFO pfontinfo); | |
| 107 static void freetype_gettextsize(PMWFONT pfont, const void *text, | |
| 108 int cc, MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase); | |
| 109 static void freetype_destroyfont(PMWFONT pfont); | |
| 110 static void freetype_drawtext(PMWFONT pfont, PSD psd, MWCOORD x, MWCOORD y, | |
| 111 const void *text, int cc, int flags); | |
| 112 static void freetype_setfontsize(PMWFONT pfont, MWCOORD fontsize); | |
| 113 static void freetype_setfontrotation(PMWFONT pfont, int tenthdegrees); | |
| 114 | |
| 115 /* handling routines for MWFREETYPEFONT*/ | |
| 116 static MWFONTPROCS freetype_procs = { | |
| 117 MWTF_UC16, /* routines expect unicode 16*/ | |
| 118 freetype_getfontinfo, | |
| 119 freetype_gettextsize, | |
| 120 NULL, /* gettextbits*/ | |
| 121 freetype_destroyfont, | |
| 122 freetype_drawtext, | |
| 123 freetype_setfontsize, | |
| 124 freetype_setfontrotation, | |
| 125 NULL, /* setfontattr*/ | |
| 126 }; | |
| 127 | |
| 128 static TT_Engine engine; /* THE ONLY freetype engine */ | |
| 129 #endif /* HAVE_FREETYPE_SUPPORT*/ | |
| 130 | |
| 131 #if HAVE_HZK_SUPPORT | |
| 132 /* | |
| 133 * 12x12 and 16x16 ascii and chinese fonts | |
| 134 * Big5 and GB2312 encodings supported | |
| 135 */ | |
| 136 #define MAX_PATH 256 | |
| 137 typedef struct { | |
| 138 int width; | |
| 139 int height; | |
| 140 int size; | |
| 141 unsigned long use_count; | |
| 142 char * pFont; | |
| 143 char file[MAX_PATH + 1]; | |
| 144 } HZKFONT; | |
| 145 | |
| 146 static int use_big5=1; | |
| 147 static HZKFONT CFont[2]; /* font cache*/ | |
| 148 static HZKFONT AFont[2]; /* font cache*/ | |
| 149 | |
| 150 /* jmt: moved inside MWHZKFONT*/ | |
| 151 static int afont_width = 8; | |
| 152 static int cfont_width = 16; | |
| 153 static int font_height = 16; | |
| 154 static char *afont_address; | |
| 155 static char *cfont_address; | |
| 156 | |
| 157 typedef struct { | |
| 158 PMWFONTPROCS fontprocs; /* common hdr*/ | |
| 159 MWCOORD fontsize; | |
| 160 int fontrotation; | |
| 161 int fontattr; | |
| 162 | |
| 163 HZKFONT CFont; /* hzkfont stuff */ | |
| 164 HZKFONT AFont; | |
| 165 int afont_width; | |
| 166 int cfont_width; | |
| 167 int font_height; | |
| 168 char *afont_address; | |
| 169 char *cfont_address; | |
| 170 } MWHZKFONT, *PMWHZKFONT; | |
| 171 | |
| 172 static int hzk_init(PSD psd); | |
| 173 static PMWHZKFONT hzk_createfont(const char *name, MWCOORD height,int fontattr); | |
| 174 static MWBOOL hzk_getfontinfo(PMWFONT pfont, PMWFONTINFO pfontinfo); | |
| 175 static void hzk_gettextsize(PMWFONT pfont, const void *text, | |
| 176 int cc, MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase); | |
| 177 #if 0 | |
| 178 static void hzk_gettextbits(PMWFONT pfont, int ch, IMAGEBITS *retmap, | |
| 179 MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase); | |
| 180 static void hzk_setfontrotation(PMWFONT pfont, int tenthdegrees); | |
| 181 #endif | |
| 182 static void hzk_destroyfont(PMWFONT pfont); | |
| 183 static void hzk_drawtext(PMWFONT pfont, PSD psd, MWCOORD x, MWCOORD y, | |
| 184 const void *text, int cc, int flags); | |
| 185 static void hzk_setfontsize(PMWFONT pfont, MWCOORD fontsize); | |
| 186 | |
| 187 /* handling routines for MWHZKFONT*/ | |
| 188 static MWFONTPROCS hzk_procs = { | |
| 189 MWTF_ASCII, /* routines expect ASCII*/ | |
| 190 hzk_getfontinfo, | |
| 191 hzk_gettextsize, | |
| 192 NULL, /* hzk_gettextbits*/ | |
| 193 hzk_destroyfont, | |
| 194 hzk_drawtext, | |
| 195 hzk_setfontsize, | |
| 196 NULL, /* setfontrotation*/ | |
| 197 NULL, /* setfontattr*/ | |
| 198 }; | |
| 199 | |
| 200 static int | |
| 201 UC16_to_GB(const unsigned char *uc16, int cc, unsigned char *ascii); | |
| 202 #endif /* HAVE_HZK_SUPPORT*/ | |
| 203 | |
| 204 static PMWFONT gr_pfont; /* current font*/ | |
| 205 | |
| 206 /* temp extern decls*/ | |
| 207 extern MWPIXELVAL gr_foreground; | |
| 208 extern MWPIXELVAL gr_background; | |
| 209 extern MWBOOL gr_usebg; | |
| 210 | |
| 211 static int utf8_to_utf16(const unsigned char *utf8, int cc, | |
| 212 unsigned short *unicode16); | |
| 213 | |
| 214 #if FONTMAPPER | |
| 215 /* entry point for font selection*/ | |
| 216 int select_font(const PMWLOGFONT plogfont, char *physname); | |
| 217 #endif | |
| 218 | |
| 219 /* | |
| 220 * Set the font for future calls. | |
| 221 */ | |
| 222 PMWFONT | |
| 223 GdSetFont(PMWFONT pfont) | |
| 224 { | |
| 225 PMWFONT oldfont = gr_pfont; | |
| 226 | |
| 227 gr_pfont = pfont; | |
| 228 return oldfont; | |
| 229 } | |
| 230 | |
| 231 /* | |
| 232 * Select a font, based on various parameters. | |
| 233 * If plogfont is specified, name and height parms are ignored | |
| 234 * and instead used from MWLOGFONT. | |
| 235 * | |
| 236 * If height is 0, return builtin font from passed name. | |
| 237 * Otherwise find builtin font best match based on height. | |
| 238 */ | |
| 239 PMWFONT | |
| 240 GdCreateFont(PSD psd, const char *name, MWCOORD height, | |
| 241 const PMWLOGFONT plogfont) | |
| 242 { | |
| 243 int i; | |
| 244 int fontht; | |
| 245 int fontno; | |
| 246 int fontclass; | |
| 247 int fontattr = 0; | |
| 248 PMWFONT pfont; | |
| 249 PMWCOREFONT pf = psd->builtin_fonts; | |
| 250 MWFONTINFO fontinfo; | |
| 251 MWSCREENINFO scrinfo; | |
| 252 char fontname[128]; | |
| 253 | |
| 254 GdGetScreenInfo(psd, &scrinfo); | |
| 255 | |
| 256 /* if plogfont not specified, use name and height*/ | |
| 257 if (!plogfont) { | |
| 258 if (!name) | |
| 259 name = MWFONT_SYSTEM_VAR; | |
| 260 strcpy(fontname, name); | |
| 261 fontclass = MWLF_CLASS_ANY; | |
| 262 } else { | |
| 263 #if FONTMAPPER | |
| 264 /* otherwise, use MWLOGFONT name and height*/ | |
| 265 fontclass = select_font(plogfont, fontname); | |
| 266 #else | |
| 267 if (!name) | |
| 268 name = MWFONT_SYSTEM_VAR; | |
| 269 strcpy(fontname, name); | |
| 270 fontclass = MWLF_CLASS_ANY; | |
| 271 #endif | |
| 272 height = plogfont->lfHeight; | |
| 273 if (plogfont->lfUnderline) | |
| 274 fontattr = MWTF_UNDERLINE; | |
| 275 } | |
| 276 height = abs(height); | |
| 277 | |
| 278 if (!fontclass) | |
| 279 goto first; | |
| 280 | |
| 281 /* use builtin screen fonts, FONT_xxx, if height is 0 */ | |
| 282 if (height == 0 || fontclass == MWLF_CLASS_ANY || | |
| 283 fontclass == MWLF_CLASS_BUILTIN) { | |
| 284 for(i = 0; i < scrinfo.fonts; ++i) { | |
| 285 if(!strcmpi(pf[i].name, fontname)) { | |
| 286 pf[i].fontsize = pf[i].cfont->height; | |
| 287 pf[i].fontattr = fontattr; | |
| 288 return (PMWFONT)&pf[i]; | |
| 289 } | |
| 290 } | |
| 291 | |
| 292 /* return first builtin font*/ | |
| 293 if (height == 0 || fontclass == MWLF_CLASS_BUILTIN) | |
| 294 goto first; | |
| 295 } | |
| 296 | |
| 297 #if HAVE_HZK_SUPPORT | |
| 298 /* Make sure the library is initialized */ | |
| 299 if (hzk_init(psd)) { | |
| 300 pfont = (PMWFONT)hzk_createfont(name, height, fontattr); | |
| 301 if(pfont) | |
| 302 return pfont; | |
| 303 fprintf(stderr, "hzk_createfont: %s not found\n", name); | |
| 304 } | |
| 305 #endif | |
| 306 | |
| 307 #if HAVE_FREETYPE_SUPPORT | |
| 308 if (fontclass == MWLF_CLASS_ANY || fontclass == MWLF_CLASS_FREETYPE) { | |
| 309 if (freetype_init(psd)) { | |
| 310 /* auto antialias for height > 14 for kaffe*/ | |
| 311 if (plogfont && plogfont->lfHeight > 14 && | |
| 312 plogfont->lfQuality) | |
| 313 fontattr |= MWTF_ANTIALIAS; | |
| 314 | |
| 315 pfont = (PMWFONT)freetype_createfont(fontname, height, | |
| 316 fontattr); | |
| 317 if(pfont) { | |
| 318 /* temp kaffe kluge*/ | |
| 319 pfont->fontattr |= FS_FREETYPE; | |
| 320 return pfont; | |
| 321 } | |
| 322 DPRINTF("freetype_createfont: %s,%d not found\n", | |
| 323 fontname, height); | |
| 324 } | |
| 325 } | |
| 326 #endif | |
| 327 | |
| 328 #if HAVE_T1LIB_SUPPORT | |
| 329 if (fontclass == MWLF_CLASS_ANY || fontclass == MWLF_CLASS_T1LIB) { | |
| 330 if (t1lib_init(psd)) { | |
| 331 pfont = (PMWFONT)t1lib_createfont(fontname, height, | |
| 332 fontattr); | |
| 333 if(pfont) | |
| 334 return pfont; | |
| 335 DPRINTF("t1lib_createfont: %s,%d not found\n", | |
| 336 fontname, height); | |
| 337 } | |
| 338 } | |
| 339 #endif | |
| 340 | |
| 341 /* find builtin font closest in height*/ | |
| 342 if(height != 0) { | |
| 343 fontno = 0; | |
| 344 height = abs(height); | |
| 345 fontht = MAX_MWCOORD; | |
| 346 for(i = 0; i < scrinfo.fonts; ++i) { | |
| 347 pfont = (PMWFONT)&pf[i]; | |
| 348 GdGetFontInfo(pfont, &fontinfo); | |
| 349 if(fontht > abs(height-fontinfo.height)) { | |
| 350 fontno = i; | |
| 351 fontht = abs(height-fontinfo.height); | |
| 352 } | |
| 353 } | |
| 354 pf[fontno].fontsize = pf[fontno].cfont->height; | |
| 355 pf[fontno].fontattr = fontattr; | |
| 356 return (PMWFONT)&pf[fontno]; | |
| 357 } | |
| 358 | |
| 359 first: | |
| 360 /* Return first builtin font*/ | |
| 361 pf->fontsize = pf->cfont->height; | |
| 362 pf->fontattr = fontattr; | |
| 363 return (PMWFONT)&pf[0]; | |
| 364 } | |
| 365 | |
| 366 /* Set the font size for the passed font*/ | |
| 367 MWCOORD | |
| 368 GdSetFontSize(PMWFONT pfont, MWCOORD fontsize) | |
| 369 { | |
| 370 MWCOORD oldfontsize = pfont->fontsize; | |
| 371 | |
| 372 pfont->fontsize = fontsize; | |
| 373 | |
| 374 if (pfont->fontprocs->SetFontSize) | |
| 375 pfont->fontprocs->SetFontSize(pfont, fontsize); | |
| 376 | |
| 377 return oldfontsize; | |
| 378 } | |
| 379 | |
| 380 /* Set the font rotation angle in tenths of degrees for the passed font*/ | |
| 381 int | |
| 382 GdSetFontRotation(PMWFONT pfont, int tenthdegrees) | |
| 383 { | |
| 384 MWCOORD oldrotation = pfont->fontrotation; | |
| 385 | |
| 386 pfont->fontrotation = tenthdegrees; | |
| 387 | |
| 388 if (pfont->fontprocs->SetFontRotation) | |
| 389 pfont->fontprocs->SetFontRotation(pfont, tenthdegrees); | |
| 390 | |
| 391 return oldrotation; | |
| 392 } | |
| 393 | |
| 394 /* | |
| 395 * Set/reset font attributes (MWTF_KERNING, MWTF_ANTIALIAS) | |
| 396 * for the passed font. | |
| 397 */ | |
| 398 int | |
| 399 GdSetFontAttr(PMWFONT pfont, int setflags, int clrflags) | |
| 400 { | |
| 401 MWCOORD oldattr = pfont->fontattr; | |
| 402 | |
| 403 pfont->fontattr &= ~clrflags; | |
| 404 pfont->fontattr |= setflags; | |
| 405 | |
| 406 if (pfont->fontprocs->SetFontAttr) | |
| 407 pfont->fontprocs->SetFontAttr(pfont, setflags, clrflags); | |
| 408 | |
| 409 return oldattr; | |
| 410 } | |
| 411 | |
| 412 /* Unload and deallocate font*/ | |
| 413 void | |
| 414 GdDestroyFont(PMWFONT pfont) | |
| 415 { | |
| 416 if (pfont->fontprocs->DestroyFont) | |
| 417 pfont->fontprocs->DestroyFont(pfont); | |
| 418 } | |
| 419 | |
| 420 /* Return information about a specified font*/ | |
| 421 MWBOOL | |
| 422 GdGetFontInfo(PMWFONT pfont, PMWFONTINFO pfontinfo) | |
| 423 { | |
| 424 if(!pfont || !pfont->fontprocs->GetFontInfo) | |
| 425 return FALSE; | |
| 426 | |
| 427 return pfont->fontprocs->GetFontInfo(pfont, pfontinfo); | |
| 428 } | |
| 429 | |
| 430 /* | |
| 431 * Convert from one encoding to another | |
| 432 * Input cc and returned cc is character count, not bytes | |
| 433 * Return < 0 on error or can't translate | |
| 434 */ | |
| 435 int | |
| 436 GdConvertEncoding(const void *istr, int iflags, int cc, void *ostr, int oflags) | |
| 437 { | |
| 438 const unsigned char *istr8; | |
| 439 const unsigned short *istr16; | |
| 440 const unsigned long *istr32; | |
| 441 unsigned char *ostr8; | |
| 442 unsigned short *ostr16; | |
| 443 unsigned long *ostr32; | |
| 444 unsigned int ch; | |
| 445 int icc; | |
| 446 unsigned short buf16[512]; | |
| 447 | |
| 448 iflags &= MWTF_PACKMASK; | |
| 449 oflags &= MWTF_PACKMASK; | |
| 450 | |
| 451 /* allow -1 for len with ascii*/ | |
| 452 if(cc == -1 && (iflags == MWTF_ASCII)) | |
| 453 cc = strlen((char *)istr); | |
| 454 | |
| 455 /* first check for utf8 input encoding*/ | |
| 456 if(iflags == MWTF_UTF8) { | |
| 457 /* we've only got uc16 now so convert to uc16...*/ | |
| 458 cc = utf8_to_utf16((unsigned char *)istr, cc, | |
| 459 oflags==MWTF_UC16?(unsigned short*) ostr: buf16); | |
| 460 | |
| 461 if(oflags == MWTF_UC16 || cc < 0) | |
| 462 return cc; | |
| 463 | |
| 464 /* will decode again to requested format (probably ascii)*/ | |
| 465 iflags = MWTF_UC16; | |
| 466 istr = buf16; | |
| 467 } | |
| 468 | |
| 469 #if HAVE_HZK_SUPPORT | |
| 470 if(iflags == MWTF_UC16 && oflags == MWTF_ASCII) { | |
| 471 /* only support uc16 convert to ascii now...*/ | |
| 472 cc = UC16_to_GB( istr, cc, ostr); | |
| 473 return cc; | |
| 474 } | |
| 475 #endif | |
| 476 | |
| 477 icc = cc; | |
| 478 istr8 = istr; | |
| 479 istr16 = istr; | |
| 480 istr32 = istr; | |
| 481 ostr8 = ostr; | |
| 482 ostr16 = ostr; | |
| 483 ostr32 = ostr; | |
| 484 | |
| 485 /* Convert between formats. Note that there's no error | |
| 486 * checking here yet. | |
| 487 */ | |
| 488 while(--icc >= 0) { | |
| 489 switch(iflags) { | |
| 490 default: | |
| 491 ch = *istr8++; | |
| 492 break; | |
| 493 case MWTF_UC16: | |
| 494 ch = *istr16++; | |
| 495 break; | |
| 496 case MWTF_UC32: | |
| 497 ch = *istr32++; | |
| 498 } | |
| 499 switch(oflags) { | |
| 500 default: | |
| 501 *ostr8++ = (unsigned char)ch; | |
| 502 break; | |
| 503 case MWTF_UC16: | |
| 504 *ostr16++ = (unsigned short)ch; | |
| 505 break; | |
| 506 case MWTF_UC32: | |
| 507 *ostr32++ = ch; | |
| 508 } | |
| 509 } | |
| 510 return cc; | |
| 511 } | |
| 512 | |
| 513 /* Get the width and height of passed text string in the passed font*/ | |
| 514 void | |
| 515 GdGetTextSize(PMWFONT pfont, const void *str, int cc, MWCOORD *pwidth, | |
| 516 MWCOORD *pheight, MWCOORD *pbase, int flags) | |
| 517 { | |
| 518 const void * text; | |
| 519 unsigned long buf[256]; | |
| 520 int defencoding = pfont->fontprocs->encoding; | |
| 521 | |
| 522 /* convert encoding if required*/ | |
| 523 if((flags & MWTF_PACKMASK) != defencoding) { | |
| 524 cc = GdConvertEncoding(str, flags, cc, buf, defencoding); | |
| 525 flags &= ~MWTF_PACKMASK; | |
| 526 flags |= defencoding; | |
| 527 text = buf; | |
| 528 } else text = str; | |
| 529 | |
| 530 if(cc == -1 && (flags & MWTF_PACKMASK) == MWTF_ASCII) | |
| 531 cc = strlen((char *)str); | |
| 532 | |
| 533 if(cc <= 0 || !pfont->fontprocs->GetTextSize) { | |
| 534 *pwidth = *pheight = *pbase = 0; | |
| 535 return; | |
| 536 } | |
| 537 | |
| 538 /* calc height and width of string*/ | |
| 539 pfont->fontprocs->GetTextSize(pfont, text, cc, pwidth, pheight, pbase); | |
| 540 } | |
| 541 | |
| 542 /* Draw a text string at a specifed coordinates in the foreground color | |
| 543 * (and possibly the background color), applying clipping if necessary. | |
| 544 * The background color is only drawn if the gr_usebg flag is set. | |
| 545 * Use the current font. | |
| 546 */ | |
| 547 void | |
| 548 GdText(PSD psd, MWCOORD x, MWCOORD y, const void *str, int cc, int flags) | |
| 549 { | |
| 550 const void * text; | |
| 551 unsigned long buf[256]; | |
| 552 int defencoding = gr_pfont->fontprocs->encoding; | |
| 553 | |
| 554 /* convert encoding if required*/ | |
| 555 if((flags & MWTF_PACKMASK) != defencoding) { | |
| 556 cc = GdConvertEncoding(str, flags, cc, buf, defencoding); | |
| 557 flags &= ~MWTF_PACKMASK; | |
| 558 flags |= defencoding; | |
| 559 text = buf; | |
| 560 } else text = str; | |
| 561 | |
| 562 if(cc == -1 && (flags & MWTF_PACKMASK) == MWTF_ASCII) | |
| 563 cc = strlen((char *)str); | |
| 564 | |
| 565 if(cc <= 0 || !gr_pfont->fontprocs->DrawText) | |
| 566 return; | |
| 567 | |
| 568 /* draw text string*/ | |
| 569 gr_pfont->fontprocs->DrawText(gr_pfont, psd, x, y, text, cc, flags); | |
| 570 } | |
| 571 | |
| 572 /* | |
| 573 * Draw ascii text using COREFONT type font. | |
| 574 */ | |
| 575 void | |
| 576 corefont_drawtext(PMWFONT pfont, PSD psd, MWCOORD x, MWCOORD y, | |
| 577 const void *text, int cc, int flags) | |
| 578 { | |
| 579 const unsigned char *str = text; | |
| 580 MWCOORD width; /* width of text area */ | |
| 581 MWCOORD height; /* height of text area */ | |
| 582 MWCOORD base; /* baseline of text*/ | |
| 583 MWCOORD startx, starty; | |
| 584 /* bitmap for characters */ | |
| 585 MWIMAGEBITS bitmap[MAX_CHAR_HEIGHT*MAX_CHAR_WIDTH/MWIMAGE_BITSPERIMAGE]; | |
| 586 | |
| 587 pfont->fontprocs->GetTextSize(pfont, str, cc, &width, &height, &base); | |
| 588 | |
| 589 if(flags & MWTF_BASELINE) | |
| 590 y -= base; | |
| 591 else if(flags & MWTF_BOTTOM) | |
| 592 y -= (height - 1); | |
| 593 startx = x; | |
| 594 starty = y + base; | |
| 595 | |
| 596 switch (GdClipArea(psd, x, y, x + width - 1, y + height - 1)) { | |
| 597 case CLIP_VISIBLE: | |
| 598 /* | |
| 599 * For size considerations, there's no low-level text | |
| 600 * draw, so we've got to draw all text | |
| 601 * with per-point clipping for the time being | |
| 602 if (gr_usebg) | |
| 603 psd->FillRect(psd, x, y, x + width - 1, y + height - 1, | |
| 604 gr_background); | |
| 605 psd->DrawText(psd, x, y, str, cc, gr_foreground, pfont); | |
| 606 GdFixCursor(psd); | |
| 607 return; | |
| 608 */ | |
| 609 break; | |
| 610 | |
| 611 case CLIP_INVISIBLE: | |
| 612 return; | |
| 613 } | |
| 614 | |
| 615 /* Get the bitmap for each character individually, and then display | |
| 616 * them using clipping for each one. | |
| 617 */ | |
| 618 while (--cc >= 0 && x < psd->xvirtres) { | |
| 619 unsigned int ch = *str++; | |
| 620 #if HAVE_BIG5_SUPPORT | |
| 621 /* chinese big5 decoding*/ | |
| 622 if (ch >= 0xA1 && ch <= 0xF9 && cc >= 1 && | |
| 623 ((*str >= 0x40 && *str <= 0x7E) || | |
| 624 (*str >= 0xA1 && *str <= 0xFE)) ) { | |
| 625 ch = (ch << 8) | *str++; | |
| 626 --cc; | |
| 627 } | |
| 628 #endif | |
| 629 #if HAVE_GB2312_SUPPORT | |
| 630 /* chinese gb2312 decoding*/ | |
| 631 if (ch >= 0xA1 && ch < 0xF8 && cc >= 1 && | |
| 632 *str >= 0xA1 && *str < 0xFF) { | |
| 633 ch = (ch << 8) | *str++; | |
| 634 --cc; | |
| 635 } | |
| 636 #endif | |
| 637 #if HAVE_KSC5601_SUPPORT | |
| 638 /* Korean KSC5601 decoding */ | |
| 639 if (ch >= 0xA1 && ch <= 0xFE && cc >= 1 && | |
| 640 (*str >= 0xA1 && *str <= 0xFE)) { | |
| 641 ch = (ch << 8) | *str++; | |
| 642 --cc; | |
| 643 } | |
| 644 #endif | |
| 645 pfont->fontprocs->GetTextBits(pfont, ch, bitmap, &width, | |
| 646 &height, &base); | |
| 647 | |
| 648 /* note: change to bitmap*/ | |
| 649 GdBitmap(psd, x, y, width, height, bitmap); | |
| 650 x += width; | |
| 651 } | |
| 652 | |
| 653 if (pfont->fontattr & MWTF_UNDERLINE) | |
| 654 GdLine(psd, startx, starty, x, starty, FALSE); | |
| 655 | |
| 656 GdFixCursor(psd); | |
| 657 } | |
| 658 | |
| 659 #if HAVE_T1LIB_SUPPORT | HAVE_FREETYPE_SUPPORT | |
| 660 /* | |
| 661 * Produce blend table from src and dst based on passed alpha table | |
| 662 * Used because we don't quite yet have GdArea with alphablending, | |
| 663 * so we pre-blend fg/bg colors for fade effect. | |
| 664 */ | |
| 665 static void | |
| 666 alphablend(PSD psd, OUTPIXELVAL *out, MWPIXELVAL src, MWPIXELVAL dst, | |
| 667 unsigned char *alpha, int count) | |
| 668 { | |
| 669 unsigned int a, d; | |
| 670 unsigned char r, g, b; | |
| 671 MWCOLORVAL palsrc, paldst; | |
| 672 extern MWPALENTRY gr_palette[256]; | |
| 673 | |
| 674 while (--count >= 0) { | |
| 675 a = *alpha++; | |
| 676 | |
| 677 #define BITS(pixel,shift,mask) (((pixel)>>shift)&(mask)) | |
| 678 if(a == 0) | |
| 679 *out++ = dst; | |
| 680 else if(a == 255) | |
| 681 *out++ = src; | |
| 682 else | |
| 683 switch(psd->pixtype) { | |
| 684 case MWPF_TRUECOLOR0888: | |
| 685 case MWPF_TRUECOLOR888: | |
| 686 d = BITS(dst, 16, 0xff); | |
| 687 r = (unsigned char)(((BITS(src, 16, 0xff) - d)*a)>>8) + d; | |
| 688 d = BITS(dst, 8, 0xff); | |
| 689 g = (unsigned char)(((BITS(src, 8, 0xff) - d)*a)>>8) + d; | |
| 690 d = BITS(dst, 0, 0xff); | |
| 691 b = (unsigned char)(((BITS(src, 0, 0xff) - d)*a)>>8) + d; | |
| 692 *out++ = (r << 16) | (g << 8) | b; | |
| 693 break; | |
| 694 | |
| 695 case MWPF_TRUECOLOR565: | |
| 696 d = BITS(dst, 11, 0x1f); | |
| 697 r = (unsigned char)(((BITS(src, 11, 0x1f) - d)*a)>>8) + d; | |
| 698 d = BITS(dst, 5, 0x3f); | |
| 699 g = (unsigned char)(((BITS(src, 5, 0x3f) - d)*a)>>8) + d; | |
| 700 d = BITS(dst, 0, 0x1f); | |
| 701 b = (unsigned char)(((BITS(src, 0, 0x1f) - d)*a)>>8) + d; | |
| 702 *out++ = (r << 11) | (g << 5) | b; | |
| 703 break; | |
| 704 | |
| 705 case MWPF_TRUECOLOR555: | |
| 706 d = BITS(dst, 10, 0x1f); | |
| 707 r = (unsigned char)(((BITS(src, 10, 0x1f) - d)*a)>>8) + d; | |
| 708 d = BITS(dst, 5, 0x1f); | |
| 709 g = (unsigned char)(((BITS(src, 5, 0x1f) - d)*a)>>8) + d; | |
| 710 d = BITS(dst, 0, 0x1f); | |
| 711 b = (unsigned char)(((BITS(src, 0, 0x1f) - d)*a)>>8) + d; | |
| 712 *out++ = (r << 10) | (g << 5) | b; | |
| 713 break; | |
| 714 | |
| 715 case MWPF_TRUECOLOR332: | |
| 716 d = BITS(dst, 5, 0x07); | |
| 717 r = (unsigned char)(((BITS(src, 5, 0x07) - d)*a)>>8) + d; | |
| 718 d = BITS(dst, 2, 0x07); | |
| 719 g = (unsigned char)(((BITS(src, 2, 0x07) - d)*a)>>8) + d; | |
| 720 d = BITS(dst, 0, 0x03); | |
| 721 b = (unsigned char)(((BITS(src, 0, 0x03) - d)*a)>>8) + d; | |
| 722 *out++ = (r << 5) | (g << 2) | b; | |
| 723 break; | |
| 724 | |
| 725 case MWPF_PALETTE: | |
| 726 /* reverse lookup palette entry for blend ;-)*/ | |
| 727 palsrc = GETPALENTRY(gr_palette, src); | |
| 728 paldst = GETPALENTRY(gr_palette, dst); | |
| 729 d = REDVALUE(paldst); | |
| 730 r = (unsigned char)(((REDVALUE(palsrc) - d)*a)>>8) + d; | |
| 731 d = GREENVALUE(paldst); | |
| 732 g = (unsigned char)(((GREENVALUE(palsrc) - d)*a)>>8) + d; | |
| 733 d = BLUEVALUE(paldst); | |
| 734 b = (unsigned char)(((BLUEVALUE(palsrc) - d)*a)>>8) + d; | |
| 735 *out++ = GdFindNearestColor(gr_palette, (int)psd->ncolors, | |
| 736 MWRGB(r, g, b)); | |
| 737 break; | |
| 738 } | |
| 739 } | |
| 740 } | |
| 741 #endif /*HAVE_T1LIB_SUPPORT | HAVE_FREETYPE_SUPPORT*/ | |
| 742 | |
| 743 #if HAVE_T1LIB_SUPPORT | |
| 744 /* contributed by Vidar Hokstad*/ | |
| 745 | |
| 746 static int | |
| 747 t1lib_init(PSD psd) | |
| 748 { | |
| 749 char **encoding; | |
| 750 static int inited = 0; | |
| 751 | |
| 752 if (inited) | |
| 753 return 1; | |
| 754 | |
| 755 T1_SetBitmapPad(8); | |
| 756 if (!T1_InitLib(0)) | |
| 757 return 0; | |
| 758 | |
| 759 /* set default Latin1 encoding*/ | |
| 760 encoding = T1_LoadEncoding("IsoLatin1.enc"); | |
| 761 T1_SetDefaultEncoding(encoding); | |
| 762 | |
| 763 #ifdef T1LIB_USE_AA_HIGH | |
| 764 T1_AASetLevel(T1_AA_HIGH); | |
| 765 #else | |
| 766 T1_AASetLevel(T1_AA_LOW); | |
| 767 #endif | |
| 768 #if 0 | |
| 769 /* kluge: this is required if 16bpp drawarea driver is used*/ | |
| 770 if(psd->bpp == 16) | |
| 771 T1_AASetBitsPerPixel(16); | |
| 772 else | |
| 773 #endif | |
| 774 T1_AASetBitsPerPixel(sizeof(MWPIXELVAL)*8); | |
| 775 | |
| 776 inited = 1; | |
| 777 return 1; | |
| 778 } | |
| 779 | |
| 780 static PMWT1LIBFONT | |
| 781 t1lib_createfont(const char *name, MWCOORD height, int attr) | |
| 782 { | |
| 783 PMWT1LIBFONT pf; | |
| 784 int id; | |
| 785 char * p; | |
| 786 char buf[256]; | |
| 787 | |
| 788 /* match name against t1 font id's from t1 font database*/ | |
| 789 for(id=0; id<T1_Get_no_fonts(); ++id) { | |
| 790 strncpy(buf, T1_GetFontFileName(id), sizeof(buf)); | |
| 791 | |
| 792 /* remove extension*/ | |
| 793 for(p=buf; *p; ++p) { | |
| 794 if(*p == '.') { | |
| 795 *p = 0; | |
| 796 break; | |
| 797 } | |
| 798 } | |
| 799 | |
| 800 if(!strcmpi(name, buf)) { | |
| 801 /* allocate font structure*/ | |
| 802 pf = (PMWT1LIBFONT)calloc(sizeof(MWT1LIBFONT), 1); | |
| 803 if (!pf) | |
| 804 return NULL; | |
| 805 pf->fontprocs = &t1lib_procs; | |
| 806 GdSetFontSize((PMWFONT)pf, height); | |
| 807 GdSetFontRotation((PMWFONT)pf, 0); | |
| 808 GdSetFontAttr((PMWFONT)pf, attr, 0); | |
| 809 pf->fontid = id; | |
| 810 return pf; | |
| 811 } | |
| 812 } | |
| 813 return NULL; | |
| 814 } | |
| 815 | |
| 816 /* | |
| 817 * Draw ascii text string using T1LIB type font | |
| 818 */ | |
| 819 static void | |
| 820 t1lib_drawtext(PMWFONT pfont, PSD psd, MWCOORD x, MWCOORD y, | |
| 821 const void *text, int cc, int flags) | |
| 822 { | |
| 823 PMWT1LIBFONT pf = (PMWT1LIBFONT)pfont; | |
| 824 const unsigned char *str = text; | |
| 825 MWCOORD width; /* width of text area */ | |
| 826 MWCOORD height; /* height of text area */ | |
| 827 MWCOORD underliney; | |
| 828 GLYPH * g; /* T1lib glyph structure. Memory handling by T1lib */ | |
| 829 #ifdef T1LIB_USE_AA_HIGH | |
| 830 OUTPIXELVAL gvals[17]; | |
| 831 | |
| 832 /* Blending array for antialiasing. The steeper the values increase | |
| 833 * near the end, the sharper the characters look, but also more jagged | |
| 834 */ | |
| 835 static unsigned char blend[17] = { | |
| 836 0x00, 0x00, 0x04, 0x0c, 0x10, 0x14, 0x18, 0x20, | |
| 837 0x30, 0x38, 0x40, 0x50, 0x70, 0x80, 0xa0, 0xc0, 0xff | |
| 838 }; | |
| 839 #else | |
| 840 OUTPIXELVAL gvals[5]; | |
| 841 static unsigned char blend[5] = { 0x00, 0x44, 0x88, 0xcc, 0xff }; | |
| 842 #endif | |
| 843 | |
| 844 /* Check if we should throw out some fonts */ | |
| 845 | |
| 846 if (pf->fontattr&MWTF_ANTIALIAS) { | |
| 847 #ifdef T1LIB_USE_AA_HIGH | |
| 848 alphablend(psd, gvals, gr_foreground, gr_background, blend, 17); | |
| 849 T1_AAHSetGrayValues(gvals); | |
| 850 #else | |
| 851 alphablend(psd, gvals, gr_foreground, gr_background, blend, 5); | |
| 852 T1_AASetGrayValues(gvals[0],gvals[1],gvals[2],gvals[3],gvals[4]); | |
| 853 #endif | |
| 854 g = T1_AASetString(pf->fontid,(char *)str,cc,0, | |
| 855 (pf->fontattr&MWTF_KERNING)? T1_KERNING: 0, | |
| 856 pf->fontsize * 1.0, 0); | |
| 857 | |
| 858 if (g && g->bits) { | |
| 859 /*MWPIXELVAL save = gr_background;*/ | |
| 860 width = g->metrics.rightSideBearing - g->metrics.leftSideBearing; | |
| 861 height = g->metrics.ascent - g->metrics.descent; | |
| 862 | |
| 863 if(flags & MWTF_BASELINE) | |
| 864 y -= g->metrics.ascent; | |
| 865 else if(flags & MWTF_BOTTOM) | |
| 866 y -= (height - 1); | |
| 867 underliney = y + g->metrics.ascent; | |
| 868 | |
| 869 /* FIXME: Looks damn ugly if usebg is false. | |
| 870 * Will be handled when using alphablending in GdArea... | |
| 871 */ | |
| 872 /* clipping handled in GdArea*/ | |
| 873 /*FIXME kluge for transparency*/ | |
| 874 /*gr_background = gr_foreground + 1;*/ | |
| 875 /*gr_usebg = 0;*/ | |
| 876 GdArea(psd,x,y, width, height, g->bits, MWPF_PIXELVAL); | |
| 877 /*gr_background = save;*/ | |
| 878 | |
| 879 if (pf->fontattr & MWTF_UNDERLINE) | |
| 880 GdLine(psd, x, underliney, x+width, underliney, FALSE); | |
| 881 | |
| 882 } | |
| 883 } else { | |
| 884 /* Do non-aa drawing */ | |
| 885 g = T1_SetString(pf->fontid,(char *)str,cc,0, | |
| 886 (pf->fontattr&MWTF_KERNING)? T1_KERNING: 0, | |
| 887 pf->fontsize * 1.0, 0); | |
| 888 | |
| 889 if (g && g->bits) { | |
| 890 unsigned char * b; | |
| 891 int xoff; | |
| 892 int maxy; | |
| 893 int xmod; | |
| 894 | |
| 895 /* I'm sure this sorry excuse for a bitmap rendering routine can | |
| 896 * be optimized quite a bit ;) | |
| 897 */ | |
| 898 width = g->metrics.rightSideBearing - g->metrics.leftSideBearing; | |
| 899 height = g->metrics.ascent - g->metrics.descent; | |
| 900 | |
| 901 if(flags & MWTF_BASELINE) | |
| 902 y -= g->metrics.ascent; | |
| 903 else if(flags & MWTF_BOTTOM) | |
| 904 y -= (height - 1); | |
| 905 underliney = y + g->metrics.ascent; | |
| 906 | |
| 907 b = g->bits; | |
| 908 maxy = y + height; | |
| 909 | |
| 910 /* if ((x + width) > psd->xvirtres) { | |
| 911 xmod = (x + width - psd->xvirtres + 7) >> 3; | |
| 912 width = width + x + width - psd->xvirtres; | |
| 913 } else xmod = 0; | |
| 914 */ | |
| 915 xmod = 0; | |
| 916 while (y < maxy) { | |
| 917 unsigned char data; | |
| 918 xoff = 0; | |
| 919 while (xoff < width ) { | |
| 920 if (!(xoff % 8)) { | |
| 921 data = *b; | |
| 922 b++; | |
| 923 } | |
| 924 | |
| 925 if (GdClipPoint(psd, x+xoff,y)) { | |
| 926 if (gr_usebg) { | |
| 927 psd->DrawPixel(psd,x+xoff,y, | |
| 928 data & (1 << (xoff % 8)) ? | |
| 929 gr_foreground : gr_background); | |
| 930 } else if (data & (1 << (xoff % 8))) { | |
| 931 psd->DrawPixel(psd,x+xoff,y, gr_foreground); | |
| 932 } | |
| 933 } | |
| 934 xoff++; | |
| 935 } | |
| 936 b += xmod; | |
| 937 y++; | |
| 938 } | |
| 939 if (pf->fontattr & MWTF_UNDERLINE) | |
| 940 GdLine(psd, x, underliney, x+xoff, underliney, FALSE); | |
| 941 } | |
| 942 } | |
| 943 | |
| 944 if (g && g->bits) { | |
| 945 /* Save some memory */ | |
| 946 free(g->bits); | |
| 947 g->bits = 0; /* Make sure T1lib doesnt try to free it again */ | |
| 948 } | |
| 949 | |
| 950 GdFixCursor(psd); | |
| 951 } | |
| 952 | |
| 953 static MWBOOL | |
| 954 t1lib_getfontinfo(PMWFONT pfont, PMWFONTINFO pfontinfo) | |
| 955 { | |
| 956 int i; | |
| 957 MWCOORD width, height, baseline; | |
| 958 | |
| 959 /* FIXME, guess all sizes*/ | |
| 960 GdGetTextSize(pfont, "A", 1, &width, &height, &baseline, MWTF_ASCII); | |
| 961 pfontinfo->height = height; | |
| 962 pfontinfo->maxwidth = width; | |
| 963 pfontinfo->baseline = 0; | |
| 964 pfontinfo->firstchar = 32; | |
| 965 pfontinfo->lastchar = 255; | |
| 966 pfontinfo->fixed = TRUE; | |
| 967 for(i=0; i<256; ++i) | |
| 968 pfontinfo->widths[i] = width; | |
| 969 return TRUE; | |
| 970 } | |
| 971 | |
| 972 /* Get the width and height of passed text string in the current font*/ | |
| 973 static void | |
| 974 t1lib_gettextsize(PMWFONT pfont, const void *text, int cc, | |
| 975 MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase) | |
| 976 { | |
| 977 PMWT1LIBFONT pf = (PMWT1LIBFONT)pfont; | |
| 978 const unsigned char * str = text; | |
| 979 GLYPH * g; | |
| 980 | |
| 981 g = T1_SetString(pf->fontid, (char *)str, cc, 0, | |
| 982 (pf->fontattr&MWTF_KERNING)? T1_KERNING: 0, pf->fontsize * 1.0, 0); | |
| 983 *pwidth = g->metrics.rightSideBearing - g->metrics.leftSideBearing; | |
| 984 *pheight = g->metrics.ascent - g->metrics.descent; | |
| 985 if(g && g->bits) { | |
| 986 free(g->bits); | |
| 987 g->bits = 0; | |
| 988 } | |
| 989 #if 0 | |
| 990 BBox b; | |
| 991 | |
| 992 /* FIXME. Something is *VERY* wrong here */ | |
| 993 b = T1_GetStringBBox(pf->fontid, str, cc, 0, (pf->fontattr&MWTF_KERNING)?T1_KERNING:0); | |
| 994 | |
| 995 DPRINTF("b.urx = %d, b.llx = %d\n",b.urx, b.llx); | |
| 996 DPRINTF("b.ury = %d, b.lly = %d\n",b.ury, b.lly); | |
| 997 *pwidth = (b.urx - b.llx); | |
| 998 *pheight = (b.lly - b.ury); | |
| 999 #endif | |
| 1000 } | |
| 1001 | |
| 1002 static void | |
| 1003 t1lib_destroyfont(PMWFONT pfont) | |
| 1004 { | |
| 1005 PMWT1LIBFONT pf = (PMWT1LIBFONT)pfont; | |
| 1006 | |
| 1007 T1_DeleteAllSizes(pf->fontid); | |
| 1008 free(pf); | |
| 1009 } | |
| 1010 | |
| 1011 #endif /* HAVE_T1LIB_SUPPORT*/ | |
| 1012 | |
| 1013 #if HAVE_FREETYPE_SUPPORT | |
| 1014 static OUTPIXELVAL gray_palette[5]; | |
| 1015 | |
| 1016 static int | |
| 1017 freetype_init(PSD psd) | |
| 1018 { | |
| 1019 static int inited = 0; | |
| 1020 | |
| 1021 if (inited) | |
| 1022 return 1; | |
| 1023 | |
| 1024 /* Init freetype library */ | |
| 1025 if (TT_Init_FreeType (&engine) != TT_Err_Ok) { | |
| 1026 return 0; | |
| 1027 } | |
| 1028 | |
| 1029 /* Init kerning extension */ | |
| 1030 if (TT_Init_Kerning_Extension (engine) != TT_Err_Ok) | |
| 1031 return 0; | |
| 1032 | |
| 1033 inited = 1; | |
| 1034 return 1; | |
| 1035 } | |
| 1036 | |
| 1037 static PMWFREETYPEFONT | |
| 1038 freetype_createfont(const char *name, MWCOORD height, int attr) | |
| 1039 { | |
| 1040 PMWFREETYPEFONT pf; | |
| 1041 unsigned short i, n; | |
| 1042 unsigned short platform, encoding; | |
| 1043 TT_Face_Properties properties; | |
| 1044 char * p; | |
| 1045 char fontname[128]; | |
| 1046 | |
| 1047 /* check for pathname prefix*/ | |
| 1048 if (strchr(name, '/') != NULL) | |
| 1049 strcpy(fontname, name); | |
| 1050 else { | |
| 1051 strcpy(fontname, FREETYPE_FONT_DIR); | |
| 1052 strcat(fontname, "/"); | |
| 1053 strcat(fontname, name); | |
| 1054 } | |
| 1055 | |
| 1056 /* check for extension*/ | |
| 1057 if ((p = strrchr(fontname, '.')) == NULL || | |
| 1058 strcmp(p, ".ttf") != 0) { | |
| 1059 strcat(fontname, ".ttf"); | |
| 1060 } | |
| 1061 | |
| 1062 /* allocate font structure*/ | |
| 1063 pf = (PMWFREETYPEFONT)calloc(sizeof(MWFREETYPEFONT), 1); | |
| 1064 if (!pf) | |
| 1065 return NULL; | |
| 1066 pf->fontprocs = &freetype_procs; | |
| 1067 | |
| 1068 /* Load face */ | |
| 1069 if (TT_Open_Face (engine, fontname, &pf->face) != TT_Err_Ok) | |
| 1070 goto out; | |
| 1071 | |
| 1072 /* Load first kerning table */ | |
| 1073 pf->can_kern = TRUE; | |
| 1074 if (TT_Load_Kerning_Table (pf->face, 0) != TT_Err_Ok) | |
| 1075 pf->can_kern = FALSE; | |
| 1076 else { | |
| 1077 if (TT_Get_Kerning_Directory (pf->face, &pf->directory) | |
| 1078 != TT_Err_Ok) | |
| 1079 pf->can_kern = FALSE; | |
| 1080 else { | |
| 1081 /* Support only version 0 kerning table ... */ | |
| 1082 if ((pf->directory.version != 0) || | |
| 1083 (pf->directory.nTables <= 0) || | |
| 1084 (pf->directory.tables->loaded != 1) || | |
| 1085 (pf->directory.tables->version != 0) || | |
| 1086 (pf->directory.tables->t.kern0.nPairs <= 0)) | |
| 1087 pf->can_kern = FALSE; | |
| 1088 } | |
| 1089 } | |
| 1090 | |
| 1091 /* get face properties and allocate preload arrays */ | |
| 1092 TT_Get_Face_Properties (pf->face, &properties); | |
| 1093 | |
| 1094 #if 0 | |
| 1095 /* | |
| 1096 * Use header information for ascent and descent | |
| 1097 * to compute scaled ascent/descent for current font height. | |
| 1098 */ | |
| 1099 h = properties.os2->sTypoAscender - properties.os2->sTypoDescender | |
| 1100 + properties.os2->sTypoLineGap; | |
| 1101 ascent = properties.os2->sTypoAscender | |
| 1102 + properties.os2->sTypoLineGap/2; | |
| 1103 pf->ascent = (ascent * height + h/2) / h; | |
| 1104 pf->descent = height - pf->ascent; | |
| 1105 #endif | |
| 1106 /* Create a glyph container */ | |
| 1107 if (TT_New_Glyph (pf->face, &pf->glyph) != TT_Err_Ok) | |
| 1108 goto out; | |
| 1109 | |
| 1110 /* create instance */ | |
| 1111 if (TT_New_Instance (pf->face, &pf->instance) != TT_Err_Ok) | |
| 1112 goto out; | |
| 1113 | |
| 1114 /* Set the instance resolution */ | |
| 1115 if (TT_Set_Instance_Resolutions (pf->instance, 96, 96) != TT_Err_Ok) | |
| 1116 goto out; | |
| 1117 | |
| 1118 /* Look for a Unicode charmap: Windows flavor of Apple flavor only */ | |
| 1119 n = properties.num_CharMaps; | |
| 1120 | |
| 1121 for (i = 0; i < n; i++) { | |
| 1122 TT_Get_CharMap_ID (pf->face, i, &platform, &encoding); | |
| 1123 if (((platform == TT_PLATFORM_MICROSOFT) && | |
| 1124 (encoding == TT_MS_ID_UNICODE_CS)) || | |
| 1125 ((platform == TT_PLATFORM_APPLE_UNICODE) && | |
| 1126 (encoding == TT_APPLE_ID_DEFAULT))) | |
| 1127 { | |
| 1128 TT_Get_CharMap (pf->face, i, &pf->char_map); | |
| 1129 i = n + 1; | |
| 1130 } | |
| 1131 } | |
| 1132 if (i == n) { | |
| 1133 DPRINTF("freetype_createfont: no unicode map table\n"); | |
| 1134 goto out; | |
| 1135 } | |
| 1136 | |
| 1137 GdSetFontSize((PMWFONT)pf, height); | |
| 1138 GdSetFontRotation((PMWFONT)pf, 0); | |
| 1139 GdSetFontAttr((PMWFONT)pf, attr, 0); | |
| 1140 | |
| 1141 return pf; | |
| 1142 | |
| 1143 out: | |
| 1144 free(pf); | |
| 1145 return NULL; | |
| 1146 } | |
| 1147 | |
| 1148 static int | |
| 1149 compute_kernval(PMWFREETYPEFONT pf, short current_glyph_code) | |
| 1150 { | |
| 1151 int i = 0; | |
| 1152 int kernval; | |
| 1153 int nPairs = pf->directory.tables->t.kern0.nPairs; | |
| 1154 TT_Kern_0_Pair *pair = pf->directory.tables->t.kern0.pairs; | |
| 1155 | |
| 1156 if (pf->last_glyph_code != -1) { | |
| 1157 while ((pair->left != pf->last_glyph_code) | |
| 1158 && (pair->right != current_glyph_code)) | |
| 1159 { | |
| 1160 pair++; | |
| 1161 i++; | |
| 1162 if (i == nPairs) | |
| 1163 break; | |
| 1164 } | |
| 1165 | |
| 1166 if (i == nPairs) | |
| 1167 kernval = 0; | |
| 1168 else | |
| 1169 /* We round the value (hence the +32) */ | |
| 1170 kernval = (pair->value + 32) & -64; | |
| 1171 } else | |
| 1172 kernval = 0; | |
| 1173 | |
| 1174 return kernval; | |
| 1175 } | |
| 1176 | |
| 1177 static TT_UShort | |
| 1178 Get_Glyph_Width(PMWFREETYPEFONT pf, TT_UShort glyph_index) | |
| 1179 { | |
| 1180 TT_Glyph_Metrics metrics; | |
| 1181 | |
| 1182 if (TT_Load_Glyph ( pf->instance, pf->glyph, | |
| 1183 TT_Char_Index (pf->char_map,glyph_index), | |
| 1184 TTLOAD_SCALE_GLYPH|TTLOAD_HINT_GLYPH) != TT_Err_Ok) | |
| 1185 { | |
| 1186 /* Try to load default glyph: index 0 */ | |
| 1187 if (TT_Load_Glyph ( pf->instance, pf->glyph, 0, | |
| 1188 TTLOAD_SCALE_GLYPH|TTLOAD_HINT_GLYPH) != TT_Err_Ok) | |
| 1189 return 0; | |
| 1190 } | |
| 1191 | |
| 1192 TT_Get_Glyph_Metrics (pf->glyph, &metrics); | |
| 1193 return((metrics.advance & 0xFFFFFFC0) >> 6); | |
| 1194 } | |
| 1195 | |
| 1196 /* Render a single glyph*/ | |
| 1197 static void | |
| 1198 drawchar(PMWFREETYPEFONT pf, PSD psd, TT_Glyph glyph, int x_offset, | |
| 1199 int y_offset) | |
| 1200 { | |
| 1201 TT_F26Dot6 xmin, ymin, xmax, ymax, x, y, z; | |
| 1202 unsigned char *src, *srcptr; | |
| 1203 MWPIXELVAL *dst, *dstptr; | |
| 1204 MWPIXELVAL *bitmap; | |
| 1205 int size, width, height; | |
| 1206 TT_Outline outline; | |
| 1207 TT_BBox bbox; | |
| 1208 TT_Raster_Map Raster; | |
| 1209 TT_Error error; | |
| 1210 /*MWPIXELVAL save;*/ | |
| 1211 | |
| 1212 /* we begin by grid-fitting the bounding box */ | |
| 1213 TT_Get_Glyph_Outline (pf->glyph, &outline); | |
| 1214 TT_Get_Outline_BBox (&outline, &bbox); | |
| 1215 | |
| 1216 xmin = (bbox.xMin & -64) >> 6; | |
| 1217 ymin = (bbox.yMin & -64) >> 6; | |
| 1218 xmax = ((bbox.xMax + 63) & -64) >> 6; | |
| 1219 ymax = ((bbox.yMax + 63) & -64) >> 6; | |
| 1220 width = xmax - xmin; | |
| 1221 height = ymax - ymin; | |
| 1222 size = width * height; | |
| 1223 | |
| 1224 /* now re-allocate the raster bitmap */ | |
| 1225 Raster.rows = height; | |
| 1226 Raster.width = width; | |
| 1227 | |
| 1228 if (pf->fontattr&MWTF_ANTIALIAS) | |
| 1229 Raster.cols = (Raster.width + 3) & -4; /* pad to 32-bits */ | |
| 1230 else | |
| 1231 Raster.cols = (Raster.width + 7) & -8; /* pad to 64-bits ??? */ | |
| 1232 | |
| 1233 Raster.flow = TT_Flow_Up; | |
| 1234 Raster.size = Raster.rows * Raster.cols; | |
| 1235 Raster.bitmap = malloc (Raster.size); | |
| 1236 | |
| 1237 memset (Raster.bitmap, 0, Raster.size); | |
| 1238 | |
| 1239 /* now render the glyph in the small pixmap */ | |
| 1240 | |
| 1241 /* IMPORTANT NOTE: the offset parameters passed to the function */ | |
| 1242 /* TT_Get_Glyph_Bitmap() must be integer pixel values, i.e., */ | |
| 1243 /* multiples of 64. HINTING WILL BE RUINED IF THIS ISN'T THE CASE! */ | |
| 1244 /* This is why we _did_ grid-fit the bounding box, especially xmin */ | |
| 1245 /* and ymin. */ | |
| 1246 | |
| 1247 if (!(pf->fontattr&MWTF_ANTIALIAS)) | |
| 1248 error = TT_Get_Glyph_Bitmap (pf->glyph, &Raster, | |
| 1249 -xmin * 64, -ymin * 64); | |
| 1250 else | |
| 1251 error = TT_Get_Glyph_Pixmap (pf->glyph, &Raster, | |
| 1252 -xmin * 64, -ymin * 64); | |
| 1253 | |
| 1254 if (error) { | |
| 1255 free (Raster.bitmap); | |
| 1256 return; | |
| 1257 } | |
| 1258 | |
| 1259 bitmap = malloc (size * sizeof (MWPIXELVAL)); | |
| 1260 memset (bitmap, 0, size * sizeof (MWPIXELVAL)); | |
| 1261 | |
| 1262 src = (char *) Raster.bitmap; | |
| 1263 dst = bitmap + (size - width); | |
| 1264 | |
| 1265 for (y = ymin; y < ymax; y++) { | |
| 1266 srcptr = src; | |
| 1267 dstptr = dst; | |
| 1268 | |
| 1269 for (x = xmin; x < xmax; x++) { | |
| 1270 if (pf->fontattr&MWTF_ANTIALIAS) | |
| 1271 *dstptr++ = gray_palette[(int) *srcptr]; | |
| 1272 else { | |
| 1273 for(z=0; | |
| 1274 z <= ((xmax-x-1) < 7 ? (xmax-x-1) : 7); | |
| 1275 z++) { | |
| 1276 *dstptr++ = ((*srcptr << z) & 0x80)? | |
| 1277 gr_foreground: gr_background; | |
| 1278 } | |
| 1279 x += 7; | |
| 1280 } | |
| 1281 | |
| 1282 srcptr++; | |
| 1283 } | |
| 1284 | |
| 1285 src += Raster.cols; | |
| 1286 dst -= width; | |
| 1287 } | |
| 1288 | |
| 1289 /* FIXME - must clear background upstairs if not gr_usebg*/ | |
| 1290 /* FIXME: GdArea problem if fg == bg*/ | |
| 1291 /*save = gr_background;*/ | |
| 1292 /*gr_background = gr_foreground + 1;*/ | |
| 1293 | |
| 1294 /* Now draw the bitmap ... */ | |
| 1295 GdArea(psd, x_offset + xmin, y_offset - (ymin + height), width, height, | |
| 1296 bitmap, MWPF_PIXELVAL); | |
| 1297 | |
| 1298 /*gr_background = save;*/ | |
| 1299 | |
| 1300 free (bitmap); | |
| 1301 free (Raster.bitmap); | |
| 1302 } | |
| 1303 | |
| 1304 /* | |
| 1305 * Draw unicode 16 text string using FREETYPE type font | |
| 1306 */ | |
| 1307 static void | |
| 1308 freetype_drawtext(PMWFONT pfont, PSD psd, MWCOORD ax, MWCOORD ay, | |
| 1309 const void *text, int cc, int flags) | |
| 1310 { | |
| 1311 PMWFREETYPEFONT pf = (PMWFREETYPEFONT)pfont; | |
| 1312 const unsigned short * str = text; | |
| 1313 TT_F26Dot6 x = ax, y = ay; | |
| 1314 TT_Pos vec_x, vec_y; | |
| 1315 int i; | |
| 1316 TT_F26Dot6 startx, starty; | |
| 1317 TT_Outline outline; | |
| 1318 TT_UShort curchar; | |
| 1319 TT_Glyph_Metrics metrics; | |
| 1320 TT_Face_Properties properties; | |
| 1321 TT_Instance_Metrics imetrics; | |
| 1322 TT_F26Dot6 ascent, descent; | |
| 1323 static unsigned char blend[5] = { 0x00, 0x44, 0x88, 0xcc, 0xff }; | |
| 1324 static unsigned char virtual_palette[5] = { 0, 1, 2, 3, 4 }; | |
| 1325 | |
| 1326 pf->last_glyph_code = -1; /* reset kerning*/ | |
| 1327 pf->last_pen_pos = -32767; | |
| 1328 | |
| 1329 /* | |
| 1330 * Compute instance ascent & descent values | |
| 1331 * in fractional units (1/64th pixel) | |
| 1332 */ | |
| 1333 TT_Get_Face_Properties (pf->face, &properties); | |
| 1334 TT_Get_Instance_Metrics(pf->instance, &imetrics); | |
| 1335 | |
| 1336 ascent = ((properties.horizontal->Ascender * imetrics.y_scale)/0x10000); | |
| 1337 descent = ((properties.horizontal->Descender*imetrics.y_scale)/0x10000); | |
| 1338 | |
| 1339 /* | |
| 1340 * Offset the starting point if necessary, | |
| 1341 * FreeType always aligns at baseline | |
| 1342 */ | |
| 1343 if (flags&MWTF_BOTTOM) { | |
| 1344 vec_x = 0; | |
| 1345 vec_y = descent; | |
| 1346 TT_Transform_Vector(&vec_x, &vec_y,&pf->matrix); | |
| 1347 x -= vec_x / 64; | |
| 1348 y += vec_y / 64; | |
| 1349 } else if (flags&MWTF_TOP) { | |
| 1350 vec_x = 0; | |
| 1351 vec_y = ascent; | |
| 1352 TT_Transform_Vector(&vec_x, &vec_y,&pf->matrix); | |
| 1353 x -= vec_x / 64; | |
| 1354 y += vec_y / 64; | |
| 1355 } | |
| 1356 | |
| 1357 /* Set the "graylevels" */ | |
| 1358 if (pf->fontattr&MWTF_ANTIALIAS) { | |
| 1359 TT_Set_Raster_Gray_Palette (engine, virtual_palette); | |
| 1360 | |
| 1361 alphablend(psd, gray_palette, gr_foreground, gr_background, | |
| 1362 blend, 5); | |
| 1363 } | |
| 1364 | |
| 1365 startx = x; | |
| 1366 starty = y; | |
| 1367 for (i = 0; i < cc; i++) { | |
| 1368 curchar = TT_Char_Index (pf->char_map, str[i]); | |
| 1369 | |
| 1370 if (TT_Load_Glyph (pf->instance, pf->glyph, curchar, | |
| 1371 TTLOAD_DEFAULT) != TT_Err_Ok) | |
| 1372 continue; | |
| 1373 | |
| 1374 if (pf->fontrotation) { | |
| 1375 TT_Get_Glyph_Outline (pf->glyph, &outline); | |
| 1376 TT_Transform_Outline (&outline, &pf->matrix); | |
| 1377 } | |
| 1378 | |
| 1379 TT_Get_Glyph_Metrics (pf->glyph, &metrics); | |
| 1380 | |
| 1381 if ((pf->fontattr&MWTF_KERNING) && pf->can_kern) { | |
| 1382 if (pf->fontrotation) { | |
| 1383 vec_x = compute_kernval(pf, curchar); | |
| 1384 vec_y = 0; | |
| 1385 TT_Transform_Vector(&vec_x, &vec_y,&pf->matrix); | |
| 1386 | |
| 1387 x += vec_x / 64; | |
| 1388 y -= vec_y / 64; | |
| 1389 } else | |
| 1390 x += compute_kernval(pf, curchar) / 64; | |
| 1391 } | |
| 1392 | |
| 1393 drawchar(pf, psd, pf->glyph, x, y); | |
| 1394 | |
| 1395 if (pf->fontrotation) { | |
| 1396 vec_x = metrics.advance; | |
| 1397 vec_y = 0; | |
| 1398 TT_Transform_Vector (&vec_x, &vec_y, &pf->matrix); | |
| 1399 | |
| 1400 x += vec_x / 64; | |
| 1401 y -= vec_y / 64; | |
| 1402 } else { | |
| 1403 x += metrics.advance / 64; | |
| 1404 | |
| 1405 /* Kerning point syndrome avoidance */ | |
| 1406 if (pf->last_pen_pos > x) | |
| 1407 x = pf->last_pen_pos; | |
| 1408 pf->last_pen_pos = x; | |
| 1409 } | |
| 1410 | |
| 1411 pf->last_glyph_code = curchar; | |
| 1412 } | |
| 1413 | |
| 1414 if (pf->fontattr & MWTF_UNDERLINE) | |
| 1415 GdLine(psd, startx, starty, x, y, FALSE); | |
| 1416 } | |
| 1417 | |
| 1418 /* | |
| 1419 * Return information about a specified font. | |
| 1420 */ | |
| 1421 static MWBOOL | |
| 1422 freetype_getfontinfo(PMWFONT pfont, PMWFONTINFO pfontinfo) | |
| 1423 { | |
| 1424 int i; | |
| 1425 PMWFREETYPEFONT pf = (PMWFREETYPEFONT)pfont; | |
| 1426 TT_Face_Properties properties; | |
| 1427 TT_Instance_Metrics imetrics; | |
| 1428 TT_UShort last_glyph_index; | |
| 1429 | |
| 1430 TT_Get_Face_Properties (pf->face, &properties); | |
| 1431 TT_Get_Instance_Metrics(pf->instance, &imetrics); | |
| 1432 | |
| 1433 /* Fill up the fields */ | |
| 1434 pfontinfo->height = (((properties.horizontal->Ascender * \ | |
| 1435 imetrics.y_scale)/ 0x10000) >> 6) - | |
| 1436 (((properties.horizontal->Descender * \ | |
| 1437 imetrics.y_scale)/ 0x10000) >> 6); | |
| 1438 pfontinfo->maxwidth = ((properties.horizontal->xMax_Extent * \ | |
| 1439 imetrics.x_scale)/ 0x10000) >> 6; | |
| 1440 pfontinfo->baseline = ((properties.horizontal->Ascender * \ | |
| 1441 imetrics.y_scale)/ 0x10000) >> 6; | |
| 1442 pfontinfo->firstchar = TT_CharMap_First(pf->char_map, NULL); | |
| 1443 pfontinfo->lastchar = TT_CharMap_Last(pf->char_map, NULL); | |
| 1444 pfontinfo->fixed = properties.postscript->isFixedPitch; | |
| 1445 | |
| 1446 last_glyph_index = properties.num_Glyphs > 255 ? 255: properties.num_Glyphs-1; | |
| 1447 | |
| 1448 /* Doesn't work ... don't know why ....*/ | |
| 1449 #if 0 | |
| 1450 if (TT_Get_Face_Widths( pf->face, 0, | |
| 1451 last_glyph_index, widths, NULL ) != TT_Err_Ok) { | |
| 1452 return TRUE; | |
| 1453 } | |
| 1454 | |
| 1455 for(i=0; i<=last_glyph_index; i++) | |
| 1456 DPRINTF("widths[%d]: %d\n", i, widths[i]); | |
| 1457 #endif | |
| 1458 | |
| 1459 /* Get glyphs widths */ | |
| 1460 for(i=0; i<=last_glyph_index; i++) | |
| 1461 pfontinfo->widths[i] = Get_Glyph_Width(pf, i); | |
| 1462 | |
| 1463 #if 0 | |
| 1464 DPRINTF("x_ppem: %d\ny_ppem: %d\nx_scale: %d\ny_scale: %d\n\ | |
| 1465 x_resolution: %d\ny_resolution: %d\n", | |
| 1466 imetrics.x_ppem, imetrics.y_ppem, imetrics.x_scale, \ | |
| 1467 imetrics.y_scale, imetrics.x_resolution, imetrics.y_resolution); | |
| 1468 | |
| 1469 DPRINTF("Ascender: %d\nDescender: %d\nxMax_Extent: %d\n\ | |
| 1470 Mac Style Say Italic?: %d\nMac Style Say Bold?: %d\n\ | |
| 1471 sTypoAscender: %d\nsTypoDescender: %d\nusWinAscent: %d\n\ | |
| 1472 usWinDescent: %d\nusFirstCharIndex: %d\nusLastCharIndex: %d\n\ | |
| 1473 OS2 Say Italic?: %d\nOS2 Say Bold?: %d\nOS2 Say monospaced?: %d\n\ | |
| 1474 Postscript Say monospaced?: %d\n",\ | |
| 1475 properties.horizontal->Ascender, | |
| 1476 properties.horizontal->Descender, | |
| 1477 properties.horizontal->xMax_Extent, | |
| 1478 (properties.header->Mac_Style & 0x2)?1:0, | |
| 1479 (properties.header->Mac_Style & 0x1)?1:0, | |
| 1480 properties.os2->sTypoAscender, | |
| 1481 properties.os2->sTypoDescender, | |
| 1482 properties.os2->usWinAscent, | |
| 1483 properties.os2->usWinDescent, | |
| 1484 properties.os2->usFirstCharIndex, | |
| 1485 properties.os2->usLastCharIndex, | |
| 1486 (properties.os2->fsSelection & 0x1)?1:0, | |
| 1487 (properties.os2->fsSelection & 0x20)?1:0, | |
| 1488 properties.postscript->isFixedPitch, | |
| 1489 (properties.os2->panose[3] == 9)?1:0); | |
| 1490 #endif | |
| 1491 | |
| 1492 return TRUE; | |
| 1493 } | |
| 1494 | |
| 1495 static void | |
| 1496 freetype_gettextsize(PMWFONT pfont, const void *text, int cc, | |
| 1497 MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase) | |
| 1498 { | |
| 1499 PMWFREETYPEFONT pf = (PMWFREETYPEFONT)pfont; | |
| 1500 const unsigned short * str = text; | |
| 1501 TT_F26Dot6 x = 0; | |
| 1502 int i; | |
| 1503 TT_UShort curchar; | |
| 1504 TT_Glyph_Metrics metrics; | |
| 1505 TT_Face_Properties properties; | |
| 1506 TT_Instance_Metrics imetrics; | |
| 1507 | |
| 1508 TT_Get_Face_Properties (pf->face, &properties); | |
| 1509 TT_Get_Instance_Metrics(pf->instance, &imetrics); | |
| 1510 | |
| 1511 pf->last_glyph_code = -1; /* reset kerning*/ | |
| 1512 pf->last_pen_pos = -32767; | |
| 1513 | |
| 1514 for (i = 0; i < cc; i++) { | |
| 1515 curchar = TT_Char_Index (pf->char_map, str[i]); | |
| 1516 | |
| 1517 if (TT_Load_Glyph (pf->instance, pf->glyph, curchar, | |
| 1518 TTLOAD_SCALE_GLYPH|TTLOAD_HINT_GLYPH) != TT_Err_Ok) | |
| 1519 continue; | |
| 1520 | |
| 1521 TT_Get_Glyph_Metrics (pf->glyph, &metrics); | |
| 1522 | |
| 1523 if ((pf->fontattr&MWTF_KERNING) && pf->can_kern) { | |
| 1524 x += compute_kernval(pf, curchar) / 64; | |
| 1525 } | |
| 1526 | |
| 1527 x += metrics.advance / 64; | |
| 1528 | |
| 1529 /* Kerning point syndrome avoidance */ | |
| 1530 if (pf->last_pen_pos > x) | |
| 1531 x = pf->last_pen_pos; | |
| 1532 pf->last_pen_pos = x; | |
| 1533 | |
| 1534 pf->last_glyph_code = curchar; | |
| 1535 } | |
| 1536 | |
| 1537 *pwidth = x; | |
| 1538 *pheight = (((properties.horizontal->Ascender * | |
| 1539 imetrics.y_scale)/ 0x10000) >> 6) - | |
| 1540 (((properties.horizontal->Descender * | |
| 1541 imetrics.y_scale)/ 0x10000) >> 6); | |
| 1542 /* FIXME: is it what's required ?? */ | |
| 1543 *pbase = (((-properties.horizontal->Descender) * | |
| 1544 imetrics.y_scale)/ 0x10000) >> 6; | |
| 1545 } | |
| 1546 | |
| 1547 static void | |
| 1548 freetype_destroyfont(PMWFONT pfont) | |
| 1549 { | |
| 1550 PMWFREETYPEFONT pf = (PMWFREETYPEFONT)pfont; | |
| 1551 | |
| 1552 TT_Close_Face(pf->face); | |
| 1553 free(pf); | |
| 1554 } | |
| 1555 | |
| 1556 static void | |
| 1557 freetype_setfontsize(PMWFONT pfont, MWCOORD fontsize) | |
| 1558 { | |
| 1559 PMWFREETYPEFONT pf = (PMWFREETYPEFONT)pfont; | |
| 1560 | |
| 1561 pf->fontsize = fontsize; | |
| 1562 | |
| 1563 /* We want real pixel sizes ... not points ...*/ | |
| 1564 TT_Set_Instance_PixelSizes( pf->instance, pf->fontsize, | |
| 1565 pf->fontsize, pf->fontsize * 64 ); | |
| 1566 #if 0 | |
| 1567 /* set charsize (convert to points for freetype)*/ | |
| 1568 TT_Set_Instance_CharSize (pf->instance, | |
| 1569 ((pf->fontsize * 72 + 96/2) / 96) * 64); | |
| 1570 #endif | |
| 1571 } | |
| 1572 | |
| 1573 static void | |
| 1574 freetype_setfontrotation(PMWFONT pfont, int tenthdegrees) | |
| 1575 { | |
| 1576 PMWFREETYPEFONT pf = (PMWFREETYPEFONT)pfont; | |
| 1577 float angle; | |
| 1578 | |
| 1579 pf->fontrotation = tenthdegrees; | |
| 1580 | |
| 1581 /* Build the rotation matrix with the given angle */ | |
| 1582 TT_Set_Instance_Transform_Flags (pf->instance, TRUE, FALSE); | |
| 1583 | |
| 1584 angle = pf->fontrotation * M_PI / 1800; | |
| 1585 pf->matrix.yy = (TT_Fixed) (cos (angle) * (1 << 16)); | |
| 1586 pf->matrix.yx = (TT_Fixed) (sin (angle) * (1 << 16)); | |
| 1587 pf->matrix.xx = pf->matrix.yy; | |
| 1588 pf->matrix.xy = -pf->matrix.yx; | |
| 1589 } | |
| 1590 | |
| 1591 #endif /* HAVE_FREETYPE_SUPPORT*/ | |
| 1592 | |
| 1593 /* UTF-8 to UTF-16 conversion. Surrogates are handeled properly, e.g. | |
| 1594 * a single 4-byte UTF-8 character is encoded into a surrogate pair. | |
| 1595 * On the other hand, if the UTF-8 string contains surrogate values, this | |
| 1596 * is considered an error and returned as such. | |
| 1597 * | |
| 1598 * The destination array must be able to hold as many Unicode-16 characters | |
| 1599 * as there are ASCII characters in the UTF-8 string. This in case all UTF-8 | |
| 1600 * characters are ASCII characters. No more will be needed. | |
| 1601 * | |
| 1602 * Copyright (c) 2000 Morten Rolland, Screen Media | |
| 1603 */ | |
| 1604 static int | |
| 1605 utf8_to_utf16(const unsigned char *utf8, int cc, unsigned short *unicode16) | |
| 1606 { | |
| 1607 int count = 0; | |
| 1608 unsigned char c0, c1; | |
| 1609 unsigned long scalar; | |
| 1610 | |
| 1611 while(--cc >= 0) { | |
| 1612 c0 = *utf8++; | |
| 1613 /*DPRINTF("Trying: %02x\n",c0);*/ | |
| 1614 | |
| 1615 if ( c0 < 0x80 ) { | |
| 1616 /* Plain ASCII character, simple translation :-) */ | |
| 1617 *unicode16++ = c0; | |
| 1618 count++; | |
| 1619 continue; | |
| 1620 } | |
| 1621 | |
| 1622 if ( (c0 & 0xc0) == 0x80 ) | |
| 1623 /* Illegal; starts with 10xxxxxx */ | |
| 1624 return -1; | |
| 1625 | |
| 1626 /* c0 must be 11xxxxxx if we get here => at least 2 bytes */ | |
| 1627 scalar = c0; | |
| 1628 if(--cc < 0) | |
| 1629 return -1; | |
| 1630 c1 = *utf8++; | |
| 1631 /*DPRINTF("c1=%02x\n",c1);*/ | |
| 1632 if ( (c1 & 0xc0) != 0x80 ) | |
| 1633 /* Bad byte */ | |
| 1634 return -1; | |
| 1635 scalar <<= 6; | |
| 1636 scalar |= (c1 & 0x3f); | |
| 1637 | |
| 1638 if ( !(c0 & 0x20) ) { | |
| 1639 /* Two bytes UTF-8 */ | |
| 1640 if ( scalar < 0x80 ) | |
| 1641 return -1; /* Overlong encoding */ | |
| 1642 *unicode16++ = scalar & 0x7ff; | |
| 1643 count++; | |
| 1644 continue; | |
| 1645 } | |
| 1646 | |
| 1647 /* c0 must be 111xxxxx if we get here => at least 3 bytes */ | |
| 1648 if(--cc < 0) | |
| 1649 return -1; | |
| 1650 c1 = *utf8++; | |
| 1651 /*DPRINTF("c1=%02x\n",c1);*/ | |
| 1652 if ( (c1 & 0xc0) != 0x80 ) | |
| 1653 /* Bad byte */ | |
| 1654 return -1; | |
| 1655 scalar <<= 6; | |
| 1656 scalar |= (c1 & 0x3f); | |
| 1657 | |
| 1658 if ( !(c0 & 0x10) ) { | |
| 1659 /*DPRINTF("####\n");*/ | |
| 1660 /* Three bytes UTF-8 */ | |
| 1661 if ( scalar < 0x800 ) | |
| 1662 return -1; /* Overlong encoding */ | |
| 1663 if ( scalar >= 0xd800 && scalar < 0xe000 ) | |
| 1664 return -1; /* UTF-16 high/low halfs */ | |
| 1665 *unicode16++ = scalar & 0xffff; | |
| 1666 count++; | |
| 1667 continue; | |
| 1668 } | |
| 1669 | |
| 1670 /* c0 must be 1111xxxx if we get here => at least 4 bytes */ | |
| 1671 c1 = *utf8++; | |
| 1672 if(--cc < 0) | |
| 1673 return -1; | |
| 1674 /*DPRINTF("c1=%02x\n",c1);*/ | |
| 1675 if ( (c1 & 0xc0) != 0x80 ) | |
| 1676 /* Bad byte */ | |
| 1677 return -1; | |
| 1678 scalar <<= 6; | |
| 1679 scalar |= (c1 & 0x3f); | |
| 1680 | |
| 1681 if ( !(c0 & 0x08) ) { | |
| 1682 /* Four bytes UTF-8, needs encoding as surrogates */ | |
| 1683 if ( scalar < 0x10000 ) | |
| 1684 return -1; /* Overlong encoding */ | |
| 1685 scalar -= 0x10000; | |
| 1686 *unicode16++ = ((scalar >> 10) & 0x3ff) + 0xd800; | |
| 1687 *unicode16++ = (scalar & 0x3ff) + 0xdc00; | |
| 1688 count += 2; | |
| 1689 continue; | |
| 1690 } | |
| 1691 | |
| 1692 return -1; /* No support for more than four byte UTF-8 */ | |
| 1693 } | |
| 1694 return count; | |
| 1695 } | |
| 1696 | |
| 1697 #if HAVE_HZK_SUPPORT | |
| 1698 | |
| 1699 /* UniCode-16 (MWTF_UC16) to GB(MWTF_ASCII) Chinese Characters conversion. | |
| 1700 * a single 2-byte UC16 character is encoded into a surrogate pair. | |
| 1701 * return -1 ,if error; | |
| 1702 * The destination array must be able to hold as many | |
| 1703 * as there are Unicode-16 characters. | |
| 1704 * | |
| 1705 * Copyright (c) 2000 Tang Hao (TownHall)(tang_hao@263.net). | |
| 1706 */ | |
| 1707 static int | |
| 1708 UC16_to_GB(const unsigned char *uc16, int cc, unsigned char *ascii) | |
| 1709 { | |
| 1710 FILE* fp; | |
| 1711 char buffer[256]; | |
| 1712 unsigned char *uc16p; | |
| 1713 int i=0,j=0, k; | |
| 1714 unsigned char *filebuffer; | |
| 1715 unsigned short *uc16pp,*table; | |
| 1716 unsigned short uc16px; | |
| 1717 int length=31504; | |
| 1718 | |
| 1719 if (use_big5) | |
| 1720 length=54840; | |
| 1721 | |
| 1722 uc16p=(unsigned char *) uc16; | |
| 1723 uc16pp=(unsigned short *) uc16; | |
| 1724 | |
| 1725 strcpy(buffer,HZK_FONT_DIR); | |
| 1726 if (use_big5) | |
| 1727 strcat(buffer,"/BG2UBG.KU"); | |
| 1728 else | |
| 1729 strcat(buffer,"/UGB2GB.KU"); | |
| 1730 if(!(fp = fopen(buffer, "rb"))) | |
| 1731 { | |
| 1732 fprintf (stderr, "Error.\nThe %s file can not be found!\n",buffer); | |
| 1733 return -1; | |
| 1734 } | |
| 1735 | |
| 1736 filebuffer= (unsigned char *)malloc ( length); | |
| 1737 | |
| 1738 if(fread(filebuffer, sizeof(char),length, fp) < length) { | |
| 1739 fprintf (stderr, "Error in reading ugb2gb.ku file!\n"); | |
| 1740 fclose(fp); | |
| 1741 return -1; | |
| 1742 } | |
| 1743 fclose(fp); | |
| 1744 | |
| 1745 if (use_big5) | |
| 1746 { | |
| 1747 table=(unsigned short *)filebuffer; | |
| 1748 while(1) | |
| 1749 { | |
| 1750 if(j>=cc) | |
| 1751 { | |
| 1752 ascii[i]=0; | |
| 1753 break; | |
| 1754 } | |
| 1755 uc16px=*uc16pp; | |
| 1756 if((uc16px)<=0x00ff) | |
| 1757 { | |
| 1758 ascii[i]=(char)(*uc16pp); | |
| 1759 i++; | |
| 1760 } | |
| 1761 else | |
| 1762 { | |
| 1763 ascii[i]=0xa1; ascii[i+1]=0x40; | |
| 1764 for (k=0; k<13710; k++) | |
| 1765 { | |
| 1766 if (*(table+(k*2+1))==(uc16px)) | |
| 1767 { | |
| 1768 ascii[i]=(char)((*(table+(k*2)) & 0xff00) >> 8); | |
| 1769 ascii[i+1]=(char)(*(table+(k*2)) & 0x00ff); | |
| 1770 break; | |
| 1771 } | |
| 1772 } | |
| 1773 i+=2; | |
| 1774 } | |
| 1775 uc16pp++; j++; | |
| 1776 } | |
| 1777 } | |
| 1778 else | |
| 1779 { | |
| 1780 while(1) | |
| 1781 { | |
| 1782 if(j>=cc) | |
| 1783 { | |
| 1784 ascii[i]=0; | |
| 1785 break; | |
| 1786 } | |
| 1787 if((*((uc16p)+j)==0)&&(*((uc16p)+j+1)==0)) | |
| 1788 { | |
| 1789 ascii[i]=0; | |
| 1790 break; | |
| 1791 } | |
| 1792 else | |
| 1793 { | |
| 1794 if(*((uc16p)+j+1)==0) | |
| 1795 { | |
| 1796 ascii[i]=*((uc16p)+j); | |
| 1797 i++; | |
| 1798 j+=2; | |
| 1799 } | |
| 1800 else | |
| 1801 { | |
| 1802 /* to find the place of unicode charater .¶þ·Ö·¨Æ¥Åä*/ | |
| 1803 { | |
| 1804 int p1=0,p2=length-4,p; | |
| 1805 unsigned int c1,c2,c,d; | |
| 1806 c1=((unsigned int )filebuffer[p1])*0x100+(filebuffer[p1+1]); | |
| 1807 c2=((unsigned int )filebuffer[p2])*0x100+(filebuffer[p2+1]); | |
| 1808 d=((unsigned int )*((uc16p)+j))*0x100+*((uc16p)+j+1); | |
| 1809 if(c1==d) | |
| 1810 { | |
| 1811 ascii[i]=filebuffer[p1+2]; | |
| 1812 ascii[i+1]=filebuffer[p1+3]; | |
| 1813 goto findit; | |
| 1814 } | |
| 1815 if(c2==d) | |
| 1816 { | |
| 1817 ascii[i]=filebuffer[p2+2]; | |
| 1818 ascii[i+1]=filebuffer[p2+3]; | |
| 1819 goto findit; | |
| 1820 } | |
| 1821 while(1) | |
| 1822 { | |
| 1823 p=(((p2-p1)/2+p1)>>2)<<2; | |
| 1824 c=((unsigned int )filebuffer[p])*0x100+(filebuffer[p+1]); | |
| 1825 if(d==c) /* find it*/ | |
| 1826 { | |
| 1827 ascii[i]=filebuffer[p+2]; | |
| 1828 ascii[i+1]=filebuffer[p+3]; | |
| 1829 break; | |
| 1830 } | |
| 1831 else if(p2<=p1+4) /* can't find.*/ | |
| 1832 { | |
| 1833 ascii[i]='.'; /* ((uc16p)+j);*/ | |
| 1834 ascii[i+1]='.'; /* ((uc16p)+j+1);*/ | |
| 1835 break; | |
| 1836 } | |
| 1837 else if(d<c) | |
| 1838 { | |
| 1839 p2=p; | |
| 1840 c2=c; | |
| 1841 } | |
| 1842 else | |
| 1843 { | |
| 1844 p1=p; | |
| 1845 c1=c; | |
| 1846 } | |
| 1847 } | |
| 1848 } | |
| 1849 findit: | |
| 1850 i+=2; | |
| 1851 j+=2; | |
| 1852 } | |
| 1853 } | |
| 1854 } | |
| 1855 } | |
| 1856 free(filebuffer); | |
| 1857 | |
| 1858 return i; | |
| 1859 } | |
| 1860 | |
| 1861 /************************** functions definition ******************************/ | |
| 1862 | |
| 1863 static int hzk_id( PMWHZKFONT pf ) | |
| 1864 { | |
| 1865 switch(pf->font_height) | |
| 1866 { | |
| 1867 case 12: | |
| 1868 return 0; | |
| 1869 case 16: default: | |
| 1870 return 1; | |
| 1871 } | |
| 1872 } | |
| 1873 | |
| 1874 /* This function get Chinese font info from etc file.*/ | |
| 1875 static MWBOOL GetCFontInfo( PMWHZKFONT pf ) | |
| 1876 { | |
| 1877 int charset; | |
| 1878 | |
| 1879 if (use_big5) | |
| 1880 charset=(13094+408); | |
| 1881 else | |
| 1882 charset=8178; | |
| 1883 | |
| 1884 CFont[hzk_id(pf)].width = pf->cfont_width; | |
| 1885 pf->CFont.width = pf->cfont_width; | |
| 1886 | |
| 1887 CFont[hzk_id(pf)].height = pf->font_height; | |
| 1888 pf->CFont.height = pf->font_height; | |
| 1889 | |
| 1890 CFont[hzk_id(pf)].size = ((pf->CFont.width + 7) / 8) * | |
| 1891 pf->CFont.height * charset; | |
| 1892 pf->CFont.size = ((pf->CFont.width + 7) / 8) * pf->CFont.height * charset; | |
| 1893 | |
| 1894 if(pf->CFont.size < charset * 8) | |
| 1895 return FALSE; | |
| 1896 | |
| 1897 strcpy(CFont[hzk_id(pf)].file,HZK_FONT_DIR); | |
| 1898 strcpy(pf->CFont.file,HZK_FONT_DIR); | |
| 1899 | |
| 1900 if(pf->font_height==16) | |
| 1901 { | |
| 1902 strcat(CFont[hzk_id(pf)].file,"/hzk16"); | |
| 1903 strcat(pf->CFont.file,"/hzk16"); | |
| 1904 } | |
| 1905 else | |
| 1906 { | |
| 1907 strcat(CFont[hzk_id(pf)].file,"/hzk12"); | |
| 1908 strcat(pf->CFont.file,"/hzk12"); | |
| 1909 } | |
| 1910 | |
| 1911 if (use_big5) | |
| 1912 { | |
| 1913 CFont[hzk_id(pf)].file[strlen(pf->CFont.file)-3]+=use_big5; | |
| 1914 pf->CFont.file[strlen(pf->CFont.file)-3]+=use_big5; | |
| 1915 } | |
| 1916 | |
| 1917 return TRUE; | |
| 1918 } | |
| 1919 | |
| 1920 /* This function get ASCII font info from etc file.*/ | |
| 1921 static MWBOOL GetAFontInfo( PMWHZKFONT pf ) | |
| 1922 { | |
| 1923 AFont[hzk_id(pf)].width = pf->afont_width; | |
| 1924 pf->AFont.width = pf->afont_width; | |
| 1925 | |
| 1926 AFont[hzk_id(pf)].height = pf->font_height; | |
| 1927 pf->AFont.height = pf->font_height; | |
| 1928 | |
| 1929 AFont[hzk_id(pf)].size = ((pf->AFont.width + 7) / 8) * | |
| 1930 pf->AFont.height * 255; | |
| 1931 pf->AFont.size = ((pf->AFont.width + 7) / 8) * pf->AFont.height * 255; | |
| 1932 | |
| 1933 if(pf->AFont.size < 255 * 8) | |
| 1934 return FALSE; | |
| 1935 | |
| 1936 strcpy(AFont[hzk_id(pf)].file,HZK_FONT_DIR); | |
| 1937 strcpy(pf->AFont.file,HZK_FONT_DIR); | |
| 1938 | |
| 1939 if(pf->font_height==16) | |
| 1940 { | |
| 1941 strcat(AFont[hzk_id(pf)].file,"/asc16"); | |
| 1942 strcat(pf->AFont.file,"/asc16"); | |
| 1943 } | |
| 1944 else | |
| 1945 { | |
| 1946 strcat(AFont[hzk_id(pf)].file,"/asc12"); | |
| 1947 strcat(pf->AFont.file,"/asc12"); | |
| 1948 } | |
| 1949 return TRUE; | |
| 1950 } | |
| 1951 | |
| 1952 /* This function load system font into memory.*/ | |
| 1953 static MWBOOL LoadFont( PMWHZKFONT pf ) | |
| 1954 { | |
| 1955 FILE* fp; | |
| 1956 | |
| 1957 if(!GetCFontInfo(pf)) | |
| 1958 { | |
| 1959 fprintf (stderr, "Get Chinese HZK font info failure!\n"); | |
| 1960 return FALSE; | |
| 1961 } | |
| 1962 if(CFont[hzk_id(pf)].pFont == NULL) /* check font cache*/ | |
| 1963 { | |
| 1964 | |
| 1965 | |
| 1966 /* Allocate system memory for Chinese font.*/ | |
| 1967 if( !(CFont[hzk_id(pf)].pFont = (char *)malloc(pf->CFont.size)) ) | |
| 1968 { | |
| 1969 fprintf (stderr, "Allocate memory for Chinese HZK font failure.\n"); | |
| 1970 return FALSE; | |
| 1971 } | |
| 1972 | |
| 1973 /* Open font file and read information to the system memory.*/ | |
| 1974 fprintf (stderr, "Loading Chinese HZK font from file(%s)..." ,pf->CFont.file); | |
| 1975 if(!(fp = fopen(CFont[hzk_id(pf)].file, "rb"))) | |
| 1976 { | |
| 1977 fprintf (stderr, "Error.\nThe Chinese HZK font file can not be found!\n"); | |
| 1978 return FALSE; | |
| 1979 } | |
| 1980 if(fread(CFont[hzk_id(pf)].pFont, sizeof(char), pf->CFont.size, fp) < pf->CFont.size) | |
| 1981 { | |
| 1982 fprintf (stderr, "Error in reading Chinese HZK font file!\n"); | |
| 1983 fclose(fp); | |
| 1984 return FALSE; | |
| 1985 } | |
| 1986 | |
| 1987 fclose(fp); | |
| 1988 | |
| 1989 CFont[hzk_id(pf)].use_count=0; | |
| 1990 | |
| 1991 fprintf (stderr, "done.\n" ); | |
| 1992 | |
| 1993 } | |
| 1994 cfont_address = CFont[hzk_id(pf)].pFont; | |
| 1995 pf->cfont_address = CFont[hzk_id(pf)].pFont; | |
| 1996 pf->CFont.pFont = CFont[hzk_id(pf)].pFont; | |
| 1997 | |
| 1998 CFont[hzk_id(pf)].use_count++; | |
| 1999 | |
| 2000 if(!GetAFontInfo(pf)) | |
| 2001 { | |
| 2002 fprintf (stderr, "Get ASCII HZK font info failure!\n"); | |
| 2003 return FALSE; | |
| 2004 } | |
| 2005 if(AFont[hzk_id(pf)].pFont == NULL) /* check font cache*/ | |
| 2006 { | |
| 2007 | |
| 2008 | |
| 2009 /* Allocate system memory for ASCII font.*/ | |
| 2010 if( !(AFont[hzk_id(pf)].pFont = (char *)malloc(pf->AFont.size)) ) | |
| 2011 { | |
| 2012 fprintf (stderr, "Allocate memory for ASCII HZK font failure.\n"); | |
| 2013 free(CFont[hzk_id(pf)].pFont); | |
| 2014 CFont[hzk_id(pf)].pFont = NULL; | |
| 2015 return FALSE; | |
| 2016 } | |
| 2017 | |
| 2018 /* Load ASCII font information to the near memory.*/ | |
| 2019 fprintf (stderr, "Loading ASCII HZK font..." ); | |
| 2020 if(!(fp = fopen(AFont[hzk_id(pf)].file, "rb"))) | |
| 2021 { | |
| 2022 fprintf (stderr, "Error.\nThe ASCII HZK font file can not be found!\n"); | |
| 2023 return FALSE; | |
| 2024 } | |
| 2025 if(fread(AFont[hzk_id(pf)].pFont, sizeof(char), pf->AFont.size, fp) < pf->AFont.size) | |
| 2026 { | |
| 2027 fprintf (stderr, "Error in reading ASCII HZK font file!\n"); | |
| 2028 fclose(fp); | |
| 2029 return FALSE; | |
| 2030 } | |
| 2031 | |
| 2032 fclose(fp); | |
| 2033 | |
| 2034 AFont[hzk_id(pf)].use_count=0; | |
| 2035 | |
| 2036 fprintf (stderr, "done.\n" ); | |
| 2037 | |
| 2038 } | |
| 2039 afont_address = AFont[hzk_id(pf)].pFont; | |
| 2040 pf->afont_address = AFont[hzk_id(pf)].pFont; | |
| 2041 pf->AFont.pFont = AFont[hzk_id(pf)].pFont; | |
| 2042 | |
| 2043 AFont[hzk_id(pf)].use_count++; | |
| 2044 | |
| 2045 return TRUE; | |
| 2046 } | |
| 2047 | |
| 2048 /* This function unload system font from memory.*/ | |
| 2049 static void UnloadFont( PMWHZKFONT pf ) | |
| 2050 { | |
| 2051 CFont[hzk_id(pf)].use_count--; | |
| 2052 AFont[hzk_id(pf)].use_count--; | |
| 2053 | |
| 2054 if (!CFont[hzk_id(pf)].use_count) | |
| 2055 { | |
| 2056 free(pf->CFont.pFont); | |
| 2057 free(pf->AFont.pFont); | |
| 2058 | |
| 2059 CFont[hzk_id(pf)].pFont = NULL; | |
| 2060 AFont[hzk_id(pf)].pFont = NULL; | |
| 2061 } | |
| 2062 } | |
| 2063 | |
| 2064 static int | |
| 2065 hzk_init(PSD psd) | |
| 2066 { | |
| 2067 /* FIXME: *.KU file should be opened and | |
| 2068 * read in here...*/ | |
| 2069 return 1; | |
| 2070 } | |
| 2071 | |
| 2072 static PMWHZKFONT | |
| 2073 hzk_createfont(const char *name, MWCOORD height, int attr) | |
| 2074 { | |
| 2075 PMWHZKFONT pf; | |
| 2076 | |
| 2077 if(strcmp(name,"HZKFONT")!=0 && strcmp(name,"HZXFONT")!=0) | |
| 2078 return FALSE; | |
| 2079 | |
| 2080 /*printf("hzk_createfont(%s,%d)\n",name,height);*/ | |
| 2081 | |
| 2082 use_big5=name[2]-'K'; | |
| 2083 | |
| 2084 /* allocate font structure*/ | |
| 2085 pf = (PMWHZKFONT)calloc(sizeof(MWHZKFONT), 1); | |
| 2086 if (!pf) | |
| 2087 return NULL; | |
| 2088 pf->fontprocs = &hzk_procs; | |
| 2089 | |
| 2090 pf->fontsize=height; | |
| 2091 #if 0 | |
| 2092 GdSetFontSize((PMWFONT)pf, height); | |
| 2093 #endif | |
| 2094 GdSetFontRotation((PMWFONT)pf, 0); | |
| 2095 GdSetFontAttr((PMWFONT)pf, attr, 0); | |
| 2096 | |
| 2097 if(height==12) | |
| 2098 { | |
| 2099 afont_width = 6; | |
| 2100 cfont_width = 12; | |
| 2101 font_height = 12; | |
| 2102 | |
| 2103 pf->afont_width = 6; | |
| 2104 pf->cfont_width = 12; | |
| 2105 pf->font_height = 12; | |
| 2106 } | |
| 2107 else | |
| 2108 { | |
| 2109 afont_width = 8; | |
| 2110 cfont_width = 16; | |
| 2111 font_height = 16; | |
| 2112 | |
| 2113 pf->afont_width = 8; | |
| 2114 pf->cfont_width = 16; | |
| 2115 pf->font_height = 16; | |
| 2116 } | |
| 2117 | |
| 2118 /* Load the font library to the system memory.*/ | |
| 2119 if(!LoadFont(pf)) | |
| 2120 return FALSE; | |
| 2121 | |
| 2122 return pf; | |
| 2123 } | |
| 2124 | |
| 2125 int IsBig5(int i) | |
| 2126 { | |
| 2127 if ((i>=0xa140 && i<=0xa3bf) || /* a140-a3bf(!a3e0) */ | |
| 2128 (i>=0xa440 && i<=0xc67e) || /* a440-c67e */ | |
| 2129 (i>=0xc6a1 && i<=0xc8d3) || /* c6a1-c8d3(!c8fe) */ | |
| 2130 (i>=0xc940 && i<=0xf9fe)) /* c940-f9fe */ | |
| 2131 return 1; | |
| 2132 else | |
| 2133 return 0; | |
| 2134 } | |
| 2135 | |
| 2136 /* | |
| 2137 * following several function is used in hzk_drawtext | |
| 2138 */ | |
| 2139 | |
| 2140 static int getnextchar(char* s, unsigned char* cc) | |
| 2141 { | |
| 2142 if( s[0] == '\0') return 0; | |
| 2143 | |
| 2144 cc[0] = (unsigned char)(*s); | |
| 2145 cc[1] = (unsigned char)(*(s + 1)); | |
| 2146 | |
| 2147 if (use_big5) | |
| 2148 { | |
| 2149 if( IsBig5( (int) ( (cc[0] << 8) + cc[1]) ) ) | |
| 2150 return 1; | |
| 2151 } | |
| 2152 else | |
| 2153 { | |
| 2154 if( ((unsigned char)cc[0] > 0xa0) && | |
| 2155 ((unsigned char)cc[1] > 0xa0) ) | |
| 2156 return 1; | |
| 2157 } | |
| 2158 | |
| 2159 cc[1] = '\0'; | |
| 2160 | |
| 2161 return 1; | |
| 2162 } | |
| 2163 | |
| 2164 static void | |
| 2165 expandcchar(PMWHZKFONT pf, int bg, int fg, unsigned char* c, MWPIXELVAL* bitmap) | |
| 2166 { | |
| 2167 int i=0; | |
| 2168 int c1, c2, seq; | |
| 2169 int x,y; | |
| 2170 unsigned char *font; | |
| 2171 int b = 0; /* keep gcc happy with b = 0 - MW */ | |
| 2172 | |
| 2173 int pixelsize; | |
| 2174 pixelsize=sizeof(MWPIXELVAL); | |
| 2175 | |
| 2176 c1 = c[0]; | |
| 2177 c2 = c[1]; | |
| 2178 if (use_big5) | |
| 2179 { | |
| 2180 seq=0; | |
| 2181 /* ladd=loby-(if(loby<127)?64:98)*/ | |
| 2182 c2-=(c2<127?64:98); | |
| 2183 | |
| 2184 /* hadd=(hiby-164)*157*/ | |
| 2185 if (c1>=0xa4) /* standard font*/ | |
| 2186 { | |
| 2187 seq=(((c1-164)*157)+c2); | |
| 2188 if (seq>=5809) seq-=408; | |
| 2189 } | |
| 2190 | |
| 2191 /* hadd=(hiby-161)*157*/ | |
| 2192 if (c1<=0xa3) /* special font*/ | |
| 2193 seq=(((c1-161)*157)+c2)+13094; | |
| 2194 } | |
| 2195 else | |
| 2196 seq=((c1 - 161)*94 + c2 - 161); | |
| 2197 | |
| 2198 font = pf->cfont_address + ((seq) * | |
| 2199 (pf->font_height * ((pf->cfont_width + 7) / 8))); | |
| 2200 | |
| 2201 for (y = 0; y < pf->font_height; y++) | |
| 2202 for (x = 0; x < pf->cfont_width; x++) | |
| 2203 { | |
| 2204 if (x % 8 == 0) | |
| 2205 b = *font++; | |
| 2206 | |
| 2207 if (b & (128 >> (x % 8))) /* pixel */ | |
| 2208 bitmap[i++]=fg; | |
| 2209 else | |
| 2210 bitmap[i++]=bg; | |
| 2211 } | |
| 2212 } | |
| 2213 | |
| 2214 static void expandchar(PMWHZKFONT pf, int bg, int fg, int c, MWPIXELVAL* bitmap) | |
| 2215 { | |
| 2216 int i=0; | |
| 2217 int x,y; | |
| 2218 unsigned char *font; | |
| 2219 int pixelsize; | |
| 2220 int b = 0; /* keep gcc happy with b = 0 - MW */ | |
| 2221 | |
| 2222 pixelsize=sizeof(MWPIXELVAL); | |
| 2223 | |
| 2224 font = pf->afont_address + c * (pf->font_height * | |
| 2225 ((pf->afont_width + 7) / 8)); | |
| 2226 | |
| 2227 for (y = 0; y < pf->font_height; y++) | |
| 2228 for (x = 0; x < pf->afont_width; x++) | |
| 2229 { | |
| 2230 if (x % 8 == 0) | |
| 2231 b = *font++; | |
| 2232 if (b & (128 >> (x % 8))) /* pixel */ | |
| 2233 bitmap[i++]=fg; | |
| 2234 else | |
| 2235 bitmap[i++]=bg; | |
| 2236 } | |
| 2237 } | |
| 2238 | |
| 2239 /* | |
| 2240 * Draw ASCII text string using HZK type font | |
| 2241 */ | |
| 2242 static void | |
| 2243 hzk_drawtext(PMWFONT pfont, PSD psd, MWCOORD ax, MWCOORD ay, | |
| 2244 const void *text, int cc, int flags) | |
| 2245 { | |
| 2246 PMWHZKFONT pf=(PMWHZKFONT)pfont; | |
| 2247 | |
| 2248 unsigned char c[2]; | |
| 2249 MWPIXELVAL *bitmap; | |
| 2250 unsigned char s1[3]; | |
| 2251 char *s,*sbegin; | |
| 2252 | |
| 2253 s=(char *)text; | |
| 2254 | |
| 2255 if(cc==1) | |
| 2256 { | |
| 2257 s1[0]=*((unsigned char*)text); | |
| 2258 s1[1]=0x0; | |
| 2259 s1[2]=0x0; | |
| 2260 s=s1; | |
| 2261 } | |
| 2262 | |
| 2263 sbegin=s; | |
| 2264 bitmap = (MWPIXELVAL *)ALLOCA(pf->cfont_width * pf->font_height * | |
| 2265 sizeof(MWPIXELVAL)); | |
| 2266 | |
| 2267 while( getnextchar(s, c) ) | |
| 2268 { | |
| 2269 if( c[1] != '\0') | |
| 2270 { | |
| 2271 expandcchar(pf, gr_background,gr_foreground, | |
| 2272 c, bitmap); | |
| 2273 /* Now draw the bitmap ... */ | |
| 2274 | |
| 2275 if (flags&MWTF_TOP) | |
| 2276 GdArea(psd,ax, ay, pf->cfont_width, | |
| 2277 pf->font_height, bitmap, MWPF_PIXELVAL); | |
| 2278 else | |
| 2279 GdArea(psd,ax, ay-pf->font_height+2, | |
| 2280 pf->cfont_width, pf->font_height, | |
| 2281 bitmap, MWPF_PIXELVAL); | |
| 2282 | |
| 2283 s += 2; | |
| 2284 ax += pf->cfont_width; | |
| 2285 } | |
| 2286 else | |
| 2287 { | |
| 2288 expandchar(pf, gr_background,gr_foreground, | |
| 2289 c[0], bitmap); | |
| 2290 /* Now draw the bitmap ... */ | |
| 2291 | |
| 2292 if (flags&MWTF_TOP) | |
| 2293 GdArea(psd,ax, ay, pf->afont_width, | |
| 2294 pf->font_height, bitmap, MWPF_PIXELVAL); | |
| 2295 else | |
| 2296 GdArea(psd,ax, ay-pf->font_height+2, | |
| 2297 pf->afont_width, pf->font_height, | |
| 2298 bitmap, MWPF_PIXELVAL); | |
| 2299 | |
| 2300 s += 1; | |
| 2301 ax += pf->afont_width; | |
| 2302 } | |
| 2303 | |
| 2304 if(s>=sbegin+cc)break; | |
| 2305 } | |
| 2306 | |
| 2307 FREEA(bitmap); | |
| 2308 } | |
| 2309 | |
| 2310 /* | |
| 2311 * Return information about a specified font. | |
| 2312 */ | |
| 2313 static MWBOOL | |
| 2314 hzk_getfontinfo(PMWFONT pfont, PMWFONTINFO pfontinfo) | |
| 2315 { | |
| 2316 PMWHZKFONT pf=(PMWHZKFONT)pfont; | |
| 2317 | |
| 2318 int i; | |
| 2319 | |
| 2320 pfontinfo->height = pf->font_height; | |
| 2321 pfontinfo->maxwidth = pf->cfont_width; | |
| 2322 pfontinfo->baseline = pf->font_height-2; | |
| 2323 pfontinfo->firstchar = 0; | |
| 2324 pfontinfo->lastchar = 0; | |
| 2325 pfontinfo->fixed = TRUE; | |
| 2326 | |
| 2327 for(i=0; i<=256; i++) | |
| 2328 pfontinfo->widths[i] = pf->afont_width; | |
| 2329 | |
| 2330 return TRUE; | |
| 2331 } | |
| 2332 | |
| 2333 static void | |
| 2334 hzk_gettextsize(PMWFONT pfont, const void *text, int cc, | |
| 2335 MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase) | |
| 2336 { | |
| 2337 PMWHZKFONT pf=(PMWHZKFONT)pfont; | |
| 2338 | |
| 2339 unsigned char c[2]; | |
| 2340 char *s,*sbegin; | |
| 2341 unsigned char s1[3]; | |
| 2342 | |
| 2343 int ax=0; | |
| 2344 s=(char *)text; | |
| 2345 if(cc==0) | |
| 2346 { | |
| 2347 *pwidth = 0; | |
| 2348 *pheight = pf->font_height; | |
| 2349 *pbase = pf->font_height-2; | |
| 2350 | |
| 2351 } | |
| 2352 if(cc==1) | |
| 2353 { | |
| 2354 s1[0]=*((unsigned char*)text); | |
| 2355 s1[1]=0x0; | |
| 2356 s1[2]=0x0; | |
| 2357 s=s1; | |
| 2358 } | |
| 2359 sbegin=s; | |
| 2360 while( getnextchar(s, c) ) | |
| 2361 { | |
| 2362 if( c[1] != '\0') | |
| 2363 { | |
| 2364 s += 2; | |
| 2365 ax += pf->cfont_width; | |
| 2366 } | |
| 2367 else | |
| 2368 { | |
| 2369 s += 1; | |
| 2370 ax += pf->afont_width; | |
| 2371 } | |
| 2372 if(s>=sbegin+cc) { | |
| 2373 /*fprintf(stderr,"s=%x,sbegin=%x,cc=%x\n",s,sbegin,cc);*/ | |
| 2374 break; | |
| 2375 } | |
| 2376 | |
| 2377 } | |
| 2378 /*fprintf(stderr,"ax=%d,\n",ax);*/ | |
| 2379 | |
| 2380 *pwidth = ax; | |
| 2381 *pheight = pf->font_height; | |
| 2382 *pbase = pf->font_height-2; | |
| 2383 } | |
| 2384 | |
| 2385 static void | |
| 2386 hzk_destroyfont(PMWFONT pfont) | |
| 2387 { | |
| 2388 PMWHZKFONT pf=(PMWHZKFONT)pfont; | |
| 2389 UnloadFont(pf); | |
| 2390 free(pf); | |
| 2391 } | |
| 2392 | |
| 2393 static void | |
| 2394 hzk_setfontsize(PMWFONT pfont, MWCOORD fontsize) | |
| 2395 { | |
| 2396 PMWHZKFONT pf=(PMWHZKFONT)pfont; | |
| 2397 /* jmt: hzk_setfontsize not supported*/ | |
| 2398 /* & pf->fontsize can't be changed*/ | |
| 2399 /* because of hzk_id() :p*/ | |
| 2400 pf->fontsize=pf->font_height; | |
| 2401 } | |
| 2402 #endif /* HAVE_HZK_SUPPORT*/ | |
| 2403 | |
| 2404 /* FIXME: this routine should work for all font renderers...*/ | |
| 2405 int | |
| 2406 GdGetTextSizeEx(PMWFONT pfont, const void *str, int cc,int nMaxExtent, | |
| 2407 int* lpnFit, int* alpDx,MWCOORD *pwidth,MWCOORD *pheight, | |
| 2408 MWCOORD *pbase, int flags) | |
| 2409 { | |
| 2410 #ifdef HAVE_FREETYPE_SUPPORT | |
| 2411 unsigned short buf[256]; | |
| 2412 unsigned short* text; | |
| 2413 PMWFREETYPEFONT pf = (PMWFREETYPEFONT)pfont; | |
| 2414 int defencoding = pf->fontprocs->encoding; | |
| 2415 int x = 0; | |
| 2416 int i; | |
| 2417 TT_UShort curchar; | |
| 2418 TT_Glyph_Metrics metrics; | |
| 2419 TT_Face_Properties properties; | |
| 2420 TT_Instance_Metrics imetrics; | |
| 2421 | |
| 2422 if ((cc<0)||(!str)) | |
| 2423 { | |
| 2424 *pwidth = *pheight = *pbase = 0; | |
| 2425 return 0; | |
| 2426 } | |
| 2427 /* convert encoding if required*/ | |
| 2428 if((flags & MWTF_PACKMASK) != defencoding) | |
| 2429 { | |
| 2430 cc = GdConvertEncoding(str, flags, cc, buf, defencoding); | |
| 2431 flags &= ~MWTF_PACKMASK; | |
| 2432 flags |= defencoding; | |
| 2433 text=buf; | |
| 2434 } else text =(unsigned short*)str; | |
| 2435 if(cc <= 0) | |
| 2436 { | |
| 2437 *pwidth = *pheight = *pbase = 0; | |
| 2438 return 0; | |
| 2439 } | |
| 2440 | |
| 2441 TT_Get_Face_Properties (pf->face, &properties); | |
| 2442 TT_Get_Instance_Metrics(pf->instance, &imetrics); | |
| 2443 | |
| 2444 pf->last_glyph_code = -1; /* reset kerning*/ | |
| 2445 pf->last_pen_pos = -32767; | |
| 2446 if (lpnFit) | |
| 2447 *lpnFit=-1; | |
| 2448 for (i = 0; i < cc; i++) | |
| 2449 { | |
| 2450 curchar = TT_Char_Index (pf->char_map,text[i]); | |
| 2451 | |
| 2452 if (TT_Load_Glyph (pf->instance, pf->glyph, curchar, | |
| 2453 TTLOAD_SCALE_GLYPH|TTLOAD_HINT_GLYPH) != TT_Err_Ok) | |
| 2454 { | |
| 2455 fprintf(stderr, "Unable to load glyph with index=%d\n",curchar); | |
| 2456 return 0; | |
| 2457 } | |
| 2458 TT_Get_Glyph_Metrics (pf->glyph, &metrics); | |
| 2459 if ((pf->fontattr&MWTF_KERNING) && pf->can_kern) | |
| 2460 { | |
| 2461 x += compute_kernval(pf, curchar) / 64; | |
| 2462 } | |
| 2463 x += metrics.advance / 64; | |
| 2464 if((lpnFit)&&(alpDx)) | |
| 2465 { | |
| 2466 if (x<=nMaxExtent) | |
| 2467 alpDx[i]=x; | |
| 2468 else | |
| 2469 if (*lpnFit==-1) | |
| 2470 (*lpnFit)=i; | |
| 2471 } | |
| 2472 /* Kerning point syndrome avoidance */ | |
| 2473 if (pf->last_pen_pos > x) | |
| 2474 x = pf->last_pen_pos; | |
| 2475 pf->last_pen_pos = x; | |
| 2476 pf->last_glyph_code = curchar; | |
| 2477 } | |
| 2478 if ((lpnFit)&&(*lpnFit==-1)) | |
| 2479 *lpnFit=cc; | |
| 2480 *pwidth = x; | |
| 2481 *pheight = (((properties.horizontal->Ascender * | |
| 2482 imetrics.y_scale)/ 0x10000) >> 6) - | |
| 2483 (((properties.horizontal->Descender * | |
| 2484 imetrics.y_scale)/ 0x10000) >> 6); | |
| 2485 /* FIXME: is it what's required ??*/ | |
| 2486 if (pbase) | |
| 2487 *pbase = (((-properties.horizontal->Descender) * | |
| 2488 imetrics.y_scale)/ 0x10000) >> 6; | |
| 2489 return 1; | |
| 2490 #else /* HAVE_FREETYPE_SUPPORT*/ | |
| 2491 *pwidth = *pheight = *pbase = 0; | |
| 2492 return 0; | |
| 2493 #endif | |
| 2494 } | |
| 2495 | |
| 2496 #ifdef HAVE_FREETYPE_SUPPORT | |
| 2497 #include <dirent.h> | |
| 2498 /* | |
| 2499 * This function is taken almost verbatim from ftdump.c from | |
| 2500 * the freetype library (version 1.3.1) | |
| 2501 */ | |
| 2502 static char * | |
| 2503 tt_lookup_name(TT_Face face) | |
| 2504 { | |
| 2505 TT_Face_Properties prop; | |
| 2506 unsigned short i, n; | |
| 2507 unsigned short platform, encoding, language, id; | |
| 2508 char *string; | |
| 2509 char *name_buffer; | |
| 2510 unsigned short string_len; | |
| 2511 int j, found; | |
| 2512 int index = 4; /* I dont know why as yet.. */ | |
| 2513 int name_len; | |
| 2514 | |
| 2515 | |
| 2516 TT_Get_Face_Properties(face, &prop); | |
| 2517 n = prop.num_Names; | |
| 2518 | |
| 2519 for ( i = 0; i < n; i++ ) { | |
| 2520 TT_Get_Name_ID( face, i, &platform, &encoding, &language, &id ); | |
| 2521 TT_Get_Name_String( face, i, &string, &string_len ); | |
| 2522 | |
| 2523 if (id == index ) { | |
| 2524 /* The following code was inspired from Mark Leisher's */ | |
| 2525 /* ttf2bdf package */ | |
| 2526 found = 0; | |
| 2527 | |
| 2528 /* Try to find a Microsoft English name */ | |
| 2529 if ( platform == 3 ) | |
| 2530 for ( j = 1; j >= 0; j-- ) | |
| 2531 if ( encoding == j ) /* Microsoft ? */ | |
| 2532 if ( (language & 0x3FF) == 0x009 ) { | |
| 2533 /* English language */ | |
| 2534 found = 1; | |
| 2535 break; | |
| 2536 } | |
| 2537 | |
| 2538 if ( !found && platform == 0 && language == 0 ) | |
| 2539 found = 1; | |
| 2540 | |
| 2541 /* Found a Unicode Name. */ | |
| 2542 if ( found ) { | |
| 2543 if ( string_len > 512 ) | |
| 2544 string_len = 512; | |
| 2545 | |
| 2546 name_len = 0; | |
| 2547 name_buffer = (char*)malloc((string_len / 2) + 1); | |
| 2548 | |
| 2549 for ( i = 1; i < string_len; i += 2 ) | |
| 2550 name_buffer[name_len++] = string[i]; | |
| 2551 | |
| 2552 name_buffer[name_len] = '\0'; | |
| 2553 | |
| 2554 return name_buffer; | |
| 2555 } | |
| 2556 } | |
| 2557 } | |
| 2558 | |
| 2559 /* Not found */ | |
| 2560 return NULL; | |
| 2561 } | |
| 2562 | |
| 2563 static char * | |
| 2564 get_tt_name(char *p) | |
| 2565 { | |
| 2566 TT_Face face; | |
| 2567 char *ret; | |
| 2568 | |
| 2569 /*printf("Trying to open: %s!\n",p);*/ | |
| 2570 | |
| 2571 if (TT_Open_Face(engine, p, &face) != TT_Err_Ok) { | |
| 2572 fprintf(stderr, "Error opening font: %s\n", p); | |
| 2573 return NULL; | |
| 2574 } | |
| 2575 | |
| 2576 ret = tt_lookup_name(face); | |
| 2577 | |
| 2578 TT_Close_Face(face); | |
| 2579 | |
| 2580 return ret; | |
| 2581 } | |
| 2582 | |
| 2583 void | |
| 2584 GdFreeFontList(MWFONTLIST ***fonts, int n) | |
| 2585 { | |
| 2586 int i; | |
| 2587 MWFONTLIST *g, **list = *fonts; | |
| 2588 | |
| 2589 for (i = 0; i < n; i++) { | |
| 2590 g = list[i]; | |
| 2591 if(g) { | |
| 2592 if(g->mwname) | |
| 2593 free(g->mwname); | |
| 2594 if(g->ttname) | |
| 2595 free(g->ttname); | |
| 2596 free(g); | |
| 2597 } | |
| 2598 } | |
| 2599 free(list); | |
| 2600 *fonts = 0; | |
| 2601 } | |
| 2602 | |
| 2603 void | |
| 2604 GdGetFontList(MWFONTLIST ***fonts, int *numfonts) | |
| 2605 { | |
| 2606 DIR *dir; | |
| 2607 struct dirent *dent; | |
| 2608 char *p, *ftmp; | |
| 2609 int pl, idx = 0; | |
| 2610 MWFONTLIST **list; | |
| 2611 | |
| 2612 | |
| 2613 if (TT_Err_Ok != TT_Init_FreeType(&engine)) { | |
| 2614 fprintf(stderr, "Unable to initialize freetype\n"); | |
| 2615 *numfonts = -1; | |
| 2616 return ; | |
| 2617 } | |
| 2618 | |
| 2619 dir = opendir(FREETYPE_FONT_DIR); | |
| 2620 | |
| 2621 if (dir <= 0) { | |
| 2622 fprintf(stderr, "Error opening font directory\n"); | |
| 2623 *numfonts = -1; | |
| 2624 return ; | |
| 2625 } | |
| 2626 | |
| 2627 /* get the number of strings we need to allocate */ | |
| 2628 while ((dent = readdir(dir)) != NULL) { | |
| 2629 p = strrchr(dent->d_name, '.'); | |
| 2630 if (strcasecmp(p, ".ttf") == 0) | |
| 2631 idx++; | |
| 2632 } | |
| 2633 | |
| 2634 *numfonts = idx; | |
| 2635 rewinddir(dir); | |
| 2636 | |
| 2637 /* allocate strings */ | |
| 2638 list = (MWFONTLIST**)malloc(idx * sizeof(MWFONTLIST*)); | |
| 2639 for (pl = 0; pl < idx; pl++) | |
| 2640 list[pl] = (MWFONTLIST*)malloc(sizeof(MWFONTLIST)); | |
| 2641 | |
| 2642 *fonts = list; | |
| 2643 | |
| 2644 idx = 0; | |
| 2645 | |
| 2646 while ((dent = readdir(dir)) != NULL) { | |
| 2647 /* check extension */ | |
| 2648 p = strrchr(dent->d_name, '.'); | |
| 2649 | |
| 2650 if (strcasecmp(p, ".ttf") == 0) { | |
| 2651 | |
| 2652 /* get full path */ | |
| 2653 p = 0; | |
| 2654 pl = strlen(FREETYPE_FONT_DIR) + strlen(dent->d_name) * | |
| 2655 sizeof(char) + 2; | |
| 2656 p = (char*)malloc(pl); | |
| 2657 p = (char*)memset(p, '\0', pl); | |
| 2658 p = (char*)strcat(p, FREETYPE_FONT_DIR); | |
| 2659 p = (char*)strcat(p, "/"); | |
| 2660 p = (char*)strcat(p, dent->d_name); | |
| 2661 | |
| 2662 | |
| 2663 if((ftmp = get_tt_name(p)) != NULL) { | |
| 2664 list[idx]->ttname = ftmp; | |
| 2665 list[idx]->mwname = malloc(strlen(dent->d_name) + 1); | |
| 2666 list[idx]->mwname = strcpy(list[idx]->mwname, dent->d_name); | |
| 2667 | |
| 2668 idx++; | |
| 2669 } | |
| 2670 | |
| 2671 free(p); | |
| 2672 } | |
| 2673 } | |
| 2674 | |
| 2675 closedir(dir); | |
| 2676 } | |
| 2677 #else /* !HAVE_FREETYPE_SUPPORT*/ | |
| 2678 | |
| 2679 void | |
| 2680 GdFreeFontList(MWFONTLIST ***fonts, int n) | |
| 2681 { | |
| 2682 } | |
| 2683 | |
| 2684 void | |
| 2685 GdGetFontList(MWFONTLIST ***fonts, int *numfonts) | |
| 2686 { | |
| 2687 *numfonts = -1; | |
| 2688 } | |
| 2689 #endif /* !HAVE_FREETYPE_SUPPORT*/ |
