]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/proof/font.c
show line numbers in dtracy type errors
[plan9front.git] / sys / src / cmd / proof / font.c
1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
4 #include <event.h>
5 #include <bio.h>
6 #include "proof.h"
7
8 char    fname[NFONT][20];       /* font names */
9 char lastload[NFONT][20];       /* last file name prefix loaded for this font */
10 Font    *fonttab[NFONT][NSIZE]; /* pointers to fonts */
11 int     fmap[NFONT];            /* what map to use with this font */
12
13 static void     loadfont(int, int);
14 static void     fontlookup(int, char *);
15 static void     buildxheight(Biobuf*);
16 static void     buildmap(Biobuf*);
17 static void     buildtroff(char *);
18 static void     addmap(int, char *, int);
19 static char     *map(Rune*, int);
20 static void     scanstr(char *, char *, char **);
21
22 int     specfont;       /* somehow, number of special font */
23
24 #define NMAP    5
25 #define QUICK   2048    /* char values less than this are quick to look up */
26 #define eq(s,t) strcmp((char *) s, (char *) t) == 0
27
28 int     curmap  = -1;   /* what map are we working on */
29
30 typedef struct Link Link;
31 struct Link     /* link names together */
32 {
33         uchar   *name;
34         int     val;
35         Link    *next;
36 };
37
38 typedef struct Map Map;
39 struct Map      /* holds a mapping from uchar name to index */
40 {
41         double  xheight;
42         Rune    quick[QUICK];   /* low values get special treatment */
43         Link    *slow;  /* other stuff goes into a link list */
44 };
45
46 Map     charmap[5];
47
48 typedef struct Fontmap Fontmap;
49 struct Fontmap  /* mapping from troff name to filename */
50 {
51         char    *troffname;
52         char    *prefix;
53         int     map;            /* which charmap to use for this font */
54         char    *fallback;      /* font to look in if can't find char here */
55 };
56
57 Fontmap fontmap[100];
58 int     pos2fontmap[NFONT];     /* indexed by troff font position, gives Fontmap */
59 int     nfontmap        = 0;    /* how many are there */
60
61
62 void
63 dochar(Rune r[])
64 {
65         char *s, *fb;
66         Font *f;
67         Point p;
68         int fontno, fm, i;
69         char buf[32];
70
71         fontno = curfont;
72         if((s = map(r, curfont)) == 0){         /* not on current font */
73                 if ((s = map(r, specfont)) != 0)        /* on special font */
74                         fontno = specfont;
75                 else{
76                         /* look for fallback */
77                         fm = pos2fontmap[curfont];
78                         fb = fontmap[fm].fallback;
79                         if(fb){
80                                 /* see if fallback is mounted */
81                                 for(i = 0; i < NFONT; i++){
82                                         if(eq(fb, fontmap[pos2fontmap[i]].troffname)){
83                                                 s = map(r, i);
84                                                 if(s){
85                                                         fontno = i;
86                                                         goto found;
87                                                 }
88                                         }
89                                 }
90                         }
91                         /* no such char; use name itself on defont */
92                         /* this is not a general solution */
93                         p.x = hpos/DIV + xyoffset.x + offset.x;
94                         p.y = vpos/DIV + xyoffset.y + offset.y;
95                         p.y -= font->ascent;
96                         snprint(buf, sizeof buf, "%S", r);
97                         string(screen, p, display->black, ZP, font, buf);
98                         return;
99                 }
100         }
101     found:
102         p.x = hpos/DIV + xyoffset.x + offset.x;
103         p.y = vpos/DIV + xyoffset.y + offset.y;
104         while ((f = fonttab[fontno][cursize]) == 0)
105                 loadfont(fontno, cursize);
106         p.y -= f->ascent;
107         dprint(2, "putting %S at %d,%d font %d, size %d\n", r, p.x, p.y, fontno, cursize);
108         string(screen, p, display->black, ZP, f, s);
109 }
110
111 /* imported from libdraw/arith.c to permit an extern log2 function */
112 static int log2[] = {
113         -1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, 4,
114         -1, -1, -1, -1, -1, -1, -1, 4 /* BUG */, -1, -1, -1, -1, -1, -1, -1, 5
115 };
116
117 static void
118 loadfont(int n, int s)
119 {
120         char file[256];
121         int i, fd, t, deep;
122         static char *try[3] = {"", "times/R.", "pelm/"};
123         Subfont *f;
124         Font *ff;
125
126         try[0] = fname[n];
127         for (t = 0; t < 3; t++){
128                 i = s * mag * charmap[fmap[n]].xheight/0.72;    /* a pixel is 0.72 points */
129                 if (i < MINSIZE)
130                         i = MINSIZE;
131                 dprint(2, "size %d, i %d, mag %g\n", s, i, mag);
132                 for(; i >= MINSIZE; i--){
133                         /* if .font file exists, take that */
134                         snprint(file, sizeof file, "%s/%s%d.font",
135                                 libfont, try[t], i);
136                         ff = openfont(display, file);
137                         if(ff != 0){
138                                 fonttab[n][s] = ff;
139                                 dprint(2, "using %s for font %d %d\n", file, n, s);
140                                 return;
141                         }
142                         /* else look for a subfont file */
143                         for (deep = log2[screen->depth]; deep >= 0; deep--){
144                                 snprint(file, sizeof file, "%s/%s%d.%d",
145                                         libfont, try[t], i, deep);
146                                 dprint(2, "trying %s for %d\n", file, i);
147                                 if ((fd = open(file, 0)) >= 0){
148                                         f = readsubfont(display, file, fd, 0);
149                                         if (f == 0) {
150                                                 fprint(2, "can't rdsubfontfile %s: %r\n", file);
151                                                 exits("rdsubfont");
152                                         }
153                                         close(fd);
154                                         ff = mkfont(f, 0);
155                                         if(ff == 0){
156                                                 fprint(2, "can't mkfont %s: %r\n", file);
157                                                 exits("rdsubfont");
158                                         }
159                                         fonttab[n][s] = ff;
160                                         dprint(2, "using %s for font %d %d\n", file, n, s);
161                                         return;
162                                 }
163                         }
164                 }
165         }
166         fprint(2, "can't find font %s.%d or substitute, quitting\n", fname[n], s);
167         exits("no font");
168 }
169
170 void
171 loadfontname(int n, char *s)
172 {
173         int i;
174         Font *f, *g = 0;
175
176         if (strcmp(s, fname[n]) == 0)
177                 return;
178         if(fname[n] && fname[n][0]){
179                 if(lastload[n] && strcmp(lastload[n], fname[n]) == 0)
180                         return;
181                 strcpy(lastload[n], fname[n]);
182         }
183         fontlookup(n, s);
184         for (i = 0; i < NSIZE; i++)
185                 if (f = fonttab[n][i]){
186                         if (f != g) {
187                                 freefont(f);
188                                 g = f;
189                         }
190                         fonttab[n][i] = 0;
191                 }
192 }
193
194 void
195 allfree(void)
196 {
197         int i;
198
199         for (i=0; i<NFONT; i++)
200                 loadfontname(i, "??");
201 }
202
203
204 void
205 readmapfile(char *file)
206 {
207         Biobuf *fp;
208         char *p, cmd[100];
209
210         if ((fp=Bopen(file, OREAD)) == 0){
211                 fprint(2, "proof: can't open map file %s\n", file);
212                 exits("urk");
213         }
214         while((p=Brdline(fp, '\n')) != 0) {
215                 p[Blinelen(fp)-1] = 0;
216                 scanstr(p, cmd, 0);
217                 if(p[0]=='\0' || eq(cmd, "#"))  /* skip comments, empty */
218                         continue;
219                 else if(eq(cmd, "xheight"))
220                         buildxheight(fp);
221                 else if(eq(cmd, "map"))
222                         buildmap(fp);
223                 else if(eq(cmd, "special"))
224                         buildtroff(p);
225                 else if(eq(cmd, "troff"))
226                         buildtroff(p);
227                 else
228                         fprint(2, "weird map line %s\n", p);
229         }
230         Bterm(fp);
231 }
232
233 static void
234 buildxheight(Biobuf *fp)        /* map goes from char name to value to print via *string() */
235 {
236         char *line;
237
238         line = Brdline(fp, '\n');
239         if(line == 0){
240                 fprint(2, "proof: bad map file\n");
241                 exits("map");
242         }
243         charmap[curmap].xheight = atof(line);
244 }
245
246 static void
247 buildmap(Biobuf *fp)    /* map goes from char name to value to print via *string() */
248 {
249         uchar *p, *line, ch[100];
250         int val;
251         Rune r;
252
253         curmap++;
254         if(curmap >= NMAP){
255                 fprint(2, "proof: out of char maps; recompile\n");
256                 exits("charmap");
257         }
258         while ((line = Brdline(fp, '\n'))!= 0){
259                 if (line[0] == '\n')
260                         return;
261                 line[Blinelen(fp)-1] = 0;
262                 scanstr((char *) line, (char *) ch, (char **) &p);
263                 if (ch[0] == '\0') {
264                         fprint(2, "bad map file line '%s'\n", (char*)line);
265                         continue;
266                 }
267                 val = strtol((char *) p, 0, 10);
268 dprint(2, "buildmap %s (%x %x) %s %d\n", (char*)ch, ch[0], ch[1], (char*)p, val);
269                 chartorune(&r, (char*)ch);
270                 if(utflen((char*)ch)==1 && r<QUICK)
271                         charmap[curmap].quick[r] = val;
272                 else
273                         addmap(curmap, strdup((char *) ch), val);       /* put somewhere else */
274         }
275 }
276
277 static void
278 addmap(int n, char *s, int val) /* stick a new link on */
279 {
280         Link *p = (Link *) malloc(sizeof(Link));
281         Link *prev = charmap[n].slow;
282
283         if(p == 0)
284                 exits("out of memory in addmap");
285         p->name = (uchar *) s;
286         p->val = val;
287         p->next = prev;
288         charmap[n].slow = p;
289 }
290
291 static void
292 buildtroff(char *buf)   /* map troff names into bitmap filenames */
293 {                               /* e.g., R -> times/R., I -> times/I., etc. */
294         char *p, cmd[100], name[200], prefix[400], fallback[100];
295
296         scanstr(buf, cmd, &p);
297         scanstr(p, name, &p);
298         scanstr(p, prefix, &p);
299         while(*p!=0 && isspace(*p))
300                 p++;
301         if(*p != 0){
302                 scanstr(p, fallback, &p);
303                 fontmap[nfontmap].fallback = strdup(fallback);
304         }else
305                 fontmap[nfontmap].fallback = 0;
306         fontmap[nfontmap].troffname = strdup(name);
307         fontmap[nfontmap].prefix = strdup(prefix);
308         fontmap[nfontmap].map = curmap;
309         dprint(2, "troff name %s is bitmap %s map %d in slot %d fallback %s\n",
310                 name, prefix, curmap, nfontmap, fontmap[nfontmap].fallback?
311                 fontmap[nfontmap].fallback: "<null>");
312         nfontmap++;
313 }
314
315 static void
316 fontlookup(int n, char *s)      /* map troff name of s into position n */
317 {
318         int i;
319
320         for(i = 0; i < nfontmap; i++)
321                 if (eq(s, fontmap[i].troffname)) {
322                         strcpy(fname[n], fontmap[i].prefix);
323                         fmap[n] = fontmap[i].map;
324                         pos2fontmap[n] = i;
325                         if (eq(s, "S"))
326                                 specfont = n;
327                         dprint(2, "font %d %s is %s\n", n, s, fname[n]);
328                         return;
329                 }
330         /* god help us if this font isn't there */
331 }
332
333
334 static char *
335 map(Rune rp[], int font)        /* figure out mapping for char in this font */
336 {
337         static char s[100];
338         unsigned m;
339         char c[32];
340         Link *p;
341         Rune r;
342
343         if((unsigned)font >= NFONT) {
344                 dprint(2, "map: font %ud >= NFONT (%d)\n", font, NFONT);
345                 return 0;
346         }
347         m = fmap[font];
348         if(m >= nelem(charmap)) {
349                 dprint(2, "map: fmap[font] %ud >= nelem(charmap) (%d)\n",
350                         m, nelem(charmap));
351                 return 0;
352         }
353         if(rp[1] == 0 && rp[0] < QUICK)         /* fast lookup */
354                 r = charmap[m].quick[rp[0]];
355         else {                  /* high-valued or compound character name */
356                 snprint(c, sizeof c, "%S", rp);
357                 r = 0;
358                 for (p = charmap[m].slow; p; p = p->next)
359                         if(eq(c, p->name)){
360                                 r = p->val;
361                                 break;
362                         }
363         }
364         if(r == 0){     /* not there */
365                 dprint(2, "didn't find %S font# %d\n", rp, font);
366                 return 0;
367         }
368         dprint(2, "map %S to %s font# %d\n", rp, s, font);
369         s[runetochar(s, &r)] = 0;
370         return s;
371 }
372
373 static void
374 scanstr(char *s, char *ans, char **ep)
375 {
376         for (; isspace((uchar) *s); s++)
377                 ;
378         for (; *s!=0 && !isspace((uchar) *s); )
379                 *ans++ = *s++;
380         *ans = 0;
381         if (ep)
382                 *ep = s;
383 }