ref: e3b49509662cc1da997db4113b743d477a9e1ac0
parent: b7ab1354e3fdf32d2a587de00b4b324779b34b20
author: cinap_lenrek <[email protected]>
date: Sun Jan 5 22:49:14 EST 2014
libdraw: fix stringwidth problems cachechars() used to skip over characters on its own when loadchar() could not find the character or a PJW replacement. this resulted in wrong width calculation. now we just return and handle the case inside _string and _stringwidth. fix subfont leak in stringwidth() remove annoying prints in stringwidth()
--- a/sys/src/libdraw/font.c
+++ b/sys/src/libdraw/font.c
@@ -10,7 +10,7 @@
int
cachechars(Font *f, char **ss, Rune **rr, ushort *cp, int max, int *wp, char **subfontname)
{
- int i, th, sh, h, ld, w, rw, wid, nc;
+ int i, th, sh, h, w, rw, wid, nc;
char *sp;
Rune r, *rp, vr;
ulong a;
@@ -81,12 +81,9 @@
if(c->age == f->age) /* flush pending string output */
break;
- ld = loadchar(f, r, c, h, i, subfontname);
- if(ld <= 0){
- if(ld == 0)
- continue;
+ if(loadchar(f, r, c, h, i, subfontname) <= 0)
break;
- }
+
c = &f->cache[h]; /* may have reallocated f->cache */
Found:
--- a/sys/src/libdraw/string.c
+++ b/sys/src/libdraw/string.c
@@ -58,13 +58,12 @@
Point
_string(Image *dst, Point pt, Image *src, Point sp, Font *f, char *s, Rune *r, int len, Rectangle clipr, Image *bg, Point bgp, Drawop op)
{
- int m, n, wid, max;
+ int m, n, wid, max, try;
ushort cbuf[Max], *c, *ec;
uchar *b;
char *subfontname;
char **sptr;
- Rune **rptr;
- Font *def;
+ Rune **rptr, rune;
Subfont *sf;
if(s == nil){
@@ -78,63 +77,76 @@
}else
rptr = &r;
sf = nil;
- while((*s || *r) && len){
+ try = 0;
+ while((*s || *r) && len > 0){
max = Max;
if(len < max)
max = len;
- n = cachechars(f, sptr, rptr, cbuf, max, &wid, &subfontname);
- if(n > 0){
- _setdrawop(dst->display, op);
-
- m = 47+2*n;
- if(bg)
- m += 4+2*4;
- b = bufimage(dst->display, m);
- if(b == 0){
- fprint(2, "string: %r\n");
- break;
+ if((n = cachechars(f, sptr, rptr, cbuf, max, &wid, &subfontname)) <= 0){
+ if(subfontname){
+ if(++try > 10)
+ break;
+ Nextfont:
+ freesubfont(sf);
+ if((sf=_getsubfont(f->display, subfontname)) != nil)
+ continue;
+ if(f->display->defaultfont == nil || f->display->defaultfont == f)
+ break;
+ f = f->display->defaultfont;
+ continue;
}
- if(bg)
- b[0] = 'x';
+ if(*r)
+ r++;
else
- b[0] = 's';
- BPLONG(b+1, dst->id);
- BPLONG(b+5, src->id);
- BPLONG(b+9, f->cacheimage->id);
- BPLONG(b+13, pt.x);
- BPLONG(b+17, pt.y+f->ascent);
- BPLONG(b+21, clipr.min.x);
- BPLONG(b+25, clipr.min.y);
- BPLONG(b+29, clipr.max.x);
- BPLONG(b+33, clipr.max.y);
- BPLONG(b+37, sp.x);
- BPLONG(b+41, sp.y);
- BPSHORT(b+45, n);
- b += 47;
- if(bg){
- BPLONG(b, bg->id);
- BPLONG(b+4, bgp.x);
- BPLONG(b+8, bgp.y);
- b += 12;
- }
- ec = &cbuf[n];
- for(c=cbuf; c<ec; c++, b+=2)
- BPSHORT(b, *c);
- pt.x += wid;
- bgp.x += wid;
- agefont(f);
- len -= n;
+ s += chartorune(&rune, s);
+ len--;
+ continue;
}
- if(subfontname){
- freesubfont(sf);
- if((sf=_getsubfont(f->display, subfontname)) == 0){
- def = f->display ? f->display->defaultfont : nil;
- if(def && f!=def)
- f = def;
- else
- break;
- }
+ try = 0;
+
+ _setdrawop(dst->display, op);
+
+ m = 47+2*n;
+ if(bg)
+ m += 4+2*4;
+ b = bufimage(dst->display, m);
+ if(b == 0){
+ fprint(2, "string: %r\n");
+ break;
}
+ if(bg)
+ b[0] = 'x';
+ else
+ b[0] = 's';
+ BPLONG(b+1, dst->id);
+ BPLONG(b+5, src->id);
+ BPLONG(b+9, f->cacheimage->id);
+ BPLONG(b+13, pt.x);
+ BPLONG(b+17, pt.y+f->ascent);
+ BPLONG(b+21, clipr.min.x);
+ BPLONG(b+25, clipr.min.y);
+ BPLONG(b+29, clipr.max.x);
+ BPLONG(b+33, clipr.max.y);
+ BPLONG(b+37, sp.x);
+ BPLONG(b+41, sp.y);
+ BPSHORT(b+45, n);
+ b += 47;
+ if(bg){
+ BPLONG(b, bg->id);
+ BPLONG(b+4, bgp.x);
+ BPLONG(b+8, bgp.y);
+ b += 12;
+ }
+ ec = &cbuf[n];
+ for(c=cbuf; c<ec; c++, b+=2)
+ BPSHORT(b, *c);
+ pt.x += wid;
+ bgp.x += wid;
+ agefont(f);
+ len -= n;
+
+ if(subfontname)
+ goto Nextfont;
}
freesubfont(sf);
return pt;
--- a/sys/src/libdraw/stringwidth.c
+++ b/sys/src/libdraw/stringwidth.c
@@ -5,13 +5,11 @@
int
_stringnwidth(Font *f, char *s, Rune *r, int len)
{
- int wid, twid, n, max, l;
- char *name;
+ int wid, twid, n, max, try;
enum { Max = 64 };
ushort cbuf[Max];
Rune rune, **rptr;
char *subfontname, **sptr;
- Font *def;
Subfont *sf;
if(s == nil){
@@ -26,38 +24,38 @@
rptr = &r;
sf = nil;
twid = 0;
- while(len>0 && (*s || *r)){
+ try = 0;
+ while((*s || *r) && len > 0){
max = Max;
if(len < max)
max = len;
- n = 0;
- while((l = cachechars(f, sptr, rptr, cbuf, max, &wid, &subfontname)) <= 0){
- if(++n > 10){
- if(*r)
- rune = *r;
- else
- chartorune(&rune, s);
- if(f->name != nil)
- name = f->name;
- else
- name = "unnamed font";
- fprint(2, "stringwidth: bad character set for rune 0x%.4ux in %s\n", rune, name);
- return twid;
- }
+ if((n = cachechars(f, sptr, rptr, cbuf, max, &wid, &subfontname)) <= 0){
if(subfontname){
+ if(++try > 10)
+ break;
+ Nextfont:
freesubfont(sf);
- if((sf=_getsubfont(f->display, subfontname)) == 0){
- def = f->display->defaultfont;
- if(def && f!=def)
- f = def;
- else
- break;
- }
+ if((sf=_getsubfont(f->display, subfontname)) != nil)
+ continue;
+ if(f->display == nil || f->display->defaultfont == nil || f->display->defaultfont == f)
+ break;
+ f = f->display->defaultfont;
+ continue;
}
+ if(*r)
+ r++;
+ else
+ s += chartorune(&rune, s);
+ len--;
+ continue;
}
+ try = 0;
agefont(f);
twid += wid;
- len -= l;
+ len -= n;
+
+ if(subfontname)
+ goto Nextfont;
}
freesubfont(sf);
return twid;