diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/libdraw |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/libdraw')
59 files changed, 6584 insertions, 0 deletions
diff --git a/sys/src/libdraw/alloc.c b/sys/src/libdraw/alloc.c new file mode 100755 index 000000000..7884321ac --- /dev/null +++ b/sys/src/libdraw/alloc.c @@ -0,0 +1,242 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +Image* +allocimage(Display *d, Rectangle r, ulong chan, int repl, ulong val) +{ + Image* i; + + i = _allocimage(nil, d, r, chan, repl, val, 0, 0); + if (i) + setmalloctag(i, getcallerpc(&d)); + return i; +} + +Image* +_allocimage(Image *ai, Display *d, Rectangle r, ulong chan, int repl, ulong val, int screenid, int refresh) +{ + uchar *a; + char *err; + Image *i; + Rectangle clipr; + int id; + int depth; + + err = 0; + i = 0; + + if(chan == 0){ + werrstr("bad channel descriptor"); + return nil; + } + + depth = chantodepth(chan); + if(depth == 0){ + err = "bad channel descriptor"; + Error: + if(err) + werrstr("allocimage: %s", err); + else + werrstr("allocimage: %r"); + free(i); + return 0; + } + + /* flush pending data so we don't get error allocating the image */ + flushimage(d, 0); + a = bufimage(d, 1+4+4+1+4+1+4*4+4*4+4); + if(a == 0) + goto Error; + d->imageid++; + id = d->imageid; + a[0] = 'b'; + BPLONG(a+1, id); + BPLONG(a+5, screenid); + a[9] = refresh; + BPLONG(a+10, chan); + a[14] = repl; + BPLONG(a+15, r.min.x); + BPLONG(a+19, r.min.y); + BPLONG(a+23, r.max.x); + BPLONG(a+27, r.max.y); + if(repl) + /* huge but not infinite, so various offsets will leave it huge, not overflow */ + clipr = Rect(-0x3FFFFFFF, -0x3FFFFFFF, 0x3FFFFFFF, 0x3FFFFFFF); + else + clipr = r; + BPLONG(a+31, clipr.min.x); + BPLONG(a+35, clipr.min.y); + BPLONG(a+39, clipr.max.x); + BPLONG(a+43, clipr.max.y); + BPLONG(a+47, val); + if(flushimage(d, 0) < 0) + goto Error; + + if(ai) + i = ai; + else{ + i = malloc(sizeof(Image)); + if(i == nil){ + a = bufimage(d, 1+4); + if(a){ + a[0] = 'f'; + BPLONG(a+1, id); + flushimage(d, 0); + } + goto Error; + } + } + i->display = d; + i->id = id; + i->depth = depth; + i->chan = chan; + i->r = r; + i->clipr = clipr; + i->repl = repl; + i->screen = 0; + i->next = 0; + return i; +} + +Image* +namedimage(Display *d, char *name) +{ + uchar *a; + char *err, buf[12*12+1]; + Image *i; + int id, n; + ulong chan; + + err = 0; + i = 0; + + n = strlen(name); + if(n >= 256){ + err = "name too long"; + Error: + if(err) + werrstr("namedimage: %s", err); + else + werrstr("namedimage: %r"); + if(i) + free(i); + return 0; + } + /* flush pending data so we don't get error allocating the image */ + flushimage(d, 0); + a = bufimage(d, 1+4+1+n); + if(a == 0) + goto Error; + d->imageid++; + id = d->imageid; + a[0] = 'n'; + BPLONG(a+1, id); + a[5] = n; + memmove(a+6, name, n); + if(flushimage(d, 0) < 0) + goto Error; + + if(pread(d->ctlfd, buf, sizeof buf, 0) < 12*12) + goto Error; + buf[12*12] = '\0'; + + i = malloc(sizeof(Image)); + if(i == nil){ + Error1: + a = bufimage(d, 1+4); + if(a){ + a[0] = 'f'; + BPLONG(a+1, id); + flushimage(d, 0); + } + goto Error; + } + i->display = d; + i->id = id; + if((chan=strtochan(buf+2*12))==0){ + werrstr("bad channel '%.12s' from devdraw", buf+2*12); + goto Error1; + } + i->chan = chan; + i->depth = chantodepth(chan); + i->repl = atoi(buf+3*12); + i->r.min.x = atoi(buf+4*12); + i->r.min.y = atoi(buf+5*12); + i->r.max.x = atoi(buf+6*12); + i->r.max.y = atoi(buf+7*12); + i->clipr.min.x = atoi(buf+8*12); + i->clipr.min.y = atoi(buf+9*12); + i->clipr.max.x = atoi(buf+10*12); + i->clipr.max.y = atoi(buf+11*12); + i->screen = 0; + i->next = 0; + return i; +} + +int +nameimage(Image *i, char *name, int in) +{ + uchar *a; + int n; + + n = strlen(name); + a = bufimage(i->display, 1+4+1+1+n); + if(a == 0) + return 0; + a[0] = 'N'; + BPLONG(a+1, i->id); + a[5] = in; + a[6] = n; + memmove(a+7, name, n); + if(flushimage(i->display, 0) < 0) + return 0; + return 1; +} + +int +_freeimage1(Image *i) +{ + uchar *a; + Display *d; + Image *w; + + if(i == 0 || i->display == 0) + return 0; + /* make sure no refresh events occur on this if we block in the write */ + d = i->display; + /* flush pending data so we don't get error deleting the image */ + flushimage(d, 0); + a = bufimage(d, 1+4); + if(a == 0) + return -1; + a[0] = 'f'; + BPLONG(a+1, i->id); + if(i->screen){ + w = d->windows; + if(w == i) + d->windows = i->next; + else + while(w){ + if(w->next == i){ + w->next = i->next; + break; + } + w = w->next; + } + } + if(flushimage(d, i->screen!=0) < 0) + return -1; + + return 0; +} + +int +freeimage(Image *i) +{ + int ret; + + ret = _freeimage1(i); + free(i); + return ret; +} diff --git a/sys/src/libdraw/allocimagemix.c b/sys/src/libdraw/allocimagemix.c new file mode 100755 index 000000000..45e26d14d --- /dev/null +++ b/sys/src/libdraw/allocimagemix.c @@ -0,0 +1,43 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +Image* +allocimagemix(Display *d, ulong color1, ulong color3) +{ + Image *t, *b; + static Image *qmask; + + if(qmask == nil) + qmask = allocimage(d, Rect(0,0,1,1), GREY8, 1, 0x3F3F3FFF); + + if(d->screenimage->depth <= 8){ /* create a 2×2 texture */ + t = allocimage(d, Rect(0,0,1,1), d->screenimage->chan, 0, color1); + if(t == nil) + return nil; + + b = allocimage(d, Rect(0,0,2,2), d->screenimage->chan, 1, color3); + if(b == nil){ + freeimage(t); + return nil; + } + + draw(b, Rect(0,0,1,1), t, nil, ZP); + freeimage(t); + return b; + }else{ /* use a solid color, blended using alpha */ + t = allocimage(d, Rect(0,0,1,1), d->screenimage->chan, 1, color1); + if(t == nil) + return nil; + + b = allocimage(d, Rect(0,0,1,1), d->screenimage->chan, 1, color3); + if(b == nil){ + freeimage(t); + return nil; + } + + draw(b, b->r, t, qmask, ZP); + freeimage(t); + return b; + } +} diff --git a/sys/src/libdraw/arith.c b/sys/src/libdraw/arith.c new file mode 100755 index 000000000..893f39ced --- /dev/null +++ b/sys/src/libdraw/arith.c @@ -0,0 +1,191 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +Point +Pt(int x, int y) +{ + Point p; + + p.x = x; + p.y = y; + return p; +} + +Rectangle +Rect(int x, int y, int bx, int by) +{ + Rectangle r; + + r.min.x = x; + r.min.y = y; + r.max.x = bx; + r.max.y = by; + return r; +} + +Rectangle +Rpt(Point min, Point max) +{ + Rectangle r; + + r.min = min; + r.max = max; + return r; +} + +Point +addpt(Point a, Point b) +{ + a.x += b.x; + a.y += b.y; + return a; +} + +Point +subpt(Point a, Point b) +{ + a.x -= b.x; + a.y -= b.y; + return a; +} + +Rectangle +insetrect(Rectangle r, int n) +{ + r.min.x += n; + r.min.y += n; + r.max.x -= n; + r.max.y -= n; + return r; +} + +Point +divpt(Point a, int b) +{ + a.x /= b; + a.y /= b; + return a; +} + +Point +mulpt(Point a, int b) +{ + a.x *= b; + a.y *= b; + return a; +} + +Rectangle +rectsubpt(Rectangle r, Point p) +{ + r.min.x -= p.x; + r.min.y -= p.y; + r.max.x -= p.x; + r.max.y -= p.y; + return r; +} + +Rectangle +rectaddpt(Rectangle r, Point p) +{ + r.min.x += p.x; + r.min.y += p.y; + r.max.x += p.x; + r.max.y += p.y; + return r; +} + +int +eqpt(Point p, Point q) +{ + return p.x==q.x && p.y==q.y; +} + +int +eqrect(Rectangle r, Rectangle s) +{ + return r.min.x==s.min.x && r.max.x==s.max.x && + r.min.y==s.min.y && r.max.y==s.max.y; +} + +int +rectXrect(Rectangle r, Rectangle s) +{ + return r.min.x<s.max.x && s.min.x<r.max.x && + r.min.y<s.max.y && s.min.y<r.max.y; +} + +int +rectinrect(Rectangle r, Rectangle s) +{ + return s.min.x<=r.min.x && r.max.x<=s.max.x && s.min.y<=r.min.y && r.max.y<=s.max.y; +} + +int +ptinrect(Point p, Rectangle r) +{ + return p.x>=r.min.x && p.x<r.max.x && + p.y>=r.min.y && p.y<r.max.y; +} + +Rectangle +canonrect(Rectangle r) +{ + int t; + if (r.max.x < r.min.x) { + t = r.min.x; + r.min.x = r.max.x; + r.max.x = t; + } + if (r.max.y < r.min.y) { + t = r.min.y; + r.min.y = r.max.y; + r.max.y = t; + } + return r; +} + +void +combinerect(Rectangle *r1, Rectangle r2) +{ + if(r1->min.x > r2.min.x) + r1->min.x = r2.min.x; + if(r1->min.y > r2.min.y) + r1->min.y = r2.min.y; + if(r1->max.x < r2.max.x) + r1->max.x = r2.max.x; + if(r1->max.y < r2.max.y) + r1->max.y = r2.max.y; +} + +ulong drawld2chan[] = { + GREY1, + GREY2, + GREY4, + CMAP8, +}; + +/* + * was used by libmemlayer/line.c; made static, instead of deleting it, + * to avoid updating many binaries on sources. + */ +static int log2[] = { -1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, -1, -1, 4 /* BUG */, -1, -1, -1, -1, -1, -1, -1, 5 }; + +ulong +setalpha(ulong color, uchar alpha) +{ + int red, green, blue; + + red = (color >> 3*8) & 0xFF; + green = (color >> 2*8) & 0xFF; + blue = (color >> 1*8) & 0xFF; + /* ignore incoming alpha */ + red = (red * alpha)/255; + green = (green * alpha)/255; + blue = (blue * alpha)/255; + return (red<<3*8) | (green<<2*8) | (blue<<1*8) | (alpha<<0*8); +} + +Point ZP; +Rectangle ZR; diff --git a/sys/src/libdraw/bezier.c b/sys/src/libdraw/bezier.c new file mode 100755 index 000000000..dca61bc0b --- /dev/null +++ b/sys/src/libdraw/bezier.c @@ -0,0 +1,244 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +#define PINC 32 /* realloc granularity */ + +typedef struct Plist Plist; +struct Plist +{ + Point *p; + int np; /* -1 if malloc/realloc failed */ +}; + +static void +appendpt(Plist *l, Point p) +{ + if(l->np == -1) + return; + if(l->np == 0) + l->p = malloc(PINC*sizeof(Point)); + else if(l->np%PINC == 0) + l->p = realloc(l->p, (l->np+PINC)*sizeof(Point)); + if(l->p == 0){ + l->np = -1; + return; + } + l->p[l->np++] = p; +} + +static int +normsq(Point p) +{ + return p.x*p.x+p.y*p.y; +} + +static int +psdist(Point p, Point a, Point b) +{ + int num, den; + + p = subpt(p, a); + b = subpt(b, a); + num = p.x*b.x + p.y*b.y; + if(num <= 0) + return normsq(p); + den = normsq(b); + if(num >= den) + return normsq(subpt(b, p)); + return normsq(subpt(divpt(mulpt(b, num), den), p)); +} + +/* + * Convert cubic Bezier curve control points to polyline + * vertices. Leaves the last vertex off, so you can continue + * with another curve. + */ +static void +bpts1(Plist *l, Point p0, Point p1, Point p2, Point p3, int scale) +{ + Point p01, p12, p23, p012, p123, p0123; + Point tp0, tp1, tp2, tp3; + tp0=divpt(p0, scale); + tp1=divpt(p1, scale); + tp2=divpt(p2, scale); + tp3=divpt(p3, scale); + if(psdist(tp1, tp0, tp3)<=1 && psdist(tp2, tp0, tp3)<=1){ + appendpt(l, tp0); + appendpt(l, tp1); + appendpt(l, tp2); + } + else{ + /* + * if scale factor is getting too big for comfort, + * rescale now & concede the rounding error + */ + if(scale>(1<<12)){ + p0=tp0; + p1=tp1; + p2=tp2; + p3=tp3; + scale=1; + } + p01=addpt(p0, p1); + p12=addpt(p1, p2); + p23=addpt(p2, p3); + p012=addpt(p01, p12); + p123=addpt(p12, p23); + p0123=addpt(p012, p123); + bpts1(l, mulpt(p0, 8), mulpt(p01, 4), mulpt(p012, 2), p0123, scale*8); + bpts1(l, p0123, mulpt(p123, 2), mulpt(p23, 4), mulpt(p3, 8), scale*8); + } +} + +static void +bpts(Plist *l, Point p0, Point p1, Point p2, Point p3) +{ + bpts1(l, p0, p1, p2, p3, 1); +} + +static void +bezierpts(Plist *l, Point p0, Point p1, Point p2, Point p3) +{ + bpts(l, p0, p1, p2, p3); + appendpt(l, p3); +} + +static void +_bezsplinepts(Plist *l, Point *pt, int npt) +{ + Point *p, *ep; + Point a, b, c, d; + int periodic; + + if(npt<3) + return; + ep = &pt[npt-3]; + periodic = eqpt(pt[0], ep[2]); + if(periodic){ + a = divpt(addpt(ep[1], pt[0]), 2); + b = divpt(addpt(ep[1], mulpt(pt[0], 5)), 6); + c = divpt(addpt(mulpt(pt[0], 5), pt[1]), 6); + d = divpt(addpt(pt[0], pt[1]), 2); + bpts(l, a, b, c, d); + } + for(p=pt; p<=ep; p++){ + if(p==pt && !periodic){ + a = p[0]; + b = divpt(addpt(p[0], mulpt(p[1], 2)), 3); + } + else{ + a = divpt(addpt(p[0], p[1]), 2); + b = divpt(addpt(p[0], mulpt(p[1], 5)), 6); + } + if(p==ep && !periodic){ + c = divpt(addpt(mulpt(p[1], 2), p[2]), 3); + d = p[2]; + } + else{ + c = divpt(addpt(mulpt(p[1], 5), p[2]), 6); + d = divpt(addpt(p[1], p[2]), 2); + } + bpts(l, a, b, c, d); + } + appendpt(l, d); +} + +int +bezsplinepts(Point *pt, int npt, Point **pp) +{ + Plist l; + l.np = 0; + l.p = nil; + _bezsplinepts(&l, pt, npt); + *pp = l.p; + return l.np; +} + +int +bezier(Image *dst, Point p0, Point p1, Point p2, Point p3, int end0, int end1, int radius, Image *src, Point sp) +{ + return bezierop(dst, p0, p1, p2, p3, end0, end1, radius, src, sp, SoverD); +} + +int +bezierop(Image *dst, Point p0, Point p1, Point p2, Point p3, int end0, int end1, int radius, Image *src, Point sp, Drawop op) +{ + Plist l; + + l.np = 0; + bezierpts(&l, p0, p1, p2, p3); + if(l.np == -1) + return 0; + if(l.np != 0){ + polyop(dst, l.p, l.np, end0, end1, radius, src, addpt(subpt(sp, p0), l.p[0]), op); + free(l.p); + } + return 1; +} + +int +bezspline(Image *dst, Point *pt, int npt, int end0, int end1, int radius, Image *src, Point sp) +{ + return bezsplineop(dst, pt, npt, end0, end1, radius, src, sp, SoverD); +} + +int +bezsplineop(Image *dst, Point *pt, int npt, int end0, int end1, int radius, Image *src, Point sp, Drawop op) +{ + Plist l; + + l.np = 0; + _bezsplinepts(&l, pt, npt); + if(l.np==-1) + return 0; + if(l.np != 0){ + polyop(dst, l.p, l.np, end0, end1, radius, src, addpt(subpt(sp, pt[0]), l.p[0]), op); + free(l.p); + } + return 1; +} + +int +fillbezier(Image *dst, Point p0, Point p1, Point p2, Point p3, int w, Image *src, Point sp) +{ + return fillbezierop(dst, p0, p1, p2, p3, w, src, sp, SoverD); +} + +int +fillbezierop(Image *dst, Point p0, Point p1, Point p2, Point p3, int w, Image *src, Point sp, Drawop op) +{ + Plist l; + + l.np = 0; + bezierpts(&l, p0, p1, p2, p3); + if(l.np == -1) + return 0; + if(l.np != 0){ + fillpolyop(dst, l.p, l.np, w, src, addpt(subpt(sp, p0), l.p[0]), op); + free(l.p); + } + return 1; +} + +int +fillbezspline(Image *dst, Point *pt, int npt, int w, Image *src, Point sp) +{ + return fillbezsplineop(dst, pt, npt, w, src, sp, SoverD); +} + +int +fillbezsplineop(Image *dst, Point *pt, int npt, int w, Image *src, Point sp, Drawop op) +{ + Plist l; + + l.np = 0; + _bezsplinepts(&l, pt, npt); + if(l.np == -1) + return 0; + if(l.np > 0){ + fillpolyop(dst, l.p, l.np, w, src, addpt(subpt(sp, pt[0]), l.p[0]), op); + free(l.p); + } + return 1; +} diff --git a/sys/src/libdraw/border.c b/sys/src/libdraw/border.c new file mode 100755 index 000000000..22637dfad --- /dev/null +++ b/sys/src/libdraw/border.c @@ -0,0 +1,21 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +void +border(Image *im, Rectangle r, int i, Image *color, Point sp) +{ + if(i < 0){ + r = insetrect(r, i); + sp = addpt(sp, Pt(i,i)); + i = -i; + } + draw(im, Rect(r.min.x, r.min.y, r.max.x, r.min.y+i), + color, nil, sp); + draw(im, Rect(r.min.x, r.max.y-i, r.max.x, r.max.y), + color, nil, Pt(sp.x, sp.y+Dy(r)-i)); + draw(im, Rect(r.min.x, r.min.y+i, r.min.x+i, r.max.y-i), + color, nil, Pt(sp.x, sp.y+i)); + draw(im, Rect(r.max.x-i, r.min.y+i, r.max.x, r.max.y-i), + color, nil, Pt(sp.x+Dx(r)-i, sp.y+i)); +} diff --git a/sys/src/libdraw/buildfont.c b/sys/src/libdraw/buildfont.c new file mode 100755 index 000000000..ba32e775b --- /dev/null +++ b/sys/src/libdraw/buildfont.c @@ -0,0 +1,141 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +static char* +skip(char *s) +{ + while(*s==' ' || *s=='\n' || *s=='\t') + s++; + return s; +} + +Font* +buildfont(Display *d, char *buf, char *name) +{ + Font *fnt; + Cachefont *c; + char *s, *t; + ulong min, max; + int offset; + char badform[] = "bad font format: number expected (char position %d)"; + + s = buf; + fnt = malloc(sizeof(Font)); + if(fnt == 0) + return 0; + memset(fnt, 0, sizeof(Font)); + fnt->display = d; + fnt->name = strdup(name); + fnt->ncache = NFCACHE+NFLOOK; + fnt->nsubf = NFSUBF; + fnt->cache = malloc(fnt->ncache * sizeof(fnt->cache[0])); + fnt->subf = malloc(fnt->nsubf * sizeof(fnt->subf[0])); + if(fnt->name==0 || fnt->cache==0 || fnt->subf==0){ + Err2: + free(fnt->name); + free(fnt->cache); + free(fnt->subf); + free(fnt->sub); + free(fnt); + return 0; + } + fnt->height = strtol(s, &s, 0); + s = skip(s); + fnt->ascent = strtol(s, &s, 0); + s = skip(s); + if(fnt->height<=0 || fnt->ascent<=0){ + werrstr("bad height or ascent in font file"); + goto Err2; + } + fnt->width = 0; + fnt->nsub = 0; + fnt->sub = 0; + + memset(fnt->subf, 0, fnt->nsubf * sizeof(fnt->subf[0])); + memset(fnt->cache, 0, fnt->ncache*sizeof(fnt->cache[0])); + fnt->age = 1; + do{ + /* must be looking at a number now */ + if(*s<'0' || '9'<*s){ + werrstr(badform, s-buf); + goto Err3; + } + min = strtol(s, &s, 0); + s = skip(s); + /* must be looking at a number now */ + if(*s<'0' || '9'<*s){ + werrstr(badform, s-buf); + goto Err3; + } + max = strtol(s, &s, 0); + s = skip(s); + if(*s==0 || min>=65536 || max>=65536 || min>max){ + werrstr("illegal subfont range"); + Err3: + freefont(fnt); + return 0; + } + t = s; + offset = strtol(s, &t, 0); + if(t>s && (*t==' ' || *t=='\t' || *t=='\n')) + s = skip(t); + else + offset = 0; + fnt->sub = realloc(fnt->sub, (fnt->nsub+1)*sizeof(Cachefont*)); + if(fnt->sub == 0){ + /* realloc manual says fnt->sub may have been destroyed */ + fnt->nsub = 0; + goto Err3; + } + c = malloc(sizeof(Cachefont)); + if(c == 0) + goto Err3; + fnt->sub[fnt->nsub] = c; + c->min = min; + c->max = max; + c->offset = offset; + t = s; + while(*s && *s!=' ' && *s!='\n' && *s!='\t') + s++; + *s++ = 0; + c->subfontname = 0; + c->name = strdup(t); + if(c->name == 0){ + free(c); + goto Err3; + } + s = skip(s); + fnt->nsub++; + }while(*s); + return fnt; +} + +void +freefont(Font *f) +{ + int i; + Cachefont *c; + Subfont *s; + + if(f == 0) + return; + + for(i=0; i<f->nsub; i++){ + c = f->sub[i]; + free(c->subfontname); + free(c->name); + free(c); + } + for(i=0; i<f->nsubf; i++){ + s = f->subf[i].f; + if(s && s!=display->defaultsubfont) + freesubfont(s); + } + freeimage(f->cacheimage); + free(f->name); + free(f->cache); + free(f->subf); + free(f->sub); + free(f); +} diff --git a/sys/src/libdraw/bytesperline.c b/sys/src/libdraw/bytesperline.c new file mode 100755 index 000000000..08ff7d7fe --- /dev/null +++ b/sys/src/libdraw/bytesperline.c @@ -0,0 +1,34 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +static +int +unitsperline(Rectangle r, int d, int bitsperunit) +{ + ulong l, t; + + if(d <= 0 || d > 32) /* being called wrong. d is image depth. */ + abort(); + + if(r.min.x >= 0){ + l = (r.max.x*d+bitsperunit-1)/bitsperunit; + l -= (r.min.x*d)/bitsperunit; + }else{ /* make positive before divide */ + t = (-r.min.x*d+bitsperunit-1)/bitsperunit; + l = t+(r.max.x*d+bitsperunit-1)/bitsperunit; + } + return l; +} + +int +wordsperline(Rectangle r, int d) +{ + return unitsperline(r, d, 8*sizeof(ulong)); +} + +int +bytesperline(Rectangle r, int d) +{ + return unitsperline(r, d, 8); +} diff --git a/sys/src/libdraw/chan.c b/sys/src/libdraw/chan.c new file mode 100755 index 000000000..9c3fe9646 --- /dev/null +++ b/sys/src/libdraw/chan.c @@ -0,0 +1,81 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +static char channames[] = "rgbkamx"; +char* +chantostr(char *buf, ulong cc) +{ + ulong c, rc; + char *p; + + if(chantodepth(cc) == 0) + return nil; + + /* reverse the channel descriptor so we can easily generate the string in the right order */ + rc = 0; + for(c=cc; c; c>>=8){ + rc <<= 8; + rc |= c&0xFF; + } + + p = buf; + for(c=rc; c; c>>=8) { + *p++ = channames[TYPE(c)]; + *p++ = '0'+NBITS(c); + } + *p = 0; + + return buf; +} + +/* avoid pulling in ctype when using with drawterm etc. */ +static int +isspace(char c) +{ + return c==' ' || c== '\t' || c=='\r' || c=='\n'; +} + +ulong +strtochan(char *s) +{ + char *p, *q; + ulong c; + int t, n, d; + + c = 0; + d = 0; + p=s; + while(*p && isspace(*p)) + p++; + + while(*p && !isspace(*p)){ + if((q = strchr(channames, p[0])) == nil) + return 0; + t = q-channames; + if(p[1] < '0' || p[1] > '9') + return 0; + n = p[1]-'0'; + d += n; + c = (c<<8) | __DC(t, n); + p += 2; + } + if(d==0 || (d>8 && d%8) || (d<8 && 8%d)) + return 0; + return c; +} + +int +chantodepth(ulong c) +{ + int n; + + for(n=0; c; c>>=8){ + if(TYPE(c) >= NChan || NBITS(c) > 8 || NBITS(c) <= 0) + return 0; + n += NBITS(c); + } + if(n==0 || (n>8 && n%8) || (n<8 && 8%n)) + return 0; + return n; +} diff --git a/sys/src/libdraw/cloadimage.c b/sys/src/libdraw/cloadimage.c new file mode 100755 index 000000000..eb30466cb --- /dev/null +++ b/sys/src/libdraw/cloadimage.c @@ -0,0 +1,49 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +int +cloadimage(Image *i, Rectangle r, uchar *data, int ndata) +{ + int m, nb, miny, maxy, ncblock; + uchar *a; + + if(!rectinrect(r, i->r)){ + werrstr("cloadimage: bad rectangle"); + return -1; + } + + miny = r.min.y; + m = 0; + ncblock = _compblocksize(r, i->depth); + while(miny != r.max.y){ + maxy = atoi((char*)data+0*12); + nb = atoi((char*)data+1*12); + if(maxy<=miny || r.max.y<maxy){ + werrstr("creadimage: bad maxy %d", maxy); + return -1; + } + data += 2*12; + ndata -= 2*12; + m += 2*12; + if(nb<=0 || ncblock<nb || nb>ndata){ + werrstr("creadimage: bad count %d", nb); + return -1; + } + a = bufimage(i->display, 21+nb); + if(a == nil) + return -1; + a[0] = 'Y'; + BPLONG(a+1, i->id); + BPLONG(a+5, r.min.x); + BPLONG(a+9, miny); + BPLONG(a+13, r.max.x); + BPLONG(a+17, maxy); + memmove(a+21, data, nb); + miny = maxy; + data += nb; + ndata += nb; + m += nb; + } + return m; +} diff --git a/sys/src/libdraw/computil.c b/sys/src/libdraw/computil.c new file mode 100755 index 000000000..30a3d11e6 --- /dev/null +++ b/sys/src/libdraw/computil.c @@ -0,0 +1,38 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +/* + * compressed data are seuences of byte codes. + * if the first byte b has the 0x80 bit set, the next (b^0x80)+1 bytes + * are data. otherwise, it's two bytes specifying a previous string to repeat. + */ +void +_twiddlecompressed(uchar *buf, int n) +{ + uchar *ebuf; + int j, k, c; + + ebuf = buf+n; + while(buf < ebuf){ + c = *buf++; + if(c >= 128){ + k = c-128+1; + for(j=0; j<k; j++, buf++) + *buf ^= 0xFF; + }else + buf++; + } +} + +int +_compblocksize(Rectangle r, int depth) +{ + int bpl; + + bpl = bytesperline(r, depth); + bpl = 2*bpl; /* add plenty extra for blocking, etc. */ + if(bpl < NCBLOCK) + return NCBLOCK; + return bpl; +} diff --git a/sys/src/libdraw/creadimage.c b/sys/src/libdraw/creadimage.c new file mode 100755 index 000000000..b9d7e4ed8 --- /dev/null +++ b/sys/src/libdraw/creadimage.c @@ -0,0 +1,122 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +Image * +creadimage(Display *d, int fd, int dolock) +{ + char hdr[5*12+1]; + Rectangle r; + int m, nb, miny, maxy, new, ldepth, ncblock; + uchar *buf, *a; + Image *i; + ulong chan; + + if(readn(fd, hdr, 5*12) != 5*12) + return nil; + + /* + * distinguish new channel descriptor from old ldepth. + * channel descriptors have letters as well as numbers, + * while ldepths are a single digit formatted as %-11d. + */ + new = 0; + for(m=0; m<10; m++){ + if(hdr[m] != ' '){ + new = 1; + break; + } + } + if(hdr[11] != ' '){ + werrstr("creadimage: bad format"); + return nil; + } + if(new){ + hdr[11] = '\0'; + if((chan = strtochan(hdr)) == 0){ + werrstr("creadimage: bad channel string %s", hdr); + return nil; + } + }else{ + ldepth = ((int)hdr[10])-'0'; + if(ldepth<0 || ldepth>3){ + werrstr("creadimage: bad ldepth %d", ldepth); + return nil; + } + chan = drawld2chan[ldepth]; + } + r.min.x=atoi(hdr+1*12); + r.min.y=atoi(hdr+2*12); + r.max.x=atoi(hdr+3*12); + r.max.y=atoi(hdr+4*12); + if(r.min.x>r.max.x || r.min.y>r.max.y){ + werrstr("creadimage: bad rectangle"); + return nil; + } + + if(d){ + if(dolock) + lockdisplay(d); + i = allocimage(d, r, chan, 0, 0); + setmalloctag(i, getcallerpc(&d)); + if(dolock) + unlockdisplay(d); + if(i == nil) + return nil; + }else{ + i = mallocz(sizeof(Image), 1); + if(i == nil) + return nil; + } + ncblock = _compblocksize(r, chantodepth(chan)); + buf = malloc(ncblock); + if(buf == nil) + goto Errout; + miny = r.min.y; + while(miny != r.max.y){ + if(readn(fd, hdr, 2*12) != 2*12){ + Errout: + if(dolock) + lockdisplay(d); + Erroutlock: + freeimage(i); + if(dolock) + unlockdisplay(d); + free(buf); + return nil; + } + maxy = atoi(hdr+0*12); + nb = atoi(hdr+1*12); + if(maxy<=miny || r.max.y<maxy){ + werrstr("creadimage: bad maxy %d", maxy); + goto Errout; + } + if(nb<=0 || ncblock<nb){ + werrstr("creadimage: bad count %d", nb); + goto Errout; + } + if(readn(fd, buf, nb)!=nb) + goto Errout; + if(d){ + if(dolock) + lockdisplay(d); + a = bufimage(i->display, 21+nb); + if(a == nil) + goto Erroutlock; + a[0] = 'Y'; + BPLONG(a+1, i->id); + BPLONG(a+5, r.min.x); + BPLONG(a+9, miny); + BPLONG(a+13, r.max.x); + BPLONG(a+17, maxy); + if(!new) /* old image: flip the data bits */ + _twiddlecompressed(buf, nb); + memmove(a+21, buf, nb); + if(dolock) + unlockdisplay(d); + } + miny = maxy; + } + free(buf); + return i; +} diff --git a/sys/src/libdraw/debug.c b/sys/src/libdraw/debug.c new file mode 100755 index 000000000..3a6788a83 --- /dev/null +++ b/sys/src/libdraw/debug.c @@ -0,0 +1,16 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +void +drawsetdebug(int v) +{ + uchar *a; + a = bufimage(display, 1+1); + if(a == 0){ + fprint(2, "drawsetdebug: %r\n"); + return; + } + a[0] = 'D'; + a[1] = v; +} diff --git a/sys/src/libdraw/defont.c b/sys/src/libdraw/defont.c new file mode 100755 index 000000000..b0c85e1dc --- /dev/null +++ b/sys/src/libdraw/defont.c @@ -0,0 +1,402 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +/* + * lucm/latin1.9, in uncompressed form + */ +uchar +defontdata[] = +{ +0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x30,0x20,0x20,0x20,0x20,0x20, +0x20,0x20,0x20,0x20,0x20,0x20,0x30,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, +0x20,0x20,0x30,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x32,0x33,0x30,0x34,0x20, +0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x31,0x35,0x20,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x30,0x06,0x06,0x03,0x42,0x40,0x00,0x00,0x00,0x18,0x03,0x03, +0x02,0x43,0x00,0x60,0x60,0x48,0x00,0x0d,0x0c,0x01,0x81,0x80,0xd0,0x90,0x00,0x00, +0x18,0x01,0x81,0x81,0x40,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x7f,0x9c,0x1c, +0x0e,0x07,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x70, +0x38,0x1c,0x0e,0x04,0x81,0xc1,0xc0,0x70,0x00,0x1c,0x1c,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xaa,0x80,0xc0,0x63,0xe3, +0xf1,0xf8,0xfe,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x7f,0xff,0xff,0x1f,0x8f, +0xc7,0xe3,0xf1,0xfb,0x7e,0x3e,0x3f,0x8f,0xff,0xe3,0xe3,0xff,0xff,0xff,0xff,0xff, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x0c,0x18,0x09,0x05,0x82,0x40,0xc0,0x00,0x00,0x06,0x0c,0x04, +0x82,0x40,0xc1,0x80,0x90,0x48,0x00,0x16,0x03,0x06,0x02,0x41,0x60,0x90,0x00,0x00, +0x06,0x06,0x02,0x41,0x41,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x7f,0xa0,0x10, +0x08,0x04,0x02,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x48, +0x24,0x12,0x09,0x06,0x82,0x01,0x00,0x90,0x00,0x20,0x10,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x04,0x80,0x00,0x40,0x00,0x00,0x38,0x06,0x18,0x00,0x00,0x00,0x00,0x00, +0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0xc6,0x01,0xf0,0x00,0x00,0x0c,0x00,0x18,0x00,0x00,0x30,0x00,0x3c, +0x00,0x60,0x06,0x01,0x8c,0x07,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xe0,0xc3,0xc0,0x01,0x54,0x9c,0xc0,0x5f,0xef, +0xf7,0xfb,0xfd,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0x7f,0xff,0xff,0x6f,0xb7, +0xdb,0xed,0xf6,0xf9,0x7d,0xfe,0xff,0x6f,0xff,0xdf,0xef,0xff,0xff,0xff,0xff,0xff, +0xff,0x00,0x01,0x00,0x00,0x00,0x00,0x30,0x00,0x14,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x30,0x06,0x06,0x06,0x82,0x80,0xc0,0x00, +0x00,0x18,0x03,0x03,0x02,0x41,0x80,0x30,0x30,0x24,0x76,0x0d,0x0c,0x00,0xc0,0xc0, +0xd0,0x50,0x00,0x00,0x18,0x01,0x81,0x81,0x40,0x30,0x00,0x28,0x0f,0x7f,0xbc,0x1c, +0x0e,0x07,0x03,0xc0,0x10,0x70,0x24,0x10,0x09,0x07,0x03,0x80,0xe0,0x70,0x90,0x48, +0x24,0x12,0x09,0x05,0x81,0x81,0xc0,0x80,0x70,0x18,0x1c,0x07,0x01,0xc1,0xc0,0x90, +0x00,0x0c,0x04,0x84,0x83,0xe1,0xc0,0xe0,0x38,0x0c,0x0c,0x02,0x00,0x00,0x00,0x00, +0x00,0x06,0x1c,0x06,0x0f,0x87,0xc0,0x63,0xf8,0x78,0xfe,0x3e,0x0e,0x00,0x00,0x00, +0x00,0x00,0x00,0x7c,0x1c,0x0c,0x1f,0x03,0xc7,0xc3,0xf1,0xf8,0x3c,0x63,0x3f,0x0f, +0x8c,0x66,0x06,0x19,0x84,0x78,0x7e,0x1e,0x1f,0x07,0xcf,0xf3,0x1b,0x0d,0x86,0x63, +0x61,0x9f,0xc6,0x06,0x00,0x30,0x00,0x00,0x10,0x00,0x18,0x00,0x00,0x30,0x00,0x60, +0x00,0x60,0x06,0x01,0x8c,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80, +0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0xc0,0x60,0x00,0xaa,0xb6,0xc0,0x43,0xe3, +0xf1,0xf8,0xfc,0x3f,0xef,0x8f,0xdb,0xef,0xf6,0xf8,0xfb,0xff,0x1f,0x8f,0x6f,0xb7, +0xdb,0xed,0xf6,0xfa,0x7e,0x7e,0x3f,0x7f,0x8f,0xe7,0xe3,0xf8,0xfe,0x3e,0x3f,0x6f, +0x00,0x00,0x01,0x01,0xc8,0x0b,0x0c,0x30,0x7c,0x14,0x0f,0x0f,0x00,0x00,0x00,0x00, +0x78,0x00,0x1c,0x00,0x0f,0x07,0x81,0x80,0x00,0x7c,0x00,0x00,0x1c,0x0f,0x80,0x04, +0x42,0x23,0x90,0x00,0x18,0x0c,0x06,0x03,0x01,0x80,0xc0,0x3c,0x3c,0x3f,0x1f,0x8f, +0xc7,0xe7,0xe3,0xf1,0xf8,0xfc,0x7c,0x30,0x8f,0x07,0x83,0xc1,0xe0,0xf0,0x00,0x3d, +0x31,0x98,0xcc,0x66,0x36,0x19,0x80,0xcc,0x0c,0x18,0x09,0x0b,0x02,0x81,0x20,0x00, +0x00,0x06,0x0c,0x04,0x82,0x40,0x60,0xc0,0x48,0x24,0x18,0x16,0x03,0x03,0x01,0x21, +0x60,0x50,0x00,0x00,0x06,0x06,0x02,0x41,0x40,0xc1,0x80,0x28,0x87,0x7f,0x84,0x10, +0x08,0x04,0x02,0x40,0x38,0x48,0x24,0x10,0x09,0x04,0x04,0x81,0x00,0x80,0x90,0x48, +0x24,0x12,0x09,0x04,0x80,0x41,0x00,0x80,0x40,0x04,0x10,0x04,0x02,0x01,0x20,0x90, +0x00,0x0c,0x04,0x84,0x86,0x53,0x65,0xb0,0x08,0x18,0x06,0x0a,0x80,0x00,0x00,0x00, +0x00,0x0c,0x36,0x0e,0x19,0xcc,0xe0,0xe3,0xf8,0xcc,0xfe,0x63,0x1b,0x00,0x00,0x00, +0x00,0x00,0x00,0xc6,0x62,0x0c,0x19,0x86,0x66,0x63,0x01,0x80,0x66,0x63,0x0c,0x01, +0x8c,0xc6,0x06,0x19,0xc4,0xcc,0x63,0x33,0x19,0x8c,0x61,0x83,0x1b,0x0d,0x86,0x63, +0x61,0x80,0xc6,0x03,0x00,0x30,0x30,0x00,0x1c,0x00,0x18,0x00,0x00,0x30,0x00,0x60, +0x00,0x60,0x00,0x00,0x0c,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80, +0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0xc0,0x60,0x01,0x54,0x86,0xc0,0x7b,0xef, +0xf7,0xfb,0xfd,0xbf,0xc7,0xb7,0xdb,0xef,0xf6,0xfb,0xfb,0x7e,0xff,0x7f,0x6f,0xb7, +0xdb,0xed,0xf6,0xfb,0x7f,0xbe,0xff,0x7f,0xbf,0xfb,0xef,0xfb,0xfd,0xfe,0xdf,0x6f, +0xff,0x00,0x07,0x83,0x24,0x13,0x0c,0x30,0xc6,0x00,0x10,0x81,0x80,0x00,0x00,0x00, +0x84,0x00,0x22,0x00,0x01,0x80,0xc0,0x00,0x00,0xf4,0x00,0x00,0x2c,0x18,0xc0,0x0c, +0x46,0x20,0x90,0x00,0x18,0x0c,0x06,0x03,0x01,0x80,0xc0,0x70,0x66,0x30,0x18,0x0c, +0x06,0x01,0x80,0xc0,0x60,0x30,0x66,0x38,0x99,0x8c,0xc6,0x63,0x31,0x98,0x00,0x66, +0x31,0x98,0xcc,0x66,0x36,0x19,0x80,0xcc,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6c,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,0x00,0xff,0x7f,0xb8,0x1c, +0x0e,0x07,0x02,0x40,0x7c,0x70,0x3c,0x10,0x09,0x07,0x04,0x00,0xc0,0x60,0xe0,0x70, +0x38,0x1c,0x0e,0x04,0x83,0x81,0xc0,0x70,0x70,0x38,0x1c,0x07,0x02,0xc1,0xc0,0x90, +0x00,0x0c,0x00,0x04,0x86,0x43,0x69,0xb0,0x30,0x18,0x06,0x07,0x01,0x00,0x00,0x00, +0x00,0x0c,0x63,0x16,0x00,0xc0,0x61,0x62,0x01,0x80,0x06,0x63,0x31,0x80,0x00,0x00, +0x60,0x00,0xc0,0x06,0x43,0x16,0x19,0x8c,0x06,0x33,0x01,0x80,0xc0,0x63,0x0c,0x01, +0x8c,0x86,0x07,0x39,0xc5,0x86,0x63,0x61,0x99,0x8c,0x01,0x83,0x1b,0x0d,0xb6,0x63, +0x31,0x01,0x86,0x03,0x00,0x30,0x30,0x00,0x1c,0x3e,0x1b,0x03,0xc1,0xf0,0xf0,0x60, +0x3e,0x6e,0x3e,0x0f,0x8c,0x60,0xc5,0xb1,0xb8,0x38,0x6c,0x0f,0x8c,0xc7,0xc1,0x83, +0x19,0x8d,0x82,0x63,0x31,0x9f,0xc1,0x80,0xc0,0xc0,0x00,0xaa,0x86,0xc0,0x47,0xe3, +0xf1,0xf8,0xfd,0xbf,0x83,0x8f,0xc3,0xef,0xf6,0xf8,0xfc,0xff,0x3f,0x9f,0x1f,0x8f, +0xc7,0xe3,0xf1,0xfb,0x7c,0x7e,0x3f,0x8f,0x8f,0xc7,0xe3,0xf8,0xfd,0x3e,0x3f,0x6f, +0x00,0x0c,0x0d,0x43,0x03,0xe1,0x88,0x30,0xc0,0x00,0x27,0x41,0x80,0x00,0x00,0x01, +0x72,0x00,0x22,0x04,0x01,0x80,0xc0,0x03,0x18,0xf4,0x00,0x00,0x0c,0x18,0xc0,0x04, +0x82,0x43,0x20,0x18,0x2c,0x16,0x0b,0x05,0x82,0xc1,0x60,0xb0,0xc0,0x30,0x18,0x0c, +0x06,0x01,0x80,0xc0,0x60,0x30,0x63,0x38,0xb0,0xd8,0x6c,0x36,0x1b,0x0c,0x00,0xc7, +0x31,0x98,0xcc,0x66,0x33,0x11,0xf8,0xc8,0x7c,0x3e,0x1f,0x0f,0x87,0xc3,0xe1,0xd8, +0x3c,0x1e,0x0f,0x07,0x83,0xc7,0xc3,0xe1,0xf0,0xf8,0x06,0x37,0x07,0x03,0x81,0xc0, +0xe0,0x70,0x10,0x1d,0x31,0x98,0xcc,0x66,0x33,0x19,0xb0,0xc6,0x8f,0x7f,0x87,0x03, +0x81,0x80,0x90,0x30,0x6c,0x48,0x24,0x10,0x06,0x04,0x04,0x80,0x20,0x10,0x10,0x0e, +0x07,0x03,0x81,0xc0,0x60,0x88,0x38,0x0c,0x40,0x09,0x03,0x84,0x02,0x41,0x40,0x90, +0x00,0x0c,0x00,0x1f,0xe7,0x41,0xd1,0xa0,0x00,0x30,0x03,0x0a,0x81,0x00,0x00,0x00, +0x00,0x18,0x63,0x06,0x00,0xc0,0xc2,0x62,0x01,0xb0,0x0c,0x72,0x31,0x86,0x03,0x00, +0xc0,0x00,0x60,0x06,0x8f,0x16,0x19,0x0c,0x06,0x33,0x01,0x80,0xc0,0x63,0x0c,0x01, +0x8d,0x06,0x07,0x39,0x65,0x86,0x63,0x61,0x99,0x0e,0x01,0x83,0x19,0x89,0xb6,0x32, +0x33,0x03,0x06,0x01,0x80,0x30,0x78,0x00,0x00,0x03,0x1d,0x86,0x23,0x31,0x99,0xfc, +0x66,0x77,0x06,0x01,0x8c,0x40,0xc6,0xd9,0xdc,0x6c,0x76,0x19,0x8d,0xcc,0x27,0xf3, +0x19,0x8d,0x82,0x63,0x31,0x80,0xc0,0x80,0xc0,0x80,0x01,0x54,0x8c,0xc0,0x78,0xfc, +0x7e,0x7f,0x6f,0xcf,0x93,0xb7,0xdb,0xef,0xf9,0xfb,0xff,0xff,0xdf,0xef,0xef,0xf1, +0xf8,0xfc,0x7e,0x3f,0x9f,0x77,0xc7,0xf3,0xbf,0xf6,0xfc,0x7b,0xfd,0xbe,0xbf,0x6f, +0xff,0x0c,0x19,0x03,0x03,0x61,0x98,0x30,0x78,0x00,0x28,0x4f,0x83,0x30,0x00,0x01, +0x4a,0x00,0x1c,0x04,0x03,0x03,0x80,0x03,0x18,0xf4,0x00,0x00,0x0c,0x18,0xd9,0x84, +0x82,0x40,0xa0,0x18,0x2c,0x16,0x0b,0x05,0x82,0xc1,0x60,0xb0,0xc0,0x30,0x18,0x0c, +0x06,0x01,0x80,0xc0,0x60,0x30,0x63,0x2c,0xb0,0xd8,0x6c,0x36,0x1b,0x0c,0x64,0xcb, +0x31,0x98,0xcc,0x66,0x33,0x31,0x8c,0xd8,0x06,0x03,0x01,0x80,0xc0,0x60,0x30,0x6c, +0x62,0x33,0x19,0x8c,0xc6,0x60,0xc0,0x60,0x30,0x18,0x1e,0x3b,0x8d,0x86,0xc3,0x61, +0xb0,0xd8,0x10,0x36,0x31,0x98,0xcc,0x66,0x33,0x19,0xd8,0xc6,0x0f,0x7f,0x82,0x01, +0x02,0x40,0xd0,0x40,0x6c,0x70,0x24,0x1c,0x06,0x04,0x03,0x01,0xc0,0xe0,0x10,0x12, +0x09,0x04,0x82,0x40,0x90,0x50,0x10,0x12,0x70,0x09,0x04,0x04,0x01,0xc1,0x20,0x60, +0x00,0x0c,0x00,0x04,0x83,0xc0,0x20,0xcc,0x00,0x30,0x03,0x02,0x01,0x00,0x00,0x00, +0x00,0x18,0x63,0x06,0x01,0x83,0x84,0x63,0xf1,0xd8,0x18,0x3c,0x31,0x86,0x03,0x01, +0x83,0xf8,0x30,0x1c,0x9b,0x33,0x1e,0x0c,0x06,0x33,0xe1,0x80,0xc0,0x7f,0x0c,0x01, +0x8f,0x06,0x07,0x79,0x65,0x86,0x66,0x61,0x9e,0x07,0x81,0x83,0x19,0x89,0xb6,0x1c, +0x1a,0x03,0x06,0x01,0x80,0x30,0x48,0x00,0x00,0x03,0x18,0xcc,0x06,0x33,0x18,0x60, +0xc6,0x63,0x06,0x01,0x8c,0x80,0xc6,0xd9,0x8c,0xc6,0x63,0x31,0x8e,0x4c,0x01,0x83, +0x19,0x8d,0x92,0x32,0x31,0x81,0x87,0x00,0xc0,0x70,0xe4,0xaa,0x98,0xc0,0x7d,0xfe, +0xfd,0xbf,0x2f,0xbf,0x93,0x8f,0xdb,0xe3,0xf9,0xfb,0xff,0x1e,0x3f,0x1f,0xef,0xed, +0xf6,0xfb,0x7d,0xbf,0x6f,0xaf,0xef,0xed,0x8f,0xf6,0xfb,0xfb,0xfe,0x3e,0xdf,0x9f, +0x00,0x00,0x19,0x0f,0xc6,0x30,0xd0,0x00,0xcc,0x00,0x28,0x59,0x86,0x67,0xf0,0x01, +0x72,0x00,0x00,0x3f,0x86,0x00,0xc0,0x03,0x18,0xf4,0x00,0x00,0x0c,0x18,0xcc,0xc5, +0x32,0x83,0x4c,0x00,0x66,0x33,0x19,0x8c,0xc6,0x63,0x31,0xbc,0xc0,0x3e,0x1f,0x0f, +0x87,0xc1,0x80,0xc0,0x60,0x30,0xfb,0x2c,0xb0,0xd8,0x6c,0x36,0x1b,0x0c,0x38,0xcb, +0x31,0x98,0xcc,0x66,0x31,0xa1,0x8c,0xcc,0x06,0x03,0x01,0x80,0xc0,0x60,0x30,0x6c, +0xc0,0x63,0x31,0x98,0xcc,0x60,0xc0,0x60,0x30,0x18,0x37,0x31,0x98,0xcc,0x66,0x33, +0x19,0x8c,0x00,0x67,0x31,0x98,0xcc,0x66,0x33,0x19,0x8c,0xc6,0x1f,0x7f,0x82,0x01, +0x02,0x40,0xb0,0x40,0x6c,0x07,0x03,0x83,0x80,0xe0,0xe0,0x00,0x18,0x0e,0x10,0x10, +0x08,0x04,0x02,0x00,0xf0,0x20,0x10,0x1e,0x08,0x89,0x03,0x00,0xe0,0x38,0x1c,0x0e, +0x00,0x0c,0x00,0x04,0x81,0xe0,0x41,0x6c,0x00,0x30,0x03,0x00,0x0f,0xe0,0x03,0xf8, +0x00,0x30,0x63,0x06,0x03,0x00,0xc7,0xf0,0x39,0x8c,0x30,0x3e,0x1b,0x80,0x00,0x03, +0x00,0x00,0x18,0x30,0x9b,0x23,0x19,0x0c,0x06,0x33,0x01,0xf8,0xc6,0x63,0x0c,0x01, +0x8d,0x86,0x05,0xd9,0x35,0x86,0x7c,0x61,0x9b,0x01,0xc1,0x83,0x19,0x99,0xb4,0x1c, +0x0c,0x06,0x06,0x00,0xc0,0x30,0xcc,0x00,0x00,0x3f,0x18,0xcc,0x06,0x33,0xf8,0x60, +0xc6,0x63,0x06,0x01,0x8f,0x00,0xc6,0xd9,0x8c,0xc6,0x63,0x31,0x8c,0x0f,0x81,0x83, +0x18,0xd9,0xba,0x1c,0x1b,0x03,0x00,0x80,0xc0,0x81,0x75,0x54,0x98,0xc0,0x7d,0xfe, +0xfd,0xbf,0x4f,0xbf,0x93,0xf8,0xfc,0x7c,0x7f,0x1f,0x1f,0x6f,0xe7,0xf1,0xef,0xef, +0xf7,0xfb,0xfd,0xff,0x0f,0xdf,0xef,0xe1,0xf7,0x76,0xfc,0xff,0x1f,0xc7,0xe3,0xf1, +0xff,0x08,0x19,0x03,0x06,0x31,0xf8,0x00,0xc6,0x00,0x28,0x5b,0x8c,0xc0,0x11,0xf1, +0x4a,0x00,0x00,0x04,0x0c,0x00,0xc0,0x03,0x18,0x74,0x38,0x00,0x0c,0x18,0xc6,0x65, +0x52,0xb8,0x54,0x18,0x46,0x23,0x11,0x88,0xc4,0x62,0x31,0x30,0xc0,0x30,0x18,0x0c, +0x06,0x01,0x80,0xc0,0x60,0x30,0x63,0x26,0xb0,0xd8,0x6c,0x36,0x1b,0x0c,0x10,0xd3, +0x31,0x98,0xcc,0x66,0x30,0xc1,0x8c,0xc6,0x7e,0x3f,0x1f,0x8f,0xc7,0xe3,0xf1,0xfc, +0xc0,0x7f,0x3f,0x9f,0xcf,0xe0,0xc0,0x60,0x30,0x18,0x63,0x31,0x98,0xcc,0x66,0x33, +0x19,0x8c,0xfe,0x6b,0x31,0x98,0xcc,0x66,0x31,0xb1,0x8c,0x6c,0x0e,0x7f,0x82,0x01, +0x01,0x80,0x90,0x30,0xc6,0x08,0x01,0x02,0x00,0x40,0x80,0xe0,0x24,0x04,0x1c,0x10, +0x08,0x04,0x02,0x00,0x90,0x20,0x10,0x12,0x0d,0x86,0x00,0x81,0x00,0x40,0x20,0x10, +0x00,0x04,0x00,0x1f,0xe1,0x70,0xbb,0x28,0x00,0x30,0x03,0x00,0x01,0x00,0x00,0x00, +0x00,0x30,0x63,0x06,0x06,0x00,0x67,0xf0,0x19,0x8c,0x30,0x67,0x0d,0x80,0x00,0x01, +0x83,0xf8,0x30,0x30,0x9b,0x7f,0x19,0x8c,0x06,0x33,0x01,0x80,0xc6,0x63,0x0c,0x01, +0x8c,0xc6,0x05,0xd9,0x35,0x86,0x60,0x61,0x99,0x80,0xe1,0x83,0x18,0xd0,0xdc,0x26, +0x0c,0x0c,0x06,0x00,0xc0,0x30,0x84,0x00,0x00,0x63,0x18,0xcc,0x06,0x33,0x00,0x60, +0xc6,0x63,0x06,0x01,0x8d,0x80,0xc6,0xd9,0x8c,0xc6,0x63,0x31,0x8c,0x03,0xe1,0x83, +0x18,0xd9,0xba,0x1c,0x1b,0x06,0x01,0x80,0xc0,0xc1,0x38,0xaa,0x80,0xc0,0x7d,0xfe, +0xfe,0x7f,0x6f,0xcf,0x39,0xf7,0xfe,0xfd,0xff,0xbf,0x7f,0x0f,0xdb,0xfb,0xe3,0xef, +0xf7,0xfb,0xfd,0xff,0x6f,0xdf,0xef,0xed,0xf2,0x79,0xff,0x7e,0xff,0xbf,0xdf,0xef, +0x00,0x0c,0x19,0x03,0x03,0x60,0x60,0x30,0x66,0x00,0x28,0x4d,0xc6,0x60,0x10,0x00, +0x84,0x00,0x00,0x04,0x0f,0x87,0x80,0x03,0x18,0x14,0x38,0x00,0x3f,0x0f,0x8c,0xc2, +0x90,0x84,0xa4,0x18,0xfe,0x7f,0x3f,0x9f,0xcf,0xe7,0xf1,0xf0,0xc0,0x30,0x18,0x0c, +0x06,0x01,0x80,0xc0,0x60,0x30,0x63,0x26,0xb0,0xd8,0x6c,0x36,0x1b,0x0c,0x38,0xd3, +0x31,0x98,0xcc,0x66,0x30,0xc1,0x98,0xc6,0xc6,0x63,0x31,0x98,0xcc,0x66,0x33,0x60, +0xc0,0x60,0x30,0x18,0x0c,0x00,0xc0,0x60,0x30,0x18,0x63,0x31,0x98,0xcc,0x66,0x33, +0x19,0x8c,0x00,0x6b,0x31,0x98,0xcc,0x66,0x31,0xb1,0x8c,0x6c,0x1c,0x7f,0x81,0x20, +0x90,0x38,0x18,0x0b,0x83,0x06,0x01,0x03,0x80,0x40,0xe0,0x90,0x24,0x04,0x03,0x8e, +0x86,0xc3,0x61,0x90,0x24,0x12,0x0e,0x04,0x8a,0x81,0xc7,0x70,0xc0,0x30,0x18,0x0c, +0x00,0x00,0x00,0x04,0x81,0x31,0x6f,0x30,0x00,0x18,0x06,0x00,0x01,0x00,0x00,0x00, +0x00,0x60,0x63,0x06,0x0c,0x00,0x60,0x60,0x19,0x8c,0x60,0x63,0x01,0x80,0x00,0x00, +0xc0,0x00,0x60,0x00,0x4d,0xe1,0x99,0x8c,0x06,0x33,0x01,0x80,0xc6,0x63,0x0c,0x01, +0x8c,0xc6,0x04,0x99,0x1d,0x86,0x60,0x61,0x99,0x80,0x61,0x83,0x18,0xd0,0xdc,0x63, +0x0c,0x0c,0x06,0x00,0x60,0x30,0x84,0x00,0x00,0x63,0x18,0xcc,0x06,0x33,0x00,0x60, +0x6e,0x63,0x06,0x01,0x8c,0xc0,0xc6,0xd9,0x8c,0xc6,0x63,0x31,0x8c,0x00,0x61,0x83, +0x18,0xd0,0xcc,0x26,0x0e,0x0c,0x03,0x00,0xc0,0x60,0x01,0x54,0x98,0xc0,0x7e,0xdf, +0x6f,0xc7,0xe7,0xf4,0x7c,0xf9,0xfe,0xfc,0x7f,0xbf,0x1f,0x5f,0xdb,0xfb,0xfc,0x71, +0x79,0x3c,0x9e,0x6f,0xdb,0xed,0xf1,0xfb,0x75,0x7e,0x38,0x8f,0x3f,0xcf,0xe7,0xf3, +0xff,0x0c,0x0d,0x03,0x03,0xe1,0xf8,0x30,0x3c,0x00,0x27,0x40,0x03,0x30,0x00,0x00, +0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x18,0x14,0x00,0x00,0x00,0x00,0x19,0x82, +0xf8,0x98,0xbe,0x70,0xc3,0x61,0xb0,0xd8,0x6c,0x36,0x1b,0x30,0xc0,0x30,0x18,0x0c, +0x06,0x01,0x80,0xc0,0x60,0x30,0x63,0x23,0xb0,0xd8,0x6c,0x36,0x1b,0x0c,0x4c,0xe3, +0x31,0x98,0xcc,0x66,0x30,0xc1,0xf0,0xc6,0xc6,0x63,0x31,0x98,0xcc,0x66,0x33,0x60, +0xc0,0x60,0x30,0x18,0x0c,0x00,0xc0,0x60,0x30,0x18,0x63,0x31,0x98,0xcc,0x66,0x33, +0x19,0x8c,0x10,0x73,0x31,0x98,0xcc,0x66,0x30,0xe1,0x8c,0x38,0x1c,0x7f,0x80,0xa0, +0x50,0x10,0x24,0x0d,0xff,0x01,0x01,0x02,0x00,0x40,0x80,0xf0,0x24,0x04,0x02,0x01, +0x81,0x20,0x10,0x30,0x28,0x1a,0x09,0x06,0x8a,0x81,0x20,0x90,0x20,0x08,0x04,0x02, +0x00,0x0c,0x00,0x04,0x85,0x32,0x6f,0xb8,0x00,0x18,0x06,0x00,0x01,0x01,0xc0,0x00, +0x70,0x60,0x36,0x06,0x1f,0xcc,0xe0,0x63,0x30,0xd8,0x60,0x63,0x33,0x06,0x03,0x00, +0x60,0x00,0xc0,0x30,0x60,0x61,0x99,0x86,0x66,0x63,0x01,0x80,0x66,0x63,0x0c,0x03, +0x0c,0x66,0x04,0x19,0x1c,0xcc,0x60,0x33,0x18,0xcc,0x61,0x81,0xb0,0x60,0xcc,0x63, +0x0c,0x18,0x06,0x00,0x60,0x30,0x00,0x00,0x00,0x67,0x19,0x86,0x23,0x71,0x88,0x60, +0x36,0x63,0x06,0x01,0x8c,0x60,0xc6,0xd9,0x8c,0x6c,0x66,0x1b,0x8c,0x08,0x61,0x83, +0xb8,0x70,0xcc,0x63,0x0c,0x18,0x03,0x00,0xc0,0x60,0x00,0xaa,0x98,0xc0,0x7f,0x5f, +0xaf,0xef,0xdb,0xf2,0x00,0xfe,0xfe,0xfd,0xff,0xbf,0x7f,0x6f,0xdb,0xfb,0xfd,0xfe, +0x7e,0xdf,0xef,0xcf,0xd7,0xe5,0xf6,0xf9,0x75,0x7e,0xdf,0x6f,0xdf,0xf7,0xfb,0xfd, +0x00,0x0c,0x07,0xc6,0x04,0x10,0x60,0x30,0x06,0x00,0x10,0x80,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x3f,0x80,0x00,0x00,0x03,0xb8,0x14,0x00,0x00,0x00,0x00,0x00,0x04, +0x11,0x21,0x04,0xc0,0xc3,0x61,0xb0,0xd8,0x6c,0x36,0x1b,0x30,0x66,0x30,0x18,0x0c, +0x06,0x01,0x80,0xc0,0x60,0x30,0x66,0x23,0x99,0x8c,0xc6,0x63,0x31,0x98,0x00,0x66, +0x1b,0x0d,0x86,0xc3,0x60,0xc1,0x80,0xc6,0xce,0x67,0x33,0x99,0xcc,0xe6,0x73,0x74, +0x62,0x31,0x18,0x8c,0x46,0x20,0xc0,0x60,0x30,0x18,0x36,0x31,0x8d,0x86,0xc3,0x61, +0xb0,0xd8,0x10,0x36,0x3b,0x9d,0xce,0xe7,0x70,0xc1,0x98,0x30,0x00,0x7f,0x80,0xc0, +0x60,0x10,0x24,0x0c,0x38,0x0e,0x01,0x02,0x00,0x40,0x80,0xa0,0x18,0x0e,0x03,0x00, +0x80,0x40,0x60,0x50,0x30,0x16,0x0e,0x05,0x88,0x81,0xc0,0x81,0xc0,0x70,0x38,0x1c, +0x00,0x0c,0x00,0x04,0x83,0xe0,0x39,0xcc,0x00,0x0c,0x0c,0x00,0x00,0x01,0xc0,0x00, +0x70,0xc0,0x1c,0x06,0x1f,0xc7,0xc0,0x61,0xe0,0x70,0x60,0x3e,0x1e,0x06,0x03,0x00, +0x00,0x00,0x00,0x30,0x1e,0x61,0x9f,0x03,0xc7,0xc3,0xf1,0x80,0x3e,0x63,0x3f,0x1e, +0x0c,0x67,0xe4,0x19,0x0c,0x78,0x60,0x1e,0x18,0xc7,0xc1,0x80,0xe0,0x60,0xcc,0x63, +0x0c,0x1f,0xc6,0x00,0x30,0x30,0x00,0x00,0x00,0x3b,0x9f,0x03,0xc1,0xb0,0xf0,0x60, +0x06,0x63,0x06,0x01,0x8c,0x70,0xc6,0xd9,0x8c,0x38,0x7c,0x0d,0x8c,0x07,0xc0,0xf1, +0xd8,0x60,0xcc,0x63,0x0c,0x1f,0xc3,0x00,0xc0,0x60,0x01,0x54,0x80,0xc0,0x7f,0x3f, +0x9f,0xef,0xdb,0xf3,0xc7,0xf1,0xfe,0xfd,0xff,0xbf,0x7f,0xff,0xe7,0xf1,0xfc,0xff, +0x7f,0xbf,0x9f,0xaf,0xcf,0xe9,0xf1,0xfa,0x77,0x7e,0x3f,0x7e,0x3f,0x8f,0xc7,0xe3, +0xff,0x0c,0x01,0x0f,0xe8,0x08,0x60,0x30,0xc6,0x00,0x0f,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xd8,0x14,0x00,0x00,0x00,0x00,0x00,0x04, +0x11,0x3d,0x04,0xc0,0xc3,0x61,0xb0,0xd8,0x6c,0x36,0x1b,0x3c,0x3c,0x3f,0x1f,0x8f, +0xc7,0xe7,0xe3,0xf1,0xf8,0xfc,0x7c,0x21,0x8f,0x07,0x83,0xc1,0xe0,0xf0,0x00,0xbc, +0x0e,0x07,0x03,0x81,0xc0,0xc1,0x80,0xcc,0x77,0x3b,0x9d,0xce,0xe7,0x73,0xb9,0x98, +0x3c,0x1e,0x0f,0x07,0x83,0xc0,0xc0,0x60,0x30,0x18,0x1c,0x31,0x87,0x03,0x81,0xc0, +0xe0,0x70,0x00,0x5c,0x1d,0x8e,0xc7,0x63,0xb0,0xc1,0xf0,0x30,0x00,0x7f,0x81,0x40, +0xa0,0x10,0x28,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x00,0x00,0x02,0x00, +0x80,0x80,0x10,0xf8,0x28,0x12,0x09,0x04,0x80,0x01,0x20,0x80,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x06,0x18,0x00,0x00,0x00,0x40,0x00, +0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0xc0,0x31,0xf0,0x01,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xcc,0x00,0x00,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x60,0x01,0x80,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x18,0x00,0x01,0xe0,0xc3,0xc0,0x00,0x00,0xff,0xc0,0x7e,0xbf, +0x5f,0xef,0xd7,0xf5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xff, +0x7f,0x7f,0xef,0x07,0xd7,0xed,0xf6,0xfb,0x7f,0xfe,0xdf,0x7f,0xff,0xff,0xff,0xff, +0x00,0x0c,0x01,0x00,0x00,0x00,0x00,0x30,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x14,0x00,0x08,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0xc6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x81,0x80,0x60,0x00,0x7f,0x81,0x20, +0x90,0x10,0x1c,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x80, +0x81,0xe0,0x60,0x10,0x24,0x12,0x0e,0x04,0x80,0x01,0xc0,0x70,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x78,0x00,0x00,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x01,0x80,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0xfe,0xdf, +0x6f,0xef,0xe3,0xf5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x7f, +0x7e,0x1f,0x9f,0xef,0xdb,0xed,0xf1,0xfb,0x7f,0xfe,0x3f,0x8f,0xff,0xff,0xff,0xff, +0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x81,0x80,0x60,0x20,0x20,0x20,0x20, +0x20,0x20,0x20,0x20,0x32,0x35,0x36,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, +0x20,0x31,0x35,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x31,0x33,0x20, +0x00,0x00,0x01,0x0c,0x00,0x09,0x09,0x00,0x01,0x0f,0x00,0x09,0x12,0x00,0x01,0x0f, +0x00,0x09,0x1b,0x00,0x01,0x0f,0x00,0x09,0x24,0x00,0x01,0x0f,0x00,0x09,0x2d,0x00, +0x01,0x0f,0x00,0x09,0x36,0x00,0x01,0x0f,0x00,0x09,0x3f,0x00,0x03,0x0d,0x00,0x09, +0x48,0x00,0x03,0x0d,0x00,0x09,0x51,0x00,0x03,0x0d,0x00,0x09,0x5a,0x00,0x03,0x0d, +0x00,0x09,0x63,0x00,0x03,0x0d,0x00,0x09,0x6c,0x00,0x03,0x0d,0x00,0x09,0x75,0x00, +0x03,0x0e,0x00,0x09,0x7e,0x00,0x03,0x0d,0x00,0x09,0x87,0x00,0x03,0x0d,0x00,0x09, +0x90,0x00,0x01,0x0f,0x00,0x09,0x99,0x00,0x01,0x0f,0x00,0x09,0xa2,0x00,0x01,0x0f, +0x00,0x09,0xab,0x00,0x01,0x0f,0x00,0x09,0xb4,0x00,0x01,0x0f,0x00,0x09,0xbd,0x00, +0x01,0x0f,0x00,0x09,0xc6,0x00,0x01,0x0f,0x00,0x09,0xcf,0x00,0x01,0x0f,0x00,0x09, +0xd8,0x00,0x01,0x0f,0x00,0x09,0xe1,0x00,0x03,0x0d,0x00,0x09,0xea,0x00,0x01,0x0f, +0x00,0x09,0xf3,0x00,0x01,0x0f,0x00,0x09,0xfc,0x00,0x03,0x0d,0x00,0x09,0x05,0x01, +0x03,0x0d,0x00,0x09,0x0e,0x01,0x03,0x0d,0x00,0x09,0x17,0x01,0x03,0x0d,0x00,0x09, +0x20,0x01,0x00,0x00,0x00,0x09,0x29,0x01,0x03,0x0d,0x00,0x09,0x32,0x01,0x02,0x05, +0x00,0x09,0x3b,0x01,0x03,0x0d,0x00,0x09,0x44,0x01,0x02,0x0e,0x00,0x09,0x4d,0x01, +0x03,0x0d,0x00,0x09,0x56,0x01,0x03,0x0d,0x00,0x09,0x5f,0x01,0x02,0x06,0x00,0x09, +0x68,0x01,0x02,0x0e,0x00,0x09,0x71,0x01,0x02,0x0e,0x00,0x09,0x7a,0x01,0x03,0x08, +0x00,0x09,0x83,0x01,0x05,0x0c,0x00,0x09,0x8c,0x01,0x0b,0x0f,0x00,0x09,0x95,0x01, +0x08,0x09,0x00,0x09,0x9e,0x01,0x0b,0x0d,0x00,0x09,0xa7,0x01,0x02,0x0e,0x00,0x09, +0xb0,0x01,0x03,0x0d,0x00,0x09,0xb9,0x01,0x03,0x0d,0x00,0x09,0xc2,0x01,0x03,0x0d, +0x00,0x09,0xcb,0x01,0x03,0x0d,0x00,0x09,0xd4,0x01,0x03,0x0d,0x00,0x09,0xdd,0x01, +0x03,0x0d,0x00,0x09,0xe6,0x01,0x03,0x0d,0x00,0x09,0xef,0x01,0x03,0x0d,0x00,0x09, +0xf8,0x01,0x03,0x0d,0x00,0x09,0x01,0x02,0x03,0x0d,0x00,0x09,0x0a,0x02,0x06,0x0d, +0x00,0x09,0x13,0x02,0x06,0x0f,0x00,0x09,0x1c,0x02,0x05,0x0c,0x00,0x09,0x25,0x02, +0x07,0x0a,0x00,0x09,0x2e,0x02,0x05,0x0c,0x00,0x09,0x37,0x02,0x03,0x0d,0x00,0x09, +0x40,0x02,0x03,0x0d,0x00,0x09,0x49,0x02,0x03,0x0d,0x00,0x09,0x52,0x02,0x03,0x0d, +0x00,0x09,0x5b,0x02,0x03,0x0d,0x00,0x09,0x64,0x02,0x03,0x0d,0x00,0x09,0x6d,0x02, +0x03,0x0d,0x00,0x09,0x76,0x02,0x03,0x0d,0x00,0x09,0x7f,0x02,0x03,0x0d,0x00,0x09, +0x88,0x02,0x03,0x0d,0x00,0x09,0x91,0x02,0x03,0x0d,0x00,0x09,0x9a,0x02,0x03,0x0d, +0x00,0x09,0xa3,0x02,0x03,0x0d,0x00,0x09,0xac,0x02,0x03,0x0d,0x00,0x09,0xb5,0x02, +0x03,0x0d,0x00,0x09,0xbe,0x02,0x03,0x0d,0x00,0x09,0xc7,0x02,0x03,0x0d,0x00,0x09, +0xd0,0x02,0x03,0x0d,0x00,0x09,0xd9,0x02,0x03,0x0f,0x00,0x09,0xe2,0x02,0x03,0x0d, +0x00,0x09,0xeb,0x02,0x03,0x0d,0x00,0x09,0xf4,0x02,0x03,0x0d,0x00,0x09,0xfd,0x02, +0x03,0x0d,0x00,0x09,0x06,0x03,0x03,0x0d,0x00,0x09,0x0f,0x03,0x03,0x0d,0x00,0x09, +0x18,0x03,0x03,0x0d,0x00,0x09,0x21,0x03,0x03,0x0d,0x00,0x09,0x2a,0x03,0x03,0x0d, +0x00,0x09,0x33,0x03,0x02,0x0e,0x00,0x09,0x3c,0x03,0x02,0x0e,0x00,0x09,0x45,0x03, +0x02,0x0e,0x00,0x09,0x4e,0x03,0x04,0x0b,0x00,0x09,0x57,0x03,0x0d,0x0e,0x00,0x09, +0x60,0x03,0x02,0x06,0x00,0x09,0x69,0x03,0x05,0x0d,0x00,0x09,0x72,0x03,0x02,0x0d, +0x00,0x09,0x7b,0x03,0x05,0x0d,0x00,0x09,0x84,0x03,0x02,0x0d,0x00,0x09,0x8d,0x03, +0x05,0x0d,0x00,0x09,0x96,0x03,0x02,0x0d,0x00,0x09,0x9f,0x03,0x05,0x0f,0x00,0x09, +0xa8,0x03,0x02,0x0d,0x00,0x09,0xb1,0x03,0x02,0x0d,0x00,0x09,0xba,0x03,0x02,0x0f, +0x00,0x09,0xc3,0x03,0x02,0x0d,0x00,0x09,0xcc,0x03,0x02,0x0d,0x00,0x09,0xd5,0x03, +0x05,0x0d,0x00,0x09,0xde,0x03,0x05,0x0d,0x00,0x09,0xe7,0x03,0x05,0x0d,0x00,0x09, +0xf0,0x03,0x05,0x0f,0x00,0x09,0xf9,0x03,0x05,0x0f,0x00,0x09,0x02,0x04,0x05,0x0d, +0x00,0x09,0x0b,0x04,0x05,0x0d,0x00,0x09,0x14,0x04,0x03,0x0d,0x00,0x09,0x1d,0x04, +0x05,0x0d,0x00,0x09,0x26,0x04,0x05,0x0d,0x00,0x09,0x2f,0x04,0x05,0x0d,0x00,0x09, +0x38,0x04,0x05,0x0d,0x00,0x09,0x41,0x04,0x05,0x0f,0x00,0x09,0x4a,0x04,0x05,0x0d, +0x00,0x09,0x53,0x04,0x02,0x0e,0x00,0x09,0x5c,0x04,0x02,0x0e,0x00,0x09,0x65,0x04, +0x02,0x0e,0x00,0x09,0x6e,0x04,0x07,0x0a,0x00,0x09,0x77,0x04,0x01,0x0d,0x00,0x09, +0x80,0x04,0x00,0x0e,0x00,0x09,0x89,0x04,0x00,0x0f,0x00,0x09,0x92,0x04,0x00,0x0f, +0x00,0x09,0x9b,0x04,0x00,0x0f,0x00,0x09,0xa4,0x04,0x00,0x0f,0x00,0x09,0xad,0x04, +0x00,0x0f,0x00,0x09,0xb6,0x04,0x00,0x0f,0x00,0x09,0xbf,0x04,0x00,0x0f,0x00,0x09, +0xc8,0x04,0x00,0x0f,0x00,0x09,0xd1,0x04,0x00,0x0f,0x00,0x09,0xda,0x04,0x00,0x0f, +0x00,0x09,0xe3,0x04,0x00,0x0f,0x00,0x09,0xec,0x04,0x00,0x0f,0x00,0x09,0xf5,0x04, +0x00,0x0f,0x00,0x09,0xfe,0x04,0x00,0x0f,0x00,0x09,0x07,0x05,0x00,0x0f,0x00,0x09, +0x10,0x05,0x00,0x0f,0x00,0x09,0x19,0x05,0x00,0x0f,0x00,0x09,0x22,0x05,0x00,0x0f, +0x00,0x09,0x2b,0x05,0x00,0x0f,0x00,0x09,0x34,0x05,0x00,0x0f,0x00,0x09,0x3d,0x05, +0x00,0x0f,0x00,0x09,0x46,0x05,0x00,0x0f,0x00,0x09,0x4f,0x05,0x00,0x0f,0x00,0x09, +0x58,0x05,0x00,0x0f,0x00,0x09,0x61,0x05,0x00,0x0f,0x00,0x09,0x6a,0x05,0x00,0x0f, +0x00,0x09,0x73,0x05,0x00,0x0f,0x00,0x09,0x7c,0x05,0x00,0x0f,0x00,0x09,0x85,0x05, +0x00,0x0f,0x00,0x09,0x8e,0x05,0x00,0x0f,0x00,0x09,0x97,0x05,0x00,0x0f,0x00,0x09, +0xa0,0x05,0x00,0x0d,0x00,0x09,0xa9,0x05,0x05,0x0f,0x00,0x09,0xb2,0x05,0x02,0x0e, +0x00,0x09,0xbb,0x05,0x03,0x0d,0x00,0x09,0xc4,0x05,0x03,0x0d,0x00,0x09,0xcd,0x05, +0x03,0x0d,0x00,0x09,0xd6,0x05,0x02,0x0e,0x00,0x09,0xdf,0x05,0x03,0x0e,0x00,0x09, +0xe8,0x05,0x02,0x04,0x00,0x09,0xf1,0x05,0x03,0x0d,0x00,0x09,0xfa,0x05,0x03,0x0a, +0x00,0x09,0x03,0x06,0x06,0x0b,0x00,0x09,0x0c,0x06,0x07,0x0a,0x00,0x09,0x15,0x06, +0x08,0x09,0x00,0x09,0x1e,0x06,0x03,0x0b,0x00,0x09,0x27,0x06,0x02,0x03,0x00,0x09, +0x30,0x06,0x03,0x07,0x00,0x09,0x39,0x06,0x05,0x0c,0x00,0x09,0x42,0x06,0x03,0x0a, +0x00,0x09,0x4b,0x06,0x03,0x0a,0x00,0x09,0x54,0x06,0x02,0x04,0x00,0x09,0x5d,0x06, +0x05,0x0f,0x00,0x09,0x66,0x06,0x03,0x0e,0x00,0x09,0x6f,0x06,0x08,0x0a,0x00,0x09, +0x78,0x06,0x0d,0x0f,0x00,0x09,0x81,0x06,0x03,0x0a,0x00,0x09,0x8a,0x06,0x03,0x0a, +0x00,0x09,0x93,0x06,0x06,0x0b,0x00,0x09,0x9c,0x06,0x03,0x0d,0x00,0x09,0xa5,0x06, +0x03,0x0d,0x00,0x09,0xae,0x06,0x03,0x0d,0x00,0x09,0xb7,0x06,0x05,0x0f,0x00,0x09, +0xc0,0x06,0x00,0x0d,0x00,0x09,0xc9,0x06,0x00,0x0d,0x00,0x09,0xd2,0x06,0x00,0x0d, +0x00,0x09,0xdb,0x06,0x00,0x0d,0x00,0x09,0xe4,0x06,0x00,0x0d,0x00,0x09,0xed,0x06, +0x01,0x0d,0x00,0x09,0xf6,0x06,0x03,0x0d,0x00,0x09,0xff,0x06,0x03,0x0f,0x00,0x09, +0x08,0x07,0x00,0x0d,0x00,0x09,0x11,0x07,0x00,0x0d,0x00,0x09,0x1a,0x07,0x00,0x0d, +0x00,0x09,0x23,0x07,0x00,0x0d,0x00,0x09,0x2c,0x07,0x00,0x0d,0x00,0x09,0x35,0x07, +0x00,0x0d,0x00,0x09,0x3e,0x07,0x00,0x0d,0x00,0x09,0x47,0x07,0x00,0x0d,0x00,0x09, +0x50,0x07,0x03,0x0d,0x00,0x09,0x59,0x07,0x00,0x0d,0x00,0x09,0x62,0x07,0x00,0x0d, +0x00,0x09,0x6b,0x07,0x00,0x0d,0x00,0x09,0x74,0x07,0x00,0x0d,0x00,0x09,0x7d,0x07, +0x00,0x0d,0x00,0x09,0x86,0x07,0x00,0x0d,0x00,0x09,0x8f,0x07,0x06,0x0b,0x00,0x09, +0x98,0x07,0x03,0x0d,0x00,0x09,0xa1,0x07,0x00,0x0d,0x00,0x09,0xaa,0x07,0x00,0x0d, +0x00,0x09,0xb3,0x07,0x00,0x0d,0x00,0x09,0xbc,0x07,0x00,0x0d,0x00,0x09,0xc5,0x07, +0x00,0x0d,0x00,0x09,0xce,0x07,0x03,0x0d,0x00,0x09,0xd7,0x07,0x02,0x0d,0x00,0x09, +0xe0,0x07,0x02,0x0d,0x00,0x09,0xe9,0x07,0x02,0x0d,0x00,0x09,0xf2,0x07,0x02,0x0d, +0x00,0x09,0xfb,0x07,0x02,0x0d,0x00,0x09,0x04,0x08,0x02,0x0d,0x00,0x09,0x0d,0x08, +0x02,0x0d,0x00,0x09,0x16,0x08,0x05,0x0d,0x00,0x09,0x1f,0x08,0x05,0x0f,0x00,0x09, +0x28,0x08,0x02,0x0d,0x00,0x09,0x31,0x08,0x02,0x0d,0x00,0x09,0x3a,0x08,0x02,0x0d, +0x00,0x09,0x43,0x08,0x02,0x0d,0x00,0x09,0x4c,0x08,0x02,0x0d,0x00,0x09,0x55,0x08, +0x02,0x0d,0x00,0x09,0x5e,0x08,0x02,0x0d,0x00,0x09,0x67,0x08,0x02,0x0d,0x00,0x09, +0x70,0x08,0x02,0x0d,0x00,0x09,0x79,0x08,0x02,0x0d,0x00,0x09,0x82,0x08,0x02,0x0d, +0x00,0x09,0x8b,0x08,0x02,0x0d,0x00,0x09,0x94,0x08,0x02,0x0d,0x00,0x09,0x9d,0x08, +0x02,0x0d,0x00,0x09,0xa6,0x08,0x02,0x0d,0x00,0x09,0xaf,0x08,0x05,0x0c,0x00,0x09, +0xb8,0x08,0x05,0x0d,0x00,0x09,0xc1,0x08,0x02,0x0d,0x00,0x09,0xca,0x08,0x02,0x0d, +0x00,0x09,0xd3,0x08,0x02,0x0d,0x00,0x09,0xdc,0x08,0x02,0x0d,0x00,0x09,0xe5,0x08, +0x02,0x0f,0x00,0x09,0xee,0x08,0x03,0x0f,0x00,0x09,0xf7,0x08,0x02,0x0f,0x00,0x09, +0x00,0x09,0x00,0x00,0x00,0x00, +}; + +int sizeofdefont = sizeof defontdata; + +void +_unpackinfo(Fontchar *fc, uchar *p, int n) +{ + int j; + + for(j=0; j<=n; j++){ + fc->x = p[0]|(p[1]<<8); + fc->top = p[2]; + fc->bottom = p[3]; + fc->left = p[4]; + fc->width = p[5]; + fc++; + p += 6; + } +} diff --git a/sys/src/libdraw/draw.c b/sys/src/libdraw/draw.c new file mode 100755 index 000000000..d3f83e885 --- /dev/null +++ b/sys/src/libdraw/draw.c @@ -0,0 +1,69 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +void +_setdrawop(Display *d, Drawop op) +{ + uchar *a; + + if(op != SoverD){ + a = bufimage(d, 1+1); + if(a == 0) + return; + a[0] = 'O'; + a[1] = op; + } +} + +static void +draw1(Image *dst, Rectangle *r, Image *src, Point *p0, Image *mask, Point *p1, Drawop op) +{ + uchar *a; + + _setdrawop(dst->display, op); + + a = bufimage(dst->display, 1+4+4+4+4*4+2*4+2*4); + if(a == 0) + return; + if(src == nil) + src = dst->display->black; + if(mask == nil) + mask = dst->display->opaque; + a[0] = 'd'; + BPLONG(a+1, dst->id); + BPLONG(a+5, src->id); + BPLONG(a+9, mask->id); + BPLONG(a+13, r->min.x); + BPLONG(a+17, r->min.y); + BPLONG(a+21, r->max.x); + BPLONG(a+25, r->max.y); + BPLONG(a+29, p0->x); + BPLONG(a+33, p0->y); + BPLONG(a+37, p1->x); + BPLONG(a+41, p1->y); +} + +void +draw(Image *dst, Rectangle r, Image *src, Image *mask, Point p1) +{ + draw1(dst, &r, src, &p1, mask, &p1, SoverD); +} + +void +drawop(Image *dst, Rectangle r, Image *src, Image *mask, Point p1, Drawop op) +{ + draw1(dst, &r, src, &p1, mask, &p1, op); +} + +void +gendraw(Image *dst, Rectangle r, Image *src, Point p0, Image *mask, Point p1) +{ + draw1(dst, &r, src, &p0, mask, &p1, SoverD); +} + +void +gendrawop(Image *dst, Rectangle r, Image *src, Point p0, Image *mask, Point p1, Drawop op) +{ + draw1(dst, &r, src, &p0, mask, &p1, op); +} diff --git a/sys/src/libdraw/drawrepl.c b/sys/src/libdraw/drawrepl.c new file mode 100755 index 000000000..c72fee26a --- /dev/null +++ b/sys/src/libdraw/drawrepl.c @@ -0,0 +1,23 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +int +drawreplxy(int min, int max, int x) +{ + int sx; + + sx = (x-min)%(max-min); + if(sx < 0) + sx += max-min; + return sx+min; +} + +Point +drawrepl(Rectangle r, Point p) +{ + p.x = drawreplxy(r.min.x, r.max.x, p.x); + p.y = drawreplxy(r.min.y, r.max.y, p.y); + return p; +} + diff --git a/sys/src/libdraw/egetrect.c b/sys/src/libdraw/egetrect.c new file mode 100755 index 000000000..2c5c98485 --- /dev/null +++ b/sys/src/libdraw/egetrect.c @@ -0,0 +1,116 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> +#include <cursor.h> +#include <event.h> + +#define W Borderwidth + +static Image *tmp[4]; +static Image *red; + +static Cursor sweep={ + {-7, -7}, + {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x07, + 0xE0, 0x07, 0xE0, 0x07, 0xE3, 0xF7, 0xE3, 0xF7, + 0xE3, 0xE7, 0xE3, 0xF7, 0xE3, 0xFF, 0xE3, 0x7F, + 0xE0, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,}, + {0x00, 0x00, 0x7F, 0xFE, 0x40, 0x02, 0x40, 0x02, + 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x41, 0xE2, + 0x41, 0xC2, 0x41, 0xE2, 0x41, 0x72, 0x40, 0x38, + 0x40, 0x1C, 0x40, 0x0E, 0x7F, 0xE6, 0x00, 0x00,} +}; + +static +void +brects(Rectangle r, Rectangle rp[4]) +{ + if(Dx(r) < 2*W) + r.max.x = r.min.x+2*W; + if(Dy(r) < 2*W) + r.max.y = r.min.y+2*W; + rp[0] = Rect(r.min.x, r.min.y, r.max.x, r.min.y+W); + rp[1] = Rect(r.min.x, r.max.y-W, r.max.x, r.max.y); + rp[2] = Rect(r.min.x, r.min.y+W, r.min.x+W, r.max.y-W); + rp[3] = Rect(r.max.x-W, r.min.y+W, r.max.x, r.max.y-W); +} + +Rectangle +egetrect(int but, Mouse *m) +{ + Rectangle r, rc; + + but = 1<<(but-1); + esetcursor(&sweep); + while(m->buttons) + *m = emouse(); + while(!(m->buttons & but)){ + *m = emouse(); + if(m->buttons & (7^but)) + goto Return; + } + r.min = m->xy; + r.max = m->xy; + do{ + rc = canonrect(r); + edrawgetrect(rc, 1); + *m = emouse(); + edrawgetrect(rc, 0); + r.max = m->xy; + }while(m->buttons == but); + + Return: + esetcursor(0); + if(m->buttons & (7^but)){ + rc.min.x = rc.max.x = 0; + rc.min.y = rc.max.y = 0; + while(m->buttons) + *m = emouse(); + } + return rc; +} + +static +void +freetmp(void) +{ + freeimage(tmp[0]); + freeimage(tmp[1]); + freeimage(tmp[2]); + freeimage(tmp[3]); + freeimage(red); + tmp[0] = tmp[1] = tmp[2] = tmp[3] = red = nil; +} + +void +edrawgetrect(Rectangle rc, int up) +{ + int i; + Rectangle r, rects[4]; + + if(up && tmp[0]!=nil) + if(Dx(tmp[0]->r)<Dx(rc) || Dy(tmp[2]->r)<Dy(rc)) + freetmp(); + + if(tmp[0] == 0){ + r = Rect(0, 0, Dx(screen->r), W); + tmp[0] = allocimage(display, r, screen->chan, 0, -1); + tmp[1] = allocimage(display, r, screen->chan, 0, -1); + r = Rect(0, 0, W, Dy(screen->r)); + tmp[2] = allocimage(display, r, screen->chan, 0, -1); + tmp[3] = allocimage(display, r, screen->chan, 0, -1); + red = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DRed); + if(tmp[0]==0 || tmp[1]==0 || tmp[2]==0 || tmp[3]==0 || red==0) + drawerror(display, "getrect: allocimage failed"); + } + brects(rc, rects); + if(!up){ + for(i=0; i<4; i++) + draw(screen, rects[i], tmp[i], nil, ZP); + return; + } + for(i=0; i<4; i++){ + draw(tmp[i], Rect(0, 0, Dx(rects[i]), Dy(rects[i])), screen, nil, rects[i].min); + draw(screen, rects[i], red, nil, ZP); + } +} diff --git a/sys/src/libdraw/ellipse.c b/sys/src/libdraw/ellipse.c new file mode 100755 index 000000000..7a063f115 --- /dev/null +++ b/sys/src/libdraw/ellipse.c @@ -0,0 +1,82 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +static +void +doellipse(int cmd, Image *dst, Point *c, int xr, int yr, int thick, Image *src, Point *sp, int alpha, int phi, Drawop op) +{ + uchar *a; + + _setdrawop(dst->display, op); + + a = bufimage(dst->display, 1+4+4+2*4+4+4+4+2*4+2*4); + if(a == 0){ + fprint(2, "image ellipse: %r\n"); + return; + } + a[0] = cmd; + BPLONG(a+1, dst->id); + BPLONG(a+5, src->id); + BPLONG(a+9, c->x); + BPLONG(a+13, c->y); + BPLONG(a+17, xr); + BPLONG(a+21, yr); + BPLONG(a+25, thick); + BPLONG(a+29, sp->x); + BPLONG(a+33, sp->y); + BPLONG(a+37, alpha); + BPLONG(a+41, phi); +} + +void +ellipse(Image *dst, Point c, int a, int b, int thick, Image *src, Point sp) +{ + doellipse('e', dst, &c, a, b, thick, src, &sp, 0, 0, SoverD); +} + +void +ellipseop(Image *dst, Point c, int a, int b, int thick, Image *src, Point sp, Drawop op) +{ + doellipse('e', dst, &c, a, b, thick, src, &sp, 0, 0, op); +} + +void +fillellipse(Image *dst, Point c, int a, int b, Image *src, Point sp) +{ + doellipse('E', dst, &c, a, b, 0, src, &sp, 0, 0, SoverD); +} + +void +fillellipseop(Image *dst, Point c, int a, int b, Image *src, Point sp, Drawop op) +{ + doellipse('E', dst, &c, a, b, 0, src, &sp, 0, 0, op); +} + +void +arc(Image *dst, Point c, int a, int b, int thick, Image *src, Point sp, int alpha, int phi) +{ + alpha |= 1<<31; + doellipse('e', dst, &c, a, b, thick, src, &sp, alpha, phi, SoverD); +} + +void +arcop(Image *dst, Point c, int a, int b, int thick, Image *src, Point sp, int alpha, int phi, Drawop op) +{ + alpha |= 1<<31; + doellipse('e', dst, &c, a, b, thick, src, &sp, alpha, phi, op); +} + +void +fillarc(Image *dst, Point c, int a, int b, Image *src, Point sp, int alpha, int phi) +{ + alpha |= 1<<31; + doellipse('E', dst, &c, a, b, 0, src, &sp, alpha, phi, SoverD); +} + +void +fillarcop(Image *dst, Point c, int a, int b, Image *src, Point sp, int alpha, int phi, Drawop op) +{ + alpha |= 1<<31; + doellipse('E', dst, &c, a, b, 0, src, &sp, alpha, phi, op); +} diff --git a/sys/src/libdraw/emenuhit.c b/sys/src/libdraw/emenuhit.c new file mode 100755 index 000000000..d1f23a4aa --- /dev/null +++ b/sys/src/libdraw/emenuhit.c @@ -0,0 +1,270 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> +#include <event.h> + +enum +{ + Margin = 4, /* outside to text */ + Border = 2, /* outside to selection boxes */ + Blackborder = 2, /* width of outlining border */ + Vspacing = 2, /* extra spacing between lines of text */ + Maxunscroll = 25, /* maximum #entries before scrolling turns on */ + Nscroll = 20, /* number entries in scrolling part */ + Scrollwid = 14, /* width of scroll bar */ + Gap = 4, /* between text and scroll bar */ +}; + +static Image *menutxt; +static Image *back; +static Image *high; +static Image *bord; +static Image *text; +static Image *htext; + +static +void +menucolors(void) +{ + /* Main tone is greenish, with negative selection */ + back = allocimagemix(display, DPalegreen, DWhite); + high = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DDarkgreen); /* dark green */ + bord = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DMedgreen); /* not as dark green */ + if(back==nil || high==nil || bord==nil) + goto Error; + text = display->black; + htext = back; + return; + + Error: + freeimage(back); + freeimage(high); + freeimage(bord); + back = display->white; + high = display->black; + bord = display->black; + text = display->black; + htext = display->white; +} + +/* + * r is a rectangle holding the text elements. + * return the rectangle, including its black edge, holding element i. + */ +static Rectangle +menurect(Rectangle r, int i) +{ + if(i < 0) + return Rect(0, 0, 0, 0); + r.min.y += (font->height+Vspacing)*i; + r.max.y = r.min.y+font->height+Vspacing; + return insetrect(r, Border-Margin); +} + +/* + * r is a rectangle holding the text elements. + * return the element number containing p. + */ +static int +menusel(Rectangle r, Point p) +{ + r = insetrect(r, Margin); + if(!ptinrect(p, r)) + return -1; + return (p.y-r.min.y)/(font->height+Vspacing); +} + +static +void +paintitem(Menu *menu, Rectangle textr, int off, int i, int highlight, Image *save, Image *restore) +{ + char *item; + Rectangle r; + Point pt; + + if(i < 0) + return; + r = menurect(textr, i); + if(restore){ + draw(screen, r, restore, nil, restore->r.min); + return; + } + if(save) + draw(save, save->r, screen, nil, r.min); + item = menu->item? menu->item[i+off] : (*menu->gen)(i+off); + pt.x = (textr.min.x+textr.max.x-stringwidth(font, item))/2; + pt.y = textr.min.y+i*(font->height+Vspacing); + draw(screen, r, highlight? high : back, nil, pt); + string(screen, pt, highlight? htext : text, pt, font, item); +} + +/* + * menur is a rectangle holding all the highlightable text elements. + * track mouse while inside the box, return what's selected when button + * is raised, -1 as soon as it leaves box. + * invariant: nothing is highlighted on entry or exit. + */ +static int +menuscan(Menu *menu, int but, Mouse *m, Rectangle textr, int off, int lasti, Image *save) +{ + int i; + + paintitem(menu, textr, off, lasti, 1, save, nil); + flushimage(display, 1); /* in case display->locking is set */ + *m = emouse(); + while(m->buttons & (1<<(but-1))){ + flushimage(display, 1); /* in case display->locking is set */ + *m = emouse(); + i = menusel(textr, m->xy); + if(i != -1 && i == lasti) + continue; + paintitem(menu, textr, off, lasti, 0, nil, save); + if(i == -1) + return i; + lasti = i; + paintitem(menu, textr, off, lasti, 1, save, nil); + } + return lasti; +} + +static void +menupaint(Menu *menu, Rectangle textr, int off, int nitemdrawn) +{ + int i; + + draw(screen, insetrect(textr, Border-Margin), back, nil, ZP); + for(i = 0; i<nitemdrawn; i++) + paintitem(menu, textr, off, i, 0, nil, nil); +} + +static void +menuscrollpaint(Rectangle scrollr, int off, int nitem, int nitemdrawn) +{ + Rectangle r; + + draw(screen, scrollr, back, nil, ZP); + r.min.x = scrollr.min.x; + r.max.x = scrollr.max.x; + r.min.y = scrollr.min.y + (Dy(scrollr)*off)/nitem; + r.max.y = scrollr.min.y + (Dy(scrollr)*(off+nitemdrawn))/nitem; + if(r.max.y < r.min.y+2) + r.max.y = r.min.y+2; + border(screen, r, 1, bord, ZP); + if(menutxt == 0) + menutxt = allocimage(display, Rect(0, 0, 1, 1), CMAP8, 1, DDarkgreen); + if(menutxt) + draw(screen, insetrect(r, 1), menutxt, nil, ZP); +} + +int +emenuhit(int but, Mouse *m, Menu *menu) +{ + int i, nitem, nitemdrawn, maxwid, lasti, off, noff, wid, screenitem; + int scrolling; + Rectangle r, menur, sc, textr, scrollr; + Image *b, *save; + Point pt; + char *item; + + if(back == nil) + menucolors(); + sc = screen->clipr; + replclipr(screen, 0, screen->r); + maxwid = 0; + for(nitem = 0; + item = menu->item? menu->item[nitem] : (*menu->gen)(nitem); + nitem++){ + i = stringwidth(font, item); + if(i > maxwid) + maxwid = i; + } + if(menu->lasthit<0 || menu->lasthit>=nitem) + menu->lasthit = 0; + screenitem = (Dy(screen->r)-10)/(font->height+Vspacing); + if(nitem>Maxunscroll || nitem>screenitem){ + scrolling = 1; + nitemdrawn = Nscroll; + if(nitemdrawn > screenitem) + nitemdrawn = screenitem; + wid = maxwid + Gap + Scrollwid; + off = menu->lasthit - nitemdrawn/2; + if(off < 0) + off = 0; + if(off > nitem-nitemdrawn) + off = nitem-nitemdrawn; + lasti = menu->lasthit-off; + }else{ + scrolling = 0; + nitemdrawn = nitem; + wid = maxwid; + off = 0; + lasti = menu->lasthit; + } + r = insetrect(Rect(0, 0, wid, nitemdrawn*(font->height+Vspacing)), -Margin); + r = rectsubpt(r, Pt(wid/2, lasti*(font->height+Vspacing)+font->height/2)); + r = rectaddpt(r, m->xy); + pt = ZP; + if(r.max.x>screen->r.max.x) + pt.x = screen->r.max.x-r.max.x; + if(r.max.y>screen->r.max.y) + pt.y = screen->r.max.y-r.max.y; + if(r.min.x<screen->r.min.x) + pt.x = screen->r.min.x-r.min.x; + if(r.min.y<screen->r.min.y) + pt.y = screen->r.min.y-r.min.y; + menur = rectaddpt(r, pt); + textr.max.x = menur.max.x-Margin; + textr.min.x = textr.max.x-maxwid; + textr.min.y = menur.min.y+Margin; + textr.max.y = textr.min.y + nitemdrawn*(font->height+Vspacing); + if(scrolling){ + scrollr = insetrect(menur, Border); + scrollr.max.x = scrollr.min.x+Scrollwid; + }else + scrollr = Rect(0, 0, 0, 0); + + b = allocimage(display, menur, screen->chan, 0, 0); + if(b == 0) + b = screen; + draw(b, menur, screen, nil, menur.min); + draw(screen, menur, back, nil, ZP); + border(screen, menur, Blackborder, bord, ZP); + save = allocimage(display, menurect(textr, 0), screen->chan, 0, -1); + r = menurect(textr, lasti); + emoveto(divpt(addpt(r.min, r.max), 2)); + menupaint(menu, textr, off, nitemdrawn); + if(scrolling) + menuscrollpaint(scrollr, off, nitem, nitemdrawn); + while(m->buttons & (1<<(but-1))){ + lasti = menuscan(menu, but, m, textr, off, lasti, save); + if(lasti >= 0) + break; + while(!ptinrect(m->xy, textr) && (m->buttons & (1<<(but-1)))){ + if(scrolling && ptinrect(m->xy, scrollr)){ + noff = ((m->xy.y-scrollr.min.y)*nitem)/Dy(scrollr); + noff -= nitemdrawn/2; + if(noff < 0) + noff = 0; + if(noff > nitem-nitemdrawn) + noff = nitem-nitemdrawn; + if(noff != off){ + off = noff; + menupaint(menu, textr, off, nitemdrawn); + menuscrollpaint(scrollr, off, nitem, nitemdrawn); + } + } + flushimage(display, 1); /* in case display->locking is set */ + *m = emouse(); + } + } + draw(screen, menur, b, nil, menur.min); + if(b != screen) + freeimage(b); + freeimage(save); + replclipr(screen, 0, sc); + if(lasti >= 0){ + menu->lasthit = lasti+off; + return menu->lasthit; + } + return -1; +} diff --git a/sys/src/libdraw/event.c b/sys/src/libdraw/event.c new file mode 100755 index 000000000..1cf223c36 --- /dev/null +++ b/sys/src/libdraw/event.c @@ -0,0 +1,486 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> +#include <cursor.h> +#include <event.h> + +typedef struct Slave Slave; +typedef struct Ebuf Ebuf; + +struct Slave +{ + int pid; + Ebuf *head; /* queue of messages for this descriptor */ + Ebuf *tail; + int (*fn)(int, Event*, uchar*, int); +}; + +struct Ebuf +{ + Ebuf *next; + int n; /* number of bytes in buf */ + uchar buf[EMAXMSG]; +}; + +static Slave eslave[MAXSLAVE]; +static int Skeyboard = -1; +static int Smouse = -1; +static int Stimer = -1; +static int logfid; + +static int nslave; +static int parentpid; +static int epipe[2]; + +static int eforkslave(ulong); +static void extract(void); +static void ekill(void); +static int enote(void *, char *); + +static int mousefd; +static int cursorfd; + +static +Ebuf* +ebread(Slave *s) +{ + Ebuf *eb; + Dir *d; + ulong l; + + for(;;){ + d = dirfstat(epipe[0]); + if(d == nil) + drawerror(display, "events: eread stat error"); + l = d->length; + free(d); + if(s->head && l==0) + break; + extract(); + } + eb = s->head; + s->head = s->head->next; + if(s->head == 0) + s->tail = 0; + return eb; +} + +ulong +event(Event *e) +{ + return eread(~0UL, e); +} + +ulong +eread(ulong keys, Event *e) +{ + Ebuf *eb; + int i, id; + + if(keys == 0) + return 0; + for(;;){ + for(i=0; i<nslave; i++) + if((keys & (1<<i)) && eslave[i].head){ + id = 1<<i; + if(i == Smouse) + e->mouse = emouse(); + else if(i == Skeyboard) + e->kbdc = ekbd(); + else if(i == Stimer) + eslave[i].head = 0; + else{ + eb = ebread(&eslave[i]); + e->n = eb->n; + if(eslave[i].fn) + id = (*eslave[i].fn)(id, e, eb->buf, eb->n); + else + memmove(e->data, eb->buf, eb->n); + free(eb); + } + return id; + } + extract(); + } +} + +int +ecanmouse(void) +{ + if(Smouse < 0) + drawerror(display, "events: mouse not initialized"); + return ecanread(Emouse); +} + +int +ecankbd(void) +{ + if(Skeyboard < 0) + drawerror(display, "events: keyboard not initialzed"); + return ecanread(Ekeyboard); +} + +int +ecanread(ulong keys) +{ + Dir *d; + int i; + ulong l; + + for(;;){ + for(i=0; i<nslave; i++) + if((keys & (1<<i)) && eslave[i].head) + return 1; + d = dirfstat(epipe[0]); + if(d == nil) + drawerror(display, "events: ecanread stat error"); + l = d->length; + free(d); + if(l == 0) + return 0; + extract(); + } +} + +ulong +estartfn(ulong key, int fd, int n, int (*fn)(int, Event*, uchar*, int)) +{ + char buf[EMAXMSG+1]; + int i, r; + + if(fd < 0) + drawerror(display, "events: bad file descriptor"); + if(n <= 0 || n > EMAXMSG) + n = EMAXMSG; + i = eforkslave(key); + if(i < MAXSLAVE){ + eslave[i].fn = fn; + return 1<<i; + } + buf[0] = i - MAXSLAVE; + while((r = read(fd, buf+1, n))>0) + if(write(epipe[1], buf, r+1)!=r+1) + break; + buf[0] = MAXSLAVE; + write(epipe[1], buf, 1); + _exits(0); + return 0; +} + +ulong +estart(ulong key, int fd, int n) +{ + return estartfn(key, fd, n, nil); +} + +ulong +etimer(ulong key, int n) +{ + char t[2]; + + if(Stimer != -1) + drawerror(display, "events: timer started twice"); + Stimer = eforkslave(key); + if(Stimer < MAXSLAVE) + return 1<<Stimer; + if(n <= 0) + n = 1000; + t[0] = t[1] = Stimer - MAXSLAVE; + do + sleep(n); + while(write(epipe[1], t, 2) == 2); + t[0] = MAXSLAVE; + write(epipe[1], t, 1); + _exits(0); + return 0; +} + +static void +ekeyslave(int fd) +{ + Rune r; + char t[3], k[10]; + int kr, kn, w; + + if(eforkslave(Ekeyboard) < MAXSLAVE) + return; + kn = 0; + t[0] = Skeyboard; + for(;;){ + while(!fullrune(k, kn)){ + kr = read(fd, k+kn, sizeof k - kn); + if(kr <= 0) + goto breakout; + kn += kr; + } + w = chartorune(&r, k); + kn -= w; + memmove(k, &k[w], kn); + t[1] = r; + t[2] = r>>8; + if(write(epipe[1], t, 3) != 3) + break; + } +breakout:; + t[0] = MAXSLAVE; + write(epipe[1], t, 1); + _exits(0); +} + +void +einit(ulong keys) +{ + int ctl, fd; + char buf[256]; + + parentpid = getpid(); + if(pipe(epipe) < 0) + drawerror(display, "events: einit pipe"); + atexit(ekill); + atnotify(enote, 1); + snprint(buf, sizeof buf, "%s/mouse", display->devdir); + mousefd = open(buf, ORDWR|OCEXEC); + if(mousefd < 0) + drawerror(display, "einit: can't open mouse\n"); + snprint(buf, sizeof buf, "%s/cursor", display->devdir); + cursorfd = open(buf, ORDWR|OCEXEC); + if(cursorfd < 0) + drawerror(display, "einit: can't open cursor\n"); + if(keys&Ekeyboard){ + snprint(buf, sizeof buf, "%s/cons", display->devdir); + fd = open(buf, OREAD); + if(fd < 0) + drawerror(display, "events: can't open console"); + snprint(buf, sizeof buf, "%s/consctl", display->devdir); + ctl = open("/dev/consctl", OWRITE|OCEXEC); + if(ctl < 0) + drawerror(display, "events: can't open consctl"); + write(ctl, "rawon", 5); + for(Skeyboard=0; Ekeyboard & ~(1<<Skeyboard); Skeyboard++) + ; + ekeyslave(fd); + } + if(keys&Emouse){ + estart(Emouse, mousefd, 1+4*12); + for(Smouse=0; Emouse & ~(1<<Smouse); Smouse++) + ; + } +} + +static void +extract(void) +{ + Slave *s; + Ebuf *eb; + int i, n; + uchar ebuf[EMAXMSG+1]; + + /* avoid generating a message if there's nothing to show. */ + /* this test isn't perfect, though; could do flushimage(display, 0) then call extract */ + /* also: make sure we don't interfere if we're multiprocessing the display */ + if(display->locking){ + /* if locking is being done by program, this means it can't depend on automatic flush in emouse() etc. */ + if(canqlock(&display->qlock)){ + if(display->bufp > display->buf) + flushimage(display, 1); + unlockdisplay(display); + } + }else + if(display->bufp > display->buf) + flushimage(display, 1); +loop: + if((n=read(epipe[0], ebuf, EMAXMSG+1)) < 0 + || ebuf[0] >= MAXSLAVE) + drawerror(display, "eof on event pipe"); + if(n == 0) + goto loop; + i = ebuf[0]; + if(i >= nslave || n <= 1) + drawerror(display, "events: protocol error: short read"); + s = &eslave[i]; + if(i == Stimer){ + s->head = (Ebuf *)1; + return; + } + if(i == Skeyboard && n != 3) + drawerror(display, "events: protocol error: keyboard"); + if(i == Smouse){ + if(n < 1+1+2*12) + drawerror(display, "events: protocol error: mouse"); + if(ebuf[1] == 'r') + eresized(1); + /* squash extraneous mouse events */ + if((eb=s->tail) && memcmp(eb->buf+1+2*12, ebuf+1+1+2*12, 12)==0){ + memmove(eb->buf, &ebuf[1], n - 1); + return; + } + } + /* try to save space by only allocating as much buffer as we need */ + eb = malloc(sizeof(*eb) - sizeof(eb->buf) + n - 1); + if(eb == 0) + drawerror(display, "events: protocol error 4"); + eb->n = n - 1; + memmove(eb->buf, &ebuf[1], n - 1); + eb->next = 0; + if(s->head) + s->tail = s->tail->next = eb; + else + s->head = s->tail = eb; +} + +static int +eforkslave(ulong key) +{ + int i, pid; + + for(i=0; i<MAXSLAVE; i++) + if((key & ~(1<<i)) == 0 && eslave[i].pid == 0){ + if(nslave <= i) + nslave = i + 1; + /* + * share the file descriptors so the last child + * out closes all connections to the window server. + */ + switch(pid = rfork(RFPROC)){ + case 0: + return MAXSLAVE+i; + case -1: + fprint(2, "events: fork error\n"); + exits("fork"); + } + eslave[i].pid = pid; + eslave[i].head = eslave[i].tail = 0; + return i; + } + drawerror(display, "events: bad slave assignment"); + return 0; +} + +static int +enote(void *v, char *s) +{ + char t[1]; + int i, pid; + + USED(v, s); + pid = getpid(); + if(pid != parentpid){ + for(i=0; i<nslave; i++){ + if(pid == eslave[i].pid){ + t[0] = MAXSLAVE; + write(epipe[1], t, 1); + break; + } + } + return 0; + } + close(epipe[0]); + epipe[0] = -1; + close(epipe[1]); + epipe[1] = -1; + for(i=0; i<nslave; i++){ + if(pid == eslave[i].pid) + continue; /* don't kill myself */ + postnote(PNPROC, eslave[i].pid, "die"); + } + return 0; +} + +static void +ekill(void) +{ + enote(0, 0); +} + +Mouse +emouse(void) +{ + Mouse m; + Ebuf *eb; + static but[2]; + int b; + + if(Smouse < 0) + drawerror(display, "events: mouse not initialized"); + eb = ebread(&eslave[Smouse]); + m.xy.x = atoi((char*)eb->buf+1+0*12); + m.xy.y = atoi((char*)eb->buf+1+1*12); + b = atoi((char*)eb->buf+1+2*12); + m.buttons = b; + m.msec = atoi((char*)eb->buf+1+3*12); + if (logfid) + fprint(logfid, "b: %d xy: %P\n", m.buttons, m.xy); + free(eb); + return m; +} + +int +ekbd(void) +{ + Ebuf *eb; + int c; + + if(Skeyboard < 0) + drawerror(display, "events: keyboard not initialzed"); + eb = ebread(&eslave[Skeyboard]); + c = eb->buf[0] + (eb->buf[1]<<8); + free(eb); + return c; +} + +void +emoveto(Point pt) +{ + char buf[2*12+2]; + int n; + + n = sprint(buf, "m%d %d", pt.x, pt.y); + write(mousefd, buf, n); +} + +void +esetcursor(Cursor *c) +{ + uchar curs[2*4+2*2*16]; + + if(c == 0) + write(cursorfd, curs, 0); + else{ + BPLONG(curs+0*4, c->offset.x); + BPLONG(curs+1*4, c->offset.y); + memmove(curs+2*4, c->clr, 2*2*16); + write(cursorfd, curs, sizeof curs); + } +} + +int +ereadmouse(Mouse *m) +{ + int n; + char buf[128]; + + do{ + n = read(mousefd, buf, sizeof(buf)); + if(n < 0) /* probably interrupted */ + return -1; + n = eatomouse(m, buf, n); + }while(n == 0); + return n; +} + +int +eatomouse(Mouse *m, char *buf, int n) +{ + if(n != 1+4*12){ + werrstr("atomouse: bad count"); + return -1; + } + + if(buf[0] == 'r') + eresized(1); + m->xy.x = atoi(buf+1+0*12); + m->xy.y = atoi(buf+1+1*12); + m->buttons = atoi(buf+1+2*12); + m->msec = atoi(buf+1+3*12); + return n; +} diff --git a/sys/src/libdraw/fmt.c b/sys/src/libdraw/fmt.c new file mode 100755 index 000000000..c3f1dd43a --- /dev/null +++ b/sys/src/libdraw/fmt.c @@ -0,0 +1,22 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +int +Rfmt(Fmt *f) +{ + Rectangle r; + + r = va_arg(f->args, Rectangle); + return fmtprint(f, "%P %P", r.min, r.max); +} + +int +Pfmt(Fmt *f) +{ + Point p; + + p = va_arg(f->args, Point); + return fmtprint(f, "[%d %d]", p.x, p.y); +} + diff --git a/sys/src/libdraw/font.c b/sys/src/libdraw/font.c new file mode 100755 index 000000000..2a74cc9c2 --- /dev/null +++ b/sys/src/libdraw/font.c @@ -0,0 +1,405 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +static int fontresize(Font*, int, int, int); +static int freeup(Font*); + +#define PJW 0 /* use NUL==pjw for invisible characters */ + +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; + char *sp; + Rune r, *rp, vr; + ulong a; + Cacheinfo *c, *tc, *ec; + + if(ss){ + sp = *ss; + rp = L""; + }else{ + sp = ""; + rp = *rr; + } + wid = 0; + *subfontname = 0; + for(i=0; i<max && (*sp || *rp); sp+=w, rp+=rw){ + if(ss){ + r = *(uchar*)sp; + if(r < Runeself) + w = 1; + else{ + w = chartorune(&vr, sp); + r = vr; + } + rw = 0; + }else{ + r = *rp; + w = 0; + rw = 1; + } + + sh = (17 * (uint)r) & (f->ncache-NFLOOK-1); + c = &f->cache[sh]; + ec = c+NFLOOK; + h = sh; + while(c < ec){ + if(c->value==r && c->age) + goto Found; + c++; + h++; + } + + /* + * Not found; toss out oldest entry + */ + a = ~0; + th = sh; + tc = &f->cache[th]; + while(tc < ec){ + if(tc->age < a){ + a = tc->age; + h = th; + c = tc; + } + tc++; + th++; + } + + if(a && (f->age-a)<500){ /* kicking out too recent; resize */ + nc = 2*(f->ncache-NFLOOK) + NFLOOK; + if(nc <= MAXFCACHE){ + if(i == 0) + fontresize(f, f->width, nc, f->maxdepth); + /* else flush first; retry will resize */ + break; + } + } + + 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; + break; + } + c = &f->cache[h]; /* may have reallocated f->cache */ + + Found: + wid += c->width; + c->age = f->age; + cp[i] = h; + i++; + } + if(ss) + *ss = sp; + else + *rr = rp; + *wp = wid; + return i; +} + +void +agefont(Font *f) +{ + Cacheinfo *c, *ec; + Cachesubf *s, *es; + + f->age++; + if(f->age == 65536){ + /* + * Renormalize ages + */ + c = f->cache; + ec = c+f->ncache; + while(c < ec){ + if(c->age){ + c->age >>= 2; + c->age++; + } + c++; + } + s = f->subf; + es = s+f->nsubf; + while(s < es){ + if(s->age){ + if(s->age<SUBFAGE && s->cf->name != nil){ + /* clean up */ + if(s->f != display->defaultsubfont) + freesubfont(s->f); + s->cf = nil; + s->f = nil; + s->age = 0; + }else{ + s->age >>= 2; + s->age++; + } + } + s++; + } + f->age = (65536>>2) + 1; + } +} + +static Subfont* +cf2subfont(Cachefont *cf, Font *f) +{ + int depth; + char *name; + Subfont *sf; + + name = cf->subfontname; + if(name == nil){ + if(f->display && f->display->screenimage) + depth = f->display->screenimage->depth; + else + depth = 8; + name = subfontname(cf->name, f->name, depth); + if(name == nil) + return nil; + cf->subfontname = name; + } + sf = lookupsubfont(f->display, name); + return sf; +} + +/* return 1 if load succeeded, 0 if failed, -1 if must retry */ +int +loadchar(Font *f, Rune r, Cacheinfo *c, int h, int noflush, char **subfontname) +{ + int i, oi, wid, top, bottom; + Rune pic; + Fontchar *fi; + Cachefont *cf; + Cachesubf *subf, *of; + uchar *b; + + pic = r; + Again: + for(i=0; i<f->nsub; i++){ + cf = f->sub[i]; + if(cf->min<=pic && pic<=cf->max) + goto Found; + } + TryPJW: + if(pic != PJW){ + pic = PJW; + goto Again; + } + return 0; + + Found: + /* + * Choose exact or oldest + */ + oi = 0; + subf = &f->subf[0]; + for(i=0; i<f->nsubf; i++){ + if(cf == subf->cf) + goto Found2; + if(subf->age < f->subf[oi].age) + oi = i; + subf++; + } + subf = &f->subf[oi]; + + if(subf->f){ + if(f->age-subf->age>SUBFAGE || f->nsubf>MAXSUBF){ + Toss: + /* ancient data; toss */ + freesubfont(subf->f); + subf->cf = nil; + subf->f = nil; + subf->age = 0; + }else{ /* too recent; grow instead */ + of = f->subf; + f->subf = malloc((f->nsubf+DSUBF)*sizeof *subf); + if(f->subf == nil){ + f->subf = of; + goto Toss; + } + memmove(f->subf, of, (f->nsubf+DSUBF)*sizeof *subf); + memset(f->subf+f->nsubf, 0, DSUBF*sizeof *subf); + subf = &f->subf[f->nsubf]; + f->nsubf += DSUBF; + free(of); + } + } + subf->age = 0; + subf->cf = nil; + subf->f = cf2subfont(cf, f); + if(subf->f == nil){ + if(cf->subfontname == nil) + goto TryPJW; + *subfontname = cf->subfontname; + return -1; + } + + subf->cf = cf; + if(subf->f->ascent > f->ascent && f->display){ + /* should print something? this is a mistake in the font file */ + /* must prevent c->top from going negative when loading cache */ + Image *b; + int d, t; + d = subf->f->ascent - f->ascent; + b = subf->f->bits; + draw(b, b->r, b, nil, addpt(b->r.min, Pt(0, d))); + 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); + for(i=0; i<subf->f->n; i++){ + t = subf->f->info[i].top-d; + if(t < 0) + t = 0; + subf->f->info[i].top = t; + t = subf->f->info[i].bottom-d; + if(t < 0) + t = 0; + subf->f->info[i].bottom = t; + } + subf->f->ascent = f->ascent; + } + + Found2: + subf->age = f->age; + + /* possible overflow here, but works out okay */ + pic += cf->offset; + pic -= cf->min; + if(pic >= subf->f->n) + goto TryPJW; + fi = &subf->f->info[pic]; + if(fi->width == 0) + goto TryPJW; + wid = (fi+1)->x - fi->x; + if(f->width < wid || f->width == 0 || f->maxdepth < subf->f->bits->depth){ + /* + * Flush, free, reload (easier than reformatting f->b) + */ + if(noflush) + return -1; + if(f->width < wid) + f->width = wid; + if(f->maxdepth < subf->f->bits->depth) + f->maxdepth = subf->f->bits->depth; + i = fontresize(f, f->width, f->ncache, f->maxdepth); + if(i <= 0) + return i; + /* c is still valid as didn't reallocate f->cache */ + } + c->value = r; + top = fi->top + (f->ascent-subf->f->ascent); + bottom = fi->bottom + (f->ascent-subf->f->ascent); + c->width = fi->width; + c->x = h*f->width; + c->left = fi->left; + if(f->display == nil) + return 1; + flushimage(f->display, 0); /* flush any pending errors */ + b = bufimage(f->display, 37); + if(b == 0) + return 0; + b[0] = 'l'; + BPLONG(b+1, f->cacheimage->id); + BPLONG(b+5, subf->f->bits->id); + BPSHORT(b+9, c-f->cache); + BPLONG(b+11, c->x); + BPLONG(b+15, top); + BPLONG(b+19, c->x+((fi+1)->x-fi->x)); + BPLONG(b+23, bottom); + BPLONG(b+27, fi->x); + BPLONG(b+31, fi->top); + b[35] = fi->left; + b[36] = fi->width; + return 1; +} + +/* release all subfonts, return number freed */ +static +int +freeup(Font *f) +{ + Cachesubf *s, *es; + int nf; + + if(f->sub[0]->name == nil) /* font from mkfont; don't free */ + return 0; + s = f->subf; + es = s+f->nsubf; + nf = 0; + while(s < es){ + if(s->age){ + freesubfont(s->f); + s->cf = nil; + s->f = nil; + s->age = 0; + nf++; + } + s++; + } + return nf; +} + +/* return whether resize succeeded && f->cache is unchanged */ +static int +fontresize(Font *f, int wid, int ncache, int depth) +{ + Cacheinfo *i; + int ret; + Image *new; + uchar *b; + Display *d; + + ret = 0; + if(depth <= 0) + depth = 1; + if(wid <= 0) + wid = 1; + + d = f->display; + if(d == nil) + goto Nodisplay; + + new = allocimage(d, Rect(0, 0, ncache*wid, f->height), CHAN1(CGrey, depth), 0, 0); + if(new == nil){ + fprint(2, "font cache resize failed: %r\n"); + abort(); + goto Return; + } + flushimage(d, 0); /* flush any pending errors */ + b = bufimage(d, 1+4+4+1); + if(b == 0){ + freeimage(new); + goto Return; + } + b[0] = 'i'; + BPLONG(b+1, new->id); + BPLONG(b+5, ncache); + b[9] = f->ascent; + if(flushimage(d, 0) < 0){ + fprint(2, "resize: init failed: %r\n"); + freeimage(new); + goto Return; + } + freeimage(f->cacheimage); + f->cacheimage = new; + Nodisplay: + f->width = wid; + f->maxdepth = depth; + ret = 1; + if(f->ncache != ncache){ + i = malloc(ncache*sizeof f->cache[0]); + if(i != nil){ + ret = 0; + free(f->cache); + f->ncache = ncache; + f->cache = i; + } + /* else just wipe the cache clean and things will be ok */ + } + Return: + memset(f->cache, 0, f->ncache*sizeof f->cache[0]); + return ret; +} diff --git a/sys/src/libdraw/freesubfont.c b/sys/src/libdraw/freesubfont.c new file mode 100755 index 000000000..6830b9dcd --- /dev/null +++ b/sys/src/libdraw/freesubfont.c @@ -0,0 +1,17 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +void +freesubfont(Subfont *f) +{ + if(f == 0) + return; + f->ref--; + if(f->ref > 0) + return; + uninstallsubfont(f); + free(f->info); /* note: f->info must have been malloc'ed! */ + freeimage(f->bits); + free(f); +} diff --git a/sys/src/libdraw/getdefont.c b/sys/src/libdraw/getdefont.c new file mode 100755 index 000000000..257b380a7 --- /dev/null +++ b/sys/src/libdraw/getdefont.c @@ -0,0 +1,60 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +Subfont* +getdefont(Display *d) +{ + char *hdr, *p; + int n; + Fontchar *fc; + Subfont *f; + int ld; + Rectangle r; + Image *i; + + /* + * make sure data is word-aligned. this is true with Plan 9 compilers + * but not in general. the byte order is right because the data is + * declared as char*, not ulong*. + */ + p = (char*)defontdata; + n = (int)(uvlong)p & 3; /* stupid ape */ + if(n != 0){ + memmove(p+(4-n), p, sizeofdefont-n); + p += 4-n; + } + ld = atoi(p+0*12); + r.min.x = atoi(p+1*12); + r.min.y = atoi(p+2*12); + r.max.x = atoi(p+3*12); + r.max.y = atoi(p+4*12); + + i = allocimage(d, r, drawld2chan[ld], 0, 0); + if(i == 0) + return 0; + + p += 5*12; + n = loadimage(i, r, (uchar*)p, (defontdata+sizeofdefont)-(uchar*)p); + if(n < 0){ + freeimage(i); + return 0; + } + + hdr = p+n; + n = atoi(hdr); + p = hdr+3*12; + fc = malloc(sizeof(Fontchar)*(n+1)); + if(fc == 0){ + freeimage(i); + return 0; + } + _unpackinfo(fc, (uchar*)p, n); + f = allocsubfont("*default*", n, atoi(hdr+12), atoi(hdr+24), fc, i); + if(f == 0){ + freeimage(i); + free(fc); + return 0; + } + return f; +} diff --git a/sys/src/libdraw/getrect.c b/sys/src/libdraw/getrect.c new file mode 100755 index 000000000..eb90f9c9a --- /dev/null +++ b/sys/src/libdraw/getrect.c @@ -0,0 +1,133 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> +#include <thread.h> +#include <cursor.h> +#include <mouse.h> + +#define W Borderwidth + +static Image *tmp[4]; +static Image *red; + +static Cursor sweep={ + {-7, -7}, + {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x07, + 0xE0, 0x07, 0xE0, 0x07, 0xE3, 0xF7, 0xE3, 0xF7, + 0xE3, 0xE7, 0xE3, 0xF7, 0xE3, 0xFF, 0xE3, 0x7F, + 0xE0, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,}, + {0x00, 0x00, 0x7F, 0xFE, 0x40, 0x02, 0x40, 0x02, + 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x41, 0xE2, + 0x41, 0xC2, 0x41, 0xE2, 0x41, 0x72, 0x40, 0x38, + 0x40, 0x1C, 0x40, 0x0E, 0x7F, 0xE6, 0x00, 0x00,} +}; + +static +void +brects(Rectangle r, Rectangle rp[4]) +{ + if(Dx(r) < 2*W) + r.max.x = r.min.x+2*W; + if(Dy(r) < 2*W) + r.max.y = r.min.y+2*W; + rp[0] = Rect(r.min.x, r.min.y, r.max.x, r.min.y+W); + rp[1] = Rect(r.min.x, r.max.y-W, r.max.x, r.max.y); + rp[2] = Rect(r.min.x, r.min.y+W, r.min.x+W, r.max.y-W); + rp[3] = Rect(r.max.x-W, r.min.y+W, r.max.x, r.max.y-W); +} + +Rectangle +getrect(int but, Mousectl *mc) +{ + Rectangle r, rc; + + but = 1<<(but-1); + setcursor(mc, &sweep); + while(mc->buttons) + readmouse(mc); + while(!(mc->buttons & but)){ + readmouse(mc); + if(mc->buttons & (7^but)) + goto Return; + } + r.min = mc->xy; + r.max = mc->xy; + do{ + rc = canonrect(r); + drawgetrect(rc, 1); + readmouse(mc); + drawgetrect(rc, 0); + r.max = mc->xy; + }while(mc->buttons == but); + + Return: + setcursor(mc, nil); + if(mc->buttons & (7^but)){ + rc.min.x = rc.max.x = 0; + rc.min.y = rc.max.y = 0; + while(mc->buttons) + readmouse(mc); + } + return rc; +} + +static +void +freetmp(void) +{ + freeimage(tmp[0]); + freeimage(tmp[1]); + freeimage(tmp[2]); + freeimage(tmp[3]); + freeimage(red); + tmp[0] = tmp[1] = tmp[2] = tmp[3] = red = nil; +} + +static +int +max(int a, int b) +{ + if(a > b) + return a; + return b; +} + +void +drawgetrect(Rectangle rc, int up) +{ + int i; + Rectangle r, rects[4]; + + /* + * BUG: if for some reason we have two of these going on at once + * when we must grow the tmp buffers, we lose data. Also if tmp + * is unallocated and we ask to restore the screen, it would be nice + * to complain, but we silently make a mess. + */ + if(up && tmp[0]!=nil) + if(Dx(tmp[0]->r)<Dx(rc) || Dy(tmp[2]->r)<Dy(rc)) + freetmp(); + if(tmp[0] == 0){ + r = Rect(0, 0, max(Dx(display->screenimage->r), Dx(rc)), W); + tmp[0] = allocimage(display, r, screen->chan, 0, -1); + tmp[1] = allocimage(display, r, screen->chan, 0, -1); + r = Rect(0, 0, W, max(Dy(display->screenimage->r), Dy(rc))); + tmp[2] = allocimage(display, r, screen->chan, 0, -1); + tmp[3] = allocimage(display, r, screen->chan, 0, -1); + red = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DRed); + if(tmp[0]==0 || tmp[1]==0 || tmp[2]==0 || tmp[3]==0 || red==0){ + freetmp(); + drawerror(display, "getrect: allocimage failed"); + } + } + brects(rc, rects); + if(!up){ + for(i=0; i<4; i++) + draw(screen, rects[i], tmp[i], nil, ZP); + return; + } + for(i=0; i<4; i++){ + draw(tmp[i], Rect(0, 0, Dx(rects[i]), Dy(rects[i])), screen, nil, rects[i].min); + draw(screen, rects[i], red, nil, ZP); + } +} diff --git a/sys/src/libdraw/getsubfont.c b/sys/src/libdraw/getsubfont.c new file mode 100755 index 000000000..04cc87355 --- /dev/null +++ b/sys/src/libdraw/getsubfont.c @@ -0,0 +1,37 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +/* + * Default version: treat as file name + */ + +Subfont* +_getsubfont(Display *d, char *name) +{ + int fd; + Subfont *f; + + fd = open(name, OREAD); + + if(fd < 0){ + fprint(2, "getsubfont: can't open %s: %r\n", name); + return 0; + } + /* + * unlock display so i/o happens with display released, unless + * user is doing his own locking, in which case this could break things. + * _getsubfont is called only from string.c and stringwidth.c, + * which are known to be safe to have this done. + */ + if(d && d->locking == 0) + unlockdisplay(d); + f = readsubfont(d, name, fd, d && d->locking==0); + if(d && d->locking == 0) + lockdisplay(d); + if(f == 0) + fprint(2, "getsubfont: can't read %s: %r\n", name); + close(fd); + setmalloctag(f, getcallerpc(&d)); + return f; +} diff --git a/sys/src/libdraw/icossin.c b/sys/src/libdraw/icossin.c new file mode 100755 index 000000000..b66417d4d --- /dev/null +++ b/sys/src/libdraw/icossin.c @@ -0,0 +1,140 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +/* + * Integer sine and cosine for integral degree argument. + * Tables computed by (sin,cos)(PI*d/180). + */ +static short sinus[91] = { + 0, /* 0 */ + 18, /* 1 */ + 36, /* 2 */ + 54, /* 3 */ + 71, /* 4 */ + 89, /* 5 */ + 107, /* 6 */ + 125, /* 7 */ + 143, /* 8 */ + 160, /* 9 */ + 178, /* 10 */ + 195, /* 11 */ + 213, /* 12 */ + 230, /* 13 */ + 248, /* 14 */ + 265, /* 15 */ + 282, /* 16 */ + 299, /* 17 */ + 316, /* 18 */ + 333, /* 19 */ + 350, /* 20 */ + 367, /* 21 */ + 384, /* 22 */ + 400, /* 23 */ + 416, /* 24 */ + 433, /* 25 */ + 449, /* 26 */ + 465, /* 27 */ + 481, /* 28 */ + 496, /* 29 */ + 512, /* 30 */ + 527, /* 31 */ + 543, /* 32 */ + 558, /* 33 */ + 573, /* 34 */ + 587, /* 35 */ + 602, /* 36 */ + 616, /* 37 */ + 630, /* 38 */ + 644, /* 39 */ + 658, /* 40 */ + 672, /* 41 */ + 685, /* 42 */ + 698, /* 43 */ + 711, /* 44 */ + 724, /* 45 */ + 737, /* 46 */ + 749, /* 47 */ + 761, /* 48 */ + 773, /* 49 */ + 784, /* 50 */ + 796, /* 51 */ + 807, /* 52 */ + 818, /* 53 */ + 828, /* 54 */ + 839, /* 55 */ + 849, /* 56 */ + 859, /* 57 */ + 868, /* 58 */ + 878, /* 59 */ + 887, /* 60 */ + 896, /* 61 */ + 904, /* 62 */ + 912, /* 63 */ + 920, /* 64 */ + 928, /* 65 */ + 935, /* 66 */ + 943, /* 67 */ + 949, /* 68 */ + 956, /* 69 */ + 962, /* 70 */ + 968, /* 71 */ + 974, /* 72 */ + 979, /* 73 */ + 984, /* 74 */ + 989, /* 75 */ + 994, /* 76 */ + 998, /* 77 */ + 1002, /* 78 */ + 1005, /* 79 */ + 1008, /* 80 */ + 1011, /* 81 */ + 1014, /* 82 */ + 1016, /* 83 */ + 1018, /* 84 */ + 1020, /* 85 */ + 1022, /* 86 */ + 1023, /* 87 */ + 1023, /* 88 */ + 1024, /* 89 */ + 1024, /* 90 */ +}; + +void +icossin(int deg, int *cosp, int *sinp) +{ + int sinsign, cossign; + short *stp, *ctp; + + deg %= 360; + if(deg < 0) + deg += 360; + sinsign = 1; + cossign = 1; + stp = 0; + ctp = 0; + switch(deg/90){ + case 2: + sinsign = -1; + cossign = -1; + deg -= 180; + /* fall through */ + case 0: + stp = &sinus[deg]; + ctp = &sinus[90-deg]; + break; + case 3: + sinsign = -1; + cossign = -1; + deg -= 180; + /* fall through */ + case 1: + deg = 180-deg; + cossign = -cossign; + stp = &sinus[deg]; + ctp = &sinus[90-deg]; + break; + } + *sinp = sinsign*stp[0]; + *cosp = cossign*ctp[0]; +} diff --git a/sys/src/libdraw/icossin2.c b/sys/src/libdraw/icossin2.c new file mode 100755 index 000000000..aa864e1a3 --- /dev/null +++ b/sys/src/libdraw/icossin2.c @@ -0,0 +1,261 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +/* + * Sine and Cosine of arctangents, calculated by + * (sin(atan(index/100.0))*1024.+0.5) + * (cos(atan(index/100.0))*1024.+0.5) + * To use, get rational tangent between 0<=tan<=1, scale by 100, + * and look up sin and cos, and use linear interpolation. divide by 1024. + * Maximum error is 0.0020. Without linear interpolation, it's 0.010. + */ +static +short sinus[] = { + 0, /* 0.00 */ + 10, /* 0.01 */ + 20, /* 0.02 */ + 31, /* 0.03 */ + 41, /* 0.04 */ + 51, /* 0.05 */ + 61, /* 0.06 */ + 72, /* 0.07 */ + 82, /* 0.08 */ + 92, /* 0.09 */ + 102, /* 0.10 */ + 112, /* 0.11 */ + 122, /* 0.12 */ + 132, /* 0.13 */ + 142, /* 0.14 */ + 152, /* 0.15 */ + 162, /* 0.16 */ + 172, /* 0.17 */ + 181, /* 0.18 */ + 191, /* 0.19 */ + 201, /* 0.20 */ + 210, /* 0.21 */ + 220, /* 0.22 */ + 230, /* 0.23 */ + 239, /* 0.24 */ + 248, /* 0.25 */ + 258, /* 0.26 */ + 267, /* 0.27 */ + 276, /* 0.28 */ + 285, /* 0.29 */ + 294, /* 0.30 */ + 303, /* 0.31 */ + 312, /* 0.32 */ + 321, /* 0.33 */ + 330, /* 0.34 */ + 338, /* 0.35 */ + 347, /* 0.36 */ + 355, /* 0.37 */ + 364, /* 0.38 */ + 372, /* 0.39 */ + 380, /* 0.40 */ + 388, /* 0.41 */ + 397, /* 0.42 */ + 405, /* 0.43 */ + 412, /* 0.44 */ + 420, /* 0.45 */ + 428, /* 0.46 */ + 436, /* 0.47 */ + 443, /* 0.48 */ + 451, /* 0.49 */ + 458, /* 0.50 */ + 465, /* 0.51 */ + 472, /* 0.52 */ + 480, /* 0.53 */ + 487, /* 0.54 */ + 493, /* 0.55 */ + 500, /* 0.56 */ + 507, /* 0.57 */ + 514, /* 0.58 */ + 520, /* 0.59 */ + 527, /* 0.60 */ + 533, /* 0.61 */ + 540, /* 0.62 */ + 546, /* 0.63 */ + 552, /* 0.64 */ + 558, /* 0.65 */ + 564, /* 0.66 */ + 570, /* 0.67 */ + 576, /* 0.68 */ + 582, /* 0.69 */ + 587, /* 0.70 */ + 593, /* 0.71 */ + 598, /* 0.72 */ + 604, /* 0.73 */ + 609, /* 0.74 */ + 614, /* 0.75 */ + 620, /* 0.76 */ + 625, /* 0.77 */ + 630, /* 0.78 */ + 635, /* 0.79 */ + 640, /* 0.80 */ + 645, /* 0.81 */ + 649, /* 0.82 */ + 654, /* 0.83 */ + 659, /* 0.84 */ + 663, /* 0.85 */ + 668, /* 0.86 */ + 672, /* 0.87 */ + 676, /* 0.88 */ + 681, /* 0.89 */ + 685, /* 0.90 */ + 689, /* 0.91 */ + 693, /* 0.92 */ + 697, /* 0.93 */ + 701, /* 0.94 */ + 705, /* 0.95 */ + 709, /* 0.96 */ + 713, /* 0.97 */ + 717, /* 0.98 */ + 720, /* 0.99 */ + 724, /* 1.00 */ + 728, /* 1.01 */ +}; + +static +short cosinus[] = { + 1024, /* 0.00 */ + 1024, /* 0.01 */ + 1024, /* 0.02 */ + 1024, /* 0.03 */ + 1023, /* 0.04 */ + 1023, /* 0.05 */ + 1022, /* 0.06 */ + 1022, /* 0.07 */ + 1021, /* 0.08 */ + 1020, /* 0.09 */ + 1019, /* 0.10 */ + 1018, /* 0.11 */ + 1017, /* 0.12 */ + 1015, /* 0.13 */ + 1014, /* 0.14 */ + 1013, /* 0.15 */ + 1011, /* 0.16 */ + 1010, /* 0.17 */ + 1008, /* 0.18 */ + 1006, /* 0.19 */ + 1004, /* 0.20 */ + 1002, /* 0.21 */ + 1000, /* 0.22 */ + 998, /* 0.23 */ + 996, /* 0.24 */ + 993, /* 0.25 */ + 991, /* 0.26 */ + 989, /* 0.27 */ + 986, /* 0.28 */ + 983, /* 0.29 */ + 981, /* 0.30 */ + 978, /* 0.31 */ + 975, /* 0.32 */ + 972, /* 0.33 */ + 969, /* 0.34 */ + 967, /* 0.35 */ + 963, /* 0.36 */ + 960, /* 0.37 */ + 957, /* 0.38 */ + 954, /* 0.39 */ + 951, /* 0.40 */ + 947, /* 0.41 */ + 944, /* 0.42 */ + 941, /* 0.43 */ + 937, /* 0.44 */ + 934, /* 0.45 */ + 930, /* 0.46 */ + 927, /* 0.47 */ + 923, /* 0.48 */ + 920, /* 0.49 */ + 916, /* 0.50 */ + 912, /* 0.51 */ + 909, /* 0.52 */ + 905, /* 0.53 */ + 901, /* 0.54 */ + 897, /* 0.55 */ + 893, /* 0.56 */ + 890, /* 0.57 */ + 886, /* 0.58 */ + 882, /* 0.59 */ + 878, /* 0.60 */ + 874, /* 0.61 */ + 870, /* 0.62 */ + 866, /* 0.63 */ + 862, /* 0.64 */ + 859, /* 0.65 */ + 855, /* 0.66 */ + 851, /* 0.67 */ + 847, /* 0.68 */ + 843, /* 0.69 */ + 839, /* 0.70 */ + 835, /* 0.71 */ + 831, /* 0.72 */ + 827, /* 0.73 */ + 823, /* 0.74 */ + 819, /* 0.75 */ + 815, /* 0.76 */ + 811, /* 0.77 */ + 807, /* 0.78 */ + 804, /* 0.79 */ + 800, /* 0.80 */ + 796, /* 0.81 */ + 792, /* 0.82 */ + 788, /* 0.83 */ + 784, /* 0.84 */ + 780, /* 0.85 */ + 776, /* 0.86 */ + 773, /* 0.87 */ + 769, /* 0.88 */ + 765, /* 0.89 */ + 761, /* 0.90 */ + 757, /* 0.91 */ + 754, /* 0.92 */ + 750, /* 0.93 */ + 746, /* 0.94 */ + 742, /* 0.95 */ + 739, /* 0.96 */ + 735, /* 0.97 */ + 731, /* 0.98 */ + 728, /* 0.99 */ + 724, /* 1.00 */ + 720, /* 1.01 */ +}; + +void +icossin2(int x, int y, int *cosp, int *sinp) +{ + int sinsign, cossign, tan, tan10, rem; + short *stp, *ctp; + + if(x == 0){ + if(y >= 0) + *sinp = ICOSSCALE, *cosp = 0; + else + *sinp = -ICOSSCALE, *cosp = 0; + return; + } + sinsign = cossign = 1; + if(x < 0){ + cossign = -1; + x = -x; + } + if(y < 0){ + sinsign = -1; + y = -y; + } + if(y > x){ + tan = 1000*x/y; + tan10 = tan/10; + stp = &cosinus[tan10]; + ctp = &sinus[tan10]; + }else{ + tan = 1000*y/x; + tan10 = tan/10; + stp = &sinus[tan10]; + ctp = &cosinus[tan10]; + } + rem = tan-(tan10*10); + *sinp = sinsign*(stp[0]+(stp[1]-stp[0])*rem/10); + *cosp = cossign*(ctp[0]+(ctp[1]-ctp[0])*rem/10); +} diff --git a/sys/src/libdraw/init.c b/sys/src/libdraw/init.c new file mode 100755 index 000000000..c0ed2edbf --- /dev/null +++ b/sys/src/libdraw/init.c @@ -0,0 +1,468 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +Display *display; +Font *font; +Image *screen; +int _drawdebug = 0; + +static char deffontname[] = "*default*"; +Screen *_screen; + +int debuglockdisplay = 0; + +static void _closedisplay(Display*, int); + +/* note handler */ +static void +drawshutdown(void) +{ + Display *d; + + d = display; + if(d){ + display = nil; + _closedisplay(d, 1); + } +} + +int +geninitdraw(char *devdir, void(*error)(Display*, char*), char *fontname, char *label, char *windir, int ref) +{ + int fd, n; + Subfont *df; + char buf[128]; + + display = initdisplay(devdir, windir, error); + if(display == nil) + return -1; + + /* + * Set up default font + */ + df = getdefont(display); + display->defaultsubfont = df; + if(df == nil){ + fprint(2, "imageinit: can't open default subfont: %r\n"); + Error: + closedisplay(display); + display = nil; + return -1; + } + if(fontname == nil){ + fd = open("/env/font", OREAD); + if(fd >= 0){ + n = read(fd, buf, sizeof(buf)); + if(n>0 && n<sizeof buf-1){ + buf[n] = 0; + fontname = buf; + } + close(fd); + } + } + /* + * Build fonts with caches==depth of screen, for speed. + * If conversion were faster, we'd use 0 and save memory. + */ + if(fontname == nil){ + snprint(buf, sizeof buf, "%d %d\n0 %d\t%s\n", df->height, df->ascent, + df->n-1, deffontname); +//BUG: Need something better for this installsubfont("*default*", df); + font = buildfont(display, buf, deffontname); + if(font == nil){ + fprint(2, "imageinit: can't open default font: %r\n"); + goto Error; + } + }else{ + font = openfont(display, fontname); /* BUG: grey fonts */ + if(font == nil){ + fprint(2, "imageinit: can't open font %s: %r\n", fontname); + goto Error; + } + } + display->defaultfont = font; + + /* + * Write label; ignore errors (we might not be running under rio) + */ + if(label){ + snprint(buf, sizeof buf, "%s/label", display->windir); + fd = open(buf, OREAD); + if(fd >= 0){ + read(fd, display->oldlabel, (sizeof display->oldlabel)-1); + close(fd); + fd = create(buf, OWRITE, 0666); + if(fd >= 0){ + write(fd, label, strlen(label)); + close(fd); + } + } + } + + snprint(buf, sizeof buf, "%s/winname", display->windir); + if(gengetwindow(display, buf, &screen, &_screen, ref) < 0) + goto Error; + + atexit(drawshutdown); + + return 1; +} + +int +initdraw(void(*error)(Display*, char*), char *fontname , char *label) +{ + char *dev = "/dev"; + + if(access("/dev/draw/new", AEXIST)<0 && bind("#i", "/dev", MAFTER)<0){ + fprint(2, "imageinit: can't bind /dev/draw: %r\n"); + return -1; + } + return geninitdraw(dev, error, fontname, label, dev, Refnone); +} + +/* + * Attach, or possibly reattach, to window. + * If reattaching, maintain value of screen pointer. + */ +int +gengetwindow(Display *d, char *winname, Image **winp, Screen **scrp, int ref) +{ + int n, fd; + char buf[64+1]; + Image *image; + Rectangle r; + + fd = open(winname, OREAD); + if(fd<0 || (n=read(fd, buf, sizeof buf-1))<=0){ + if((image=d->image) == nil){ + fprint(2, "gengetwindow: %r\n"); + *winp = nil; + d->screenimage = nil; + return -1; + } + strcpy(buf, "noborder"); + }else{ + close(fd); + buf[n] = '\0'; + if(*winp != nil){ + _freeimage1(*winp); + freeimage((*scrp)->image); + freescreen(*scrp); + *scrp = nil; + } + image = namedimage(d, buf); + if(image == 0){ + fprint(2, "namedimage %s failed: %r\n", buf); + *winp = nil; + d->screenimage = nil; + return -1; + } + assert(image->chan != 0); + } + + d->screenimage = image; + *scrp = allocscreen(image, d->white, 0); + if(*scrp == nil){ + freeimage(d->screenimage); + *winp = nil; + d->screenimage = nil; + return -1; + } + + r = image->r; + if(strncmp(buf, "noborder", 8) != 0) + r = insetrect(image->r, Borderwidth); + *winp = _allocwindow(*winp, *scrp, r, ref, DWhite); + if(*winp == nil){ + freescreen(*scrp); + *scrp = nil; + freeimage(image); + d->screenimage = nil; + return -1; + } + d->screenimage = *winp; + assert((*winp)->chan != 0); + return 1; +} + +int +getwindow(Display *d, int ref) +{ + char winname[128]; + + snprint(winname, sizeof winname, "%s/winname", d->windir); + return gengetwindow(d, winname, &screen, &_screen, ref); +} + +#define NINFO 12*12 + +Display* +initdisplay(char *dev, char *win, void(*error)(Display*, char*)) +{ + char buf[128], info[NINFO+1], *t, isnew; + int n, datafd, ctlfd, reffd; + Display *disp; + Dir *dir; + Image *image; + + fmtinstall('P', Pfmt); + fmtinstall('R', Rfmt); + if(dev == 0) + dev = "/dev"; + if(win == 0) + win = "/dev"; + if(strlen(dev)>sizeof buf-25 || strlen(win)>sizeof buf-25){ + werrstr("initdisplay: directory name too long"); + return nil; + } + t = strdup(win); + if(t == nil) + return nil; + + sprint(buf, "%s/draw/new", dev); + ctlfd = open(buf, ORDWR|OCEXEC); + if(ctlfd < 0){ + if(bind("#i", dev, MAFTER) < 0){ + Error1: + free(t); + werrstr("initdisplay: %s: %r", buf); + return 0; + } + ctlfd = open(buf, ORDWR|OCEXEC); + } + if(ctlfd < 0) + goto Error1; + if((n=read(ctlfd, info, sizeof info)) < 12){ + Error2: + close(ctlfd); + goto Error1; + } + if(n==NINFO+1) + n = NINFO; + buf[n] = '\0'; + isnew = 0; + if(n < NINFO) /* this will do for now, we need something better here */ + isnew = 1; + sprint(buf, "%s/draw/%d/data", dev, atoi(info+0*12)); + datafd = open(buf, ORDWR|OCEXEC); + if(datafd < 0) + goto Error2; + sprint(buf, "%s/draw/%d/refresh", dev, atoi(info+0*12)); + reffd = open(buf, OREAD|OCEXEC); + if(reffd < 0){ + Error3: + close(datafd); + goto Error2; + } + disp = mallocz(sizeof(Display), 1); + if(disp == 0){ + Error4: + close(reffd); + goto Error3; + } + image = nil; + if(0){ + Error5: + free(image); + free(disp); + goto Error4; + } + if(n >= NINFO){ + image = mallocz(sizeof(Image), 1); + if(image == nil) + goto Error5; + image->display = disp; + image->id = 0; + image->chan = strtochan(info+2*12); + image->depth = chantodepth(image->chan); + image->repl = atoi(info+3*12); + image->r.min.x = atoi(info+4*12); + image->r.min.y = atoi(info+5*12); + image->r.max.x = atoi(info+6*12); + image->r.max.y = atoi(info+7*12); + image->clipr.min.x = atoi(info+8*12); + image->clipr.min.y = atoi(info+9*12); + image->clipr.max.x = atoi(info+10*12); + image->clipr.max.y = atoi(info+11*12); + } + + disp->_isnewdisplay = isnew; + disp->bufsize = iounit(datafd); + if(disp->bufsize <= 0) + disp->bufsize = 8000; + if(disp->bufsize < 512){ + werrstr("iounit %d too small", disp->bufsize); + goto Error5; + } + disp->buf = malloc(disp->bufsize+5); /* +5 for flush message */ + if(disp->buf == nil) + goto Error5; + + disp->image = image; + disp->dirno = atoi(info+0*12); + disp->fd = datafd; + disp->ctlfd = ctlfd; + disp->reffd = reffd; + disp->bufp = disp->buf; + disp->error = error; + disp->windir = t; + disp->devdir = strdup(dev); + qlock(&disp->qlock); + disp->white = allocimage(disp, Rect(0, 0, 1, 1), GREY1, 1, DWhite); + disp->black = allocimage(disp, Rect(0, 0, 1, 1), GREY1, 1, DBlack); + if(disp->white == nil || disp->black == nil){ + free(disp->devdir); + free(disp->white); + free(disp->black); + goto Error5; + } + disp->opaque = disp->white; + disp->transparent = disp->black; + dir = dirfstat(ctlfd); + if(dir!=nil && dir->type=='i'){ + disp->local = 1; + disp->dataqid = dir->qid.path; + } + if(dir!=nil && dir->qid.vers==1) /* other way to tell */ + disp->_isnewdisplay = 1; + free(dir); + + return disp; +} + +/* + * Call with d unlocked. + * Note that disp->defaultfont and defaultsubfont are not freed here. + */ +void +closedisplay(Display *disp) +{ + _closedisplay(disp, 0); +} + +static void +_closedisplay(Display *disp, int isshutdown) +{ + int fd; + char buf[128]; + + if(disp == nil) + return; + if(disp == display) + display = nil; + if(disp->oldlabel[0]){ + snprint(buf, sizeof buf, "%s/label", disp->windir); + fd = open(buf, OWRITE); + if(fd >= 0){ + write(fd, disp->oldlabel, strlen(disp->oldlabel)); + close(fd); + } + } + + /* + * if we're shutting down, don't free all the resources. + * if other procs are getting shot down by notes too, + * one might get shot down while holding the malloc lock. + * just let the kernel clean things up when we exit. + */ + if(isshutdown) + return; + + free(disp->devdir); + free(disp->windir); + freeimage(disp->white); + freeimage(disp->black); + close(disp->fd); + close(disp->ctlfd); + /* should cause refresh slave to shut down */ + close(disp->reffd); + qunlock(&disp->qlock); + free(disp); +} + +void +lockdisplay(Display *disp) +{ + if(debuglockdisplay){ + /* avoid busy looping; it's rare we collide anyway */ + while(!canqlock(&disp->qlock)){ + fprint(1, "proc %d waiting for display lock...\n", getpid()); + sleep(1000); + } + }else + qlock(&disp->qlock); +} + +void +unlockdisplay(Display *disp) +{ + qunlock(&disp->qlock); +} + +void +drawerror(Display *d, char *s) +{ + char err[ERRMAX]; + + if(d && d->error) + d->error(d, s); + else{ + errstr(err, sizeof err); + fprint(2, "draw: %s: %s\n", s, err); + exits(s); + } +} + +static +int +doflush(Display *d) +{ + int n, nn; + + n = d->bufp-d->buf; + if(n <= 0) + return 1; + + if((nn=write(d->fd, d->buf, n)) != n){ + if(_drawdebug) + fprint(2, "flushimage fail: d=%p: n=%d nn=%d %r\n", d, n, nn); /**/ + d->bufp = d->buf; /* might as well; chance of continuing */ + return -1; + } + d->bufp = d->buf; + return 1; +} + +int +flushimage(Display *d, int visible) +{ + if(d == nil) + return 0; + if(visible){ + *d->bufp++ = 'v'; /* five bytes always reserved for this */ + if(d->_isnewdisplay){ + BPLONG(d->bufp, d->screenimage->id); + d->bufp += 4; + } + } + return doflush(d); +} + +uchar* +bufimage(Display *d, int n) +{ + uchar *p; + + if(n<0 || n>d->bufsize){ + werrstr("bad count in bufimage"); + return 0; + } + if(d->bufp+n > d->buf+d->bufsize) + if(doflush(d) < 0) + return 0; + p = d->bufp; + d->bufp += n; + return p; +} + diff --git a/sys/src/libdraw/keyboard.c b/sys/src/libdraw/keyboard.c new file mode 100755 index 000000000..5ab911ab8 --- /dev/null +++ b/sys/src/libdraw/keyboard.c @@ -0,0 +1,102 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> +#include <thread.h> +#include <keyboard.h> + + +void +closekeyboard(Keyboardctl *kc) +{ + if(kc == nil) + return; + + postnote(PNPROC, kc->pid, "kill"); + +#ifdef BUG + /* Drain the channel */ + while(?kc->c) + <-kc->c; +#endif + + close(kc->ctlfd); + close(kc->consfd); + free(kc->file); + free(kc->c); + free(kc); +} + +static +void +_ioproc(void *arg) +{ + int m, n; + char buf[20]; + Rune r; + Keyboardctl *kc; + + kc = arg; + threadsetname("kbdproc"); + kc->pid = getpid(); + n = 0; + for(;;){ + while(n>0 && fullrune(buf, n)){ + m = chartorune(&r, buf); + n -= m; + memmove(buf, buf+m, n); + send(kc->c, &r); + } + m = read(kc->consfd, buf+n, sizeof buf-n); + if(m <= 0){ + yield(); /* if error is due to exiting, we'll exit here */ + fprint(2, "keyboard read error: %r\n"); + threadexits("error"); + } + n += m; + } +} + +Keyboardctl* +initkeyboard(char *file) +{ + Keyboardctl *kc; + char *t; + + kc = mallocz(sizeof(Keyboardctl), 1); + if(kc == nil) + return nil; + if(file == nil) + file = "/dev/cons"; + kc->file = strdup(file); + kc->consfd = open(file, ORDWR|OCEXEC); + t = malloc(strlen(file)+16); + if(kc->consfd<0 || t==nil){ +Error1: + free(kc); + return nil; + } + sprint(t, "%sctl", file); + kc->ctlfd = open(t, OWRITE|OCEXEC); + if(kc->ctlfd < 0){ + fprint(2, "initkeyboard: can't open %s: %r\n", t); +Error2: + close(kc->consfd); + free(t); + goto Error1; + } + if(ctlkeyboard(kc, "rawon") < 0){ + fprint(2, "initkeyboard: can't turn on raw mode on %s: %r\n", t); + close(kc->ctlfd); + goto Error2; + } + free(t); + kc->c = chancreate(sizeof(Rune), 20); + proccreate(_ioproc, kc, 4096); + return kc; +} + +int +ctlkeyboard(Keyboardctl *kc, char *m) +{ + return write(kc->ctlfd, m, strlen(m)); +} diff --git a/sys/src/libdraw/line.c b/sys/src/libdraw/line.c new file mode 100755 index 000000000..a06b5927e --- /dev/null +++ b/sys/src/libdraw/line.c @@ -0,0 +1,35 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +void +line(Image *dst, Point p0, Point p1, int end0, int end1, int radius, Image *src, Point sp) +{ + lineop(dst, p0, p1, end0, end1, radius, src, sp, SoverD); +} + +void +lineop(Image *dst, Point p0, Point p1, int end0, int end1, int radius, Image *src, Point sp, Drawop op) +{ + uchar *a; + + _setdrawop(dst->display, op); + + a = bufimage(dst->display, 1+4+2*4+2*4+4+4+4+4+2*4); + if(a == 0){ + fprint(2, "image line: %r\n"); + return; + } + a[0] = 'L'; + BPLONG(a+1, dst->id); + BPLONG(a+5, p0.x); + BPLONG(a+9, p0.y); + BPLONG(a+13, p1.x); + BPLONG(a+17, p1.y); + BPLONG(a+21, end0); + BPLONG(a+25, end1); + BPLONG(a+29, radius); + BPLONG(a+33, src->id); + BPLONG(a+37, sp.x); + BPLONG(a+41, sp.y); +} diff --git a/sys/src/libdraw/loadimage.c b/sys/src/libdraw/loadimage.c new file mode 100755 index 000000000..d8d8c40bf --- /dev/null +++ b/sys/src/libdraw/loadimage.c @@ -0,0 +1,54 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +int +loadimage(Image *i, Rectangle r, uchar *data, int ndata) +{ + long dy; + int n, bpl; + uchar *a; + int chunk; + + chunk = i->display->bufsize - 64; + + if(!rectinrect(r, i->r)){ + werrstr("loadimage: bad rectangle"); + return -1; + } + bpl = bytesperline(r, i->depth); + n = bpl*Dy(r); + if(n > ndata){ + werrstr("loadimage: insufficient data"); + return -1; + } + ndata = 0; + while(r.max.y > r.min.y){ + dy = r.max.y - r.min.y; + if(dy*bpl > chunk) + dy = chunk/bpl; + if(dy <= 0){ + werrstr("loadimage: image too wide for buffer"); + return -1; + } + n = dy*bpl; + a = bufimage(i->display, 21+n); + if(a == nil){ + werrstr("bufimage failed"); + return -1; + } + a[0] = 'y'; + BPLONG(a+1, i->id); + BPLONG(a+5, r.min.x); + BPLONG(a+9, r.min.y); + BPLONG(a+13, r.max.x); + BPLONG(a+17, r.min.y+dy); + memmove(a+21, data, n); + ndata += n; + data += n; + r.min.y += dy; + } + if(flushimage(i->display, 0) < 0) + return -1; + return ndata; +} diff --git a/sys/src/libdraw/makefile b/sys/src/libdraw/makefile new file mode 100755 index 000000000..e7e3ec557 --- /dev/null +++ b/sys/src/libdraw/makefile @@ -0,0 +1,44 @@ +!include "..\mkconfig.nmk" +!include "..\$(SYSHOST)\mkhost" +!include "..\$(OBJDIR)\makefile" + +LIB=libimage.$A +OFILES_C= \ + alloc.$O\ + arith.$O\ + bezier.$O\ + buildfont.$O\ + bytesperline.$O\ + creadimage.$O\ + cursor.$O\ + defont.$O\ + draw.$O\ + ellipse.$O\ + font.$O\ + freesubfont.$O\ + getsubfont.$O\ + init.$O\ + line.$O\ + loadimage.$O\ + mkfont.$O\ + openfont.$O\ + poly.$O\ + readimage.$O\ + readsubfont.$O\ + rectclip.$O\ + replclipr.$O\ + rgb.$O\ + string.$O\ + stringsubfont.$O\ + stringwidth.$O\ + subfont.$O\ + subfontcache.$O\ + subfontname.$O\ + unloadimage.$O\ + window.$O\ + writeimage.$O\ + +HFILES=\ + ../include/memimage.h + +!include <..\$(SYSTARG)\mksyslib.nmk> diff --git a/sys/src/libdraw/menuhit.c b/sys/src/libdraw/menuhit.c new file mode 100755 index 000000000..851c97676 --- /dev/null +++ b/sys/src/libdraw/menuhit.c @@ -0,0 +1,277 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> +#include <thread.h> +#include <mouse.h> + +enum +{ + Margin = 4, /* outside to text */ + Border = 2, /* outside to selection boxes */ + Blackborder = 2, /* width of outlining border */ + Vspacing = 2, /* extra spacing between lines of text */ + Maxunscroll = 25, /* maximum #entries before scrolling turns on */ + Nscroll = 20, /* number entries in scrolling part */ + Scrollwid = 14, /* width of scroll bar */ + Gap = 4, /* between text and scroll bar */ +}; + +static Image *menutxt; +static Image *back; +static Image *high; +static Image *bord; +static Image *text; +static Image *htext; + +static +void +menucolors(void) +{ + /* Main tone is greenish, with negative selection */ + back = allocimagemix(display, DPalegreen, DWhite); + high = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DDarkgreen); /* dark green */ + bord = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DMedgreen); /* not as dark green */ + if(back==nil || high==nil || bord==nil) + goto Error; + text = display->black; + htext = back; + return; + + Error: + freeimage(back); + freeimage(high); + freeimage(bord); + back = display->white; + high = display->black; + bord = display->black; + text = display->black; + htext = display->white; +} + +/* + * r is a rectangle holding the text elements. + * return the rectangle, including its black edge, holding element i. + */ +static Rectangle +menurect(Rectangle r, int i) +{ + if(i < 0) + return Rect(0, 0, 0, 0); + r.min.y += (font->height+Vspacing)*i; + r.max.y = r.min.y+font->height+Vspacing; + return insetrect(r, Border-Margin); +} + +/* + * r is a rectangle holding the text elements. + * return the element number containing p. + */ +static int +menusel(Rectangle r, Point p) +{ + r = insetrect(r, Margin); + if(!ptinrect(p, r)) + return -1; + return (p.y-r.min.y)/(font->height+Vspacing); +} + +static +void +paintitem(Image *m, Menu *menu, Rectangle textr, int off, int i, int highlight, Image *save, Image *restore) +{ + char *item; + Rectangle r; + Point pt; + + if(i < 0) + return; + r = menurect(textr, i); + if(restore){ + draw(m, r, restore, nil, restore->r.min); + return; + } + if(save) + draw(save, save->r, m, nil, r.min); + item = menu->item? menu->item[i+off] : (*menu->gen)(i+off); + pt.x = (textr.min.x+textr.max.x-stringwidth(font, item))/2; + pt.y = textr.min.y+i*(font->height+Vspacing); + draw(m, r, highlight? high : back, nil, pt); + string(m, pt, highlight? htext : text, pt, font, item); +} + +/* + * menur is a rectangle holding all the highlightable text elements. + * track mouse while inside the box, return what's selected when button + * is raised, -1 as soon as it leaves box. + * invariant: nothing is highlighted on entry or exit. + */ +static int +menuscan(Image *m, Menu *menu, int but, Mousectl *mc, Rectangle textr, int off, int lasti, Image *save) +{ + int i; + + paintitem(m, menu, textr, off, lasti, 1, save, nil); + for(readmouse(mc); mc->buttons & (1<<(but-1)); readmouse(mc)){ + i = menusel(textr, mc->xy); + if(i != -1 && i == lasti) + continue; + paintitem(m, menu, textr, off, lasti, 0, nil, save); + if(i == -1) + return i; + lasti = i; + paintitem(m, menu, textr, off, lasti, 1, save, nil); + } + return lasti; +} + +static void +menupaint(Image *m, Menu *menu, Rectangle textr, int off, int nitemdrawn) +{ + int i; + + draw(m, insetrect(textr, Border-Margin), back, nil, ZP); + for(i = 0; i<nitemdrawn; i++) + paintitem(m, menu, textr, off, i, 0, nil, nil); +} + +static void +menuscrollpaint(Image *m, Rectangle scrollr, int off, int nitem, int nitemdrawn) +{ + Rectangle r; + + draw(m, scrollr, back, nil, ZP); + r.min.x = scrollr.min.x; + r.max.x = scrollr.max.x; + r.min.y = scrollr.min.y + (Dy(scrollr)*off)/nitem; + r.max.y = scrollr.min.y + (Dy(scrollr)*(off+nitemdrawn))/nitem; + if(r.max.y < r.min.y+2) + r.max.y = r.min.y+2; + border(m, r, 1, bord, ZP); + if(menutxt == 0) + menutxt = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, DDarkgreen); /* border color; BUG? */ + if(menutxt) + draw(m, insetrect(r, 1), menutxt, nil, ZP); +} + +int +menuhit(int but, Mousectl *mc, Menu *menu, Screen *scr) +{ + int i, nitem, nitemdrawn, maxwid, lasti, off, noff, wid, screenitem; + int scrolling; + Rectangle r, menur, sc, textr, scrollr; + Image *b, *save, *backup; + Point pt; + char *item; + + if(back == nil) + menucolors(); + sc = screen->clipr; + replclipr(screen, 0, screen->r); + maxwid = 0; + for(nitem = 0; + item = menu->item? menu->item[nitem] : (*menu->gen)(nitem); + nitem++){ + i = stringwidth(font, item); + if(i > maxwid) + maxwid = i; + } + if(menu->lasthit<0 || menu->lasthit>=nitem) + menu->lasthit = 0; + screenitem = (Dy(screen->r)-10)/(font->height+Vspacing); + if(nitem>Maxunscroll || nitem>screenitem){ + scrolling = 1; + nitemdrawn = Nscroll; + if(nitemdrawn > screenitem) + nitemdrawn = screenitem; + wid = maxwid + Gap + Scrollwid; + off = menu->lasthit - nitemdrawn/2; + if(off < 0) + off = 0; + if(off > nitem-nitemdrawn) + off = nitem-nitemdrawn; + lasti = menu->lasthit-off; + }else{ + scrolling = 0; + nitemdrawn = nitem; + wid = maxwid; + off = 0; + lasti = menu->lasthit; + } + r = insetrect(Rect(0, 0, wid, nitemdrawn*(font->height+Vspacing)), -Margin); + r = rectsubpt(r, Pt(wid/2, lasti*(font->height+Vspacing)+font->height/2)); + r = rectaddpt(r, mc->xy); + pt = ZP; + if(r.max.x>screen->r.max.x) + pt.x = screen->r.max.x-r.max.x; + if(r.max.y>screen->r.max.y) + pt.y = screen->r.max.y-r.max.y; + if(r.min.x<screen->r.min.x) + pt.x = screen->r.min.x-r.min.x; + if(r.min.y<screen->r.min.y) + pt.y = screen->r.min.y-r.min.y; + menur = rectaddpt(r, pt); + textr.max.x = menur.max.x-Margin; + textr.min.x = textr.max.x-maxwid; + textr.min.y = menur.min.y+Margin; + textr.max.y = textr.min.y + nitemdrawn*(font->height+Vspacing); + if(scrolling){ + scrollr = insetrect(menur, Border); + scrollr.max.x = scrollr.min.x+Scrollwid; + }else + scrollr = Rect(0, 0, 0, 0); + + if(scr){ + b = allocwindow(scr, menur, Refbackup, DWhite); + if(b == nil) + b = screen; + backup = nil; + }else{ + b = screen; + backup = allocimage(display, menur, screen->chan, 0, -1); + if(backup) + draw(backup, menur, screen, nil, menur.min); + } + draw(b, menur, back, nil, ZP); + border(b, menur, Blackborder, bord, ZP); + save = allocimage(display, menurect(textr, 0), screen->chan, 0, -1); + r = menurect(textr, lasti); + moveto(mc, divpt(addpt(r.min, r.max), 2)); + menupaint(b, menu, textr, off, nitemdrawn); + if(scrolling) + menuscrollpaint(b, scrollr, off, nitem, nitemdrawn); + while(mc->buttons & (1<<(but-1))){ + lasti = menuscan(b, menu, but, mc, textr, off, lasti, save); + if(lasti >= 0) + break; + while(!ptinrect(mc->xy, textr) && (mc->buttons & (1<<(but-1)))){ + if(scrolling && ptinrect(mc->xy, scrollr)){ + noff = ((mc->xy.y-scrollr.min.y)*nitem)/Dy(scrollr); + noff -= nitemdrawn/2; + if(noff < 0) + noff = 0; + if(noff > nitem-nitemdrawn) + noff = nitem-nitemdrawn; + if(noff != off){ + off = noff; + menupaint(b, menu, textr, off, nitemdrawn); + menuscrollpaint(b, scrollr, off, nitem, nitemdrawn); + } + } + readmouse(mc); + } + } + if(b != screen) + freeimage(b); + if(backup){ + draw(screen, menur, backup, nil, menur.min); + freeimage(backup); + } + freeimage(save); + replclipr(screen, 0, sc); + flushimage(display, 1); + if(lasti >= 0){ + menu->lasthit = lasti+off; + return menu->lasthit; + } + return -1; +} diff --git a/sys/src/libdraw/mkfile b/sys/src/libdraw/mkfile new file mode 100755 index 000000000..86f275bd0 --- /dev/null +++ b/sys/src/libdraw/mkfile @@ -0,0 +1,75 @@ +</$objtype/mkfile + +LIB=/$objtype/lib/libdraw.a + +OFILES=\ + alloc.$O\ + allocimagemix.$O\ + arith.$O\ + bezier.$O\ + border.$O\ + buildfont.$O\ + bytesperline.$O\ + chan.$O\ + cloadimage.$O\ + computil.$O\ + creadimage.$O\ + debug.$O\ + defont.$O\ + draw.$O\ + drawrepl.$O\ + egetrect.$O\ + ellipse.$O\ + emenuhit.$O\ + event.$O\ + fmt.$O\ + font.$O\ + freesubfont.$O\ + getdefont.$O\ + getrect.$O\ + getsubfont.$O\ + icossin.$O\ + icossin2.$O\ + init.$O\ + keyboard.$O\ + line.$O\ + menuhit.$O\ + mkfont.$O\ + mouse.$O\ + newwindow.$O\ + openfont.$O\ + poly.$O\ + loadimage.$O\ + readcolmap.$O\ + readimage.$O\ + readsubfont.$O\ + rectclip.$O\ + replclipr.$O\ + rgb.$O\ + scroll.$O\ + string.$O\ + stringbg.$O\ + stringsubfont.$O\ + stringwidth.$O\ + subfont.$O\ + subfontcache.$O\ + subfontname.$O\ + unloadimage.$O\ + window.$O\ + writecolmap.$O\ + writeimage.$O\ + writesubfont.$O\ + +HFILES=\ + /sys/include/draw.h\ + /sys/include/event.h\ + /sys/include/mouse.h\ + /sys/include/keyboard.h + +UPDATE=\ + mkfile\ + $HFILES\ + ${OFILES:%.$O=%.c}\ + ${LIB:/$objtype/%=/386/%}\ + +</sys/src/cmd/mksyslib diff --git a/sys/src/libdraw/mkfont.c b/sys/src/libdraw/mkfont.c new file mode 100755 index 000000000..df6b0ec2f --- /dev/null +++ b/sys/src/libdraw/mkfont.c @@ -0,0 +1,55 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +/* + * Cobble fake font using existing subfont + */ +Font* +mkfont(Subfont *subfont, Rune min) +{ + Font *font; + Cachefont *c; + + font = malloc(sizeof(Font)); + if(font == 0) + return 0; + memset(font, 0, sizeof(Font)); + font->display = subfont->bits->display; + font->name = strdup("<synthetic>"); + font->ncache = NFCACHE+NFLOOK; + font->nsubf = NFSUBF; + font->cache = malloc(font->ncache * sizeof(font->cache[0])); + font->subf = malloc(font->nsubf * sizeof(font->subf[0])); + if(font->name==0 || font->cache==0 || font->subf==0){ + Err: + free(font->name); + free(font->cache); + free(font->subf); + free(font->sub); + free(font); + return 0; + } + memset(font->cache, 0, font->ncache*sizeof(font->cache[0])); + memset(font->subf, 0, font->nsubf*sizeof(font->subf[0])); + font->height = subfont->height; + font->ascent = subfont->ascent; + font->age = 1; + font->sub = malloc(sizeof(Cachefont*)); + if(font->sub == 0) + goto Err; + c = malloc(sizeof(Cachefont)); + if(c == 0) + goto Err; + font->nsub = 1; + font->sub[0] = c; + c->min = min; + c->max = min+subfont->n-1; + c->offset = 0; + c->name = 0; /* noticed by freeup() and agefont() */ + c->subfontname = 0; + font->subf[0].age = 0; + font->subf[0].cf = c; + font->subf[0].f = subfont; + return font; +} diff --git a/sys/src/libdraw/mouse.c b/sys/src/libdraw/mouse.c new file mode 100755 index 000000000..cbcfade28 --- /dev/null +++ b/sys/src/libdraw/mouse.c @@ -0,0 +1,144 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> +#include <thread.h> +#include <cursor.h> +#include <mouse.h> + +void +moveto(Mousectl *m, Point pt) +{ + fprint(m->mfd, "m%d %d", pt.x, pt.y); + m->xy = pt; +} + +void +closemouse(Mousectl *mc) +{ + if(mc == nil) + return; + + postnote(PNPROC, mc->pid, "kill"); + + do; while(nbrecv(mc->c, &mc->Mouse) > 0); + + close(mc->mfd); + close(mc->cfd); + free(mc->file); + free(mc->c); + free(mc->resizec); + free(mc); +} + +int +readmouse(Mousectl *mc) +{ + if(mc->image) + flushimage(mc->image->display, 1); + if(recv(mc->c, &mc->Mouse) < 0){ + fprint(2, "readmouse: %r\n"); + return -1; + } + return 0; +} + +static +void +_ioproc(void *arg) +{ + int n, nerr, one; + char buf[1+5*12]; + Mouse m; + Mousectl *mc; + + mc = arg; + threadsetname("mouseproc"); + one = 1; + memset(&m, 0, sizeof m); + mc->pid = getpid(); + nerr = 0; + for(;;){ + n = read(mc->mfd, buf, sizeof buf); + if(n != 1+4*12){ + yield(); /* if error is due to exiting, we'll exit here */ + fprint(2, "mouse: bad count %d not 49: %r\n", n); + if(n<0 || ++nerr>10) + threadexits("read error"); + continue; + } + nerr = 0; + switch(buf[0]){ + case 'r': + send(mc->resizec, &one); + /* fall through */ + case 'm': + m.xy.x = atoi(buf+1+0*12); + m.xy.y = atoi(buf+1+1*12); + m.buttons = atoi(buf+1+2*12); + m.msec = atoi(buf+1+3*12); + send(mc->c, &m); + /* + * mc->Mouse is updated after send so it doesn't have wrong value if we block during send. + * This means that programs should receive into mc->Mouse (see readmouse() above) if + * they want full synchrony. + */ + mc->Mouse = m; + break; + } + } +} + +Mousectl* +initmouse(char *file, Image *i) +{ + Mousectl *mc; + char *t, *sl; + + mc = mallocz(sizeof(Mousectl), 1); + if(file == nil) + file = "/dev/mouse"; + mc->file = strdup(file); + mc->mfd = open(file, ORDWR|OCEXEC); + if(mc->mfd<0 && strcmp(file, "/dev/mouse")==0){ + bind("#m", "/dev", MAFTER); + mc->mfd = open(file, ORDWR|OCEXEC); + } + if(mc->mfd < 0){ + free(mc); + return nil; + } + t = malloc(strlen(file)+16); + if (t == nil) { + close(mc->mfd); + free(mc); + return nil; + } + strcpy(t, file); + sl = utfrrune(t, '/'); + if(sl) + strcpy(sl, "/cursor"); + else + strcpy(t, "/dev/cursor"); + mc->cfd = open(t, ORDWR|OCEXEC); + free(t); + mc->image = i; + mc->c = chancreate(sizeof(Mouse), 0); + mc->resizec = chancreate(sizeof(int), 2); + proccreate(_ioproc, mc, 4096); + return mc; +} + +void +setcursor(Mousectl *mc, Cursor *c) +{ + char curs[2*4+2*2*16]; + + if(c == nil) + write(mc->cfd, curs, 0); + else{ + BPLONG(curs+0*4, c->offset.x); + BPLONG(curs+1*4, c->offset.y); + memmove(curs+2*4, c->clr, 2*2*16); + write(mc->cfd, curs, sizeof curs); + } +} diff --git a/sys/src/libdraw/newwindow.c b/sys/src/libdraw/newwindow.c new file mode 100755 index 000000000..88784adf5 --- /dev/null +++ b/sys/src/libdraw/newwindow.c @@ -0,0 +1,27 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +/* Connect us to new window, if possible */ +int +newwindow(char *str) +{ + int fd; + char *wsys; + char buf[256]; + + wsys = getenv("wsys"); + if(wsys == nil) + return -1; + fd = open(wsys, ORDWR); + free(wsys); + if(fd < 0) + return -1; + rfork(RFNAMEG); + if(str) + snprint(buf, sizeof buf, "new %s", str); + else + strcpy(buf, "new"); + return mount(fd, -1, "/dev", MBEFORE, buf); +} + diff --git a/sys/src/libdraw/openfont.c b/sys/src/libdraw/openfont.c new file mode 100755 index 000000000..3d9fa3ee1 --- /dev/null +++ b/sys/src/libdraw/openfont.c @@ -0,0 +1,38 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +Font* +openfont(Display *d, char *name) +{ + Font *fnt; + int fd, i, n; + char *buf; + Dir *dir; + + fd = open(name, OREAD); + if(fd < 0) + return 0; + + dir = dirfstat(fd); + if(dir == nil){ + Err0: + close(fd); + return 0; + } + n = dir->length; + free(dir); + buf = malloc(n+1); + if(buf == 0) + goto Err0; + buf[n] = 0; + i = read(fd, buf, n); + close(fd); + if(i != n){ + free(buf); + return 0; + } + fnt = buildfont(d, buf, name); + free(buf); + return fnt; +} diff --git a/sys/src/libdraw/poly.c b/sys/src/libdraw/poly.c new file mode 100755 index 000000000..96effaec8 --- /dev/null +++ b/sys/src/libdraw/poly.c @@ -0,0 +1,87 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +static +uchar* +addcoord(uchar *p, int oldx, int newx) +{ + int dx; + + dx = newx-oldx; + /* does dx fit in 7 signed bits? */ + if((unsigned)(dx - -0x40) <= 0x7F) + *p++ = dx&0x7F; + else{ + *p++ = 0x80 | (newx&0x7F); + *p++ = newx>>7; + *p++ = newx>>15; + } + return p; +} + +static +void +dopoly(int cmd, Image *dst, Point *pp, int np, int end0, int end1, int radius, Image *src, Point *sp, Drawop op) +{ + uchar *a, *t, *u; + int i, ox, oy; + + if(np == 0) + return; + t = malloc(np*2*3); + if(t == nil) + return; + u = t; + ox = oy = 0; + for(i=0; i<np; i++){ + u = addcoord(u, ox, pp[i].x); + ox = pp[i].x; + u = addcoord(u, oy, pp[i].y); + oy = pp[i].y; + } + + _setdrawop(dst->display, op); + + a = bufimage(dst->display, 1+4+2+4+4+4+4+2*4+(u-t)); + if(a == 0){ + free(t); + fprint(2, "image poly: %r\n"); + return; + } + a[0] = cmd; + BPLONG(a+1, dst->id); + BPSHORT(a+5, np-1); + BPLONG(a+7, end0); + BPLONG(a+11, end1); + BPLONG(a+15, radius); + BPLONG(a+19, src->id); + BPLONG(a+23, sp->x); + BPLONG(a+27, sp->y); + memmove(a+31, t, u-t); + free(t); +} + +void +poly(Image *dst, Point *p, int np, int end0, int end1, int radius, Image *src, Point sp) +{ + dopoly('p', dst, p, np, end0, end1, radius, src, &sp, SoverD); +} + +void +polyop(Image *dst, Point *p, int np, int end0, int end1, int radius, Image *src, Point sp, Drawop op) +{ + dopoly('p', dst, p, np, end0, end1, radius, src, &sp, op); +} + +void +fillpoly(Image *dst, Point *p, int np, int wind, Image *src, Point sp) +{ + dopoly('P', dst, p, np, wind, 0, 0, src, &sp, SoverD); +} + +void +fillpolyop(Image *dst, Point *p, int np, int wind, Image *src, Point sp, Drawop op) +{ + dopoly('P', dst, p, np, wind, 0, 0, src, &sp, op); +} diff --git a/sys/src/libdraw/readcolmap.c b/sys/src/libdraw/readcolmap.c new file mode 100755 index 000000000..6eb8ee26e --- /dev/null +++ b/sys/src/libdraw/readcolmap.c @@ -0,0 +1,49 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> +#include <bio.h> + +static ulong +getval(char **p) +{ + ulong v; + char *q; + + v = strtoul(*p, &q, 0); + v |= v<<8; + v |= v<<16; + *p = q; + return v; +} + +void +readcolmap(Display *d, RGB *colmap) +{ + int i; + char *p, *q; + Biobuf *b; + char buf[128]; + + USED(screen); + + sprint(buf, "/dev/draw/%d/colormap", d->dirno); + b = Bopen(buf, OREAD); + if(b == 0) + drawerror(d, "rdcolmap: can't open colormap device"); + + for(;;) { + p = Brdline(b, '\n'); + if(p == 0) + break; + i = strtoul(p, &q, 0); + if(i < 0 || i > 255) { + fprint(2, "rdcolmap: bad index\n"); + exits("bad"); + } + p = q; + colmap[255-i].red = getval(&p); + colmap[255-i].green = getval(&p); + colmap[255-i].blue = getval(&p); + } + Bterm(b); +} diff --git a/sys/src/libdraw/readimage.c b/sys/src/libdraw/readimage.c new file mode 100755 index 000000000..61dbd12a6 --- /dev/null +++ b/sys/src/libdraw/readimage.c @@ -0,0 +1,130 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +Image* +readimage(Display *d, int fd, int dolock) +{ + char hdr[5*12+1]; + int dy; + int new; + uint l, n; + int m, j, chunk; + int miny, maxy; + Rectangle r; + int ldepth; + ulong chan; + uchar *tmp; + Image *i; + + if(readn(fd, hdr, 11) != 11) + return nil; + if(memcmp(hdr, "compressed\n", 11) == 0) + return creadimage(d, fd, dolock); + if(readn(fd, hdr+11, 5*12-11) != 5*12-11) + return nil; + if(d) + chunk = d->bufsize - 32; /* a little room for header */ + else + chunk = 8192; + + /* + * distinguish new channel descriptor from old ldepth. + * channel descriptors have letters as well as numbers, + * while ldepths are a single digit formatted as %-11d. + */ + new = 0; + for(m=0; m<10; m++){ + if(hdr[m] != ' '){ + new = 1; + break; + } + } + if(hdr[11] != ' '){ + werrstr("readimage: bad format"); + return nil; + } + if(new){ + hdr[11] = '\0'; + if((chan = strtochan(hdr)) == 0){ + werrstr("readimage: bad channel string %s", hdr); + return nil; + } + }else{ + ldepth = ((int)hdr[10])-'0'; + if(ldepth<0 || ldepth>3){ + werrstr("readimage: bad ldepth %d", ldepth); + return nil; + } + chan = drawld2chan[ldepth]; + } + + r.min.x = atoi(hdr+1*12); + r.min.y = atoi(hdr+2*12); + r.max.x = atoi(hdr+3*12); + r.max.y = atoi(hdr+4*12); + if(r.min.x>r.max.x || r.min.y>r.max.y){ + werrstr("readimage: bad rectangle"); + return nil; + } + + miny = r.min.y; + maxy = r.max.y; + + l = bytesperline(r, chantodepth(chan)); + if(d){ + if(dolock) + lockdisplay(d); + i = allocimage(d, r, chan, 0, -1); + if(dolock) + unlockdisplay(d); + if(i == nil) + return nil; + }else{ + i = mallocz(sizeof(Image), 1); + if(i == nil) + return nil; + } + + tmp = malloc(chunk); + if(tmp == nil) + goto Err; + while(maxy > miny){ + dy = maxy - miny; + if(dy*l > chunk) + dy = chunk/l; + if(dy <= 0){ + werrstr("readimage: image too wide for buffer"); + goto Err; + } + n = dy*l; + m = readn(fd, tmp, n); + if(m != n){ + werrstr("readimage: read count %d not %d: %r", m, n); + Err: + if(dolock) + lockdisplay(d); + Err1: + freeimage(i); + if(dolock) + unlockdisplay(d); + free(tmp); + return nil; + } + if(!new) /* an old image: must flip all the bits */ + for(j=0; j<chunk; j++) + tmp[j] ^= 0xFF; + + if(d){ + if(dolock) + lockdisplay(d); + if(loadimage(i, Rect(r.min.x, miny, r.max.x, miny+dy), tmp, chunk) <= 0) + goto Err1; + if(dolock) + unlockdisplay(d); + } + miny += dy; + } + free(tmp); + return i; +} diff --git a/sys/src/libdraw/readsubfont.c b/sys/src/libdraw/readsubfont.c new file mode 100755 index 000000000..5314df82d --- /dev/null +++ b/sys/src/libdraw/readsubfont.c @@ -0,0 +1,60 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +Subfont* +readsubfonti(Display*d, char *name, int fd, Image *ai, int dolock) +{ + char hdr[3*12+4+1]; + int n; + uchar *p; + Fontchar *fc; + Subfont *f; + Image *i; + + i = ai; + if(i == nil){ + i = readimage(d, fd, dolock); + if(i == nil) + return nil; + } + if(read(fd, hdr, 3*12) != 3*12){ + if(ai == nil) + freeimage(i); + werrstr("rdsubfonfile: header read error: %r"); + return nil; + } + n = atoi(hdr); + p = malloc(6*(n+1)); + if(p == nil) + goto Err; + if(read(fd, p, 6*(n+1)) != 6*(n+1)){ + werrstr("rdsubfonfile: fontchar read error: %r"); + Err: + if(ai == nil) + freeimage(i); + free(p); + return nil; + } + fc = malloc(sizeof(Fontchar)*(n+1)); + if(fc == nil) + goto Err; + _unpackinfo(fc, p, n); + if(dolock) + lockdisplay(d); + f = allocsubfont(name, n, atoi(hdr+12), atoi(hdr+24), fc, i); + if(dolock) + unlockdisplay(d); + if(f == nil){ + free(fc); + goto Err; + } + free(p); + return f; +} + +Subfont* +readsubfont(Display *d, char *name, int fd, int dolock) +{ + return readsubfonti(d, name, fd, nil, dolock); +} diff --git a/sys/src/libdraw/rectclip.c b/sys/src/libdraw/rectclip.c new file mode 100755 index 000000000..2228628b8 --- /dev/null +++ b/sys/src/libdraw/rectclip.c @@ -0,0 +1,25 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +int +rectclip(Rectangle *rp, Rectangle b) /* first by reference, second by value */ +{ + Rectangle *bp = &b; + /* + * Expand rectXrect() in line for speed + */ + if((rp->min.x<bp->max.x && bp->min.x<rp->max.x && + rp->min.y<bp->max.y && bp->min.y<rp->max.y)==0) + return 0; + /* They must overlap */ + if(rp->min.x < bp->min.x) + rp->min.x = bp->min.x; + if(rp->min.y < bp->min.y) + rp->min.y = bp->min.y; + if(rp->max.x > bp->max.x) + rp->max.x = bp->max.x; + if(rp->max.y > bp->max.y) + rp->max.y = bp->max.y; + return 1; +} diff --git a/sys/src/libdraw/replclipr.c b/sys/src/libdraw/replclipr.c new file mode 100755 index 000000000..ffd24b47b --- /dev/null +++ b/sys/src/libdraw/replclipr.c @@ -0,0 +1,21 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +void +replclipr(Image *i, int repl, Rectangle clipr) +{ + uchar *b; + + b = bufimage(i->display, 22); + b[0] = 'c'; + BPLONG(b+1, i->id); + repl = repl!=0; + b[5] = repl; + BPLONG(b+6, clipr.min.x); + BPLONG(b+10, clipr.min.y); + BPLONG(b+14, clipr.max.x); + BPLONG(b+18, clipr.max.y); + i->repl = repl; + i->clipr = clipr; +} diff --git a/sys/src/libdraw/rgb.c b/sys/src/libdraw/rgb.c new file mode 100755 index 000000000..eda28b4c8 --- /dev/null +++ b/sys/src/libdraw/rgb.c @@ -0,0 +1,99 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +/* + * This original version, although fast and a true inverse of + * cmap2rgb, in the sense that rgb2cmap(cmap2rgb(c)) + * returned the original color, does a terrible job for RGB + * triples that do not appear in the color map, so it has been + * replaced by the much slower version below, that loops + * over the color map looking for the nearest point in RGB + * space. There is no visual psychology reason for that + * criterion, but it's easy to implement and the results are + * far more pleasing. + * +int +rgb2cmap(int cr, int cg, int cb) +{ + int r, g, b, v, cv; + + if(cr < 0) + cr = 0; + else if(cr > 255) + cr = 255; + if(cg < 0) + cg = 0; + else if(cg > 255) + cg = 255; + if(cb < 0) + cb = 0; + else if(cb > 255) + cb = 255; + r = cr>>6; + g = cg>>6; + b = cb>>6; + cv = cr; + if(cg > cv) + cv = cg; + if(cb > cv) + cv = cb; + v = (cv>>4)&3; + return ((((r<<2)+v)<<4)+(((g<<2)+b+v-r)&15)); +} +*/ + +int +rgb2cmap(int cr, int cg, int cb) +{ + int i, r, g, b, sq; + ulong rgb; + int best, bestsq; + + best = 0; + bestsq = 0x7FFFFFFF; + for(i=0; i<256; i++){ + rgb = cmap2rgb(i); + r = (rgb>>16) & 0xFF; + g = (rgb>>8) & 0xFF; + b = (rgb>>0) & 0xFF; + sq = (r-cr)*(r-cr)+(g-cg)*(g-cg)+(b-cb)*(b-cb); + if(sq < bestsq){ + bestsq = sq; + best = i; + } + } + return best; +} + +int +cmap2rgb(int c) +{ + int j, num, den, r, g, b, v, rgb; + + r = c>>6; + v = (c>>4)&3; + j = (c-v+r)&15; + g = j>>2; + b = j&3; + den=r; + if(g>den) + den=g; + if(b>den) + den=b; + if(den==0) { + v *= 17; + rgb = (v<<16)|(v<<8)|v; + } + else{ + num=17*(4*den+v); + rgb = ((r*num/den)<<16)|((g*num/den)<<8)|(b*num/den); + } + return rgb; +} + +int +cmap2rgba(int c) +{ + return (cmap2rgb(c)<<8)|0xFF; +} diff --git a/sys/src/libdraw/scroll.c b/sys/src/libdraw/scroll.c new file mode 100755 index 000000000..ea0aa25c7 --- /dev/null +++ b/sys/src/libdraw/scroll.c @@ -0,0 +1,29 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +int +mousescrollsize(int maxlines) +{ + static int lines, pcnt; + char *mss; + + if(lines == 0 && pcnt == 0){ + mss = getenv("mousescrollsize"); + if(mss){ + if(strchr(mss, '%') != nil) + pcnt = atof(mss); + else + lines = atoi(mss); + free(mss); + } + if(lines == 0 && pcnt == 0) + lines = 1; + if(pcnt>=100) + pcnt = 100; + } + + if(lines) + return lines; + return pcnt * maxlines/100.0; +} diff --git a/sys/src/libdraw/string.c b/sys/src/libdraw/string.c new file mode 100755 index 000000000..4e876c170 --- /dev/null +++ b/sys/src/libdraw/string.c @@ -0,0 +1,144 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +enum +{ + Max = 100 +}; + +Point +string(Image *dst, Point pt, Image *src, Point sp, Font *f, char *s) +{ + return _string(dst, pt, src, sp, f, s, nil, 1<<24, dst->clipr, nil, ZP, SoverD); +} + +Point +stringop(Image *dst, Point pt, Image *src, Point sp, Font *f, char *s, Drawop op) +{ + return _string(dst, pt, src, sp, f, s, nil, 1<<24, dst->clipr, nil, ZP, op); +} + +Point +stringn(Image *dst, Point pt, Image *src, Point sp, Font *f, char *s, int len) +{ + return _string(dst, pt, src, sp, f, s, nil, len, dst->clipr, nil, ZP, SoverD); +} + +Point +stringnop(Image *dst, Point pt, Image *src, Point sp, Font *f, char *s, int len, Drawop op) +{ + return _string(dst, pt, src, sp, f, s, nil, len, dst->clipr, nil, ZP, op); +} + +Point +runestring(Image *dst, Point pt, Image *src, Point sp, Font *f, Rune *r) +{ + return _string(dst, pt, src, sp, f, nil, r, 1<<24, dst->clipr, nil, ZP, SoverD); +} + +Point +runestringop(Image *dst, Point pt, Image *src, Point sp, Font *f, Rune *r, Drawop op) +{ + return _string(dst, pt, src, sp, f, nil, r, 1<<24, dst->clipr, nil, ZP, op); +} + +Point +runestringn(Image *dst, Point pt, Image *src, Point sp, Font *f, Rune *r, int len) +{ + return _string(dst, pt, src, sp, f, nil, r, len, dst->clipr, nil, ZP, SoverD); +} + +Point +runestringnop(Image *dst, Point pt, Image *src, Point sp, Font *f, Rune *r, int len, Drawop op) +{ + return _string(dst, pt, src, sp, f, nil, r, len, dst->clipr, nil, ZP, op); +} + +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; + ushort cbuf[Max], *c, *ec; + uchar *b; + char *subfontname; + char **sptr; + Rune **rptr; + Font *def; + Subfont *sf; + + if(s == nil){ + s = ""; + sptr = nil; + }else + sptr = &s; + if(r == nil){ + r = (Rune*) L""; + rptr = nil; + }else + rptr = &r; + sf = nil; + while((*s || *r) && len){ + 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(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){ + freesubfont(sf); + if((sf=_getsubfont(f->display, subfontname)) == 0){ + def = f->display ? f->display->defaultfont : nil; + if(def && f!=def) + f = def; + else + break; + } + /* + * must not free sf until cachechars has found it in the cache + * and picked up its own reference. + */ + } + } + return pt; +} diff --git a/sys/src/libdraw/stringbg.c b/sys/src/libdraw/stringbg.c new file mode 100755 index 000000000..e4e26a2e2 --- /dev/null +++ b/sys/src/libdraw/stringbg.c @@ -0,0 +1,51 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +Point +stringbg(Image *dst, Point pt, Image *src, Point sp, Font *f, char *s, Image *bg, Point bgp) +{ + return _string(dst, pt, src, sp, f, s, nil, 1<<24, dst->clipr, bg, bgp, SoverD); +} + +Point +stringbgop(Image *dst, Point pt, Image *src, Point sp, Font *f, char *s, Image *bg, Point bgp, int op) +{ + return _string(dst, pt, src, sp, f, s, nil, 1<<24, dst->clipr, bg, bgp, op); +} + +Point +stringnbg(Image *dst, Point pt, Image *src, Point sp, Font *f, char *s, int len, Image *bg, Point bgp) +{ + return _string(dst, pt, src, sp, f, s, nil, len, dst->clipr, bg, bgp, SoverD); +} + +Point +stringnbgop(Image *dst, Point pt, Image *src, Point sp, Font *f, char *s, int len, Image *bg, Point bgp, int op) +{ + return _string(dst, pt, src, sp, f, s, nil, len, dst->clipr, bg, bgp, op); +} + +Point +runestringbg(Image *dst, Point pt, Image *src, Point sp, Font *f, Rune *r, Image *bg, Point bgp) +{ + return _string(dst, pt, src, sp, f, nil, r, 1<<24, dst->clipr, bg, bgp, SoverD); +} + +Point +runestringbgop(Image *dst, Point pt, Image *src, Point sp, Font *f, Rune *r, Image *bg, Point bgp, int op) +{ + return _string(dst, pt, src, sp, f, nil, r, 1<<24, dst->clipr, bg, bgp, op); +} + +Point +runestringnbg(Image *dst, Point pt, Image *src, Point sp, Font *f, Rune *r, int len, Image *bg, Point bgp) +{ + return _string(dst, pt, src, sp, f, nil, r, len, dst->clipr, bg, bgp, SoverD); +} + +Point +runestringnbgop(Image *dst, Point pt, Image *src, Point sp, Font *f, Rune *r, int len, Image *bg, Point bgp, int op) +{ + return _string(dst, pt, src, sp, f, nil, r, len, dst->clipr, bg, bgp, op); +} diff --git a/sys/src/libdraw/stringsubfont.c b/sys/src/libdraw/stringsubfont.c new file mode 100755 index 000000000..cc8347329 --- /dev/null +++ b/sys/src/libdraw/stringsubfont.c @@ -0,0 +1,65 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +Point +stringsubfont(Image *b, Point p, Image *color, Subfont *f, char *cs) +{ + int w, width; + uchar *s; + Rune c; + Fontchar *i; + + s = (uchar*)cs; + for(; c=*s; p.x+=width){ + width = 0; + if(c < Runeself) + s++; + else{ + w = chartorune(&c, (char*)s); + if(w == 0){ + s++; + continue; + } + s += w; + } + if(c >= f->n) + continue; + i = f->info+c; + width = i->width; + draw(b, Rect(p.x+i->left, p.y+i->top, p.x+i->left+(i[1].x-i[0].x), p.y+i->bottom), + color, f->bits, Pt(i->x, i->top)); + } + return p; +} + +Point +strsubfontwidth(Subfont *f, char *cs) +{ + Rune c; + Point p; + uchar *s; + Fontchar *i; + int w, width; + + p = Pt(0, f->height); + s = (uchar*)cs; + for(; c=*s; p.x+=width){ + width = 0; + if(c < Runeself) + s++; + else{ + w = chartorune(&c, (char*)s); + if(w == 0){ + s++; + continue; + } + s += w; + } + if(c >= f->n) + continue; + i = f->info+c; + width = i->width; + } + return p; +} diff --git a/sys/src/libdraw/stringwidth.c b/sys/src/libdraw/stringwidth.c new file mode 100755 index 000000000..eb2bb42e7 --- /dev/null +++ b/sys/src/libdraw/stringwidth.c @@ -0,0 +1,96 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +int +_stringnwidth(Font *f, char *s, Rune *r, int len) +{ + int wid, twid, n, max, l; + char *name; + enum { Max = 64 }; + ushort cbuf[Max]; + Rune rune, **rptr; + char *subfontname, **sptr; + Font *def; + + if(s == nil){ + s = ""; + sptr = nil; + }else + sptr = &s; + if(r == nil){ + r = L""; + rptr = nil; + }else + rptr = &r; + twid = 0; + while(len>0 && (*s || *r)){ + 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(subfontname){ + if(_getsubfont(f->display, subfontname) == 0){ + def = f->display->defaultfont; + if(def && f!=def) + f = def; + else + break; + } + } + } + agefont(f); + twid += wid; + len -= l; + } + return twid; +} + +int +stringnwidth(Font *f, char *s, int len) +{ + return _stringnwidth(f, s, nil, len); +} + +int +stringwidth(Font *f, char *s) +{ + return _stringnwidth(f, s, nil, 1<<24); +} + +Point +stringsize(Font *f, char *s) +{ + return Pt(_stringnwidth(f, s, nil, 1<<24), f->height); +} + +int +runestringnwidth(Font *f, Rune *r, int len) +{ + return _stringnwidth(f, nil, r, len); +} + +int +runestringwidth(Font *f, Rune *r) +{ + return _stringnwidth(f, nil, r, 1<<24); +} + +Point +runestringsize(Font *f, Rune *r) +{ + return Pt(_stringnwidth(f, nil, r, 1<<24), f->height); +} diff --git a/sys/src/libdraw/subfont.c b/sys/src/libdraw/subfont.c new file mode 100755 index 000000000..61838b054 --- /dev/null +++ b/sys/src/libdraw/subfont.c @@ -0,0 +1,28 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +Subfont* +allocsubfont(char *name, int n, int height, int ascent, Fontchar *info, Image *i) +{ + Subfont *f; + + assert(height != 0 /* allocsubfont */); + + f = malloc(sizeof(Subfont)); + if(f == 0) + return 0; + f->n = n; + f->height = height; + f->ascent = ascent; + f->info = info; + f->bits = i; + f->ref = 1; + if(name){ + f->name = strdup(name); + if(lookupsubfont(i->display, name) == 0) + installsubfont(name, f); + }else + f->name = 0; + return f; +} diff --git a/sys/src/libdraw/subfontcache.c b/sys/src/libdraw/subfontcache.c new file mode 100755 index 000000000..2a7f489b4 --- /dev/null +++ b/sys/src/libdraw/subfontcache.c @@ -0,0 +1,40 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +/* + * Easy versions of the cache routines; may be substituted by fancier ones for other purposes + */ + +static char *lastname; +Subfont *lastsubfont; + +Subfont* +lookupsubfont(Display *d, char *name) +{ + if(d && strcmp(name, "*default*") == 0) + return d->defaultsubfont; + if(lastname && strcmp(name, lastname)==0) + if(d==lastsubfont->bits->display){ + lastsubfont->ref++; + return lastsubfont; + } + return 0; +} + +void +installsubfont(char *name, Subfont *subfont) +{ + free(lastname); + lastname = strdup(name); + lastsubfont = subfont; /* notice we don't free the old one; that's your business */ +} + +void +uninstallsubfont(Subfont *subfont) +{ + if(subfont == lastsubfont){ + lastname = 0; + lastsubfont = 0; + } +} diff --git a/sys/src/libdraw/subfontname.c b/sys/src/libdraw/subfontname.c new file mode 100755 index 000000000..8ab79408c --- /dev/null +++ b/sys/src/libdraw/subfontname.c @@ -0,0 +1,52 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +/* + * Default version: convert to file name + */ + +char* +subfontname(char *cfname, char *fname, int maxdepth) +{ + char *t, *u, *tmp1, *tmp2; + int i; + + t = strdup(cfname); /* t is the return string */ + if(strcmp(cfname, "*default*") == 0) + return t; + if(t[0] != '/'){ + tmp2 = strdup(fname); + u = utfrrune(tmp2, '/'); + if(u) + u[0] = 0; + else + strcpy(tmp2, "."); + tmp1 = smprint("%s/%s", tmp2, t); + free(tmp2); + free(t); + t = tmp1; + } + + if(maxdepth > 8) + maxdepth = 8; + + for(i=3; i>=0; i--){ + if((1<<i) > maxdepth) + continue; + /* try i-bit grey */ + tmp2 = smprint("%s.%d", t, i); + if(access(tmp2, AREAD) == 0) { + free(t); + return tmp2; + } + free(tmp2); + } + + /* try default */ + if(access(t, AREAD) == 0) + return t; + + free(t); + return nil; +} diff --git a/sys/src/libdraw/test.c b/sys/src/libdraw/test.c new file mode 100755 index 000000000..962764509 --- /dev/null +++ b/sys/src/libdraw/test.c @@ -0,0 +1,10 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + + +void +main(int argc, char **argv) +{ + print("%dn", wordsperline(Rect(atoi(argv[1]), atoi(argv[2]), atoi(argv[3]), atoi(argv[4])), atoi(argv[5]))); +} diff --git a/sys/src/libdraw/unloadimage.c b/sys/src/libdraw/unloadimage.c new file mode 100755 index 000000000..ead36b0c8 --- /dev/null +++ b/sys/src/libdraw/unloadimage.c @@ -0,0 +1,53 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +int +unloadimage(Image *i, Rectangle r, uchar *data, int ndata) +{ + int bpl, n, ntot, dy; + uchar *a; + Display *d; + + if(!rectinrect(r, i->r)){ + werrstr("unloadimage: bad rectangle"); + return -1; + } + bpl = bytesperline(r, i->depth); + if(ndata < bpl*Dy(r)){ + werrstr("unloadimage: buffer too small"); + return -1; + } + + d = i->display; + flushimage(d, 0); /* make sure subsequent flush is for us only */ + ntot = 0; + while(r.min.y < r.max.y){ + a = bufimage(d, 1+4+4*4); + if(a == 0){ + werrstr("unloadimage: %r"); + return -1; + } + dy = 8000/bpl; + if(dy <= 0){ + werrstr("unloadimage: image too wide"); + return -1; + } + if(dy > Dy(r)) + dy = Dy(r); + a[0] = 'r'; + BPLONG(a+1, i->id); + BPLONG(a+5, r.min.x); + BPLONG(a+9, r.min.y); + BPLONG(a+13, r.max.x); + BPLONG(a+17, r.min.y+dy); + if(flushimage(d, 0) < 0) + return -1; + n = read(d->fd, data+ntot, ndata-ntot); + if(n < 0) + return n; + ntot += n; + r.min.y += dy; + } + return ntot; +} diff --git a/sys/src/libdraw/window.c b/sys/src/libdraw/window.c new file mode 100755 index 000000000..4c734208b --- /dev/null +++ b/sys/src/libdraw/window.c @@ -0,0 +1,214 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +typedef struct Memimage Memimage; + +static int screenid; + +Screen* +allocscreen(Image *image, Image *fill, int public) +{ + uchar *a; + Screen *s; + int id, try; + Display *d; + + d = image->display; + if(d != fill->display){ + werrstr("allocscreen: image and fill on different displays"); + return 0; + } + s = malloc(sizeof(Screen)); + if(s == 0) + return 0; + SET(id); + for(try=0; try<25; try++){ + /* loop until find a free id */ + a = bufimage(d, 1+4+4+4+1); + if(a == 0){ + free(s); + return 0; + } + id = ++screenid; + a[0] = 'A'; + BPLONG(a+1, id); + BPLONG(a+5, image->id); + BPLONG(a+9, fill->id); + a[13] = public; + if(flushimage(d, 0) != -1) + break; + } + s->display = d; + s->id = id; + s->image = image; + assert(s->image && s->image->chan != 0); + + s->fill = fill; + return s; +} + +Screen* +publicscreen(Display *d, int id, ulong chan) +{ + uchar *a; + Screen *s; + + s = malloc(sizeof(Screen)); + if(s == 0) + return 0; + a = bufimage(d, 1+4+4); + if(a == 0){ + Error: + free(s); + return 0; + } + a[0] = 'S'; + BPLONG(a+1, id); + BPLONG(a+5, chan); + if(flushimage(d, 0) < 0) + goto Error; + + s->display = d; + s->id = id; + s->image = 0; + s->fill = 0; + return s; +} + +int +freescreen(Screen *s) +{ + uchar *a; + Display *d; + + if(s == 0) + return 0; + d = s->display; + a = bufimage(d, 1+4); + if(a == 0) + return -1; + a[0] = 'F'; + BPLONG(a+1, s->id); + /* + * flush(1) because screen is likely holding last reference to + * window, and want it to disappear visually. + */ + if(flushimage(d, 1) < 0) + return -1; + free(s); + return 1; +} + +Image* +allocwindow(Screen *s, Rectangle r, int ref, ulong val) +{ + return _allocwindow(nil, s, r, ref, val); +} + +Image* +_allocwindow(Image *i, Screen *s, Rectangle r, int ref, ulong val) +{ + Display *d; + + d = s->display; + i = _allocimage(i, d, r, d->screenimage->chan, 0, val, s->id, ref); + if(i == 0) + return 0; + i->screen = s; + i->next = s->display->windows; + s->display->windows = i; + return i; +} + +static +void +topbottom(Image **w, int n, int top) +{ + int i; + uchar *b; + Display *d; + + if(n < 0){ + Ridiculous: + fprint(2, "top/bottom: ridiculous number of windows\n"); + return; + } + if(n == 0) + return; + if(n > (w[0]->display->bufsize-100)/4) + goto Ridiculous; + /* + * this used to check that all images were on the same screen. + * we don't know the screen associated with images we acquired + * by name. instead, check that all images are on the same display. + * the display will check that they are all on the same screen. + */ + d = w[0]->display; + for(i=1; i<n; i++) + if(w[i]->display != d){ + fprint(2, "top/bottom: windows not on same screen\n"); + return; + } + + if(n==0) + return; + b = bufimage(d, 1+1+2+4*n); + b[0] = 't'; + b[1] = top; + BPSHORT(b+2, n); + for(i=0; i<n; i++) + BPLONG(b+4+4*i, w[i]->id); +} + +void +bottomwindow(Image *w) +{ + if(w->screen == 0) + return; + topbottom(&w, 1, 0); +} + +void +topwindow(Image *w) +{ + if(w->screen == 0) + return; + topbottom(&w, 1, 1); +} + +void +bottomnwindows(Image **w, int n) +{ + topbottom(w, n, 0); +} + +void +topnwindows(Image **w, int n) +{ + topbottom(w, n, 1); +} + +int +originwindow(Image *w, Point log, Point scr) +{ + uchar *b; + Point delta; + + flushimage(w->display, 0); + b = bufimage(w->display, 1+4+2*4+2*4); + if(b == nil) + return 0; + b[0] = 'o'; + BPLONG(b+1, w->id); + BPLONG(b+5, log.x); + BPLONG(b+9, log.y); + BPLONG(b+13, scr.x); + BPLONG(b+17, scr.y); + if(flushimage(w->display, 1) < 0) + return -1; + delta = subpt(log, w->r.min); + w->r = rectaddpt(w->r, delta); + w->clipr = rectaddpt(w->clipr, delta); + return 1; +} diff --git a/sys/src/libdraw/writecolmap.c b/sys/src/libdraw/writecolmap.c new file mode 100755 index 000000000..26c1f7f1f --- /dev/null +++ b/sys/src/libdraw/writecolmap.c @@ -0,0 +1,37 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +/* + * This code (and the devdraw interface) will have to change + * if we ever get bitmaps with ldepth > 3, because the + * colormap will have to be written in chunks + */ + +void +writecolmap(Display *d, RGB *m) +{ + int i, n, fd; + char buf[64], *t; + ulong r, g, b; + + sprint(buf, "/dev/draw/%d/colormap", d->dirno); + fd = open(buf, OWRITE); + if(fd < 0) + drawerror(d, "writecolmap: open colormap failed"); + t = malloc(8192); + if (t == nil) + drawerror(d, "writecolmap: no memory"); + n = 0; + for(i = 0; i < 256; i++) { + r = m[i].red>>24; + g = m[i].green>>24; + b = m[i].blue>>24; + n += sprint(t+n, "%d %lud %lud %lud\n", 255-i, r, g, b); + } + i = write(fd, t, n); + free(t); + close(fd); + if(i != n) + drawerror(d, "writecolmap: bad write"); +} diff --git a/sys/src/libdraw/writeimage.c b/sys/src/libdraw/writeimage.c new file mode 100755 index 000000000..b4dcff061 --- /dev/null +++ b/sys/src/libdraw/writeimage.c @@ -0,0 +1,185 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +#define HSHIFT 3 /* HSHIFT==5 runs slightly faster, but hash table is 64x bigger */ +#define NHASH (1<<(HSHIFT*NMATCH)) +#define HMASK (NHASH-1) +#define hupdate(h, c) ((((h)<<HSHIFT)^(c))&HMASK) +typedef struct Hlist Hlist; +struct Hlist{ + uchar *s; + Hlist *next, *prev; +}; + +int +writeimage(int fd, Image *i, int dolock) +{ + uchar *outbuf, *outp, *eout; /* encoded data, pointer, end */ + uchar *loutp; /* start of encoded line */ + Hlist *hash; /* heads of hash chains of past strings */ + Hlist *chain, *hp; /* hash chain members, pointer */ + Hlist *cp; /* next Hlist to fall out of window */ + int h; /* hash value */ + uchar *line, *eline; /* input line, end pointer */ + uchar *data, *edata; /* input buffer, end pointer */ + ulong n; /* length of input buffer */ + ulong nb; /* # of bytes returned by unloadimage */ + int bpl; /* input line length */ + int offs, runlen; /* offset, length of consumed data */ + uchar dumpbuf[NDUMP]; /* dump accumulator */ + int ndump; /* length of dump accumulator */ + int miny, dy; /* y values while unloading input */ + int chunk, ncblock; + Rectangle r; + uchar *p, *q, *s, *es, *t; + char hdr[11+5*12+1]; + char cbuf[20]; + + chunk = i->display->bufsize - 32; /* a little room for header */ + r = i->r; + bpl = bytesperline(r, i->depth); + n = Dy(r)*bpl; + data = malloc(n); + ncblock = _compblocksize(r, i->depth); + outbuf = malloc(ncblock); + hash = malloc(NHASH*sizeof(Hlist)); + chain = malloc(NMEM*sizeof(Hlist)); + if(data == 0 || outbuf == 0 || hash == 0 || chain == 0){ + ErrOut: + free(data); + free(outbuf); + free(hash); + free(chain); + return -1; + } + for(miny = r.min.y; miny != r.max.y; miny += dy){ + dy = r.max.y-miny; + if(dy*bpl > chunk) + dy = chunk/bpl; + if(dolock) + lockdisplay(i->display); + nb = unloadimage(i, Rect(r.min.x, miny, r.max.x, miny+dy), + data+(miny-r.min.y)*bpl, dy*bpl); + if(dolock) + unlockdisplay(i->display); + if(nb != dy*bpl) + goto ErrOut; + } + sprint(hdr, "compressed\n%11s %11d %11d %11d %11d ", + chantostr(cbuf, i->chan), r.min.x, r.min.y, r.max.x, r.max.y); + if(write(fd, hdr, 11+5*12) != 11+5*12) + goto ErrOut; + edata = data+n; + eout = outbuf+ncblock; + line = data; + r.max.y = r.min.y; + while(line != edata){ + memset(hash, 0, NHASH*sizeof(Hlist)); + memset(chain, 0, NMEM*sizeof(Hlist)); + cp = chain; + h = 0; + outp = outbuf; + for(n = 0; n != NMATCH; n++) + h = hupdate(h, line[n]); + loutp = outbuf; + while(line != edata){ + ndump = 0; + eline = line+bpl; + for(p = line; p != eline; ){ + if(eline-p < NRUN) + es = eline; + else + es = p+NRUN; + q = 0; + runlen = 0; + for(hp = hash[h].next; hp; hp = hp->next){ + s = p + runlen; + if(s >= es) + continue; + t = hp->s + runlen; + for(; s >= p; s--) + if(*s != *t--) + goto matchloop; + t += runlen+2; + s += runlen+2; + for(; s < es; s++) + if(*s != *t++) + break; + n = s-p; + if(n > runlen){ + runlen = n; + q = hp->s; + if(n == NRUN) + break; + } + matchloop: ; + } + if(runlen < NMATCH){ + if(ndump == NDUMP){ + if(eout-outp < ndump+1) + goto Bfull; + *outp++ = ndump-1+128; + memmove(outp, dumpbuf, ndump); + outp += ndump; + ndump = 0; + } + dumpbuf[ndump++] = *p; + runlen = 1; + } + else{ + if(ndump != 0){ + if(eout-outp < ndump+1) + goto Bfull; + *outp++ = ndump-1+128; + memmove(outp, dumpbuf, ndump); + outp += ndump; + ndump = 0; + } + offs = p-q-1; + if(eout-outp < 2) + goto Bfull; + *outp++ = ((runlen-NMATCH)<<2) + (offs>>8); + *outp++ = offs&255; + } + for(q = p+runlen; p != q; p++){ + if(cp->prev) + cp->prev->next = 0; + cp->next = hash[h].next; + cp->prev = &hash[h]; + if(cp->next) + cp->next->prev = cp; + cp->prev->next = cp; + cp->s = p; + if(++cp == &chain[NMEM]) + cp = chain; + if(edata-p > NMATCH) + h = hupdate(h, p[NMATCH]); + } + } + if(ndump != 0){ + if(eout-outp < ndump+1) + goto Bfull; + *outp++ = ndump-1+128; + memmove(outp, dumpbuf, ndump); + outp += ndump; + } + line = eline; + loutp = outp; + r.max.y++; + } + Bfull: + if(loutp == outbuf) + goto ErrOut; + n = loutp-outbuf; + sprint(hdr, "%11d %11ld ", r.max.y, n); + write(fd, hdr, 2*12); + write(fd, outbuf, n); + r.min.y = r.max.y; + } + free(data); + free(outbuf); + free(hash); + free(chain); + return 0; +} diff --git a/sys/src/libdraw/writesubfont.c b/sys/src/libdraw/writesubfont.c new file mode 100755 index 000000000..1ea985f00 --- /dev/null +++ b/sys/src/libdraw/writesubfont.c @@ -0,0 +1,45 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +static +void +packinfo(Fontchar *fc, uchar *p, int n) +{ + int j; + + for(j=0; j<=n; j++){ + p[0] = fc->x; + p[1] = fc->x>>8; + p[2] = fc->top; + p[3] = fc->bottom; + p[4] = fc->left; + p[5] = fc->width; + fc++; + p += 6; + } +} + +int +writesubfont(int fd, Subfont *f) +{ + char hdr[3*12+1]; + uchar *data; + int nb; + + sprint(hdr, "%11d %11d %11d ", f->n, f->height, f->ascent); + if(write(fd, hdr, 3*12) != 3*12){ + Err: + werrstr("writesubfont: bad write: %r"); + return -1; + } + nb = 6*(f->n+1); + data = malloc(nb); + if(data == nil) + return -1; + packinfo(f->info, data, f->n); + if(write(fd, data, nb) != nb) + goto Err; + free(data); + return 0; +} |