font.c 9.2 KB

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