topenfont.c - plan9port - [fork] Plan 9 from user space
 (HTM) git clone git://src.adamsgaard.dk/plan9port
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       topenfont.c (5560B)
       ---
            1 #include <u.h>
            2 #include <libc.h>
            3 #include <draw.h>
            4 
            5 extern vlong _drawflength(int);
            6 int _fontpipe(char*);
            7 
            8 int
            9 parsefontscale(char *name, char **base)
           10 {
           11         char *p;
           12         int scale;
           13 
           14         p = name;
           15         scale = 0;
           16         while('0' <= *p && *p <= '9') {
           17                 scale = scale*10 + *p - '0';
           18                 p++;
           19         }
           20         if(*p == '*' && scale > 0)
           21                 *base = p+1;
           22         else {
           23                 *base = name;
           24                 scale = 1;
           25         }
           26         return scale;
           27 }
           28 
           29 extern char _defontfile[];
           30 
           31 Font*
           32 openfont1(Display *d, char *name)
           33 {
           34         Font *fnt;
           35         int fd, i, n, scale;
           36         char *buf, *nambuf, *nambuf0, *fname, *freename;
           37 
           38         nambuf = 0;
           39         freename = nil;
           40         scale = parsefontscale(name, &fname);
           41 
           42         if(strcmp(fname, "*default*") == 0) {
           43                 buf = strdup(_defontfile);
           44                 goto build;
           45         }
           46         fd = open(fname, OREAD);
           47         if(fd < 0 && strncmp(fname, "/lib/font/bit/", 14) == 0){
           48                 nambuf = smprint("#9/font/%s", fname+14);
           49                 if(nambuf == nil)
           50                         return 0;
           51                 nambuf0 = unsharp(nambuf);
           52                 if(nambuf0 != nambuf)
           53                         free(nambuf);
           54                 nambuf = nambuf0;
           55                 if(nambuf == nil)
           56                         return 0;
           57                 if((fd = open(nambuf, OREAD)) < 0){
           58                         free(nambuf);
           59                         return 0;
           60                 }
           61                 if(scale > 1) {
           62                         name = smprint("%d*%s", scale, nambuf);
           63                         freename = name;
           64                 } else {
           65                         name = nambuf;
           66                 }
           67         }
           68         if(fd >= 0)
           69                 n = _drawflength(fd);
           70         if(fd < 0 && strncmp(fname, "/mnt/font/", 10) == 0) {
           71                 fd = _fontpipe(fname+10);
           72                 n = 1024*1024;
           73         }
           74         if(fd < 0){
           75                 free(nambuf);
           76                 free(freename);
           77                 return 0;
           78         }
           79 
           80         buf = malloc(n+1);
           81         if(buf == 0){
           82                 close(fd);
           83                 free(nambuf);
           84                 free(freename);
           85                 return 0;
           86         }
           87         i = readn(fd, buf, n);
           88         close(fd);
           89         if(i <= 0){
           90                 free(buf);
           91                 free(nambuf);
           92                 free(freename);
           93                 return 0;
           94         }
           95         buf[i] = 0;
           96 build:
           97         fnt = buildfont(d, buf, name);
           98         free(buf);
           99         free(nambuf);
          100         free(freename);
          101         if(scale != 1) {
          102                 fnt->scale = scale;
          103                 fnt->height *= scale;
          104                 fnt->ascent *= scale;
          105                 fnt->width *= scale;
          106         }
          107         return fnt;
          108 }
          109 
          110 void
          111 swapfont(Font *targ, Font **oldp, Font **newp)
          112 {
          113         Font f, *old, *new;
          114 
          115         if(targ != *oldp)
          116                 sysfatal("bad swapfont %p %p %p", targ, *oldp, *newp);
          117 
          118         old = *oldp;
          119         new = *newp;
          120 
          121         f.name = old->name;
          122         f.display = old->display;
          123         f.height = old->height;
          124         f.ascent = old->ascent;
          125         f.width = old->width;
          126         f.nsub = old->nsub;
          127         f.age = old->age;
          128         f.maxdepth = old->maxdepth;
          129         f.ncache = old->ncache;
          130         f.nsubf = old->nsubf;
          131         f.scale = old->scale;
          132         f.cache = old->cache;
          133         f.subf = old->subf;
          134         f.sub = old->sub;
          135         f.cacheimage = old->cacheimage;
          136 
          137         old->name = new->name;
          138         old->display = new->display;
          139         old->height = new->height;
          140         old->ascent = new->ascent;
          141         old->width = new->width;
          142         old->nsub = new->nsub;
          143         old->age = new->age;
          144         old->maxdepth = new->maxdepth;
          145         old->ncache = new->ncache;
          146         old->nsubf = new->nsubf;
          147         old->scale = new->scale;
          148         old->cache = new->cache;
          149         old->subf = new->subf;
          150         old->sub = new->sub;
          151         old->cacheimage = new->cacheimage;
          152 
          153         new->name = f.name;
          154         new->display = f.display;
          155         new->height = f.height;
          156         new->ascent = f.ascent;
          157         new->width = f.width;
          158         new->nsub = f.nsub;
          159         new->age = f.age;
          160         new->maxdepth = f.maxdepth;
          161         new->ncache = f.ncache;
          162         new->nsubf = f.nsubf;
          163         new->scale = f.scale;
          164         new->cache = f.cache;
          165         new->subf = f.subf;
          166         new->sub = f.sub;
          167         new->cacheimage = f.cacheimage;
          168 
          169         *oldp = new;
          170         *newp = old;
          171 }
          172 
          173 static char*
          174 hidpiname(Font *f)
          175 {
          176         char *p, *q;
          177         int size;
          178 
          179         // If font name has form x,y return y.
          180         p = strchr(f->namespec, ',');
          181         if(p != nil)
          182                 return strdup(p+1);
          183 
          184         // If font name is /mnt/font/Name/Size/font, scale Size.
          185         if(strncmp(f->name, "/mnt/font/", 10) == 0) {
          186                 p = strchr(f->name+10, '/');
          187                 if(p == nil || *++p < '0' || *p > '9')
          188                         goto scale;
          189                 q = p;
          190                 size = 0;
          191                 while('0' <= *q && *q <= '9')
          192                         size = size*10 + *q++ - '0';
          193                 return smprint("%.*s%d%s", utfnlen(f->name, p-f->name), f->name, size*2, q);
          194         }
          195 
          196         // Otherwise use pixel doubling.
          197 scale:
          198         return smprint("%d*%s", f->scale*2, f->name);
          199 }
          200 
          201 void
          202 loadhidpi(Font *f)
          203 {
          204         char *name;
          205         Font *fnew;
          206 
          207         if(f->hidpi == f)
          208                 return;
          209         if(f->hidpi != nil) {
          210                 swapfont(f, &f->lodpi, &f->hidpi);
          211                 return;
          212         }
          213 
          214         name = hidpiname(f);
          215         fnew = openfont1(f->display, name);
          216         if(fnew == nil)
          217                 return;
          218         f->hidpi = fnew;
          219         free(name);
          220 
          221         swapfont(f, &f->lodpi, &f->hidpi);
          222 }
          223 
          224 Font*
          225 openfont(Display *d, char *name)
          226 {
          227         Font *f;
          228         char *p;
          229         char *namespec;
          230 
          231         // If font name has form x,y use x for lodpi, y for hidpi.
          232         name = strdup(name);
          233         namespec = strdup(name);
          234         if((p = strchr(name, ',')) != nil)
          235                 *p = '\0';
          236 
          237         f = openfont1(d, name);
          238         if(!f)
          239                 return nil;
          240         f->lodpi = f;
          241         free(f->namespec);
          242         f->namespec = namespec;
          243 
          244         /* add to display list for when dpi changes */
          245         /* d can be nil when invoked from mc. */
          246         if(d != nil) {
          247                 f->ondisplaylist = 1;
          248                 f->prev = d->lastfont;
          249                 f->next = nil;
          250                 if(f->prev)
          251                         f->prev->next = f;
          252                 else
          253                         d->firstfont = f;
          254                 d->lastfont = f;
          255 
          256                 /* if this is a hi-dpi display, find hi-dpi version and swap */
          257                 if(d->dpi >= DefaultDPI*3/2)
          258                         loadhidpi(f);
          259         }
          260 
          261         free(name);
          262 
          263         return f;
          264 }
          265 
          266 int
          267 _fontpipe(char *name)
          268 {
          269         int p[2];
          270         char c;
          271         char buf[1024], *argv[10];
          272         int nbuf, pid;
          273 
          274         if(pipe(p) < 0)
          275                 return -1;
          276         pid = rfork(RFNOWAIT|RFFDG|RFPROC);
          277         if(pid < 0) {
          278                 close(p[0]);
          279                 close(p[1]);
          280                 return -1;
          281         }
          282         if(pid == 0) {
          283                 close(p[0]);
          284                 dup(p[1], 1);
          285                 dup(p[1], 2);
          286                 if(p[1] > 2)
          287                         close(p[1]);
          288                 argv[0] = "fontsrv";
          289                 argv[1] = "-pp";
          290                 argv[2] = name;
          291                 argv[3] = nil;
          292                 execvp("fontsrv", argv);
          293                 print("exec fontsrv: %r\n");
          294                 _exit(0);
          295         }
          296         close(p[1]);
          297 
          298         // success marked with leading \001.
          299         // otherwise an error happened.
          300         for(nbuf=0; nbuf<sizeof buf-1; nbuf++) {
          301                 if(read(p[0], &c, 1) < 1 || c == '\n') {
          302                         buf[nbuf] = '\0';
          303                         werrstr(buf);
          304                         close(p[0]);
          305                         return -1;
          306                 }
          307                 if(c == '\001')
          308                         break;
          309         }
          310         return p[0];
          311 }