magicpoint-1.10a.tar.gz (MirPorts)
[alioth/magicpoint.git] / tfont.c
1 /*
2  * Copyright (C) 1997 and 1998 WIDE Project.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  * 3. Neither the name of the project nor the names of its contributors
13  *    may be used to endorse or promote products derived from this software
14  *    without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 /*
29  * $Id: tfont.c,v 1.43 2002/01/12 01:56:25 nishida Exp $
30  */
31
32 #include "mgp.h"
33
34 #ifdef FREETYPE
35
36 int tfcachesize = 3000; /*XXX*/
37 #define TFFONT_NUM      128
38 #define TFHASH_SIZE     255
39 #define TFCACHE_HASH(c, siz)   ((c ^ siz) % TFHASH_SIZE)
40
41 static TT_Raster_Map            bitmap;
42 static TT_Face_Properties       properties[TFFONT_NUM];
43 static TT_Face                  face[TFFONT_NUM];
44 static TT_Glyph                 glyph[TFFONT_NUM];
45 static TT_Instance              instance[TFFONT_NUM];
46 static TT_Glyph_Metrics         metrics;
47 static TT_Error                 error;
48 static TT_Engine                engine;
49 static XImage *xim;
50
51 static char *tf_curname[4]; /* contains iso8859-[2-4] fonts */
52 static char *tf_mcurname = NULL;
53 static int tfcinitdone;
54 static int tfcachecnt;
55 static struct tfont tfclru;
56 static struct tfont tfcache[TFHASH_SIZE];
57 static int tffontcnt = 0;
58 static int tfcachehit = 0;
59 static int tfcachemiss = 0;
60 static int tfcuridx = -1;
61 static char tfloadedfont[1024][TFFONT_NUM];
62 static int tfloadedregistry[TFFONT_NUM];
63
64 #define TFC_INSHASH(tfc) { \
65         struct tfont *h, *n;                                            \
66         h = &tfcache[TFCACHE_HASH(tfc->code, tfc->size)]; \
67         n = h->next; tfc->next = n; n->prev = tfc;                      \
68         h->next = tfc; tfc->prev = h;                                   \
69 }
70 #define TFC_DELHASH(tfc) { \
71         struct tfont *n, *p;                                            \
72         n = tfc->next; p = tfc->prev;                                   \
73         n->prev = p; p->next = n;                                       \
74 }
75 #define TFC_INSLRU(tfc) { \
76         struct tfont *p;                                                \
77         p = tfclru.lruprev; tfc->lruprev = p; p->lrunext = tfc;         \
78         tfclru.lruprev = tfc; tfc->lrunext = &tfclru;                   \
79 }
80 #define TFC_DELLRU(tfc) { \
81         struct tfont *n, *p;                                            \
82         n = tfc->lrunext; p = tfc->lruprev;                             \
83         n->lruprev = p; p->lrunext = n;                                 \
84 }
85
86 static void tfc_init __P((void));
87 static void tfc_free __P((struct tfont *));
88 static struct tfont *tfc_lookup __P((u_int, u_int, char*, int));
89 static struct tfont *tfc_alloc __P((u_int, u_int, char *, char *));
90 static short CharToUnicode __P((u_int, char *));
91 static short jistosjis __P((u_int));
92 static TT_Error LoadTrueTypeChar __P((int, int));
93
94 #define TTFLOOR(x)      ((x) & -64)
95 #define TTCEIL(x)       (((x) + 63) & -64)
96
97 static void
98 tfc_init()
99 {
100         u_int   i;
101         struct tfont *tfc;
102
103         /* Initialize engine */
104         if ((error = TT_Init_FreeType(&engine))) {
105                 fprintf(stderr, "Error while initializing engine, code = %d.\n",
106                         (int)error);
107                 cleanup(-1);
108         }
109
110         tfc = tfcache;
111         for (tfc = tfcache, i = 0; i < TFHASH_SIZE; tfc++, i++)
112                 tfc->next = tfc->prev = tfc;
113         tfclru.lrunext = tfclru.lruprev = &tfclru;
114         tfcinitdone ++;
115
116         latin_unicode_map_init();
117 #ifdef FREETYPE_CHARSET16
118         unicode_map_init();
119 #endif
120 }
121
122 static void
123 tfc_free(tfc)
124         struct tfont *tfc;
125 {
126         TFC_DELHASH(tfc);
127         TFC_DELLRU(tfc);
128         free(tfc->fontname);
129         free(tfc->dbitmap);
130         free(tfc);
131         tfcachecnt--;
132 }
133
134 int
135 tfc_setsize(char_size)
136         u_int char_size;
137 {
138         if (!tfcinitdone)
139                 return -1;
140
141         if (tfcuridx < 0 || tffontcnt <= tfcuridx) {
142                 if (verbose)
143                         fprintf(stderr, "tfc_setsize: font index out of bound\n");
144                 return -1;
145         }
146
147         error = TT_Set_Instance_CharSize(instance[tfcuridx],
148                         (char_size * 0.75) * 64);
149         if (error) {
150                 fprintf(stderr,
151                         "Could not set device resolutions for \"%s\".\n",
152                         tfloadedfont[tfcuridx]);
153                 return -1;
154         }
155         return 0;
156 }
157
158 struct tfont *
159 tfc_get(code, size, force, registry, charset16)
160         u_int code, size;
161         int force;
162         char *registry;
163         int charset16;
164 {
165         struct tfont *tfc, *ntfc;
166         int     regid;
167
168         if (!tfcinitdone)
169                 tfc_init();
170
171         if (charset16)
172                 tfc = tfc_lookup(code, size, tf_mcurname, 0);
173         else {
174                 if (code >= 0xa0 && ((!registry || !registry[0]) && mgp_charset)){
175                         regid = get_regid(mgp_charset);
176                 } else 
177                         regid = get_regid(registry);
178                 tfc = tfc_lookup(code, size, tf_curname[regid], regid);
179         }
180
181         if (tfc == NULL) {
182                 /* XXX */
183                 if (tfcachecnt >= tfcachesize) {
184                         if (!force)
185                                 return NULL;
186                         tfc = tfclru.lrunext;
187                         while (tfcachecnt >= tfcachesize) {
188                                 if (tfc == &tfclru)
189                                         break;
190                                 ntfc = tfc->lrunext;
191                                 if (tfc->ref == 0)
192                                         tfc_free(tfc);
193                                 tfc = ntfc;
194                         }
195                 }
196
197                 if (charset16)
198                         tfc = tfc_alloc(code, size, tf_mcurname, registry);
199                 else
200                         tfc = tfc_alloc(code, size, tf_curname[regid], registry);
201         }
202         return tfc;
203 }
204
205 void
206 tfc_setfont(name, charset16, registry)
207         char *name;
208         int charset16;  /*2-octet charset?*/
209         char *registry;
210 {
211         char *fontname = NULL;
212         u_int i, regid = 0;
213         int res = 96; /* XXX */
214         char pathname[MAXPATHLEN];
215         int trial;
216         TT_Face tface;
217
218         if (!tfcinitdone)
219                 tfc_init();
220
221         if (TFFONT_NUM <= tffontcnt) {
222                 fprintf(stderr, "internal error: "
223                         "too many fonts opened (increase TFFONT_NUM)\n");
224                 cleanup(-1);
225         }
226
227         if (!name || !name[0]) {
228                 if (freetypefont0 && freetypefont0[0]) {
229                         if (verbose) {
230                                 fprintf(stderr, "tfc_setfont: "
231                                         "font name not given, "
232                                         "using last resort (%s)\n",
233                                         freetypefont0);
234                         }
235                         name = freetypefont0;
236                 } else {
237                         if (verbose) {
238                                 fprintf(stderr, "tfc_setfont: "
239                                         "font name not given, fail\n");
240                         }
241                         goto fail;
242                 }
243         }
244
245         /* check font cache first */
246         for (trial = 0; trial < 2; trial++) {
247                 switch (trial) {
248                 case 0:
249                         fontname = name;
250                         break;
251                 case 1:
252                         snprintf(pathname, sizeof(pathname),
253                                 "%s/%s", freetypefontdir, name);
254                         fontname = pathname;
255                         break;
256                 }
257
258                 for (i = 0; i < tffontcnt; i ++) {
259                         if (!strcmp(fontname, tfloadedfont[i])) {
260                                 /* already loaded */
261 #if 0
262                                 if (verbose) {
263                                         fprintf(stderr,
264                                                 "font cache hit for \"%s\"\n",
265                                                 fontname);
266                                 }
267 #endif
268                                 tfcuridx = i;
269                                 if (charset16)
270                                         tf_mcurname = tfloadedfont[i];
271                                 else {
272                                         regid = get_regid(registry);
273                                         tf_curname[regid] = tfloadedfont[i];
274                                 }
275 #if 0
276                                 tfc_setsize(char_size);
277 #endif
278                                 return;
279                         }
280                 }
281         }
282
283         /* try to load font */
284         for (trial = 0; trial < 3; trial++) {
285                 switch (trial) {
286                 case 0:
287                         fontname = name;
288                         break;
289                 case 1:
290                         snprintf(pathname, sizeof(pathname),
291                                 "%s/%s", freetypefontdir, name);
292                         fontname = pathname;
293                         break;
294                 case 2:
295                         if (!freetypefont0 || !freetypefont0[0])
296                                 continue;
297                         fontname = freetypefont0;
298                         /* already loaded? */
299                         for (i = 0; i < tffontcnt; i ++) {
300                                 if (!strcmp(fontname, tfloadedfont[i])){
301                                         tfcuridx = i;
302                                         if (verbose) 
303                                                 fprintf(stderr, "font \"%s\" already loaded: %d\n", 
304                                                         fontname, tffontcnt);
305                                         goto cached;
306                                 }
307                         }
308                         break;
309                 }
310
311                 /* Load face */
312                 if (verbose) fprintf(stderr, "trying to open font \"%s\"\n", fontname);
313                 error = TT_Open_Face(engine, fontname, &tface);
314                 if (!error)
315                         break;
316         }
317         if (trial == 2) {
318                 if (verbose) {
319                         fprintf(stderr, "font \"%s\" not found, "
320                                 "last resort font \"%s\" was used\n",
321                                 name, freetypefont0);
322                 }
323         } else if (trial == 3) {
324                 if (verbose) {
325                         fprintf(stderr, "could not load font \"%s\", "
326                                 "using other rendering engine\n", name);
327                 }
328                 goto fail;
329         }
330         if (verbose) {
331                 fprintf(stderr, "font \"%s\" opened successfully\n",
332                         fontname);
333         }
334
335         /* get registry id */
336         if ((regid = get_regid(registry)) < 0){
337                 fprintf(stderr, "font \"%s\" has irregal registry\n", fontname);
338                         goto fail2;     
339         }
340
341         tfloadedregistry[tffontcnt] = regid;
342         strcpy(tfloadedfont[tffontcnt], fontname);
343         tfcuridx = tffontcnt;
344         face[tfcuridx] = tface;
345         tffontcnt++;
346
347         /* get face properties and allocate preload arrays */
348         error = TT_Get_Face_Properties(face[tfcuridx], &properties[tfcuridx]);
349         if (error) {
350                 fprintf(stderr, "Could not create face property for "
351                         "\"%s\" (err 0x%04x).\n", fontname, (int)error);
352                 goto fail2;
353         }
354
355         /* create glyph */
356         error = TT_New_Glyph(face[tfcuridx], &glyph[tfcuridx]);
357         if (error) {
358                 fprintf(stderr, "Could not create glyph container for "
359                         "\"%s\" (err 0x%04x).\n", fontname, (int)error);
360                 goto fail2;
361         }
362
363         /* create instance */
364         error = TT_New_Instance(face[tfcuridx], &instance[tfcuridx]);
365         if (error) {
366                 fprintf(stderr, "Could not create instance for "
367                         "\"%s\" (err 0x%04x).\n", fontname, (int)error);
368                 goto fail2;
369         }
370
371         error = TT_Set_Instance_Resolutions(instance[tfcuridx], res, res);
372         if (error) {
373                 fprintf(stderr, "Could not set device resolutions for "
374                         "\"%s\" (err 0x%04x).\n", fontname, (int)error);
375                 goto fail2;
376         }
377
378 cached:
379         if (charset16)
380                 tf_mcurname = tfloadedfont[tfcuridx];
381         else {
382                 if (registry)
383                         tf_curname[regid] = tfloadedfont[tfcuridx];
384                 else {
385                         /* this should be default font */
386                         for (i = 0; i < 4; i ++)
387                                 tf_curname[i] = tfloadedfont[tfcuridx];
388                 }
389         }
390         if (tfc_setsize(char_size[caching]) < 0)
391                 goto fail2;
392
393         /* success */
394         return;
395
396 fail2:
397         TT_Close_Face(tface);
398         tffontcnt--;
399 fail:
400         if (!charset16){
401                 tf_curname[regid] = "";
402                 tfcuridx = -1;
403         } else 
404                 tf_mcurname = "";
405         return;
406 }
407
408 static struct tfont *
409 tfc_lookup(code, size, fontname, regid)
410         u_int code, size;
411         char *fontname;
412         int     regid;
413 {
414         u_int   i;
415         struct tfont *tfc, *htfc;
416
417         if (!fontname)  
418                 return NULL;    
419
420         for (i = 0; i < tffontcnt; i ++) {
421                 if (!strcmp(fontname, tfloadedfont[i]))
422                         tfcuridx = i;
423         }
424
425         htfc = &tfcache[TFCACHE_HASH(code, size)];
426         for (tfc = htfc->next; tfc != htfc; tfc = tfc->next) {
427                 if (tfc->code == code
428                  && tfc->size == size
429                  && tfc->regid == regid
430                  && strcmp(tfc->fontname, fontname) == 0) {
431                         tfcachehit++;
432                         TFC_DELLRU(tfc);
433                         TFC_INSLRU(tfc);
434                         return tfc;
435                 }
436         }
437         tfcachemiss++;
438
439         return NULL;
440 }
441
442 static struct tfont *
443 tfc_alloc(code, size, fontname, registry)
444         u_int code, size;
445         char *fontname;
446         char *registry;
447 {
448         struct tfont *tfc;
449         short unicode;
450
451         /* if no font was ever loaded, try loading the last resort font */
452         if (!tffontcnt) {
453                 if (verbose)
454                         fprintf(stderr, "no fontcount\n");
455                 tfc_setfont(NULL, 0, NULL);
456         }
457
458         /* font out of bounds, suggests no font was available */
459         if (tfcuridx < 0 || tffontcnt <= tfcuridx) {
460                 if (verbose)
461                         fprintf(stderr, "tfc_alloc: font index out of bound\n");
462                 return NULL;
463         }
464
465         if (fontname == NULL)
466                 return NULL;
467         
468
469         /* This is required! */
470         if (tfc_setsize(char_size[caching]) < 0)
471                 return NULL;
472
473         tfc = (struct tfont *)malloc(sizeof(*tfc));
474         if (tfc == NULL) {
475                 fprintf(stderr, "tfc_alloc: malloc failed\n");
476                 return NULL;
477         }
478
479 #if 1
480         unicode = CharToUnicode(code, registry);
481 #else
482         unicode = code;
483 #endif
484         if (!unicode)
485                 return NULL;
486         if ((error = LoadTrueTypeChar(unicode, 0))) {
487                 fprintf(stderr, "LoadTrueTypeChar fail %d\n", (int)error);
488                 fprintf(stderr, "fontfile: \"%s\" char: '%c' (0x%04x)\n",
489                         tfloadedfont[tfcuridx],
490                         isprint(unicode) ? unicode : '?',
491                         unicode);
492                 return NULL;
493         }
494
495         TT_Get_Glyph_Metrics(glyph[tfcuridx], &metrics);
496
497         /*
498          * TT_Get_Glyph_Pixmap generates pixmap starting from FreeType
499          * origin (leftmost side, baseline). Because of this 3rd and 4th
500          * arguments are necessary.
501          * For X axis (3rd argument), we have to take metrics.bearingX as
502          * offset.  Y axis must be shifted if there's descent box (image
503          * below the baseline).  4th argument is specified for that.
504          */
505         bitmap.rows = (metrics.bbox.yMax - metrics.bbox.yMin) >> 6;
506         bitmap.rows += 2;       /* insurance to cope with number-round error */
507         bitmap.width = metrics.bbox.xMax - metrics.bbox.xMin;
508         bitmap.width >>= 6;
509         bitmap.width += 2;      /* insurance to cope with number-round error */
510         bitmap.cols = (bitmap.width+3) & -4;
511         bitmap.flow   = TT_Flow_Down;
512         bitmap.size   = (long)bitmap.cols * bitmap.rows;
513         bitmap.bitmap = (void *)malloc((int)bitmap.size);
514         memset(bitmap.bitmap, 0, bitmap.size);
515
516         /* be very careful about CEIL/FLOOR. */
517         TT_Get_Glyph_Pixmap(glyph[tfcuridx], &bitmap,
518                 TTCEIL(-metrics.bearingX),
519                 TTCEIL(metrics.bbox.yMax - metrics.bbox.yMin - metrics.bearingY));
520
521         tfc->code = code;
522         tfc->size = size;
523         tfc->width = bitmap.width;
524         tfc->bwidth = bitmap.cols;
525         tfc->height = bitmap.rows;
526         /*
527          * ascent must be derived from descent, to avoid number-rounding
528          * errors.
529          */
530         tfc->descent =
531                 TTCEIL(metrics.bbox.yMax - metrics.bbox.yMin - metrics.bearingY) >> 6;
532         tfc->ascent = bitmap.rows - tfc->descent;
533         tfc->xoff = metrics.bearingX >> 6;
534         tfc->fontname = strdup(fontname);
535         tfc->charlen = metrics.advance >> 6;
536         tfc->xmax = metrics.bbox.xMax >> 6;
537         tfc->ref = 0;
538         tfc->dbitmap = bitmap.bitmap;
539         tfc->regid = get_regid(registry);
540         if (!tfc->charlen) tfc->charlen = 1;
541
542         TFC_INSHASH(tfc);
543         TFC_INSLRU(tfc);
544         tfcachecnt++;
545
546         return tfc;
547 }
548
549 static short
550 CharToUnicode(code, registry)
551         u_int code;
552         char *registry;
553 {
554         TT_CharMap      char_map;
555         unsigned short  i, n;
556         unsigned short  platform, encoding;
557         unsigned int    regid;
558         char                    p;
559
560         /* First, look for a Unicode charmap */
561 #ifdef HAVE_TT_FACE_PROPERTIES_CHARMAPS
562         n = properties[tfcuridx].num_CharMaps;
563 #else
564         n = TT_Get_CharMap_Count(face[tfcuridx]);
565 #endif
566
567 #if 1
568         if (verbose) {
569                 fprintf(stderr, "%d charmaps for font %s code %04x\n",
570                         n, tfloadedfont[tfcuridx], code & 0xffff);
571         }
572 #endif
573
574         for (i = 0; i < n; i++) {
575                 TT_Get_CharMap_ID(face[tfcuridx], i, &platform, &encoding);
576                 if ((platform == 3 && encoding == 1)
577                  || (platform == 0 && encoding == 0)) {
578                         TT_Get_CharMap(face[tfcuridx], i, &char_map);
579 #ifdef FREETYPE_CHARSET16
580                         if (code > 256 && strncmp(registry, "jisx0208.1983-", 14) != 0) {
581                                 /*
582                                  * unicode_map assumes JIS X0208.
583                                  * it is not usable for other encodings.
584                                  * try the next CharMap available.
585                                  */
586                                 continue;
587                         }
588                         if (code > 256)
589                                 code = unicode_map[code];
590 #endif /* FREETYPE_CHARSET16 */
591
592 #if 1 /* latin2-4 encoding processing */
593                         if (code > 0xa0 && code < 256) {
594                                 if (registry)
595                                         regid = get_regid(registry) -1;
596                                 else {
597                                         if (mgp_charset)
598                                                 regid = get_regid(mgp_charset) -1;
599                                 }
600                                 if (latin_unicode_map[regid][code])
601                                         code = latin_unicode_map[regid][code];
602                         }
603 #endif
604
605 /*
606  * For freetype 1.4, suggested by mituharu@math.s.chiba-u.ac.jp 
607  */ 
608 #if TT_FREETYPE_MAJOR == 1 &&  TT_FREETYPE_MINOR == 4
609                         return TT_Char_Index(char_map, (u_short) code);
610 #else
611                         return TT_Char_Index(char_map, (short) code);
612 #endif
613                 }
614 #ifdef FREETYPE_CHARSET16
615                 else {
616                         /*
617                          * very adhoc processing for truetype fonts generated by cb2ttj.
618                          */
619                         if ((platform == 3 && encoding == 2)
620                                 || (platform == 1 && encoding == 1)) {
621                                         if (code < 256) continue;
622                                         TT_Get_CharMap(face[tfcuridx], i, &char_map);
623                                         return TT_Char_Index(char_map, (u_short) jistosjis(code));
624                         } else {
625                                 if (platform == 1 && encoding == 0) {
626                                         if (code >= 0xa0) continue;
627                                         TT_Get_CharMap(face[tfcuridx], i, &char_map);
628                                         return TT_Char_Index(char_map, (short) code);
629                                 }
630                         }
631                 }
632 #endif
633         }
634
635         fprintf(stderr, "Sorry, but the fontfile \"%s\" doesn't "
636                 "contain any Unicode mapping table\n", tfloadedfont[tfcuridx]);
637         return 0;
638 }
639
640 static TT_Error
641 LoadTrueTypeChar(int idx, int hint)
642 {
643         int             flags;
644
645         flags = TTLOAD_SCALE_GLYPH;
646         if (hint)
647                 flags |= TTLOAD_HINT_GLYPH;
648
649         return TT_Load_Glyph(instance[tfcuridx], glyph[tfcuridx], idx, flags);
650 }
651
652 /*
653  * NOTE: this is upper-layer's responsibility to adjust the (bx, by)
654  * so that the font bitmap fits into the given XImage.
655  * see draw_onechar_tf() for the code.
656  */
657 XImage *
658 tfc_image(tfc, fore, back, xim, bx, by)
659         struct tfont *tfc;
660         long fore, back;
661         XImage *xim;
662         int bx, by;
663 {
664         int x, y;
665         static XColor col[5];
666         u_char d, *s;
667         u_long p;
668         XColor *bcol = NULL, *bc;
669         u_int charlen;
670
671         charlen = tfc->charlen;
672
673         if (back == -1) {
674                 u_long r, g, b;
675                 int dots;
676
677                 dots = charlen * tfc->height;
678                 bcol = malloc(sizeof(XColor) * dots);
679                 if (bcol == NULL)
680                         return NULL;
681                 bc = bcol;
682                 for (y = 0; y < tfc->height; y++) {
683                         for (x = 0; x < charlen; x++, bc++) {
684                                 bc->pixel = XGetPixel(xim, bx + tfc->xoff + x,
685                                         by - tfc->ascent + y);
686                                 bc->flags = DoRed|DoGreen|DoBlue;
687                         }
688                 }
689                 XQueryColors(display, colormap, bcol, dots);
690                 r = g = b = 0;
691                 for (y = 0; y < tfc->height; y++) {
692                         for (x = 0; x < charlen; x++) {
693                                 r += bcol[x].red;
694                                 g += bcol[x].green;
695                                 b += bcol[x].blue;
696                         }
697                 }
698                 r /= dots; g /= dots; b /= dots;
699                 bc = &col[0];
700                 if (bc->red == r && bc->green == g && bc->blue == b)
701                         bc->pixel = back;
702                 else {
703                         bc->pixel = ~back;
704                         bc->red   = r; bc->green = g; bc->blue  = b;
705                 }
706         }
707         if (fore != col[4].pixel || back != col[0].pixel) {
708                 col[4].pixel = fore;
709                 col[4].flags = DoRed|DoGreen|DoBlue;
710                 if (back != -1) {
711                         col[3].pixel = back;
712                         col[3].flags = DoRed|DoGreen|DoBlue;
713                         XQueryColors(display, colormap, &col[3], 2);
714                         col[0] = col[3];
715                 } else {
716                         XQueryColor(display, colormap, &col[4]);
717                 }
718                 for (x = 3; x > 0; x--) {
719                         col[x].red   = (col[4].red  *x + col[0].red  *(4-x)) /4;
720                         col[x].green = (col[4].green*x + col[0].green*(4-x)) /4;
721                         col[x].blue  = (col[4].blue *x + col[0].blue *(4-x)) /4;
722                         if (!XAllocColor(display, colormap, &col[x])) {
723                                 if (verbose)
724                                         printf("tfc_image: cannot allocate color for level %d (using %d)\n", x, x + 1);
725                                 col[x].pixel = col[x + 1].pixel;
726                         }
727                         else regist_alloc_colors(&font_clr, &col[x].pixel, 1);
728                 }
729         }
730
731         /* XXX: need optimization */
732         s = tfc->dbitmap;
733         bc = bcol;
734         for (y = 0; y < tfc->height; y++) {
735                 for (x = 0; x < tfc->bwidth; x++) {
736                         d = *s++;
737                         if (d && x < tfc->width) {
738                                 p = col[d].pixel;
739                                 XPutPixel(xim, bx + tfc->xoff + x,
740                                         by - tfc->ascent + y, p);
741                         }
742                 }
743         }
744         if (mgp_flag & FL_GLYPHEDGE) {
745                 /*
746                  * for debugging treatment of font metrics, for 16bpp displays
747                  */
748                 /* pixmap bounding box */
749                 for (y = 0; y < tfc->height; y++) {
750                         XPutPixel(xim, bx + tfc->xoff, by - tfc->ascent + y,
751                                 0xffff);
752                         XPutPixel(xim, bx + tfc->xoff + tfc->width - 1,
753                                 by - tfc->ascent + y, 0xffff);
754                 }
755                 for (x = 0; x < tfc->width; x++) {
756                         XPutPixel(xim, bx + tfc->xoff + x, by - tfc->ascent,
757                                 0xffff);
758                         XPutPixel(xim, bx + tfc->xoff + x,
759                                 by - tfc->ascent + tfc->height - 1, 0xffff);
760                 }
761                 /* origin */
762                 XPutPixel(xim, bx, by, 0xaaaa);
763                 /* baseline */
764                 for (x = 0; x < tfc->width; x++)
765                         XPutPixel(xim, bx + tfc->xoff + x, by, 0xaaaa);
766         }
767         if (bcol)
768                 free(bcol);
769         return xim;
770 }
771
772 static short
773 jistosjis(code)
774         u_int code;
775 {
776         u_char c1 = code >> 8;
777         u_char c2 = code % 256;
778         int rowOffset = c1 < 95 ? 112: 176;
779         int cellOffset = c1 % 2 ? (c2 > 95 ? 32 : 31) : 126;
780
781         return (((c1 + 1) >> 1) + rowOffset) * 256 + c2 + cellOffset;
782 }
783
784 #endif /* FRRETYPE */