Back to index

radiance  4R0+20100331
font.c
Go to the documentation of this file.
00001 #ifndef lint
00002 static const char    RCSid[] = "$Id: font.c,v 2.19 2004/03/26 23:04:23 greg Exp $";
00003 #endif
00004 /*
00005  * Polygonal font handling routines
00006  */
00007 
00008 #include "copyright.h"
00009 
00010 #include <stdlib.h>
00011 
00012 #include "paths.h"
00013 #include "rtio.h"
00014 #include "rterror.h"
00015 #include "font.h"
00016 
00017 #define galloc(nv)   (GLYPH *)malloc(sizeof(GLYPH)+2*sizeof(GORD)*(nv))
00018 
00019 
00020 int    retainfonts = 0;            /* retain loaded fonts? */
00021 
00022 static FONT   *fontlist = NULL;    /* list of loaded fonts */
00023 
00024 
00025 FONT *
00026 getfont(fname)                            /* return font fname */
00027 char  *fname;
00028 {
00029        FILE  *fp;
00030        char  *pathname, *err = NULL;
00031        unsigned  wsum, hsum, ngly;
00032        int  gn, ngv, gv;
00033        register GLYPH       *g;
00034        GORD  *gp;
00035        register FONT  *f;
00036 
00037        for (f = fontlist; f != NULL; f = f->next)
00038               if (!strcmp(f->name, fname)) {
00039                      f->nref++;
00040                      return(f);
00041               }
00042                                           /* load the font file */
00043        if ((pathname = getpath(fname, getrlibpath(), R_OK)) == NULL) {
00044               sprintf(errmsg, "cannot find font file \"%s\"", fname);
00045               error(USER, errmsg);
00046        }
00047        f = (FONT *)calloc(1, sizeof(FONT));
00048        if (f == NULL)
00049               goto memerr;
00050        f->name = savestr(fname);
00051        f->nref = 1;
00052        if ((fp = fopen(pathname, "r")) == NULL) {
00053               sprintf(errmsg, "cannot open font file \"%s\"",
00054                             pathname);
00055               error(SYSTEM, errmsg);
00056        }
00057        wsum = hsum = ngly = 0;                   /* get each glyph */
00058        while ((ngv = fgetval(fp, 'i', (char *)&gn)) != EOF) {
00059               if (ngv == 0)
00060                      goto nonint;
00061               if (gn < 1 || gn > 255) {
00062                      err = "illegal";
00063                      goto fonterr;
00064               }
00065               if (f->fg[gn] != NULL) {
00066                      err = "duplicate";
00067                      goto fonterr;
00068               }
00069               if (fgetval(fp, 'i', (char *)&ngv) <= 0 ||
00070                             ngv < 0 || ngv > 32000) {
00071                      err = "bad # vertices for";
00072                      goto fonterr;
00073               }
00074               g = galloc(ngv);
00075               if (g == NULL)
00076                      goto memerr;
00077               g->nverts = ngv;
00078               g->left = g->right = g->top = g->bottom = 128;
00079               ngv *= 2;
00080               gp = gvlist(g);
00081               while (ngv--) {
00082                      if (fgetval(fp, 'i', (char *)&gv) <= 0 ||
00083                                    gv < 0 || gv > 255) {
00084                             err = "bad vertex for";
00085                             goto fonterr;
00086                      }
00087                      *gp++ = gv;
00088                      if (ngv & 1) {              /* follow x limits */
00089                             if (gv < g->left)
00090                                    g->left = gv;
00091                             else if (gv > g->right)
00092                                    g->right = gv;
00093                      } else {             /* follow y limits */
00094                             if (gv < g->bottom)
00095                                    g->bottom = gv;
00096                             else if (gv > g->top)
00097                                    g->top = gv;
00098                      }
00099               }
00100               if (g->right - g->left && g->top - g->bottom) {
00101                      ngly++;
00102                      wsum += g->right - g->left;
00103                      hsum += g->top - g->bottom;
00104               }
00105               f->fg[gn] = g;
00106        }
00107        fclose(fp);
00108        if (ngly) {
00109               f->mwidth = wsum / ngly;
00110               f->mheight = hsum / ngly;
00111        }
00112        f->next = fontlist;
00113        return(fontlist = f);
00114 nonint:
00115        sprintf(errmsg, "non-integer in font file \"%s\"", pathname);
00116        error(USER, errmsg);
00117 fonterr:
00118        sprintf(errmsg, "%s character (%d) in font file \"%s\"",
00119                      err, gn, pathname);
00120        error(USER, errmsg);
00121 memerr:
00122        error(SYSTEM, "out of memory in fontglyph");
00123        return NULL; /* pro forma return */
00124 }
00125 
00126 
00127 void
00128 freefont(fnt)               /* release a font (free all if NULL) */
00129 FONT *fnt;
00130 {
00131        FONT  head;
00132        register FONT  *fl, *f;
00133        register int  i;
00134                                    /* check reference count */
00135        if (fnt != NULL && ((fnt->nref-- > 1) | retainfonts))
00136               return;
00137        head.next = fontlist;
00138        fl = &head;
00139        while ((f = fl->next) != NULL)
00140               if ((fnt == NULL) | (fnt == f)) {
00141                      fl->next = f->next;
00142                      for (i = 0; i < 256; i++)
00143                             if (f->fg[i] != NULL)
00144                                    free((void *)f->fg[i]);
00145                      freestr(f->name);
00146                      free((void *)f);
00147               } else
00148                      fl = f;
00149        fontlist = head.next;
00150 }
00151 
00152 
00153 int
00154 uniftext(sp, tp, f)                /* uniformly space text line */
00155 register short       *sp;          /* returned character spacing */
00156 register char  *tp;         /* text line */
00157 register FONT  *f;          /* font */
00158 {
00159        int  linelen;
00160 
00161        linelen = *sp++ = 0;
00162        while (*tp)
00163               if (f->fg[*tp++&0xff] == NULL)
00164                      *sp++ = 0;
00165               else
00166                      linelen += *sp++ = 255;
00167        return(linelen);
00168 }
00169 
00170 
00171 int
00172 squeeztext(sp, tp, f, cis)         /* squeeze text line */
00173 short  *sp;                 /* returned character spacing */
00174 char  *tp;                  /* text line */
00175 FONT  *f;                   /* font */
00176 int  cis;                   /* intercharacter spacing */
00177 {
00178        int  linelen;
00179        register GLYPH       *gp;
00180 
00181        linelen = 0;
00182        gp = NULL;
00183        while (*tp && (gp = f->fg[*tp++&0xff]) == NULL)
00184               *sp++ = 0;
00185        cis /= 2;
00186        *sp = cis;
00187        while (gp != NULL) {
00188               if (gp->nverts) {           /* regular character */
00189                      linelen += *sp++ += cis - gp->left;
00190                      *sp = gp->right + cis;
00191               } else {                    /* space */
00192                      linelen += *sp++;
00193                      *sp = f->mwidth;
00194               }
00195               gp = NULL;
00196               while (*tp && (gp = f->fg[*tp++&0xff]) == NULL) {
00197                      linelen += *sp++;
00198                      *sp = 0;
00199               }
00200        }
00201        linelen += *sp += cis;
00202        return(linelen);
00203 }
00204 
00205 
00206 int
00207 proptext(sp, tp, f, cis, nsi)             /* space line proportionally */
00208 short  *sp;                 /* returned character spacing */
00209 char  *tp;                  /* text line */
00210 FONT  *f;                   /* font */
00211 int  cis;                   /* target intercharacter spacing */
00212 int  nsi;                   /* minimum number of spaces for indent */
00213 {
00214        register char  *end, *tab = NULL;
00215        GLYPH  *gp;
00216        short  *nsp;
00217        int  alen, len, width;
00218                                    /* start by squeezing it */
00219        squeeztext(sp, tp, f, cis);
00220                                    /* now, realign spacing */
00221        width = *sp++;
00222        while (*tp) {
00223               len = alen = 0;
00224               nsp = sp;
00225               for (end = tp; *end; end = tab) {
00226                      tab = end + 1;
00227                      alen += *nsp++;
00228                      if (f->fg[*end&0xff]) {
00229                             while ((gp = f->fg[*tab&0xff]) != NULL &&
00230                                           gp->nverts == 0) { /* tab in */
00231                                    alen += *nsp++;
00232                                    tab++;
00233                             }
00234                             len += tab - end;
00235                      }
00236                      if (nsi && tab - end > nsi)
00237                             break;
00238               }
00239               len *= f->mwidth + cis;            /* compute target length */
00240               width += len;
00241               len -= alen;                /* necessary adjustment */
00242               while (sp < nsp) {
00243                      alen = len/(nsp-sp);
00244                      *sp++ += alen;
00245                      len -= alen;
00246               }
00247               tp = tab;
00248        }
00249        return(width);
00250 }