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*/