plan9port

[fork] Plan 9 from user space
git clone git://src.adamsgaard.dk/plan9port # fast
git clone https://src.adamsgaard.dk/plan9port.git # slow
Log | Files | Refs | README | LICENSE Back to index

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 }