--- ray/src/common/font.c 1992/06/16 13:16:50 2.2 +++ ray/src/common/font.c 2004/03/26 21:29:19 2.18 @@ -1,21 +1,22 @@ -/* Copyright (c) 1992 Regents of the University of California */ - #ifndef lint -static char SCCSid[] = "$SunId$ LBL"; +static const char RCSid[] = "$Id: font.c,v 2.18 2004/03/26 21:29:19 schorsch Exp $"; #endif - /* * Polygonal font handling routines */ -#include "standard.h" +#include "copyright.h" +#include + +#include "rtio.h" +#include "rterror.h" #include "font.h" #define galloc(nv) (GLYPH *)malloc(sizeof(GLYPH)+2*sizeof(GORD)*(nv)) -extern char *libpath; /* list of library directories */ +int retainfonts = 0; /* retain loaded fonts? */ static FONT *fontlist = NULL; /* list of loaded fonts */ @@ -24,20 +25,21 @@ FONT * getfont(fname) /* return font fname */ char *fname; { - char buf[16]; FILE *fp; - char *pathname, *err; - int gn, ngv; - register int gv; - register GLYPH *g; + char *pathname, *err = NULL; + unsigned wsum, hsum, ngly; + int gn, ngv, gv; + register GLYPH *g; GORD *gp; register FONT *f; for (f = fontlist; f != NULL; f = f->next) - if (!strcmp(f->name, fname)) + if (!strcmp(f->name, fname)) { + f->nref++; return(f); + } /* load the font file */ - if ((pathname = getpath(fname, libpath, R_OK)) == NULL) { + if ((pathname = getpath(fname, getrlibpath(), R_OK)) == NULL) { sprintf(errmsg, "cannot find font file \"%s\"", fname); error(USER, errmsg); } @@ -45,16 +47,17 @@ char *fname; if (f == NULL) goto memerr; f->name = savestr(fname); + f->nref = 1; if ((fp = fopen(pathname, "r")) == NULL) { sprintf(errmsg, "cannot open font file \"%s\"", pathname); error(SYSTEM, errmsg); } - while (fgetword(buf,sizeof(buf),fp) != NULL) { /* get each glyph */ - if (!isint(buf)) + wsum = hsum = ngly = 0; /* get each glyph */ + while ((ngv = fgetval(fp, 'i', (char *)&gn)) != EOF) { + if (ngv == 0) goto nonint; - gn = atoi(buf); - if (gn < 0 || gn > 255) { + if (gn < 1 || gn > 255) { err = "illegal"; goto fonterr; } @@ -62,8 +65,8 @@ char *fname; err = "duplicate"; goto fonterr; } - if (fgetword(buf,sizeof(buf),fp) == NULL || !isint(buf) || - (ngv = atoi(buf)) < 0 || ngv > 32000) { + if (fgetval(fp, 'i', (char *)&ngv) <= 0 || + ngv < 0 || ngv > 32000) { err = "bad # vertices for"; goto fonterr; } @@ -75,9 +78,8 @@ char *fname; ngv *= 2; gp = gvlist(g); while (ngv--) { - if (fgetword(buf,sizeof(buf),fp) == NULL || - !isint(buf) || - (gv = atoi(buf)) < 0 || gv > 255) { + if (fgetval(fp, 'i', (char *)&gv) <= 0 || + gv < 0 || gv > 255) { err = "bad vertex for"; goto fonterr; } @@ -94,9 +96,18 @@ char *fname; g->top = gv; } } + if (g->right - g->left && g->top - g->bottom) { + ngly++; + wsum += g->right - g->left; + hsum += g->top - g->bottom; + } f->fg[gn] = g; } fclose(fp); + if (ngly) { + f->mwidth = wsum / ngly; + f->mheight = hsum / ngly; + } f->next = fontlist; return(fontlist = f); nonint: @@ -108,10 +119,55 @@ fonterr: error(USER, errmsg); memerr: error(SYSTEM, "out of memory in fontglyph"); + return NULL; /* pro forma return */ } +void +freefont(fnt) /* release a font (free all if NULL) */ +FONT *fnt; +{ + FONT head; + register FONT *fl, *f; + register int i; + /* check reference count */ + if (fnt != NULL && ((fnt->nref-- > 1) | retainfonts)) + return; + head.next = fontlist; + fl = &head; + while ((f = fl->next) != NULL) + if ((fnt == NULL) | (fnt == f)) { + fl->next = f->next; + for (i = 0; i < 256; i++) + if (f->fg[i] != NULL) + free((void *)f->fg[i]); + freestr(f->name); + free((void *)f); + } else + fl = f; + fontlist = head.next; +} + + int +uniftext(sp, tp, f) /* uniformly space text line */ +register short *sp; /* returned character spacing */ +register char *tp; /* text line */ +register FONT *f; /* font */ +{ + int linelen; + + linelen = *sp++ = 0; + while (*tp) + if (f->fg[*tp++&0xff] == NULL) + *sp++ = 0; + else + linelen += *sp++ = 255; + return(linelen); +} + + +int squeeztext(sp, tp, f, cis) /* squeeze text line */ short *sp; /* returned character spacing */ char *tp; /* text line */ @@ -119,20 +175,21 @@ FONT *f; /* font */ int cis; /* intercharacter spacing */ { int linelen; - register GLYPH *gp; + register GLYPH *gp; + linelen = 0; gp = NULL; while (*tp && (gp = f->fg[*tp++&0xff]) == NULL) *sp++ = 0; cis /= 2; - linelen = *sp = 0; + *sp = cis; while (gp != NULL) { if (gp->nverts) { /* regular character */ linelen += *sp++ += cis - gp->left; *sp = gp->right + cis; } else { /* space */ linelen += *sp++; - *sp = 256; + *sp = f->mwidth; } gp = NULL; while (*tp && (gp = f->fg[*tp++&0xff]) == NULL) { @@ -140,11 +197,12 @@ int cis; /* intercharacter spacing */ *sp = 0; } } - linelen += *sp; + linelen += *sp += cis; return(linelen); } +int proptext(sp, tp, f, cis, nsi) /* space line proportionally */ short *sp; /* returned character spacing */ char *tp; /* text line */ @@ -152,6 +210,40 @@ FONT *f; /* font */ int cis; /* target intercharacter spacing */ int nsi; /* minimum number of spaces for indent */ { + register char *end, *tab = NULL; + GLYPH *gp; + short *nsp; + int alen, len, width; + /* start by squeezing it */ + squeeztext(sp, tp, f, cis); + /* now, realign spacing */ + width = *sp++; + while (*tp) { + len = alen = 0; + nsp = sp; + for (end = tp; *end; end = tab) { + tab = end + 1; + alen += *nsp++; + if (f->fg[*end&0xff]) { + while ((gp = f->fg[*tab&0xff]) != NULL && + gp->nverts == 0) { /* tab in */ + alen += *nsp++; + tab++; + } + len += tab - end; + } + if (nsi && tab - end > nsi) + break; + } + len *= f->mwidth + cis; /* compute target length */ + width += len; + len -= alen; /* necessary adjustment */ + while (sp < nsp) { + alen = len/(nsp-sp); + *sp++ += alen; + len -= alen; + } + tp = tab; + } + return(width); } - -