tfont.c - plan9port - [fork] Plan 9 from user space
git clone git://src.adamsgaard.dk/plan9port
Log
Files
Refs
README
LICENSE
---
tfont.c (7635B)
---
     1 #include 
     2 #include 
     3 #include 
     4 
     5 static int        fontresize(Font*, int, int, int);
     6 #if 0
     7 static int        freeup(Font*);
     8 #endif
     9 
    10 #define        PJW        0        /* use NUL==pjw for invisible characters */
    11 
    12 static Rune empty[] = { 0 };
    13 int
    14 cachechars(Font *f, char **ss, Rune **rr, ushort *cp, int max, int *wp, char **subfontname)
    15 {
    16         int i, th, sh, h, ld, w, rw, wid, nc;
    17         char *sp;
    18         Rune r, *rp, vr;
    19         ulong a;
    20         Cacheinfo *c, *tc, *ec;
    21 
    22         if(ss){
    23                 sp = *ss;
    24                 rp = empty;
    25         }else{
    26                 sp = "";
    27                 rp = *rr;
    28         }
    29         wid = 0;
    30         *subfontname = 0;
    31         for(i=0; incache-NFLOOK-1);
    48                 c = &f->cache[sh];
    49                 ec = c+NFLOOK;
    50                 h = sh;
    51                 while(c < ec){
    52                         if(c->value==r && c->age)
    53                                 goto Found;
    54                         c++;
    55                         h++;
    56                 }
    57 
    58                 /*
    59                  * Not found; toss out oldest entry
    60                  */
    61                 a = ~0;
    62                 th = sh;
    63                 tc = &f->cache[th];
    64                 while(tc < ec){
    65                         if(tc->age < a){
    66                                 a = tc->age;
    67                                 h = th;
    68                                 c = tc;
    69                         }
    70                         tc++;
    71                         th++;
    72                 }
    73 
    74                 if(a && (f->age-a)<500){        /* kicking out too recent; resize */
    75                         nc = 2*(f->ncache-NFLOOK) + NFLOOK;
    76                         if(nc <= MAXFCACHE){
    77                                 if(i == 0)
    78                                         fontresize(f, f->width, nc, f->maxdepth);
    79                                 /* else flush first; retry will resize */
    80                                 break;
    81                         }
    82                 }
    83 
    84                 if(c->age == f->age)        /* flush pending string output */
    85                         break;
    86 
    87                 ld = loadchar(f, r, c, h, i, subfontname);
    88                 if(ld <= 0){
    89                         if(ld == 0)
    90                                 continue;
    91                         break;
    92                 }
    93                 c = &f->cache[h];        /* may have reallocated f->cache */
    94 
    95             Found:
    96                 wid += c->width;
    97                 c->age = f->age;
    98                 cp[i] = h;
    99                 i++;
   100         }
   101         if(ss)
   102                 *ss = sp;
   103         else
   104                 *rr = rp;
   105         *wp = wid;
   106         return i;
   107 }
   108 
   109 void
   110 agefont(Font *f)
   111 {
   112         Cacheinfo *c, *ec;
   113         Cachesubf *s, *es;
   114 
   115         f->age++;
   116         if(f->age == 65536){
   117                 /*
   118                  * Renormalize ages
   119                  */
   120                 c = f->cache;
   121                 ec = c+f->ncache;
   122                 while(c < ec){
   123                         if(c->age){
   124                                 c->age >>= 2;
   125                                 c->age++;
   126                         }
   127                         c++;
   128                 }
   129                 s = f->subf;
   130                 es = s+f->nsubf;
   131                 while(s < es){
   132                         if(s->age){
   133                                 if(s->agecf->name != nil){
   134                                         /* clean up */
   135                                         freesubfont(s->f);
   136                                         s->cf = nil;
   137                                         s->f = nil;
   138                                         s->age = 0;
   139                                 }else{
   140                                         s->age >>= 2;
   141                                         s->age++;
   142                                 }
   143                         }
   144                         s++;
   145                 }
   146                 f->age = (65536>>2) + 1;
   147         }
   148 }
   149 
   150 static Subfont*
   151 cf2subfont(Cachefont *cf, Font *f)
   152 {
   153         int depth;
   154         char *name;
   155         Subfont *sf;
   156 
   157         name = cf->subfontname;
   158         if(name == nil){
   159                 depth = 0;
   160                 if(f->display){
   161                         if(f->display->screenimage)
   162                                 depth = f->display->screenimage->depth;
   163                 }else
   164                         depth = 8;
   165                 name = subfontname(cf->name, f->name, depth);
   166                 if(name == nil)
   167                         return nil;
   168                 cf->subfontname = name;
   169         }
   170         sf = lookupsubfont(f->display, name);
   171         return sf;
   172 }
   173 
   174 /* return 1 if load succeeded, 0 if failed, -1 if must retry */
   175 int
   176 loadchar(Font *f, Rune r, Cacheinfo *c, int h, int noflush, char **subfontname)
   177 {
   178         int i, oi, wid, top, bottom;
   179         int pic;        /* need >16 bits for adding offset below */
   180         Fontchar *fi;
   181         Cachefont *cf;
   182         Cachesubf *subf, *of;
   183         uchar *b;
   184 
   185         pic = r;
   186     Again:
   187         for(i=0; insub; i++){
   188                 cf = f->sub[i];
   189                 if(cf->min<=pic && pic<=cf->max)
   190                         goto Found;
   191         }
   192     TryPJW:
   193         if(pic != PJW){
   194                 pic = PJW;
   195                 goto Again;
   196         }
   197         return 0;
   198 
   199     Found:
   200         /*
   201          * Choose exact or oldest
   202          */
   203         oi = 0;
   204         subf = &f->subf[0];
   205         for(i=0; insubf; i++){
   206                 if(cf == subf->cf)
   207                         goto Found2;
   208                 if(subf->age < f->subf[oi].age)
   209                         oi = i;
   210                 subf++;
   211         }
   212         subf = &f->subf[oi];
   213 
   214         if(subf->f){
   215                 if(f->age-subf->age>SUBFAGE || f->nsubf>MAXSUBF){
   216     Toss:
   217                         /* ancient data; toss */
   218                         freesubfont(subf->f);
   219                         subf->cf = nil;
   220                         subf->f = nil;
   221                         subf->age = 0;
   222                 }else{                                /* too recent; grow instead */
   223                         of = f->subf;
   224                         f->subf = realloc(of, (f->nsubf+DSUBF)*sizeof *subf);
   225                         if(f->subf == nil){
   226                                 f->subf = of;
   227                                 goto Toss;
   228                         }
   229                         memset(f->subf+f->nsubf, 0, DSUBF*sizeof *subf);
   230                         subf = &f->subf[f->nsubf];
   231                         f->nsubf += DSUBF;
   232                 }
   233         }
   234         subf->age = 0;
   235         subf->cf = nil;
   236         subf->f = cf2subfont(cf, f);
   237         if(subf->f == nil){
   238                 if(cf->subfontname == nil)
   239                         goto TryPJW;
   240                 *subfontname = cf->subfontname;
   241                 return -1;
   242         }
   243 
   244         subf->cf = cf;
   245         if(subf->f->ascent > f->ascent && f->display){
   246                 /* should print something? this is a mistake in the font file */
   247                 /* must prevent c->top from going negative when loading cache */
   248                 Image *b;
   249                 int d, t;
   250                 d = subf->f->ascent - f->ascent;
   251                 b = subf->f->bits;
   252                 draw(b, b->r, b, nil, addpt(b->r.min, Pt(0, d)));
   253                 draw(b, Rect(b->r.min.x, b->r.max.y-d, b->r.max.x, b->r.max.y), f->display->black, nil, b->r.min);
   254                 for(i=0; if->n; i++){
   255                         t = subf->f->info[i].top-d;
   256                         if(t < 0)
   257                                 t = 0;
   258                         subf->f->info[i].top = t;
   259                         t = subf->f->info[i].bottom-d;
   260                         if(t < 0)
   261                                 t = 0;
   262                         subf->f->info[i].bottom = t;
   263                 }
   264                 subf->f->ascent = f->ascent;
   265         }
   266 
   267     Found2:
   268         subf->age = f->age;
   269 
   270         /* possible overflow here, but works out okay */
   271         pic += cf->offset;
   272         pic -= cf->min;
   273         if(pic >= subf->f->n)
   274                 goto TryPJW;
   275         fi = &subf->f->info[pic];
   276         if(fi->width == 0)
   277                 goto TryPJW;
   278         wid = (fi+1)->x - fi->x;
   279         if(f->width < wid || f->width == 0 || f->maxdepth < subf->f->bits->depth){
   280                 /*
   281                  * Flush, free, reload (easier than reformatting f->b)
   282                  */
   283                 if(noflush)
   284                         return -1;
   285                 if(f->width < wid)
   286                         f->width = wid;
   287                 if(f->maxdepth < subf->f->bits->depth)
   288                         f->maxdepth = subf->f->bits->depth;
   289                 i = fontresize(f, f->width, f->ncache, f->maxdepth);
   290                 if(i <= 0)
   291                         return i;
   292                 /* c is still valid as didn't reallocate f->cache */
   293         }
   294         c->value = r;
   295         top = fi->top + (f->ascent-subf->f->ascent);
   296         bottom = fi->bottom + (f->ascent-subf->f->ascent);
   297         c->width = fi->width;
   298         c->x = h*f->width;
   299         c->left = fi->left;
   300         if(f->display == nil)
   301                 return 1;
   302         flushimage(f->display, 0);        /* flush any pending errors */
   303         b = bufimage(f->display, 37);
   304         if(b == 0)
   305                 return 0;
   306         b[0] = 'l';
   307         BPLONG(b+1, f->cacheimage->id);
   308         BPLONG(b+5, subf->f->bits->id);
   309         BPSHORT(b+9, c-f->cache);
   310         BPLONG(b+11, c->x);
   311         BPLONG(b+15, top);
   312         BPLONG(b+19, c->x+((fi+1)->x-fi->x));
   313         BPLONG(b+23, bottom);
   314         BPLONG(b+27, fi->x);
   315         BPLONG(b+31, fi->top);
   316         b[35] = fi->left;
   317         b[36] = fi->width;
   318         return 1;
   319 }
   320 
   321 /* release all subfonts, return number freed */
   322 #if 0
   323 static
   324 int
   325 freeup(Font *f)
   326 {
   327         Cachesubf *s, *es;
   328         int nf;
   329 
   330         if(f->sub[0]->name == nil)        /* font from mkfont; don't free */
   331                 return 0;
   332         s = f->subf;
   333         es = s+f->nsubf;
   334         nf = 0;
   335         while(s < es){
   336                 if(s->age){
   337                         freesubfont(s->f);
   338                         s->cf = nil;
   339                         s->f = nil;
   340                         s->age = 0;
   341                         nf++;
   342                 }
   343                 s++;
   344         }
   345         return nf;
   346 }
   347 #endif
   348 
   349 /* return whether resize succeeded && f->cache is unchanged */
   350 static int
   351 fontresize(Font *f, int wid, int ncache, int depth)
   352 {
   353         Cacheinfo *i;
   354         int ret;
   355         Image *new;
   356         uchar *b;
   357         Display *d;
   358 
   359         ret = 0;
   360         if(depth <= 0)
   361                 depth = 1;
   362 
   363         d = f->display;
   364         if(d == nil)
   365                 goto Nodisplay;
   366 
   367         new = allocimage(d, Rect(0, 0, ncache*wid, f->height), CHAN1(CGrey, depth), 0, 0);
   368         if(new == nil){
   369                 fprint(2, "font cache resize failed: %r\n");
   370                 abort();
   371                 goto Return;
   372         }
   373         flushimage(d, 0);        /* flush any pending errors */
   374         b = bufimage(d, 1+4+4+1);
   375         if(b == 0){
   376                 freeimage(new);
   377                 goto Return;
   378         }
   379         b[0] = 'i';
   380         BPLONG(b+1, new->id);
   381         BPLONG(b+5, ncache);
   382         b[9] = f->ascent;
   383         if(flushimage(d, 0) < 0){
   384                 fprint(2, "resize: init failed: %r\n");
   385                 freeimage(new);
   386                 goto Return;
   387         }
   388         freeimage(f->cacheimage);
   389         f->cacheimage = new;
   390     Nodisplay:
   391         f->width = wid;
   392         f->maxdepth = depth;
   393         ret = 1;
   394         if(f->ncache != ncache){
   395                 i = malloc(ncache*sizeof f->cache[0]);
   396                 if(i != nil){
   397                         ret = 0;
   398                         free(f->cache);
   399                         f->ncache = ncache;
   400                         f->cache = i;
   401                 }
   402                 /* else just wipe the cache clean and things will be ok */
   403         }
   404     Return:
   405         memset(f->cache, 0, f->ncache*sizeof f->cache[0]);
   406         return ret;
   407 }