ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/font.c
Revision: 2.25
Committed: Wed Feb 2 00:01:48 2022 UTC (2 years, 3 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.24: +4 -2 lines
Log Message:
feat: added maximum # glyph vertices for font

File Contents

# User Rev Content
1 greg 2.1 #ifndef lint
2 greg 2.25 static const char RCSid[] = "$Id: font.c,v 2.24 2021/11/20 22:39:01 greg Exp $";
3 greg 2.1 #endif
4     /*
5     * Polygonal font handling routines
6     */
7    
8 greg 2.13 #include "copyright.h"
9 greg 2.12
10 schorsch 2.18 #include <stdlib.h>
11    
12 greg 2.19 #include "paths.h"
13 schorsch 2.17 #include "rtio.h"
14 greg 2.23 #include "rterror.h"
15 greg 2.1 #include "font.h"
16    
17     #define galloc(nv) (GLYPH *)malloc(sizeof(GLYPH)+2*sizeof(GORD)*(nv))
18    
19 greg 2.12 int retainfonts = 0; /* retain loaded fonts? */
20 greg 2.1
21     static FONT *fontlist = NULL; /* list of loaded fonts */
22    
23    
24     FONT *
25 greg 2.21 getfont( /* return font fname */
26     char *fname
27     )
28 greg 2.1 {
29 greg 2.24 char embuf[512];
30 greg 2.1 FILE *fp;
31 schorsch 2.17 char *pathname, *err = NULL;
32 greg 2.3 unsigned wsum, hsum, ngly;
33 greg 2.11 int gn, ngv, gv;
34 greg 2.21 GLYPH *g;
35 greg 2.1 GORD *gp;
36 greg 2.21 FONT *f;
37 greg 2.1
38     for (f = fontlist; f != NULL; f = f->next)
39 greg 2.12 if (!strcmp(f->name, fname)) {
40     f->nref++;
41 greg 2.1 return(f);
42 greg 2.12 }
43 greg 2.1 /* load the font file */
44 greg 2.14 if ((pathname = getpath(fname, getrlibpath(), R_OK)) == NULL) {
45 greg 2.24 sprintf(embuf, "cannot find font file \"%s\"\n", fname);
46     eputs(embuf);
47 greg 2.22 return(NULL);
48     }
49     if ((fp = fopen(pathname, "r")) == NULL) {
50 greg 2.24 sprintf(embuf, "cannot open font file \"%s\"\n", pathname);
51     eputs(embuf);
52 greg 2.22 return(NULL);
53 greg 2.1 }
54     f = (FONT *)calloc(1, sizeof(FONT));
55     if (f == NULL)
56     goto memerr;
57 greg 2.22 strcpy(f->name, fname);
58 greg 2.12 f->nref = 1;
59     wsum = hsum = ngly = 0; /* get each glyph */
60     while ((ngv = fgetval(fp, 'i', (char *)&gn)) != EOF) {
61 greg 2.11 if (ngv == 0)
62 greg 2.1 goto nonint;
63 greg 2.3 if (gn < 1 || gn > 255) {
64 greg 2.1 err = "illegal";
65     goto fonterr;
66     }
67     if (f->fg[gn] != NULL) {
68     err = "duplicate";
69     goto fonterr;
70     }
71 greg 2.12 if (fgetval(fp, 'i', (char *)&ngv) <= 0 ||
72     ngv < 0 || ngv > 32000) {
73 greg 2.1 err = "bad # vertices for";
74     goto fonterr;
75     }
76 greg 2.25 if (ngv > f->maxgv)
77     f->maxgv = ngv;
78 greg 2.1 g = galloc(ngv);
79     if (g == NULL)
80     goto memerr;
81     g->nverts = ngv;
82 greg 2.2 g->left = g->right = g->top = g->bottom = 128;
83 greg 2.1 ngv *= 2;
84     gp = gvlist(g);
85     while (ngv--) {
86 greg 2.12 if (fgetval(fp, 'i', (char *)&gv) <= 0 ||
87     gv < 0 || gv > 255) {
88 greg 2.1 err = "bad vertex for";
89     goto fonterr;
90     }
91     *gp++ = gv;
92 greg 2.2 if (ngv & 1) { /* follow x limits */
93     if (gv < g->left)
94     g->left = gv;
95     else if (gv > g->right)
96     g->right = gv;
97     } else { /* follow y limits */
98     if (gv < g->bottom)
99     g->bottom = gv;
100     else if (gv > g->top)
101     g->top = gv;
102     }
103 greg 2.1 }
104 greg 2.3 if (g->right - g->left && g->top - g->bottom) {
105     ngly++;
106     wsum += g->right - g->left;
107     hsum += g->top - g->bottom;
108     }
109 greg 2.1 f->fg[gn] = g;
110     }
111     fclose(fp);
112 greg 2.3 if (ngly) {
113     f->mwidth = wsum / ngly;
114     f->mheight = hsum / ngly;
115     }
116 greg 2.1 f->next = fontlist;
117     return(fontlist = f);
118     nonint:
119 greg 2.24 sprintf(embuf, "non-integer in font file \"%s\"\n", pathname);
120     eputs(embuf);
121 greg 2.22 fclose(fp);
122     return(NULL);
123 greg 2.1 fonterr:
124 greg 2.24 sprintf(embuf, "%s character (%d) in font file \"%s\"\n",
125 greg 2.1 err, gn, pathname);
126 greg 2.24 eputs(embuf);
127 greg 2.22 fclose(fp);
128     return(NULL);
129 greg 2.1 memerr:
130 greg 2.23 eputs("out of memory in getfont()\n");
131 greg 2.22 fclose(fp);
132     return(NULL);
133 greg 2.1 }
134 greg 2.2
135    
136 greg 2.12 void
137 greg 2.21 freefont( /* release a font (free all if NULL) */
138     FONT *fnt
139     )
140 greg 2.6 {
141     FONT head;
142 greg 2.21 FONT *fl, *f;
143     int i;
144 greg 2.12 /* check reference count */
145 greg 2.25 if (fnt != NULL && (fnt->nref -= (f->nref > 0)) | retainfonts))
146 greg 2.12 return;
147 greg 2.6 head.next = fontlist;
148     fl = &head;
149     while ((f = fl->next) != NULL)
150 schorsch 2.16 if ((fnt == NULL) | (fnt == f)) {
151 greg 2.6 fl->next = f->next;
152     for (i = 0; i < 256; i++)
153     if (f->fg[i] != NULL)
154 greg 2.12 free((void *)f->fg[i]);
155     free((void *)f);
156 greg 2.6 } else
157     fl = f;
158     fontlist = head.next;
159     }
160    
161    
162 greg 2.2 int
163 greg 2.21 uniftext( /* uniformly space text line */
164     short *sp, /* returned character spacing */
165     char *tp, /* text line */
166     FONT *f /* font */
167     )
168 greg 2.3 {
169     int linelen;
170    
171     linelen = *sp++ = 0;
172     while (*tp)
173     if (f->fg[*tp++&0xff] == NULL)
174     *sp++ = 0;
175     else
176 greg 2.10 linelen += *sp++ = 255;
177 greg 2.3 return(linelen);
178     }
179    
180    
181     int
182 greg 2.21 squeeztext( /* squeeze text line */
183     short *sp, /* returned character spacing */
184     char *tp, /* text line */
185     FONT *f, /* font */
186     int cis /* intercharacter spacing */
187     )
188 greg 2.2 {
189     int linelen;
190 greg 2.21 GLYPH *gp;
191 greg 2.2
192 greg 2.8 linelen = 0;
193 greg 2.2 gp = NULL;
194     while (*tp && (gp = f->fg[*tp++&0xff]) == NULL)
195     *sp++ = 0;
196     cis /= 2;
197 greg 2.8 *sp = cis;
198 greg 2.2 while (gp != NULL) {
199     if (gp->nverts) { /* regular character */
200     linelen += *sp++ += cis - gp->left;
201     *sp = gp->right + cis;
202     } else { /* space */
203     linelen += *sp++;
204 greg 2.3 *sp = f->mwidth;
205 greg 2.2 }
206     gp = NULL;
207     while (*tp && (gp = f->fg[*tp++&0xff]) == NULL) {
208     linelen += *sp++;
209     *sp = 0;
210     }
211     }
212 greg 2.3 linelen += *sp += cis;
213 greg 2.2 return(linelen);
214     }
215    
216    
217 greg 2.3 int
218 greg 2.21 proptext( /* space line proportionally */
219     short *sp, /* returned character spacing */
220     char *tp, /* text line */
221     FONT *f, /* font */
222     int cis, /* target intercharacter spacing */
223     int nsi /* minimum number of spaces for indent */
224     )
225 greg 2.2 {
226 greg 2.21 char *end, *tab = NULL;
227 greg 2.3 GLYPH *gp;
228     short *nsp;
229     int alen, len, width;
230     /* start by squeezing it */
231     squeeztext(sp, tp, f, cis);
232     /* now, realign spacing */
233 greg 2.7 width = *sp++;
234 greg 2.3 while (*tp) {
235 greg 2.7 len = alen = 0;
236 greg 2.3 nsp = sp;
237     for (end = tp; *end; end = tab) {
238     tab = end + 1;
239     alen += *nsp++;
240     if (f->fg[*end&0xff]) {
241     while ((gp = f->fg[*tab&0xff]) != NULL &&
242     gp->nverts == 0) { /* tab in */
243     alen += *nsp++;
244     tab++;
245     }
246     len += tab - end;
247     }
248 greg 2.4 if (nsi && tab - end > nsi)
249 greg 2.3 break;
250     }
251     len *= f->mwidth + cis; /* compute target length */
252     width += len;
253     len -= alen; /* necessary adjustment */
254     while (sp < nsp) {
255     alen = len/(nsp-sp);
256     *sp++ += alen;
257     len -= alen;
258     }
259     tp = tab;
260     }
261     return(width);
262 greg 2.2 }