2 * Copyright (C) 1997 and 1998 WIDE Project. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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
29 * $Id: tfont.c,v 1.43 2002/01/12 01:56:25 nishida Exp $
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)
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;
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];
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; \
70 #define TFC_DELHASH(tfc) { \
71 struct tfont *n, *p; \
72 n = tfc->next; p = tfc->prev; \
73 n->prev = p; p->next = n; \
75 #define TFC_INSLRU(tfc) { \
77 p = tfclru.lruprev; tfc->lruprev = p; p->lrunext = tfc; \
78 tfclru.lruprev = tfc; tfc->lrunext = &tfclru; \
80 #define TFC_DELLRU(tfc) { \
81 struct tfont *n, *p; \
82 n = tfc->lrunext; p = tfc->lruprev; \
83 n->lruprev = p; p->lrunext = n; \
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));
94 #define TTFLOOR(x) ((x) & -64)
95 #define TTCEIL(x) (((x) + 63) & -64)
103 /* Initialize engine */
104 if ((error = TT_Init_FreeType(&engine))) {
105 fprintf(stderr, "Error while initializing engine, code = %d.\n",
111 for (tfc = tfcache, i = 0; i < TFHASH_SIZE; tfc++, i++)
112 tfc->next = tfc->prev = tfc;
113 tfclru.lrunext = tfclru.lruprev = &tfclru;
116 latin_unicode_map_init();
117 #ifdef FREETYPE_CHARSET16
135 tfc_setsize(char_size)
141 if (tfcuridx < 0 || tffontcnt <= tfcuridx) {
143 fprintf(stderr, "tfc_setsize: font index out of bound\n");
147 error = TT_Set_Instance_CharSize(instance[tfcuridx],
148 (char_size * 0.75) * 64);
151 "Could not set device resolutions for \"%s\".\n",
152 tfloadedfont[tfcuridx]);
159 tfc_get(code, size, force, registry, charset16)
165 struct tfont *tfc, *ntfc;
172 tfc = tfc_lookup(code, size, tf_mcurname, 0);
174 if (code >= 0xa0 && ((!registry || !registry[0]) && mgp_charset)){
175 regid = get_regid(mgp_charset);
177 regid = get_regid(registry);
178 tfc = tfc_lookup(code, size, tf_curname[regid], regid);
183 if (tfcachecnt >= tfcachesize) {
186 tfc = tfclru.lrunext;
187 while (tfcachecnt >= tfcachesize) {
198 tfc = tfc_alloc(code, size, tf_mcurname, registry);
200 tfc = tfc_alloc(code, size, tf_curname[regid], registry);
206 tfc_setfont(name, charset16, registry)
208 int charset16; /*2-octet charset?*/
211 char *fontname = NULL;
213 int res = 96; /* XXX */
214 char pathname[MAXPATHLEN];
221 if (TFFONT_NUM <= tffontcnt) {
222 fprintf(stderr, "internal error: "
223 "too many fonts opened (increase TFFONT_NUM)\n");
227 if (!name || !name[0]) {
228 if (freetypefont0 && freetypefont0[0]) {
230 fprintf(stderr, "tfc_setfont: "
231 "font name not given, "
232 "using last resort (%s)\n",
235 name = freetypefont0;
238 fprintf(stderr, "tfc_setfont: "
239 "font name not given, fail\n");
245 /* check font cache first */
246 for (trial = 0; trial < 2; trial++) {
252 snprintf(pathname, sizeof(pathname),
253 "%s/%s", freetypefontdir, name);
258 for (i = 0; i < tffontcnt; i ++) {
259 if (!strcmp(fontname, tfloadedfont[i])) {
264 "font cache hit for \"%s\"\n",
270 tf_mcurname = tfloadedfont[i];
272 regid = get_regid(registry);
273 tf_curname[regid] = tfloadedfont[i];
276 tfc_setsize(char_size);
283 /* try to load font */
284 for (trial = 0; trial < 3; trial++) {
290 snprintf(pathname, sizeof(pathname),
291 "%s/%s", freetypefontdir, name);
295 if (!freetypefont0 || !freetypefont0[0])
297 fontname = freetypefont0;
298 /* already loaded? */
299 for (i = 0; i < tffontcnt; i ++) {
300 if (!strcmp(fontname, tfloadedfont[i])){
303 fprintf(stderr, "font \"%s\" already loaded: %d\n",
304 fontname, tffontcnt);
312 if (verbose) fprintf(stderr, "trying to open font \"%s\"\n", fontname);
313 error = TT_Open_Face(engine, fontname, &tface);
319 fprintf(stderr, "font \"%s\" not found, "
320 "last resort font \"%s\" was used\n",
321 name, freetypefont0);
323 } else if (trial == 3) {
325 fprintf(stderr, "could not load font \"%s\", "
326 "using other rendering engine\n", name);
331 fprintf(stderr, "font \"%s\" opened successfully\n",
335 /* get registry id */
336 if ((regid = get_regid(registry)) < 0){
337 fprintf(stderr, "font \"%s\" has irregal registry\n", fontname);
341 tfloadedregistry[tffontcnt] = regid;
342 strcpy(tfloadedfont[tffontcnt], fontname);
343 tfcuridx = tffontcnt;
344 face[tfcuridx] = tface;
347 /* get face properties and allocate preload arrays */
348 error = TT_Get_Face_Properties(face[tfcuridx], &properties[tfcuridx]);
350 fprintf(stderr, "Could not create face property for "
351 "\"%s\" (err 0x%04x).\n", fontname, (int)error);
356 error = TT_New_Glyph(face[tfcuridx], &glyph[tfcuridx]);
358 fprintf(stderr, "Could not create glyph container for "
359 "\"%s\" (err 0x%04x).\n", fontname, (int)error);
363 /* create instance */
364 error = TT_New_Instance(face[tfcuridx], &instance[tfcuridx]);
366 fprintf(stderr, "Could not create instance for "
367 "\"%s\" (err 0x%04x).\n", fontname, (int)error);
371 error = TT_Set_Instance_Resolutions(instance[tfcuridx], res, res);
373 fprintf(stderr, "Could not set device resolutions for "
374 "\"%s\" (err 0x%04x).\n", fontname, (int)error);
380 tf_mcurname = tfloadedfont[tfcuridx];
383 tf_curname[regid] = tfloadedfont[tfcuridx];
385 /* this should be default font */
386 for (i = 0; i < 4; i ++)
387 tf_curname[i] = tfloadedfont[tfcuridx];
390 if (tfc_setsize(char_size[caching]) < 0)
397 TT_Close_Face(tface);
401 tf_curname[regid] = "";
408 static struct tfont *
409 tfc_lookup(code, size, fontname, regid)
415 struct tfont *tfc, *htfc;
420 for (i = 0; i < tffontcnt; i ++) {
421 if (!strcmp(fontname, tfloadedfont[i]))
425 htfc = &tfcache[TFCACHE_HASH(code, size)];
426 for (tfc = htfc->next; tfc != htfc; tfc = tfc->next) {
427 if (tfc->code == code
429 && tfc->regid == regid
430 && strcmp(tfc->fontname, fontname) == 0) {
442 static struct tfont *
443 tfc_alloc(code, size, fontname, registry)
451 /* if no font was ever loaded, try loading the last resort font */
454 fprintf(stderr, "no fontcount\n");
455 tfc_setfont(NULL, 0, NULL);
458 /* font out of bounds, suggests no font was available */
459 if (tfcuridx < 0 || tffontcnt <= tfcuridx) {
461 fprintf(stderr, "tfc_alloc: font index out of bound\n");
465 if (fontname == NULL)
469 /* This is required! */
470 if (tfc_setsize(char_size[caching]) < 0)
473 tfc = (struct tfont *)malloc(sizeof(*tfc));
475 fprintf(stderr, "tfc_alloc: malloc failed\n");
480 unicode = CharToUnicode(code, registry);
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 : '?',
495 TT_Get_Glyph_Metrics(glyph[tfcuridx], &metrics);
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.
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;
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);
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));
523 tfc->width = bitmap.width;
524 tfc->bwidth = bitmap.cols;
525 tfc->height = bitmap.rows;
527 * ascent must be derived from descent, to avoid number-rounding
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;
538 tfc->dbitmap = bitmap.bitmap;
539 tfc->regid = get_regid(registry);
540 if (!tfc->charlen) tfc->charlen = 1;
550 CharToUnicode(code, registry)
556 unsigned short platform, encoding;
560 /* First, look for a Unicode charmap */
561 #ifdef HAVE_TT_FACE_PROPERTIES_CHARMAPS
562 n = properties[tfcuridx].num_CharMaps;
564 n = TT_Get_CharMap_Count(face[tfcuridx]);
569 fprintf(stderr, "%d charmaps for font %s code %04x\n",
570 n, tfloadedfont[tfcuridx], code & 0xffff);
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) {
582 * unicode_map assumes JIS X0208.
583 * it is not usable for other encodings.
584 * try the next CharMap available.
589 code = unicode_map[code];
590 #endif /* FREETYPE_CHARSET16 */
592 #if 1 /* latin2-4 encoding processing */
593 if (code > 0xa0 && code < 256) {
595 regid = get_regid(registry) -1;
598 regid = get_regid(mgp_charset) -1;
600 if (latin_unicode_map[regid][code])
601 code = latin_unicode_map[regid][code];
606 * For freetype 1.4, suggested by mituharu@math.s.chiba-u.ac.jp
608 #if TT_FREETYPE_MAJOR == 1 && TT_FREETYPE_MINOR == 4
609 return TT_Char_Index(char_map, (u_short) code);
611 return TT_Char_Index(char_map, (short) code);
614 #ifdef FREETYPE_CHARSET16
617 * very adhoc processing for truetype fonts generated by cb2ttj.
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));
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);
635 fprintf(stderr, "Sorry, but the fontfile \"%s\" doesn't "
636 "contain any Unicode mapping table\n", tfloadedfont[tfcuridx]);
641 LoadTrueTypeChar(int idx, int hint)
645 flags = TTLOAD_SCALE_GLYPH;
647 flags |= TTLOAD_HINT_GLYPH;
649 return TT_Load_Glyph(instance[tfcuridx], glyph[tfcuridx], idx, flags);
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.
658 tfc_image(tfc, fore, back, xim, bx, by)
665 static XColor col[5];
668 XColor *bcol = NULL, *bc;
671 charlen = tfc->charlen;
677 dots = charlen * tfc->height;
678 bcol = malloc(sizeof(XColor) * dots);
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;
689 XQueryColors(display, colormap, bcol, dots);
691 for (y = 0; y < tfc->height; y++) {
692 for (x = 0; x < charlen; x++) {
698 r /= dots; g /= dots; b /= dots;
700 if (bc->red == r && bc->green == g && bc->blue == b)
704 bc->red = r; bc->green = g; bc->blue = b;
707 if (fore != col[4].pixel || back != col[0].pixel) {
709 col[4].flags = DoRed|DoGreen|DoBlue;
712 col[3].flags = DoRed|DoGreen|DoBlue;
713 XQueryColors(display, colormap, &col[3], 2);
716 XQueryColor(display, colormap, &col[4]);
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])) {
724 printf("tfc_image: cannot allocate color for level %d (using %d)\n", x, x + 1);
725 col[x].pixel = col[x + 1].pixel;
727 else regist_alloc_colors(&font_clr, &col[x].pixel, 1);
731 /* XXX: need optimization */
734 for (y = 0; y < tfc->height; y++) {
735 for (x = 0; x < tfc->bwidth; x++) {
737 if (d && x < tfc->width) {
739 XPutPixel(xim, bx + tfc->xoff + x,
740 by - tfc->ascent + y, p);
744 if (mgp_flag & FL_GLYPHEDGE) {
746 * for debugging treatment of font metrics, for 16bpp displays
748 /* pixmap bounding box */
749 for (y = 0; y < tfc->height; y++) {
750 XPutPixel(xim, bx + tfc->xoff, by - tfc->ascent + y,
752 XPutPixel(xim, bx + tfc->xoff + tfc->width - 1,
753 by - tfc->ascent + y, 0xffff);
755 for (x = 0; x < tfc->width; x++) {
756 XPutPixel(xim, bx + tfc->xoff + x, by - tfc->ascent,
758 XPutPixel(xim, bx + tfc->xoff + x,
759 by - tfc->ascent + tfc->height - 1, 0xffff);
762 XPutPixel(xim, bx, by, 0xaaaa);
764 for (x = 0; x < tfc->width; x++)
765 XPutPixel(xim, bx + tfc->xoff + x, by, 0xaaaa);
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;
781 return (((c1 + 1) >> 1) + rowOffset) * 256 + c2 + cellOffset;
784 #endif /* FRRETYPE */