font.c (8658B)
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[10]; 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 sprint(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 static int drawlog2[] = { 112 0, 0, 113 1, 1, 114 2, 2, 2, 2, 115 3, 3, 3, 3, 3, 3, 3, 3, 116 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 117 5 118 }; 119 120 static void 121 loadfont(int n, int s) 122 { 123 char file[100]; 124 int i, fd, t, deep; 125 static char *try[3] = {"", "times/R.", "pelm/"}; 126 Subfont *f; 127 Font *ff; 128 129 try[0] = fname[n]; 130 dprint(2, "loadfont %d %d\n", n, s); 131 for (t = 0; t < 3; t++){ 132 i = s * mag * charmap[fmap[n]].xheight/0.72; /* a pixel is 0.72 points */ 133 if (i < MINSIZE) 134 i = MINSIZE; 135 dprint(2, "size %d, i %d, mag %g\n", s, i, mag); 136 for(; i >= MINSIZE; i--){ 137 /* if .font file exists, take that */ 138 sprint(file, "%s/%s%d.font", libfont, try[t], i); 139 ff = openfont(display, file); 140 if(ff != 0){ 141 fonttab[n][s] = ff; 142 dprint(2, "using %s for font %d %d\n", file, n, s); 143 return; 144 } 145 /* else look for a subfont file */ 146 for (deep = drawlog2[screen->depth]; deep >= 0; deep--){ 147 sprint(file, "%s/%s%d.%d", libfont, try[t], i, deep); 148 dprint(2, "trying %s for %d\n", file, i); 149 if ((fd = open(file, 0)) >= 0){ 150 f = readsubfont(display, file, fd, 0); 151 if (f == 0) { 152 fprint(2, "can't rdsubfontfile %s: %r\n", file); 153 exits("rdsubfont"); 154 } 155 close(fd); 156 ff = mkfont(f, 0); 157 if(ff == 0){ 158 fprint(2, "can't mkfont %s: %r\n", file); 159 exits("rdsubfont"); 160 } 161 fonttab[n][s] = ff; 162 dprint(2, "using %s for font %d %d\n", file, n, s); 163 return; 164 } 165 } 166 } 167 } 168 fprint(2, "can't find font %s.%d or substitute, quitting\n", fname[n], s); 169 exits("no font"); 170 } 171 172 void 173 loadfontname(int n, char *s) 174 { 175 int i; 176 Font *f, *g = 0; 177 178 if (strcmp(s, fname[n]) == 0) 179 return; 180 if(fname[n] && fname[n][0]){ 181 if(lastload[n] && strcmp(lastload[n], fname[n]) == 0) 182 return; 183 strcpy(lastload[n], fname[n]); 184 } 185 fontlookup(n, s); 186 for (i = 0; i < NSIZE; i++) 187 if (f = fonttab[n][i]){ 188 if (f != g) { 189 freefont(f); 190 g = f; 191 } 192 fonttab[n][i] = 0; 193 } 194 } 195 196 void 197 allfree(void) 198 { 199 int i; 200 201 for (i=0; i<NFONT; i++) 202 loadfontname(i, "??"); 203 } 204 205 206 void 207 readmapfile(char *file) 208 { 209 Biobuf *fp; 210 char *p, cmd[100]; 211 212 if ((fp=Bopen(file, OREAD)) == 0){ 213 fprint(2, "proof: can't open map file %s\n", file); 214 exits("urk"); 215 } 216 while((p=Brdline(fp, '\n')) != 0) { 217 p[Blinelen(fp)-1] = 0; 218 scanstr(p, cmd, 0); 219 if(p[0]=='\0' || eq(cmd, "#")) /* skip comments, empty */ 220 continue; 221 else if(eq(cmd, "xheight")) 222 buildxheight(fp); 223 else if(eq(cmd, "map")) 224 buildmap(fp); 225 else if(eq(cmd, "special")) 226 buildtroff(p); 227 else if(eq(cmd, "troff")) 228 buildtroff(p); 229 else 230 fprint(2, "weird map line %s\n", p); 231 } 232 Bterm(fp); 233 } 234 235 static void 236 buildxheight(Biobuf *fp) /* map goes from char name to value to print via *string() */ 237 { 238 char *line; 239 240 line = Brdline(fp, '\n'); 241 if(line == 0){ 242 fprint(2, "proof: bad map file\n"); 243 exits("map"); 244 } 245 charmap[curmap].xheight = atof(line); 246 } 247 248 static void 249 buildmap(Biobuf *fp) /* map goes from char name to value to print via *string() */ 250 { 251 uchar *p, *line, ch[100]; 252 int val; 253 Rune r; 254 255 curmap++; 256 if(curmap >= NMAP){ 257 fprint(2, "proof: out of char maps; recompile\n"); 258 exits("charmap"); 259 } 260 while ((line = Brdline(fp, '\n'))!= 0){ 261 if (line[0] == '\n') 262 return; 263 line[Blinelen(fp)-1] = 0; 264 scanstr((char *) line, (char *) ch, (char **)(void*)&p); 265 if (ch[0] == '\0') { 266 fprint(2, "bad map file line '%s'\n", (char*)line); 267 continue; 268 } 269 val = strtol((char *) p, 0, 10); 270 dprint(2, "buildmap %s (%x %x) %s %d\n", (char*)ch, ch[0], ch[1], (char*)p, val); 271 chartorune(&r, (char*)ch); 272 if(utflen((char*)ch)==1 && r<QUICK) 273 charmap[curmap].quick[r] = val; 274 else 275 addmap(curmap, strdup((char *) ch), val); /* put somewhere else */ 276 } 277 } 278 279 static void 280 addmap(int n, char *s, int val) /* stick a new link on */ 281 { 282 Link *p = (Link *) malloc(sizeof(Link)); 283 Link *prev = charmap[n].slow; 284 285 if(p == 0) 286 exits("out of memory in addmap"); 287 p->name = (uchar *) s; 288 p->val = val; 289 p->next = prev; 290 charmap[n].slow = p; 291 } 292 293 static void 294 buildtroff(char *buf) /* map troff names into bitmap filenames */ 295 { /* e.g., R -> times/R., I -> times/I., etc. */ 296 char *p, cmd[100], name[200], prefix[400], fallback[100]; 297 298 scanstr(buf, cmd, &p); 299 scanstr(p, name, &p); 300 scanstr(p, prefix, &p); 301 while(*p!=0 && isspace(*p)) 302 p++; 303 if(*p != 0){ 304 scanstr(p, fallback, &p); 305 fontmap[nfontmap].fallback = strdup(fallback); 306 }else 307 fontmap[nfontmap].fallback = 0; 308 fontmap[nfontmap].troffname = strdup(name); 309 fontmap[nfontmap].prefix = strdup(prefix); 310 fontmap[nfontmap].map = curmap; 311 dprint(2, "troff name %s is bitmap %s map %d in slot %d fallback %s\n", name, prefix, curmap, nfontmap, fontmap[nfontmap].fallback? 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 char c[10]; 339 Link *p; 340 Rune r; 341 342 if(rp[1]==0 && rp[0]<QUICK) /* fast lookup */ 343 r = charmap[fmap[font]].quick[rp[0]]; 344 else { /* high-valued or compound character name */ 345 sprint(c, "%S", rp); 346 r = 0; 347 for (p = charmap[fmap[font]].slow; p; p = p->next) 348 if(eq(c, p->name)){ 349 r = p->val; 350 break; 351 } 352 } 353 if(r == 0){ /* not there */ 354 dprint(2, "didn't find %S font# %d\n", rp, font); 355 return 0; 356 } 357 dprint(2, "map %S to %s font# %d\n", rp, s, font); 358 s[runetochar(s, &r)] = 0; 359 return s; 360 } 361 362 static void 363 scanstr(char *s, char *ans, char **ep) 364 { 365 for (; isspace((uchar) *s); s++) 366 ; 367 for (; *s!=0 && !isspace((uchar) *s); ) 368 *ans++ = *s++; 369 *ans = 0; 370 if (ep) 371 *ep = s; 372 }