plan 9 kernel history: overview | file list | diff list

1992/0706/port/devbit.c (diff list | history)

port/devbit.c on 1990/0324
1990/0324    
#include	"u.h" 
1992/0321    
#include	"../port/lib.h" 
1990/0324    
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
1992/0111    
#include	"../port/error.h" 
1990/0324    
 
#include	"devtab.h" 
 
1992/0211    
#include	<libg.h> 
1990/0902    
#include	<gnot.h> 
1991/0708    
#include	"screen.h" 
1990/0324    
 
1992/0208    
extern GSubfont	*defont; 
1990/0329    
 
1990/0327    
/* 
1991/0706    
 * Some monochrome screens are reversed from what we like: 
1992/0209    
 * We want 0's bright and 1's dark. 
1991/0706    
 * Indexed by an Fcode, these compensate for the source bitmap being wrong 
 * (exchange S rows) and destination (exchange D columns and invert result) 
 */ 
int flipS[] = { 
	0x0, 0x4, 0x8, 0xC, 0x1, 0x5, 0x9, 0xD, 
	0x2, 0x6, 0xA, 0xE, 0x3, 0x7, 0xB, 0xF 
}; 
 
int flipD[] = { 
	0xF, 0xD, 0xE, 0xC, 0x7, 0x5, 0x6, 0x4, 
	0xB, 0x9, 0xA, 0x8, 0x3, 0x1, 0x2, 0x0,  
}; 
 
int flipping;	/* are flip tables being used to transform Fcodes? */ 
 
/* 
1990/0329    
 * Device (#b/bitblt) is exclusive use on open, so no locks are necessary 
 * for i/o 
 */ 
 
/* 
1992/0622    
 * Arena is a word containing N, followed by a pointer to the Arena, 
 * followed by a pointer to the Bitmap, followed by N words. 
 * The bitmap pointer is zero if block is free. 
1992/0621    
 * bit.map is an array of pointers to GBitmaps.  The GBitmaps are 
 * freed individually and their corresponding entries in bit.map are zeroed. 
 * The index into bit.map is the Bitmap id as seen in libg.  Subfonts and 
 * fonts are handled similarly. 
1990/0327    
 */ 
1990/0324    
 
1992/0622    
typedef struct	Arena	Arena; 
struct Arena 
{ 
	ulong	*words;		/* storage */ 
	ulong	*wfree;		/* pointer to next free word */ 
	ulong	nwords;		/* total in arena */ 
	int	nbusy;		/* number of busy blocks */ 
}; 
 
1992/06271    
typedef struct	BSubfont BSubfont; 
struct BSubfont 
{ 
	GSubfont; 
	int	ref;		/* number of times this subfont is open */ 
	ulong	qid[2];		/* unique id used as a cache tag */ 
}; 
 
1990/05313    
struct 
{ 
1990/0324    
	Ref; 
1992/0622    
	QLock; 
1992/0621    
	GBitmap	**map;		/* indexed array */ 
	int	nmap;		/* number allocated */ 
	GFont	**font;		/* indexed array */ 
	int	nfont;		/* number allocated */ 
1992/06271    
	BSubfont**subfont;	/* indexed array */ 
1992/0621    
	int	nsubfont;	/* number allocated */ 
1992/0622    
	Arena	*arena;		/* array */ 
	int	narena;		/* number allocated */ 
1992/0630    
	int	bid;		/* last allocated bitmap id */ 
	int	subfid;		/* last allocated subfont id */ 
	int	cacheid;	/* last cached subfont id */ 
	int	fid;		/* last allocated font id */ 
1990/0329    
	int	init;		/* freshly opened; init message pending */ 
1990/0613    
	int	rid;		/* read bitmap id */ 
	int	rminy;		/* read miny */ 
	int	rmaxy;		/* read maxy */ 
1991/0706    
	int	mid;		/* colormap read bitmap id */ 
1990/0324    
}bit; 
 
1992/0622    
#define	DMAP	16		/* delta increase in size of arrays */ 
1990/0327    
#define	FREE	0x80000000 
1992/0622    
 
1990/0327    
void	bitcompact(void); 
1992/0621    
int	bitalloc(Rectangle, int); 
1990/0902    
void	bitfree(GBitmap*); 
1992/0621    
void	fontfree(GFont*); 
1992/0702    
void	subfontfree(BSubfont*, int); 
1992/0622    
void	arenafree(Arena*); 
1992/0209    
void	bitstring(GBitmap*, Point, GFont*, uchar*, long, Fcode); 
void	bitloadchar(GFont*, int, GSubfont*, int); 
1990/0912    
extern	GBitmap	gscreen; 
1990/0327    
 
1991/0707    
Mouseinfo	mouse; 
Cursorinfo	cursor; 
1990/0504    
 
1990/05313    
Cursor	arrow = 
{ 
1990/0730    
	{-1, -1}, 
1990/05313    
	{0xFF, 0xE0, 0xFF, 0xE0, 0xFF, 0xC0, 0xFF, 0x00, 
	 0xFF, 0x00, 0xFF, 0x80, 0xFF, 0xC0, 0xFF, 0xE0, 
	 0xE7, 0xF0, 0xE3, 0xF8, 0xC1, 0xFC, 0x00, 0xFE, 
	 0x00, 0x7F, 0x00, 0x3E, 0x00, 0x1C, 0x00, 0x08, 
	}, 
	{0x00, 0x00, 0x7F, 0xC0, 0x7F, 0x00, 0x7C, 0x00, 
	 0x7E, 0x00, 0x7F, 0x00, 0x6F, 0x80, 0x67, 0xC0, 
	 0x43, 0xE0, 0x41, 0xF0, 0x00, 0xF8, 0x00, 0x7C, 
	 0x00, 0x3E, 0x00, 0x1C, 0x00, 0x08, 0x00, 0x00, 
	} 
}; 
 
1990/0504    
ulong setbits[16]; 
1990/0902    
GBitmap	set = 
1990/0504    
{ 
	setbits, 
	0, 
	1, 
	0, 
1992/0604    
	{0, 0, 16, 16}, 
1990/0504    
	{0, 0, 16, 16} 
}; 
 
ulong clrbits[16]; 
1990/0902    
GBitmap	clr = 
1990/0504    
{ 
	clrbits, 
	0, 
	1, 
	0, 
1992/0604    
	{0, 0, 16, 16}, 
1990/0504    
	{0, 0, 16, 16} 
}; 
 
1991/0706    
ulong cursorbackbits[16*4]; 
1990/0902    
GBitmap cursorback = 
1990/0504    
{ 
	cursorbackbits, 
	0, 
	1, 
	0, 
1992/0604    
	{0, 0, 16, 16}, 
1990/0504    
	{0, 0, 16, 16} 
}; 
 
1990/05313    
void	Cursortocursor(Cursor*); 
1990/0504    
void	cursoron(int); 
void	cursoroff(int); 
1990/0505    
int	mousechanged(void*); 
1990/0504    
 
1990/0324    
enum{ 
	Qdir, 
	Qbitblt, 
1990/0329    
	Qmouse, 
1990/0709    
	Qscreen, 
1990/0324    
}; 
 
Dirtab bitdir[]={ 
1991/1112    
	"bitblt",	{Qbitblt},	0,			0666, 
	"mouse",	{Qmouse},	0,			0666, 
	"screen",	{Qscreen},	0,			0444, 
1990/0324    
}; 
 
#define	NBIT	(sizeof bitdir/sizeof(Dirtab)) 
1992/06271    
#define	NINFO	8192	/* max chars per subfont; sanity check only */ 
1992/0622    
#define	HDR	3 
1990/0324    
 
void 
1992/0706    
bitfreeup(void) 
{ 
	int i; 
	BSubfont *s; 
 
	/* free unused subfonts and compact */ 
	for(i=0; i<bit.nsubfont; i++){ 
		s = bit.subfont[i]; 
		if(s && s!=defont && s->ref==0){ 
			s->ref = 1; 
			s->qid[0] = ~0;	/* force cleanup */ 
			subfontfree(s, i); 
		} 
	} 
	bitcompact(); 
} 
 
void* 
bitmalloc(ulong n) 
{ 
	void *p; 
 
	p = malloc(n); 
	if(p) 
		return p; 
	bitfreeup(); 
	return malloc(n); 
} 
 
void 
1992/0704    
bitdebug(void) 
{ 
	int i; 
	long l; 
	Arena *a; 
 
	l = 0; 
	for(i=0; i<bit.narena; i++){ 
		a = &bit.arena[i]; 
		if(a->words){ 
			l += a->nwords; 
			print("%d: %ld used; %ld total\n", i, 
				(a->wfree-a->words)*sizeof(ulong), 
				a->nwords*sizeof(ulong)); 
		} 
	} 
	print("arena: %ld words\n", l*sizeof(ulong)); 
	l = 0; 
	for(i=0; i<bit.nmap; i++) 
		if(bit.map[i]) 
			l++; 
	print("%d bitmaps ", l); 
	l = 0; 
	for(i=0; i<bit.nfont; i++) 
		if(bit.font[i]) 
			l++; 
	print("%d fonts ", l); 
	l = 0; 
	for(i=0; i<bit.nsubfont; i++) 
		if(bit.subfont[i]){ 
			print("%d: %lux %lux ", i, bit.subfont[i]->qid[0], bit.subfont[i]->qid[1]); 
			l++; 
		} 
	print("%d subfonts\n", l); 
} 
 
void 
1990/0324    
bitreset(void) 
{ 
1992/0706    
	int i, ws; 
1990/0902    
	GBitmap *bp; 
1991/0706    
	ulong r; 
1992/0622    
	Arena *a; 
1990/0327    
 
1992/0621    
	bit.map = smalloc(DMAP*sizeof(GBitmap*)); 
	bit.nmap = DMAP; 
1991/0706    
	getcolor(0, &r, &r, &r); 
	if(r == 0) 
		flipping = 1; 
1992/0630    
	bit.bid = -1; 
	bit.subfid = -1; 
	bit.fid = -1; 
	bit.cacheid = -1; 
1992/0621    
	bit.font = smalloc(DMAP*sizeof(GFont*)); 
	bit.nfont = DMAP; 
1992/06271    
	bit.subfont = smalloc(DMAP*sizeof(BSubfont*)); 
1992/0621    
	bit.nsubfont = DMAP; 
1992/0622    
	bit.arena = smalloc(DMAP*sizeof(Arena)); 
	bit.narena = DMAP; 
	a = &bit.arena[0]; 
	/* 
	 * Somewhat of a heuristic: start with three screensful and 
	 * allocate single screensful dynamically if needed. 
	 */ 
1992/0706    
	ws = BI2WD>>gscreen.ldepth;	/* pixels per word */ 
	a->nwords = 3*(HDR + gscreen.r.max.y*gscreen.r.max.x/ws); 
1992/0622    
	a->words = xalloc(a->nwords*sizeof(ulong)); 
1992/0706    
	if(a->words == 0){ 
		/* try again */ 
		print("bitreset: allocating only 1 screenful\n"); 
		a->nwords /= 3; 
		a->words = a->words = xalloc(a->nwords*sizeof(ulong)); 
		if(a->words == 0) 
			panic("bitreset"); 
	} 
1992/0622    
	a->wfree = a->words; 
	a->nbusy = 1;	/* keep 0th arena from being freed */ 
1990/05313    
	Cursortocursor(&arrow); 
1990/0324    
} 
 
void 
bitinit(void) 
{ 
1991/0706    
	if(gscreen.ldepth > 3) 
		cursorback.ldepth = 0; 
1992/0621    
	else{ 
1991/0706    
		cursorback.ldepth = gscreen.ldepth; 
		cursorback.width = ((16 << gscreen.ldepth) + 31) >> 5; 
	} 
1990/0504    
	cursoron(1); 
1990/0324    
} 
 
Chan* 
bitattach(char *spec) 
{ 
	return devattach('b', spec); 
} 
 
Chan* 
bitclone(Chan *c, Chan *nc) 
{ 
	nc = devclone(c, nc); 
1990/11211    
	if(c->qid.path != CHDIR) 
1990/0324    
		incref(&bit); 
1991/0706    
	return nc; 
1990/0324    
} 
 
int 
bitwalk(Chan *c, char *name) 
{ 
	return devwalk(c, name, bitdir, NBIT, devgen); 
} 
 
void 
bitstat(Chan *c, char *db) 
{ 
	devstat(c, db, bitdir, NBIT, devgen); 
} 
 
1992/0621    
Chan* 
1990/0324    
bitopen(Chan *c, int omode) 
{ 
1992/0621    
	GBitmap *b; 
 
1990/11211    
	if(c->qid.path == CHDIR){ 
1990/0324    
		if(omode != OREAD) 
1990/11211    
			error(Eperm); 
	}else if(c->qid.path == Qbitblt){ 
1990/0324    
		lock(&bit); 
1990/0515    
		if(bit.ref){ 
1990/0324    
			unlock(&bit); 
1990/11211    
			error(Einuse); 
1990/0324    
		} 
1992/0621    
		b = smalloc(sizeof(GBitmap)); 
		*b = gscreen; 
		bit.map[0] = b;			/* bitmap 0 is screen */ 
1992/06271    
		bit.subfont[0] = (BSubfont*)defont;	/* subfont 0 is default */ 
		bit.subfont[0]->ref = 1; 
		bit.subfont[0]->qid[0] = 0; 
		bit.subfont[0]->qid[1] = 0; 
1992/0630    
		bit.bid = -1; 
		bit.fid = -1; 
		bit.subfid = -1; 
		bit.cacheid = -1; 
1990/0613    
		bit.rid = -1; 
1991/0706    
		bit.mid = -1; 
1990/0604    
		bit.init = 0; 
1990/05151    
		bit.ref = 1; 
1990/05313    
		Cursortocursor(&arrow); 
1990/0324    
		unlock(&bit); 
1990/05151    
	}else 
1990/0324    
		incref(&bit); 
	c->mode = openmode(omode); 
	c->flag |= COPEN; 
	c->offset = 0; 
	return c; 
} 
 
void 
bitcreate(Chan *c, char *name, int omode, ulong perm) 
{ 
1991/1115    
	USED(c, name, omode, perm); 
1990/11211    
	error(Eperm); 
1990/0324    
} 
 
void 
bitremove(Chan *c) 
{ 
1991/1115    
	USED(c); 
1990/11211    
	error(Eperm); 
1990/0324    
} 
 
void 
bitwstat(Chan *c, char *db) 
{ 
1991/1115    
	USED(c, db); 
1990/11211    
	error(Eperm); 
1990/0324    
} 
 
void 
bitclose(Chan *c) 
{ 
1992/0621    
	GBitmap *b, **bp, **ebp; 
1992/06271    
	BSubfont *s, **sp, **esp; 
1992/0621    
	GFont *f, **fp, **efp; 
1990/0327    
 
1990/11211    
	if(c->qid.path!=CHDIR && (c->flag&COPEN)){ 
1990/0329    
		lock(&bit); 
1990/0327    
		if(--bit.ref == 0){ 
1992/0621    
			ebp = &bit.map[bit.nmap]; 
1992/0630    
			for(bp = bit.map; bp<ebp; bp++){ 
1992/0621    
				b = *bp; 
				if(b){ 
					bitfree(b); 
					*bp = 0; 
				} 
1992/0209    
			} 
1992/0621    
			esp = &bit.subfont[bit.nsubfont]; 
1992/0630    
			for(sp=bit.subfont; sp<esp; sp++){ 
1992/0621    
				s = *sp; 
1992/0628    
				if(s) 
1992/0702    
					subfontfree(s, sp-bit.subfont); 
1992/0630    
				/* don't clear *sp: cached */ 
1992/0621    
			} 
			efp = &bit.font[bit.nfont]; 
			for(fp=bit.font; fp<efp; fp++){ 
				f = *fp; 
				if(f){ 
					fontfree(f); 
					*fp = 0; 
				} 
			} 
1990/0327    
		} 
1990/0324    
		unlock(&bit); 
	} 
} 
 
long 
1991/0411    
bitread(Chan *c, void *va, long n, ulong offset) 
1990/0324    
{ 
1990/0613    
	uchar *p, *q; 
	long miny, maxy, t, x, y; 
1992/0630    
	ulong l, v, nw, ws, rv, gv, bv; 
1992/0627    
	int off, j; 
1990/06231    
	Fontchar *i; 
1990/0902    
	GBitmap *src; 
1992/0628    
	BSubfont *s; 
1990/0327    
 
1990/11211    
	if(c->qid.path & CHDIR) 
1990/0324    
		return devdirread(c, va, n, bitdir, NBIT, devgen); 
 
1992/0622    
	if(c->qid.path == Qmouse){ 
1990/0329    
		/* 
1990/0505    
		 * mouse: 
		 *	'm'		1 
		 *	buttons		1 
		 * 	point		8 
1992/06271    
		 * 	msec		4 
1990/0329    
		 */ 
1992/06271    
		if(n < 14) 
1990/11211    
			error(Ebadblt); 
1990/0505    
	    Again: 
		while(mouse.changed == 0) 
			sleep(&mouse.r, mousechanged, 0); 
		lock(&cursor); 
		if(mouse.changed == 0){ 
			unlock(&cursor); 
			goto Again; 
		} 
		p = va; 
		p[0] = 'm'; 
		p[1] = mouse.buttons; 
1992/0630    
		BPLONG(p+2, mouse.xy.x); 
		BPLONG(p+6, mouse.xy.y); 
		BPLONG(p+10, TK2MS(MACHP(0)->ticks)); 
1990/0505    
		mouse.changed = 0; 
		unlock(&cursor); 
1992/06271    
		return 14; 
1992/0622    
	} 
	if(c->qid.path == Qscreen){ 
1991/0411    
		if(offset==0){ 
1990/0709    
			if(n < 5*12) 
1990/11211    
				error(Eio); 
1990/0709    
			sprint(va, "%11d %11d %11d %11d %11d ", 
1990/0912    
				gscreen.ldepth, gscreen.r.min.x, 
				gscreen.r.min.y, gscreen.r.max.x, 
				gscreen.r.max.y); 
1992/0622    
			return 5*12; 
1990/0709    
		} 
1990/0912    
		ws = 1<<(3-gscreen.ldepth);	/* pixels per byte */ 
		l = (gscreen.r.max.x+ws-1)/ws - gscreen.r.min.x/ws; 
1991/0411    
		t = offset-5*12; 
1991/1023    
		miny = t/l;	/* unsigned computation */ 
1990/0709    
		maxy = (t+n)/l; 
1990/0912    
		if(miny >= gscreen.r.max.y) 
1990/0709    
			return 0; 
1990/0912    
		if(maxy >= gscreen.r.max.y) 
			maxy = gscreen.r.max.y; 
1990/0709    
		n = 0; 
		p = va; 
		for(y=miny; y<maxy; y++){ 
1990/0912    
			q = (uchar*)gaddr(&gscreen, Pt(0, y)); 
1992/0630    
			for(x=0; x<l; x++,p++,q++){ 
				v = *q; 
				if(flipping) 
					v = ~v; 
				BPLONG(p, v); 
			} 
1990/0709    
			n += l; 
		} 
1992/0622    
		return n; 
	} 
	if(c->qid.path != Qbitblt) 
1990/11211    
		error(Egreg); 
1992/0622    
 
	qlock(&bit); 
	if(waserror()){ 
		qunlock(&bit); 
		nexterror(); 
1990/0327    
	} 
1992/0622    
	p = va; 
	/* 
	 * Fuss about and figure out what to say. 
	 */ 
	if(bit.init){ 
		/* 
		 * init: 
		 *	'I'		1 
		 *	ldepth		1 
		 * 	rectangle	16 
1992/0627    
		 * 	clip rectangle	16 
1992/0622    
		 *	font info	3*12 
		 *	fontchars	6*(defont->n+1) 
		 */ 
1992/0627    
		if(n < 34) 
1992/0622    
			error(Ebadblt); 
		p[0] = 'I'; 
		p[1] = gscreen.ldepth; 
1992/0630    
		BPLONG(p+2, gscreen.r.min.x); 
		BPLONG(p+6, gscreen.r.min.y); 
		BPLONG(p+10, gscreen.r.max.x); 
		BPLONG(p+14, gscreen.r.max.y); 
		BPLONG(p+18, gscreen.clipr.min.x); 
		BPLONG(p+22, gscreen.clipr.min.y); 
		BPLONG(p+26, gscreen.clipr.max.x); 
		BPLONG(p+30, gscreen.clipr.max.y); 
1992/0627    
		if(n >= 34+3*12+6*(defont->n+1)){ 
			p += 34; 
1992/0622    
			sprint((char*)p, "%11d %11d %11d ", defont->n, 
				defont->height, defont->ascent); 
			p += 3*12; 
			for(i=defont->info,j=0; j<=defont->n; j++,i++,p+=6){ 
1992/0630    
				BPSHORT(p, i->x); 
1992/0622    
				p[2] = i->top; 
				p[3] = i->bottom; 
				p[4] = i->left; 
				p[5] = i->width; 
			} 
1992/0627    
			n = 34+3*12+6*(defont->n+1); 
1992/0622    
		}else 
1992/0627    
			n = 34; 
1992/0622    
		bit.init = 0; 
1992/0630    
	}else if(bit.bid > 0){ 
1992/0622    
		/* 
		 * allocate: 
		 *	'A'		1 
		 *	bitmap id	2 
		 */ 
		if(n < 3) 
			error(Ebadblt); 
1992/0630    
		if(bit.bid<0 || bit.map[bit.bid]==0) 
			error(Ebadbitmap); 
1992/0622    
		p[0] = 'A'; 
1992/0630    
		BPSHORT(p+1, bit.bid); 
		bit.bid = -1; 
1992/0622    
		n = 3; 
1992/0630    
	}else if(bit.subfid > 0){ 
1992/0622    
		/* 
		 * allocate subfont: 
		 *	'K'		1 
		 *	subfont id	2 
		 */ 
1992/0630    
		if(n<3 || bit.subfid<0) 
1992/0622    
			error(Ebadblt); 
1992/0630    
		s = bit.subfont[bit.subfid]; 
		if(s==0 || s->ref==0) 
			error(Ebadfont); 
1992/0622    
		p[0] = 'K'; 
1992/0630    
		BPSHORT(p+1, bit.subfid); 
		bit.subfid = -1; 
1992/0622    
		n = 3; 
1992/0630    
	}else if(bit.cacheid >= 0){ 
1992/0628    
		/* 
		 * allocate subfont: 
		 *	'J'		1 
		 *	subfont id	2 
		 *	font info	3*12 
		 *	fontchars	6*(subfont->n+1) 
		 */ 
		p[0] = 'J'; 
1992/0702    
		if(bit.cacheid < 0) 
1992/0630    
			error(Ebadfont); 
		s = bit.subfont[bit.cacheid]; 
		if(s==0 || s->ref==0) 
			error(Ebadfont); 
		if(n < 3+3*12+6*(s->n+1)) 
1992/0628    
			error(Ebadblt); 
1992/0630    
		BPSHORT(p+1, bit.cacheid); 
1992/0628    
		p += 3; 
1992/0630    
		sprint((char*)p, "%11d %11d %11d ", s->n, s->height, s->ascent); 
1992/0628    
		p += 3*12; 
		for(i=s->info,j=0; j<=s->n; j++,i++,p+=6){ 
1992/0630    
			BPSHORT(p, i->x); 
1992/0628    
			p[2] = i->top; 
			p[3] = i->bottom; 
			p[4] = i->left; 
			p[5] = i->width; 
		} 
		n = 3+3*12+6*(s->n+1); 
1992/0630    
		bit.cacheid = -1; 
	}else if(bit.fid >= 0){ 
1992/0622    
		/* 
		 * allocate font: 
		 *	'N'		1 
		 *	font id		2 
		 */ 
		if(n < 3) 
			error(Ebadblt); 
1992/0630    
		if(bit.fid<0 || bit.font[bit.fid]==0) 
			error(Ebadfont); 
1992/0622    
		p[0] = 'N'; 
1992/0630    
		BPSHORT(p+1, bit.fid); 
		bit.fid = -1; 
1992/0622    
		n = 3; 
	}else if(bit.mid >= 0){ 
		/* 
		 * read colormap: 
		 *	data		12*(2**bitmapdepth) 
		 */ 
		src = bit.map[bit.mid]; 
		if(src == 0) 
			error(Ebadbitmap); 
		l = (1<<src->ldepth); 
		nw = 1 << l; 
		if(n < 12*nw) 
			error(Ebadblt); 
		for(j = 0; j < nw; j++){ 
			if(bit.mid == 0){ 
				getcolor(flipping? ~j : j, &rv, &gv, &bv); 
			}else{ 
				rv = j; 
				for(off = 32-l; off > 0; off -= l) 
					rv = (rv << l) | j; 
				gv = bv = rv; 
			} 
1992/0630    
			BPLONG(p, rv); 
			BPLONG(p+4, gv); 
			BPLONG(p+8, bv); 
1992/0622    
			p += 12; 
		} 
		bit.mid = -1; 
		n = 12*nw; 
	}else if(bit.rid >= 0){ 
		/* 
		 * read bitmap: 
		 *	data		bytewidth*(maxy-miny) 
		 */ 
		src = bit.map[bit.rid]; 
		if(src == 0) 
			error(Ebadbitmap); 
		off = 0; 
		if(bit.rid == 0) 
			off = 1; 
		miny = bit.rminy; 
		maxy = bit.rmaxy; 
		if(miny>maxy || miny<src->r.min.y || maxy>src->r.max.y) 
			error(Ebadblt); 
		ws = 1<<(3-src->ldepth);	/* pixels per byte */ 
		/* set l to number of bytes of incoming data per scan line */ 
		if(src->r.min.x >= 0) 
			l = (src->r.max.x+ws-1)/ws - src->r.min.x/ws; 
		else{	/* make positive before divide */ 
			t = (-src->r.min.x)+ws-1; 
			t = (t/ws)*ws; 
			l = (t+src->r.max.x+ws-1)/ws; 
		} 
		if(n < l*(maxy-miny)) 
			error(Ebadblt); 
		if(off) 
			cursoroff(1); 
		n = 0; 
		p = va; 
		for(y=miny; y<maxy; y++){ 
			q = (uchar*)gaddr(src, Pt(src->r.min.x, y)); 
			q += (src->r.min.x&((sizeof(ulong))*ws-1))/ws; 
1992/0630    
			if(bit.rid == 0) 
				for(x=0; x<l; x++,p++,q++) 
					BPLONG(p, ~*q); 
1992/0622    
			else 
				for(x=0; x<l; x++) 
					*p++ = *q++; 
			n += l; 
		} 
		if(off) 
			cursoron(1); 
		bit.rid = -1; 
	} 
1990/0327    
 
1992/0622    
	poperror(); 
	qunlock(&bit); 
1990/0327    
	return n; 
1990/0324    
} 
 
long 
1991/0411    
bitwrite(Chan *c, void *va, long n, ulong offset) 
1990/0324    
{ 
1990/0329    
	uchar *p, *q; 
1991/0706    
	long m, v, miny, maxy, minx, maxx, t, x, y; 
1992/0628    
	ulong l, nw, ws, rv, q0, q1; 
1992/0621    
	int off, isoff, i, j, ok; 
1990/06111    
	Point pt, pt1, pt2; 
1990/0324    
	Rectangle rect; 
1990/05313    
	Cursor curs; 
1991/0706    
	Fcode fc; 
1990/0623    
	Fontchar *fcp; 
1992/0621    
	GBitmap *b, *src, *dst, *bp; 
1992/0702    
	BSubfont *f, *tf, **fp; 
1992/0621    
	GFont *ff, **ffp; 
1992/0706    
	GCacheinfo *gc; 
1990/0324    
 
1990/11211    
	if(c->qid.path == CHDIR) 
		error(Eisdir); 
1990/0324    
 
1990/11211    
	if(c->qid.path != Qbitblt) 
		error(Egreg); 
1990/0327    
 
1990/0721    
	isoff = 0; 
1992/0622    
	qlock(&bit); 
1990/0721    
	if(waserror()){ 
1992/0622    
		qunlock(&bit); 
1990/0721    
		if(isoff) 
			cursoron(1); 
		nexterror(); 
	} 
1990/0324    
	p = va; 
	m = n; 
1992/0621    
	SET(src, dst, f, ff); 
1990/0327    
	while(m > 0) 
		switch(*p){ 
1990/0329    
		default: 
			pprint("bitblt request 0x%x\n", *p); 
1990/11211    
			error(Ebadblt); 
1990/0329    
 
1990/0327    
		case 'a': 
			/* 
			 * allocate: 
			 *	'a'		1 
			 *	ldepth		1 
			 *	Rectangle	16 
			 * next read returns allocated bitmap id 
			 */ 
			if(m < 18) 
1990/11211    
				error(Ebadblt); 
1990/0327    
			v = *(p+1); 
1992/0209    
			if(v > 3)	/* BUG */ 
1990/11211    
				error(Ebadblt); 
1992/0630    
			rect.min.x = BGLONG(p+2); 
			rect.min.y = BGLONG(p+6); 
			rect.max.x = BGLONG(p+10); 
			rect.max.y = BGLONG(p+14); 
1991/0423    
			if(Dx(rect) < 0 || Dy(rect) < 0) 
				error(Ebadblt); 
1992/0630    
			bit.bid = bitalloc(rect, v); 
1990/0327    
			m -= 18; 
			p += 18; 
			break; 
1990/0324    
 
1990/0327    
		case 'b': 
			/* 
			 * bitblt 
			 *	'b'		1 
			 *	dst id		2 
			 *	dst Point	8 
			 *	src id		2 
			 *	src Rectangle	16 
			 *	code		2 
			 */ 
			if(m < 31) 
1990/11211    
				error(Ebadblt); 
1992/0630    
			fc = BGSHORT(p+29) & 0xF; 
			v = BGSHORT(p+11); 
1992/0621    
			if(v<0 || v>=bit.nmap || (src=bit.map[v])==0) 
1991/0706    
				error(Ebadbitmap); 
			off = 0; 
			if(v == 0){ 
				if(flipping) 
					fc = flipS[fc]; 
				off = 1; 
			} 
1992/0630    
			v = BGSHORT(p+1); 
1992/0621    
			if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0) 
1990/11211    
				error(Ebadbitmap); 
1991/0706    
			if(v == 0){ 
				if(flipping) 
					fc = flipD[fc]; 
1990/0504    
				off = 1; 
1991/0706    
			} 
1992/0630    
			pt.x = BGLONG(p+3); 
			pt.y = BGLONG(p+7); 
			rect.min.x = BGLONG(p+13); 
			rect.min.y = BGLONG(p+17); 
			rect.max.x = BGLONG(p+21); 
			rect.max.y = BGLONG(p+25); 
1990/0721    
			if(off && !isoff){ 
1990/0504    
				cursoroff(1); 
1990/0721    
				isoff = 1; 
			} 
1991/1225    
			gbitblt(dst, pt, src, rect, fc); 
1990/0327    
			m -= 31; 
			p += 31; 
			break; 
 
1990/05313    
		case 'c': 
			/* 
			 * cursorswitch 
			 *	'c'		1 
			 * nothing more: return to arrow; else 
			 * 	Point		8 
			 *	clr		32 
			 *	set		32 
			 */ 
			if(m == 1){ 
1990/0721    
				if(!isoff){ 
					cursoroff(1); 
					isoff = 1; 
				} 
1990/05313    
				Cursortocursor(&arrow); 
				m -= 1; 
				p += 1; 
				break; 
			} 
			if(m < 73) 
1990/11211    
				error(Ebadblt); 
1992/0630    
			curs.offset.x = BGLONG(p+1); 
			curs.offset.y = BGLONG(p+5); 
1991/0318    
			memmove(curs.clr, p+9, 2*16); 
			memmove(curs.set, p+41, 2*16); 
1990/0721    
			if(!isoff){ 
				cursoroff(1); 
				isoff = 1; 
			} 
1990/05313    
			Cursortocursor(&curs); 
			m -= 73; 
			p += 73; 
			break; 
 
1990/0327    
		case 'f': 
			/* 
			 * free 
			 *	'f'		1 
			 *	id		2 
			 */ 
			if(m < 3) 
1990/11211    
				error(Ebadblt); 
1992/0630    
			v = BGSHORT(p+1); 
1992/0621    
			if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0) 
1990/11211    
				error(Ebadbitmap); 
1990/0327    
			bitfree(dst); 
1992/0621    
			bit.map[v] = 0; 
1990/0327    
			m -= 3; 
			p += 3; 
1990/0604    
			break; 
 
1990/0623    
		case 'g': 
			/* 
1992/0628    
			 * free subfont 
1990/0623    
			 *	'g'		1 
			 *	id		2 
			 */ 
			if(m < 3) 
1990/11211    
				error(Ebadblt); 
1992/0630    
			v = BGSHORT(p+1); 
1992/0628    
			if(v<0 || v>=bit.nsubfont || (f=bit.subfont[v])==0 || f->ref==0) 
1990/11211    
				error(Ebadfont); 
1992/0702    
			subfontfree(f, v); 
1990/0623    
			m -= 3; 
			p += 3; 
			break; 
 
1992/0209    
		case 'h': 
			/* 
			 * free font 
			 *	'h'		1 
			 *	id		2 
			 */ 
			if(m < 3) 
				error(Ebadblt); 
1992/0630    
			v = BGSHORT(p+1); 
1992/0621    
			if(v<0 || v>=bit.nfont || (ff=bit.font[v])==0) 
1992/0209    
				error(Ebadfont); 
1992/0621    
			fontfree(ff); 
			bit.font[v] = 0; 
1992/0209    
			m -= 3; 
			p += 3; 
			break; 
 
1990/0604    
		case 'i': 
			/* 
			 * init 
			 * 
1992/0627    
			 *	'i'		1 
1990/0604    
			 */ 
1992/0627    
			bit.init = 1; 
1990/0604    
			m -= 1; 
			p += 1; 
1990/0327    
			break; 
1990/0329    
 
1992/06271    
		case 'j': 
			/* 
1992/0628    
			 * subfont cache check 
1992/06271    
			 * 
			 *	'j'		1 
1992/0702    
			 *	qid		8 
1992/06271    
			 */ 
1992/0628    
			if(m < 9) 
				error(Ebadblt); 
1992/0630    
			q0 = BGLONG(p+1); 
			q1 = BGLONG(p+5); 
1992/0629    
			i = 0; 
			if(q0 != ~0) 
				for(; i<bit.nsubfont; i++){ 
					f = bit.subfont[i]; 
					if(f && f->qid[0]==q0 && f->qid[1]==q1) 
						goto sfcachefound; 
				} 
1992/0628    
			error(Esfnotcached); 
 
		sfcachefound: 
			f->ref++; 
1992/0630    
			bit.cacheid = i; 
1992/06271    
			m -= 9; 
			p += 9; 
			break; 
 
1990/0623    
		case 'k': 
			/* 
1992/0209    
			 * allocate subfont 
1990/0623    
			 *	'k'		1 
			 *	n		2 
			 *	height		1 
			 *	ascent		1 
			 *	bitmap id	2 
1992/06271    
			 *	qid		8 
1990/0707    
			 *	fontchars	6*(n+1) 
1990/0623    
			 * next read returns allocated font id 
			 */ 
1992/06271    
			if(m < 15) 
1990/11211    
				error(Ebadblt); 
1992/0630    
			v = BGSHORT(p+1); 
1992/06271    
			if(v<0 || v>NINFO || m<15+6*(v+1)) 
1990/11211    
				error(Ebadblt); 
1992/0621    
			for(i=1; i<bit.nsubfont; i++) 
				if(bit.subfont[i] == 0) 
1992/0209    
					goto subfontfound; 
1992/0706    
			fp = bitmalloc((bit.nsubfont+DMAP)*sizeof(BSubfont*)); 
			if(fp == 0) 
				error(Enomem); 
			memmove(fp, bit.subfont, bit.nsubfont*sizeof(BSubfont*)); 
			free(bit.subfont); 
			bit.subfont = fp; 
1992/0621    
			bit.nsubfont += DMAP; 
1992/0209    
		subfontfound: 
1992/0706    
			f = bitmalloc(sizeof(BSubfont)); 
			if(f == 0) 
				error(Enomem); 
1992/0621    
			bit.subfont[i] = f; 
1992/0706    
			f->info = bitmalloc((v+1)*sizeof(Fontchar)); 
			if(f->info == 0){ 
				free(f); 
				error(Enomem); 
			} 
1990/0623    
			f->n = v; 
			f->height = p[3]; 
			f->ascent = p[4]; 
1992/0630    
			f->qid[0] = BGLONG(p+7); 
			f->qid[1] = BGLONG(p+11); 
1992/0702    
			/* check to see if already there, uncache if so */ 
			for(j=0; j<bit.nsubfont; j++){ 
				if(j == i) 
					continue; 
				tf = bit.subfont[j]; 
1992/0704    
				if(tf && tf->qid[0]==f->qid[0] && tf->qid[1]==f->qid[1]){ 
1992/0702    
					f->qid[0] = ~0;	/* uncached */ 
1992/0704    
					break; 
				} 
1992/0702    
			} 
1992/0628    
			f->ref = 1; 
1992/0630    
			v = BGSHORT(p+5); 
1992/0621    
			if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0) 
1990/11211    
				error(Ebadbitmap); 
1992/06271    
			f->bits = dst; 
			bit.map[v] = 0;	/* subfont now owns bitmap */ 
			m -= 15; 
			p += 15; 
1990/0623    
			fcp = f->info; 
1992/0621    
			for(j=0; j<=f->n; j++,fcp++){ 
1992/0630    
				fcp->x = BGSHORT(p); 
1990/0623    
				fcp->top = p[2]; 
				fcp->bottom = p[3]; 
				fcp->left = p[4]; 
				fcp->width = p[5]; 
				fcp->top = p[2]; 
				p += 6; 
				m -= 6; 
			} 
1992/0630    
			bit.subfid = i; 
1990/0623    
			break; 
 
1990/06111    
		case 'l': 
			/* 
			 * line segment 
			 * 
			 *	'l'		1 
			 *	id		2 
			 *	pt1		8 
			 *	pt2		8 
			 *	value		1 
			 *	code		2 
			 */ 
			if(m < 22) 
1990/11211    
				error(Ebadblt); 
1992/0630    
			v = BGSHORT(p+1); 
1992/0621    
			if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0) 
1990/11211    
				error(Ebadbitmap); 
1990/06111    
			off = 0; 
1992/0630    
			fc = BGSHORT(p+20) & 0xF; 
1991/0706    
			if(v == 0){ 
				if(flipping) 
					fc = flipD[fc]; 
1990/06111    
				off = 1; 
1991/0706    
			} 
1992/0630    
			pt1.x = BGLONG(p+3); 
			pt1.y = BGLONG(p+7); 
			pt2.x = BGLONG(p+11); 
			pt2.y = BGLONG(p+15); 
1990/06111    
			t = p[19]; 
1990/0721    
			if(off && !isoff){ 
1990/06111    
				cursoroff(1); 
1990/0721    
				isoff = 1; 
			} 
1991/0706    
			gsegment(dst, pt1, pt2, t, fc); 
1990/06111    
			m -= 22; 
			p += 22; 
1990/0613    
			break; 
 
1991/0706    
		case 'm': 
			/* 
			 * read colormap 
			 * 
			 *	'm'		1 
			 *	id		2 
			 */ 
			if(m < 3) 
				error(Ebadblt); 
1992/0630    
			v = BGSHORT(p+1); 
1992/0621    
			if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0) 
1991/0706    
				error(Ebadbitmap); 
			bit.mid = v; 
			m -= 3; 
			p += 3; 
			break; 
 
1992/0209    
		case 'n': 
			/* 
			 * allocate font 
			 *	'n'		1 
			 *	height		1 
			 *	ascent		1 
			 *	ldepth		2 
1992/0627    
			 *	ncache		2 
1992/0209    
			 * next read returns allocated font id 
			 */ 
1992/0627    
			if(m < 7) 
1992/0209    
				error(Ebadblt); 
1992/0630    
			v = BGSHORT(p+3); 
			t = BGSHORT(p+5); 
1992/0627    
			if(v<0 || t<0) 
1992/0209    
				error(Ebadblt); 
1992/0621    
			for(i=0; i<bit.nfont; i++) 
				if(bit.font[i] == 0) 
1992/0209    
					goto fontfound; 
1992/0706    
			ffp = bitmalloc((bit.nfont+DMAP)*sizeof(GFont*)); 
			if(ffp == 0) 
				error(Enomem); 
			memmove(ffp, bit.font, bit.nfont*sizeof(GFont*)); 
			free(bit.font); 
			bit.font = ffp; 
1992/0621    
			bit.nfont += DMAP; 
1992/0209    
		fontfound: 
1992/0706    
			ff = bitmalloc(sizeof(GFont)); 
			if(ff == 0) 
				error(Enomem); 
1992/0627    
			ff->ncache = t; 
1992/0706    
			ff->cache = bitmalloc(t*sizeof(GCacheinfo)); 
			if(ff->cache == 0){ 
				free(ff); 
				error(Enomem); 
			} 
1992/0621    
			bit.font[i] = ff; 
			ff = bit.font[i]; 
1992/0209    
			ff->height = p[1]; 
			ff->ascent = p[2]; 
			ff->ldepth = v; 
			ff->width = 0; 
			ff->b = 0; 
1992/0627    
			m -= 7; 
			p += 7; 
1992/0630    
			bit.fid = i; 
1992/0209    
			break; 
 
1990/0722    
		case 'p': 
			/* 
			 * point 
			 * 
			 *	'p'		1 
			 *	id		2 
			 *	pt		8 
			 *	value		1 
			 *	code		2 
			 */ 
			if(m < 14) 
1990/11211    
				error(Ebadblt); 
1992/0630    
			v = BGSHORT(p+1); 
1992/0621    
			if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0) 
1990/11211    
				error(Ebadbitmap); 
1990/0722    
			off = 0; 
1992/0630    
			fc = BGSHORT(p+12) & 0xF; 
1991/0706    
			if(v == 0){ 
				if(flipping) 
					fc = flipD[fc]; 
1990/0722    
				off = 1; 
1991/0706    
			} 
1992/0630    
			pt1.x = BGLONG(p+3); 
			pt1.y = BGLONG(p+7); 
1990/0722    
			t = p[11]; 
			if(off && !isoff){ 
				cursoroff(1); 
				isoff = 1; 
			} 
1991/0706    
			gpoint(dst, pt1, t, fc); 
1990/0722    
			m -= 14; 
			p += 14; 
			break; 
 
1992/0604    
		case 'q': 
			/* 
			 * clip rectangle 
			 *	'q'		1 
			 *	id		2 
			 *	rect		16 
			 */ 
			if(m < 19) 
				error(Ebadblt); 
1992/0630    
			v = BGSHORT(p+1); 
1992/0621    
			if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0) 
1992/0604    
				error(Ebadbitmap); 
1992/0630    
			rect.min.x = BGLONG(p+3); 
			rect.min.y = BGLONG(p+7); 
			rect.max.x = BGLONG(p+11); 
			rect.max.y = BGLONG(p+15); 
1992/0604    
			if(rectclip(&rect, dst->r)) 
				dst->clipr = rect; 
			else 
				dst->clipr = dst->r; 
			m -= 19; 
			p += 19; 
			break; 
 
1990/0613    
		case 'r': 
			/* 
			 * read 
			 *	'r'		1 
			 *	src id		2 
			 *	miny		4 
			 *	maxy		4 
			 */ 
			if(m < 11) 
1990/11211    
				error(Ebadblt); 
1992/0630    
			v = BGSHORT(p+1); 
1992/0621    
			if(v<0 || v>=bit.nmap || (src=bit.map[v])==0) 
1990/11211    
				error(Ebadbitmap); 
1992/0630    
			miny = BGLONG(p+3); 
			maxy = BGLONG(p+7); 
1990/0613    
			if(miny>maxy || miny<src->r.min.y || maxy>src->r.max.y) 
1990/11211    
				error(Ebadblt); 
1990/0613    
			bit.rid = v; 
			bit.rminy = miny; 
			bit.rmaxy = maxy; 
			p += 11; 
			m -= 11; 
1990/06111    
			break; 
 
1992/0627    
		case 's': 
1990/0329    
			/* 
1992/0209    
			 * string 
1992/0627    
			 *	's'		1 
1992/0209    
			 *	id		2 
			 *	pt		8 
			 *	font id		2 
			 *	code		2 
			 *	n		2 
1992/0627    
			 * 	cache indices	2*n (not null terminated) 
1992/0209    
			 */ 
			if(m < 17) 
				error(Ebadblt); 
1992/0630    
			v = BGSHORT(p+1); 
1992/0621    
			if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0) 
1992/0209    
				error(Ebadbitmap); 
			off = 0; 
1992/0630    
			fc = BGSHORT(p+13) & 0xF; 
1992/0209    
			if(v == 0){ 
				if(flipping) 
					fc = flipD[fc]; 
				off = 1; 
			} 
1992/0630    
			pt.x = BGLONG(p+3); 
			pt.y = BGLONG(p+7); 
			v = BGSHORT(p+11); 
1992/0621    
			if(v<0 || v>=bit.nfont || (ff=bit.font[v])==0) 
1992/0209    
				error(Ebadblt); 
1992/0630    
			l = BGSHORT(p+15)*2; 
1992/0209    
			p += 17; 
			m -= 17; 
			if(l > m) 
				error(Ebadblt); 
			if(off && !isoff){ 
				cursoroff(1); 
				isoff = 1; 
			} 
			bitstring(dst, pt, ff, p, l, fc); 
			m -= l; 
			p += l; 
			break; 
 
1992/0627    
		case 't': 
			/* 
			 * texture 
			 *	't'		1 
			 *	dst id		2 
			 *	rect		16 
			 *	src id		2 
			 *	fcode		2 
			 */ 
			if(m < 23) 
				error(Ebadblt); 
1992/0630    
			v = BGSHORT(p+1); 
1992/0627    
			if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0) 
				error(Ebadbitmap); 
			off = 0; 
1992/0630    
			fc = BGSHORT(p+21) & 0xF; 
1992/0627    
			if(v == 0){ 
				if(flipping) 
					fc = flipD[fc]; 
				off = 1; 
			} 
1992/0630    
			rect.min.x = BGLONG(p+3); 
			rect.min.y = BGLONG(p+7); 
			rect.max.x = BGLONG(p+11); 
			rect.max.y = BGLONG(p+15); 
			v = BGSHORT(p+19); 
1992/0627    
			if(v<0 || v>=bit.nmap || (src=bit.map[v])==0) 
				error(Ebadbitmap); 
			if(off && !isoff){ 
				cursoroff(1); 
				isoff = 1; 
			} 
			gtexture(dst, rect, src, fc); 
			m -= 23; 
			p += 23; 
			break; 
 
1992/0209    
		case 'v': 
			/* 
1992/0704    
			 * clear font cache and bitmap. 
			 * if error, font is unchanged. 
1992/0209    
			 *	'v'		1 
			 *	id		2 
1992/06271    
			 *	ncache		2 
1992/0209    
			 *	width		2 
			 */ 
1992/06271    
			if(m < 7) 
1992/0209    
				error(Ebadblt); 
1992/0630    
			v = BGSHORT(p+1); 
			t = BGSHORT(p+3); 
1992/06271    
			if(t<0 || v<0 || v>=bit.nfont || (ff=bit.font[v])==0) 
1992/0209    
				error(Ebadblt); 
1992/0704    
			x = BGSHORT(p+5); 
			i = bitalloc(Rect(0, 0, t*x, ff->height), ff->ldepth); 
1992/0706    
			if(t != ff->ncache){ 
				gc = bitmalloc(t*sizeof(ff->cache[0])); 
				if(gc == 0){ 
					bitfree(bit.map[i]); 
					bit.map[i] = 0; 
					error(Enomem); 
				} 
				free(ff->cache); 
				ff->cache = gc; 
				ff->ncache = t; 
			}else{ 
				/* 
				 * memset not necessary but helps avoid 
				 * confusion if the cache is mishandled by the 
				 * user. 
				 */ 
				memset(ff->cache, 0, t*sizeof(ff->cache[0])); 
			} 
1992/0704    
			if(ff->b) 
				bitfree(ff->b); 
			ff->b = bit.map[i]; 
			bit.map[i] = 0;	/* disconnect it from GBitmap space */ 
			ff->width = x; 
1992/06271    
			p += 7; 
			m -= 7; 
1992/0209    
			break; 
 
1990/0329    
		case 'w': 
			/* 
			 * write 
			 *	'w'		1 
			 *	dst id		2 
			 *	miny		4 
			 *	maxy		4 
			 *	data		bytewidth*(maxy-miny) 
			 */ 
			if(m < 11) 
1990/11211    
				error(Ebadblt); 
1992/0630    
			v = BGSHORT(p+1); 
1992/0621    
			if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0) 
1990/11211    
				error(Ebadbitmap); 
1990/0504    
			off = 0; 
			if(v == 0) 
				off = 1; 
1992/0630    
			miny = BGLONG(p+3); 
			maxy = BGLONG(p+7); 
1990/03291    
			if(miny>maxy || miny<dst->r.min.y || maxy>dst->r.max.y) 
1990/11211    
				error(Ebadblt); 
1990/0329    
			ws = 1<<(3-dst->ldepth);	/* pixels per byte */ 
			/* set l to number of bytes of incoming data per scan line */ 
			if(dst->r.min.x >= 0) 
				l = (dst->r.max.x+ws-1)/ws - dst->r.min.x/ws; 
			else{	/* make positive before divide */ 
				t = (-dst->r.min.x)+ws-1; 
				t = (t/ws)*ws; 
				l = (t+dst->r.max.x+ws-1)/ws; 
			} 
			p += 11; 
			m -= 11; 
			if(m < l*(maxy-miny)) 
1990/11211    
				error(Ebadblt); 
1990/0721    
			if(off && !isoff){ 
1990/0504    
				cursoroff(1); 
1990/0721    
				isoff = 1; 
			} 
1990/0329    
			for(y=miny; y<maxy; y++){ 
1990/0912    
				q = (uchar*)gaddr(dst, Pt(dst->r.min.x, y)); 
1990/0911    
				q += (dst->r.min.x&((sizeof(ulong))*ws-1))/ws; 
1991/0706    
				if(v == 0 && flipping)	/* flip bits */ 
					for(x=0; x<l; x++) 
1992/0209    
						*q++ = ~(*p++); 
1991/0706    
				else 
					for(x=0; x<l; x++) 
1992/0209    
						*q++ = *p++; 
1990/0329    
				m -= l; 
			} 
			break; 
1990/0826    
 
		case 'x': 
			/* 
			 * cursorset 
			 * 
			 *	'x'		1 
			 *	pt		8 
			 */ 
			if(m < 9) 
1990/11211    
				error(Ebadblt); 
1992/0630    
			pt1.x = BGLONG(p+1); 
			pt1.y = BGLONG(p+5); 
1991/0706    
/*			if(!eqpt(mouse.xy, pt1))*/{ 
1991/0619    
				mouse.xy = pt1; 
				mouse.track = 1; 
				mouseclock(); 
			} 
1990/0826    
			m -= 9; 
			p += 9; 
			break; 
1991/0706    
 
1992/0209    
		case 'y': 
			/* 
			 * load font from subfont 
			 *	'y'		1 
			 *	id		2 
1992/0212    
			 *	cache index	2 
1992/0209    
			 *	subfont id	2 
			 *	subfont index	2 
			 */ 
			if(m < 9) 
				error(Ebadblt); 
1992/0630    
			v = BGSHORT(p+1); 
1992/0622    
			if(v<0 || v>=bit.nfont || (ff=bit.font[v])==0) 
1992/0209    
				error(Ebadblt); 
1992/0630    
			l = BGSHORT(p+3); 
			if(l >= ff->ncache) 
1992/0209    
				error(Ebadblt); 
1992/0630    
			v = BGSHORT(p+5); 
1992/0628    
			if(v<0 || v>=bit.nsubfont || (f=bit.subfont[v])==0 || f->ref==0) 
				error(Ebadfont); 
1992/0630    
			nw = BGSHORT(p+7); 
1992/0209    
			if(nw >= f->n) 
				error(Ebadblt); 
			bitloadchar(ff, l, f, nw); 
			p += 9; 
			m -= 9; 
			break; 
 
1991/0706    
		case 'z': 
			/* 
			 * write the colormap 
			 * 
			 *	'z'		1 
			 *	id		2 
			 *	map		12*(2**bitmapdepth) 
			 */ 
			if(m < 3) 
				error(Ebadblt); 
1992/0630    
			v = BGSHORT(p+1); 
1991/0706    
			if(v != 0) 
				error(Ebadbitmap); 
			m -= 3; 
			p += 3; 
1992/0621    
			nw = 1 << (1 << gscreen.ldepth); 
1991/0706    
			if(m < 12*nw) 
				error(Ebadblt); 
			ok = 1; 
			for(i = 0; i < nw; i++){ 
1992/0630    
				ok &= setcolor(i, BGLONG(p), BGLONG(p+4), BGLONG(p+8)); 
1991/0706    
				p += 12; 
				m -= 12; 
			} 
			if(!ok){ 
				/* assume monochrome: possibly change flipping */ 
1992/0630    
				l = BGLONG(p-12); 
1991/0706    
				getcolor(nw-1, &rv, &rv, &rv); 
				flipping = (l != rv); 
			} 
			break; 
1990/0327    
		} 
 
1991/0614    
	poperror(); 
1990/0721    
	if(isoff) 
		cursoron(1); 
1992/0622    
	qunlock(&bit); 
1990/0324    
	return n; 
} 
 
1992/0621    
int 
1992/0209    
bitalloc(Rectangle rect, int ld) 
{ 
1992/0622    
	Arena *a, *ea, *na, *aa; 
1992/0621    
	GBitmap *b, **bp, **ep; 
1992/0628    
	BSubfont *s; 
1992/0209    
	ulong l, ws, nw; 
	long t; 
1992/0622    
	int i, try; 
1992/0209    
 
1992/0706    
	ws = BI2WD>>ld;	/* pixels per word */ 
1992/0621    
	if(rect.min.x >= 0){ 
1992/0519    
		l = (rect.max.x+ws-1)/ws; 
		l -= rect.min.x/ws; 
1992/0621    
	}else{	/* make positive before divide */ 
1992/0209    
		t = (-rect.min.x)+ws-1; 
		t = (t/ws)*ws; 
		l = (t+rect.max.x+ws-1)/ws; 
	} 
	nw = l*Dy(rect); 
1992/0622    
	ea = &bit.arena[bit.narena]; 
 
	/* first try easy fit */ 
	for(a=bit.arena; a<ea; a++){ 
		if(a->words == 0) 
			continue; 
		if(a->wfree+HDR+nw <= a->words+a->nwords) 
			goto found; 
1992/0209    
	} 
1992/0622    
 
	/* compact and try again */ 
	bitcompact(); 
	aa = 0; 
	for(a=bit.arena; a<ea; a++){ 
		if(a->words == 0){ 
			if(aa == 0) 
				aa = a; 
			continue; 
		} 
		if(a->wfree+HDR+nw <= a->words+a->nwords) 
			goto found; 
	} 
 
	/* need new arena */ 
1992/0630    
	if(aa){ 
1992/0622    
		a = aa; 
1992/0706    
		a->nwords = HDR + (gscreen.r.max.y*gscreen.r.max.x)/ws; 
1992/0630    
		if(a->nwords < HDR+nw) 
			a->nwords = HDR+nw; 
		a->words = xalloc(a->nwords*sizeof(ulong)); 
		if(a->words){ 
			a->wfree = a->words; 
			a->nbusy = 0; 
			goto found; 
		} 
1992/0622    
	} 
1992/0630    
	/* else can't grow list: bitmaps have backpointers */ 
1992/0628    
 
1992/0706    
	bitfreeup(); 
 
1992/0628    
	for(a=bit.arena; a<ea; a++){ 
		if(a->words == 0) 
			continue; 
		if(a->wfree+HDR+nw <= a->words+a->nwords) 
			goto found; 
	} 
	if(a == ea) 
1992/0622    
		error(Enobitstore); 
	 
    found: 
1992/0706    
	b = bitmalloc(sizeof(GBitmap)); 
	if(b == 0) 
		error(Enomem); 
1992/0622    
	*a->wfree++ = nw; 
	*a->wfree++ = (ulong)a; 
	*a->wfree++ = (ulong)b; 
1992/0706    
	memset(a->wfree, 0, nw*sizeof(ulong)); 
1992/0622    
	b->base = a->wfree; 
	a->wfree += nw; 
	a->nbusy++; 
1992/0621    
	b->zero = l*rect.min.y; 
1992/0209    
	if(rect.min.x >= 0) 
1992/0621    
		b->zero += rect.min.x/ws; 
1992/0209    
	else 
1992/0621    
		b->zero -= (-rect.min.x+ws-1)/ws; 
	b->zero = -b->zero; 
	b->width = l; 
	b->ldepth = ld; 
	b->r = rect; 
	b->clipr = rect; 
	b->cache = 0; 
	/* worth doing better than linear lookup? */ 
	ep = bit.map+bit.nmap; 
	for(bp=bit.map; bp<ep; bp++) 
		if(*bp == 0) 
			break; 
	if(bp == ep){ 
1992/0706    
		bp = bitmalloc((bit.nmap+DMAP)*sizeof(GBitmap*)); 
		if(bp == 0){ 
			bitfree(b); 
			error(Enomem); 
		} 
		memmove(bp, bit.map, bit.nmap*sizeof(GBitmap*)); 
		free(bit.map); 
		bit.map = bp; 
		bp += bit.nmap; 
1992/0621    
		bit.nmap += DMAP; 
	} 
	*bp = b; 
	return bp-bit.map; 
1992/0209    
} 
 
1990/0324    
void 
1992/0621    
bitfree(GBitmap *b) 
1990/0327    
{ 
1992/0622    
	Arena *a; 
 
1992/0630    
	if(b->base != gscreen.base){	/* can't free screen memory */ 
		a = (Arena*)(b->base[-2]); 
		a->nbusy--; 
		if(a->nbusy == 0) 
			arenafree(a); 
		b->base[-1] = 0; 
	} 
1992/0621    
	free(b); 
1990/0327    
} 
 
1992/0209    
void 
1992/0621    
fontfree(GFont *f) 
{ 
	if(f->b) 
		bitfree(f->b); 
1992/0627    
	free(f->cache); 
1992/0621    
	free(f); 
} 
 
void 
1992/0702    
subfontfree(BSubfont *s, int i) 
1992/0621    
{ 
1992/0702    
	if(s!=defont && s->ref>0){	/* don't free subfont 0, defont */ 
1992/0630    
		s->ref--; 
1992/0702    
		if(s->ref==0 && s->qid[0]==~0){	/* uncached */ 
			bitfree(s->bits); 
			free(s->info); 
			free(s); 
			bit.subfont[i] = 0; 
		} 
	} 
1992/0628    
	return; 
1992/0621    
} 
 
void 
1992/0622    
arenafree(Arena *a) 
{ 
	xfree(a->words); 
	a->words = 0; 
} 
 
void 
1992/0209    
bitstring(GBitmap *bp, Point pt, GFont *f, uchar *p, long l, Fcode fc) 
{ 
	int full; 
	Rectangle rect; 
	ushort r; 
	GCacheinfo *c; 
 
	full = (fc==S || fc==notS);	/* for reverse-video */ 
	if(full){ 
		rect.min.y = 0; 
		rect.max.y = f->height; 
	} 
 
	while(l > 0){ 
1992/0630    
		r = BGSHORT(p); 
1992/0209    
		p += 2; 
		l -= 2; 
1992/0630    
		if(r >= f->ncache) 
1992/0211    
			continue; 
1992/0209    
		c = &f->cache[r]; 
		if(!full){ 
			rect.min.y = c->top; 
			rect.max.y = c->bottom; 
		} 
		rect.min.x = c->x; 
		rect.max.x = c->xright; 
		gbitblt(bp, Pt(pt.x+c->left, pt.y+rect.min.y), f->b, rect, fc); 
		pt.x += c->width; 
	} 
} 
 
void 
bitloadchar(GFont *f, int ci, GSubfont *subf, int si) 
{ 
	GCacheinfo *c; 
	Rectangle rect; 
	Fontchar *fi; 
1992/0219    
	int y; 
1992/0209    
 
	c = &f->cache[ci]; 
	fi = &subf->info[si]; 
1992/0219    
	/* careful about sign extension: top and bottom are uchars */ 
	y = fi->top + (f->ascent-subf->ascent); 
	if(y < 0) 
		y = 0; 
	c->top = y; 
	y = fi->bottom + (f->ascent-subf->ascent); 
	if(y < 0) 
		y = 0; 
	c->bottom = y; 
1992/0209    
	c->width = fi->width; 
	c->left = fi->left; 
	c->x = ci*f->width; 
	c->xright = c->x + ((fi+1)->x - fi->x); 
	rect.min.y = 0; 
	rect.max.y = f->height; 
	rect.min.x = c->x; 
1992/0214    
	rect.max.x = c->x+f->width; 
	gbitblt(f->b, rect.min, f->b, rect, 0); 
1992/0209    
	rect.min.x = fi->x; 
	rect.max.x = (fi+1)->x; 
1992/0219    
	rect.max.y = subf->height; 
1992/0209    
	gbitblt(f->b, Pt(c->x, f->ascent-subf->ascent), subf->bits, rect, S); 
} 
 
1990/0327    
void 
bitcompact(void) 
{ 
1992/0622    
	Arena *a, *b, *ea, *na; 
	ulong *p1, *p2, n; 
1990/0327    
 
1992/0622    
	ea = &bit.arena[bit.narena]; 
	for(a=bit.arena; a<ea; a++){ 
		if(a->words == 0) 
1990/0327    
			continue; 
1992/0622    
		/* first compact what's here */ 
		p1 = p2 = a->words; 
		while(p2 < a->wfree){ 
			n = HDR+p2[0]; 
			if(p2[2] == 0){ 
				p2 += n; 
				continue; 
			} 
			if(p1 != p2){ 
				memmove(p1, p2, n*sizeof(ulong)); 
				((GBitmap*)p1[2])->base = p1+HDR; 
			} 
			p2 += n; 
			p1 += n; 
1990/0327    
		} 
1992/0622    
		/* now pull stuff from later arena to fill this one */ 
		na = a+1; 
		while(na<ea && p1<a->words+a->nwords){ 
			p2 = na->words; 
			if(p2 == 0){ 
				na++; 
				continue; 
			} 
			while(p2 < na->wfree){ 
				n = HDR+p2[0]; 
				if(p2[2] == 0){ 
					p2 += n; 
					continue; 
				} 
				if(p1+n < a->words+a->nwords){ 
					memmove(p1, p2, n*sizeof(ulong)); 
					((GBitmap*)p1[2])->base = p1+HDR; 
					/* block now in new arena... */ 
					p1[1] = (ulong)a; 
					a->nbusy++; 
					/* ... not in old arena */ 
					na->nbusy--; 
					p2[2] = 0; 
					p1 += n; 
				} 
				p2 += n; 
			} 
			na++; 
1990/0327    
		} 
1992/0622    
		a->wfree = p1; 
1990/0327    
	} 
1992/0630    
	for(a=bit.arena; a<ea; a++) 
		if(a->words && a->nbusy==0) 
1992/0622    
			arenafree(a); 
1990/0329    
} 
 
void 
1990/05313    
Cursortocursor(Cursor *c) 
1990/0329    
{ 
1990/0504    
	int i; 
1991/0731    
	uchar *p; 
1990/0504    
 
	lock(&cursor); 
1991/0318    
	memmove(&cursor, c, sizeof(Cursor)); 
1990/0504    
	for(i=0; i<16; i++){ 
1991/0731    
		p = (uchar*)&setbits[i]; 
		*p = c->set[2*i]; 
		*(p+1) = c->set[2*i+1]; 
		p = (uchar*)&clrbits[i]; 
		*p = c->clr[2*i]; 
		*(p+1) = c->clr[2*i+1]; 
1990/0504    
	} 
	unlock(&cursor); 
} 
 
void 
cursoron(int dolock) 
{ 
	if(dolock) 
		lock(&cursor); 
	if(cursor.visible++ == 0){ 
		cursor.r.min = mouse.xy; 
		cursor.r.max = add(mouse.xy, Pt(16, 16)); 
		cursor.r = raddp(cursor.r, cursor.offset); 
1991/1225    
		gbitblt(&cursorback, Pt(0, 0), &gscreen, cursor.r, S); 
		gbitblt(&gscreen, add(mouse.xy, cursor.offset), 
1991/0706    
			&clr, Rect(0, 0, 16, 16), flipping? flipD[D&~S] : D&~S); 
1991/1225    
		gbitblt(&gscreen, add(mouse.xy, cursor.offset), 
1991/0706    
			&set, Rect(0, 0, 16, 16), flipping? flipD[S|D] : S|D); 
1990/0504    
	} 
	if(dolock) 
		unlock(&cursor); 
} 
 
void 
cursoroff(int dolock) 
{ 
	if(dolock) 
		lock(&cursor); 
	if(--cursor.visible == 0) 
1991/1225    
		gbitblt(&gscreen, cursor.r.min, &cursorback, Rect(0, 0, 16, 16), S); 
1990/0504    
	if(dolock) 
		unlock(&cursor); 
} 
 
void 
1991/0706    
mousedelta(int b, int dx, int dy)	/* called at higher priority */ 
1990/0504    
{ 
1991/0706    
	mouse.dx += dx; 
	mouse.dy += dy; 
	mouse.newbuttons = b; 
	mouse.track = 1; 
} 
 
void 
mousebuttons(int b)	/* called at higher priority */ 
{ 
1990/0505    
	/* 
	 * It is possible if you click very fast and get bad luck 
	 * you could miss a button click (down up).  Doesn't seem 
	 * likely or important enough to worry about. 
	 */ 
	mouse.newbuttons = b; 
	mouse.track = 1;		/* aggressive but o.k. */ 
	mouseclock(); 
1990/0504    
} 
 
void 
1991/0707    
mouseupdate(int dolock) 
1990/0504    
{ 
1991/0706    
	int x, y; 
1991/0707    
 
	if(!mouse.track || (dolock && !canlock(&cursor))) 
		return; 
 
	x = mouse.xy.x + mouse.dx; 
	if(x < gscreen.r.min.x) 
		x = gscreen.r.min.x; 
	if(x >= gscreen.r.max.x) 
		x = gscreen.r.max.x; 
	y = mouse.xy.y + mouse.dy; 
	if(y < gscreen.r.min.y) 
		y = gscreen.r.min.y; 
	if(y >= gscreen.r.max.y) 
		y = gscreen.r.max.y; 
	cursoroff(0); 
	mouse.xy = Pt(x, y); 
	cursoron(0); 
	mouse.dx = 0; 
	mouse.dy = 0; 
	mouse.clock = 0; 
	mouse.track = 0; 
	mouse.buttons = mouse.newbuttons; 
	mouse.changed = 1; 
 
	if(dolock){ 
1991/0423    
		unlock(&cursor); 
		wakeup(&mouse.r); 
	} 
} 
 
1991/0605    
int 
mouseputc(IOQ *q, int c) 
{ 
1991/0706    
	static short msg[5]; 
	static int nb; 
	static uchar b[] = {0, 4, 2, 6, 1, 5, 3, 7}; 
1991/0605    
 
1991/1115    
	USED(q); 
1991/0706    
	if((c&0xF0) == 0x80) 
		nb=0; 
	msg[nb] = c; 
	if(c & 0x80) 
1992/0630    
		msg[nb] |= ~0xFF;	/* sign extend */ 
1991/0706    
	if(++nb == 5){ 
		mouse.newbuttons = b[(msg[0]&7)^7]; 
		mouse.dx = msg[1]+msg[3]; 
		mouse.dy = -(msg[2]+msg[4]); 
		mouse.track = 1; 
		mouseclock(); 
		nb = 0; 
1990/0329    
	} 
1992/0522    
	return 0; 
1990/0505    
} 
 
int 
mousechanged(void *m) 
{ 
1991/1115    
	USED(m); 
1990/0505    
	return mouse.changed; 
1990/0324    
} 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)