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.45 2007/11/24 17:29:40 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
tfc_init()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
tfc_free(tfc)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
tfc_setsize(char_size)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 *
tfc_get(code,size,force,registry,charset16)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
tfc_setfont(name,charset16,registry)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 *
tfc_lookup(code,size,fontname,regid)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 *
tfc_alloc(code,size,fontname,registry)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
CharToUnicode(code,registry)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 				int tempregid;
595 				if (registry)
596 					tempregid = get_regid(registry) -1;
597 				else {
598 					if (mgp_charset)
599 						tempregid = get_regid(mgp_charset)-1;
600 				}
601 				if (tempregid >= 0) {
602 					regid = tempregid;
603 					if (latin_unicode_map[regid][code])
604 					code = latin_unicode_map[regid][code];
605 				}
606 			}
607 #endif
608 
609 /*
610  * For freetype 1.4, suggested by mituharu@math.s.chiba-u.ac.jp
611  */
612 #if TT_FREETYPE_MAJOR == 1 &&  TT_FREETYPE_MINOR == 4
613 			return TT_Char_Index(char_map, (u_short) code);
614 #else
615 			return TT_Char_Index(char_map, (short) code);
616 #endif
617 		}
618 #ifdef FREETYPE_CHARSET16
619 		else {
620 			/*
621 			 * very adhoc processing for truetype fonts generated by cb2ttj.
622 			 */
623 			if ((platform == 3 && encoding == 2)
624 		 		|| (platform == 1 && encoding == 1)) {
625 					if (code < 256) continue;
626 					TT_Get_CharMap(face[tfcuridx], i, &char_map);
627 					return TT_Char_Index(char_map, (u_short) jistosjis(code));
628 			} else {
629 				if (platform == 1 && encoding == 0) {
630 					if (code >= 0xa0) continue;
631 					TT_Get_CharMap(face[tfcuridx], i, &char_map);
632 					return TT_Char_Index(char_map, (short) code);
633 				}
634 #endif
635 				else {
636 					/* symbol font */
637 					if (platform == 3 && encoding == 0) {
638 						code |= 0xf000;
639 						TT_Get_CharMap(face[tfcuridx],
640 								i, &char_map);
641 						return TT_Char_Index(char_map,
642 								code);
643 					}
644 				}
645 #ifdef FREETYPE_CHARSET16
646 			}
647 		}
648 #endif
649 	}
650 
651 	fprintf(stderr, "Sorry, but the fontfile \"%s\" doesn't "
652 		"contain any Unicode mapping table\n", tfloadedfont[tfcuridx]);
653 	return 0;
654 }
655 
656 static TT_Error
LoadTrueTypeChar(int idx,int hint)657 LoadTrueTypeChar(int idx, int hint)
658 {
659 	int             flags;
660 
661 	flags = TTLOAD_SCALE_GLYPH;
662 	if (hint)
663 		flags |= TTLOAD_HINT_GLYPH;
664 
665 	return TT_Load_Glyph(instance[tfcuridx], glyph[tfcuridx], idx, flags);
666 }
667 
668 /*
669  * NOTE: this is upper-layer's responsibility to adjust the (bx, by)
670  * so that the font bitmap fits into the given XImage.
671  * see draw_onechar_tf() for the code.
672  */
673 XImage *
tfc_image(tfc,fore,back,xim,bx,by)674 tfc_image(tfc, fore, back, xim, bx, by)
675 	struct tfont *tfc;
676 	long fore, back;
677 	XImage *xim;
678 	int bx, by;
679 {
680 	int x, y;
681 	static XColor col[5];
682 	u_char d, *s;
683 	u_long p;
684 	XColor *bcol = NULL, *bc;
685 	u_int charlen;
686 
687 	charlen = tfc->charlen;
688 
689 	if (back == -1) {
690 		u_long r, g, b;
691 		int dots;
692 
693 		dots = charlen * tfc->height;
694 		bcol = malloc(sizeof(XColor) * dots);
695 		if (bcol == NULL)
696 			return NULL;
697 		bc = bcol;
698 		for (y = 0; y < tfc->height; y++) {
699 			for (x = 0; x < charlen; x++, bc++) {
700 				bc->pixel = XGetPixel(xim, bx + tfc->xoff + x,
701 					by - tfc->ascent + y);
702 				bc->flags = DoRed|DoGreen|DoBlue;
703 			}
704 		}
705 		XQueryColors(display, colormap, bcol, dots);
706 		r = g = b = 0;
707 		for (y = 0; y < tfc->height; y++) {
708 			for (x = 0; x < charlen; x++) {
709 				r += bcol[x].red;
710 				g += bcol[x].green;
711 				b += bcol[x].blue;
712 			}
713 		}
714 		r /= dots; g /= dots; b /= dots;
715 		bc = &col[0];
716 		if (bc->red == r && bc->green == g && bc->blue == b)
717 			bc->pixel = back;
718 		else {
719 			bc->pixel = ~back;
720 			bc->red   = r; bc->green = g; bc->blue  = b;
721 		}
722 	}
723 	if (fore != col[4].pixel || back != col[0].pixel) {
724 		col[4].pixel = fore;
725 		col[4].flags = DoRed|DoGreen|DoBlue;
726 		if (back != -1) {
727 			col[3].pixel = back;
728 			col[3].flags = DoRed|DoGreen|DoBlue;
729 			XQueryColors(display, colormap, &col[3], 2);
730 			col[0] = col[3];
731 		} else {
732 			XQueryColor(display, colormap, &col[4]);
733 		}
734 		for (x = 3; x > 0; x--) {
735 			col[x].red   = (col[4].red  *x + col[0].red  *(4-x)) /4;
736 			col[x].green = (col[4].green*x + col[0].green*(4-x)) /4;
737 			col[x].blue  = (col[4].blue *x + col[0].blue *(4-x)) /4;
738 			if (!XAllocColor(display, colormap, &col[x])) {
739 				if (verbose)
740 					printf("tfc_image: cannot allocate color for level %d (using %d)\n", x, x + 1);
741 				col[x].pixel = col[x + 1].pixel;
742 			}
743 			else regist_alloc_colors(&font_clr, &col[x].pixel, 1);
744 		}
745 	}
746 
747 	/* XXX: need optimization */
748 	s = tfc->dbitmap;
749 	bc = bcol;
750 	for (y = 0; y < tfc->height; y++) {
751 		for (x = 0; x < tfc->bwidth; x++) {
752 			d = *s++;
753 			if (d && x < tfc->width) {
754 				p = col[d].pixel;
755 				XPutPixel(xim, bx + tfc->xoff + x,
756 					by - tfc->ascent + y, p);
757 			}
758 		}
759 	}
760 	if (mgp_flag & FL_GLYPHEDGE) {
761 		/*
762 		 * for debugging treatment of font metrics, for 16bpp displays
763 		 */
764 		/* pixmap bounding box */
765 		for (y = 0; y < tfc->height; y++) {
766 			XPutPixel(xim, bx + tfc->xoff, by - tfc->ascent + y,
767 				0xffff);
768 			XPutPixel(xim, bx + tfc->xoff + tfc->width - 1,
769 				by - tfc->ascent + y, 0xffff);
770 		}
771 		for (x = 0; x < tfc->width; x++) {
772 			XPutPixel(xim, bx + tfc->xoff + x, by - tfc->ascent,
773 				0xffff);
774 			XPutPixel(xim, bx + tfc->xoff + x,
775 				by - tfc->ascent + tfc->height - 1, 0xffff);
776 		}
777 		/* origin */
778 		XPutPixel(xim, bx, by, 0xaaaa);
779 		/* baseline */
780 		for (x = 0; x < tfc->width; x++)
781 			XPutPixel(xim, bx + tfc->xoff + x, by, 0xaaaa);
782 	}
783 	if (bcol)
784 		free(bcol);
785 	return xim;
786 }
787 
788 static short
jistosjis(code)789 jistosjis(code)
790 	u_int code;
791 {
792 	u_char c1 = code >> 8;
793 	u_char c2 = code % 256;
794 	int rowOffset = c1 < 95 ? 112: 176;
795 	int cellOffset = c1 % 2 ? (c2 > 95 ? 32 : 31) : 126;
796 
797 	return (((c1 + 1) >> 1) + rowOffset) * 256 + c2 + cellOffset;
798 }
799 
800 #endif /* FRRETYPE */
801