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