xref: /plan9/sys/src/cmd/vnc/rre.c (revision f8e525ac91e3a7fae3f104837a69862dc348aa81)
19a747e4fSDavid du Colombier #include "vnc.h"
29a747e4fSDavid du Colombier #include "vncs.h"
39a747e4fSDavid du Colombier 
49a747e4fSDavid du Colombier /*
59a747e4fSDavid du Colombier  * rise and run length encoding, aka rre.
69a747e4fSDavid du Colombier  *
79a747e4fSDavid du Colombier  * the pixel contained in r are subdivided into
89a747e4fSDavid du Colombier  * rectangles of uniform color, each of which
99a747e4fSDavid du Colombier  * is encoded by <color, x, y, w, h>.
109a747e4fSDavid du Colombier  *
119a747e4fSDavid du Colombier  * use raw encoding if it's shorter.
129a747e4fSDavid du Colombier  *
139a747e4fSDavid du Colombier  * for compact rre, use limited size rectangles,
149a747e4fSDavid du Colombier  * which are shorter to encode and therefor give better compression.
159a747e4fSDavid du Colombier  *
169a747e4fSDavid du Colombier  * hextile encoding uses rre encoding on at most 16x16 rectangles tiled
179a747e4fSDavid du Colombier  * across and then down the screen.
189a747e4fSDavid du Colombier  */
199a747e4fSDavid du Colombier static int	encrre(uchar *raw, int stride, int w, int h, int back, int pixb, uchar *buf, int maxr, uchar *done, int (*eqpix)(uchar*, int, int), uchar *(putr)(uchar*, uchar*, int, int, int, int, int, int));
209a747e4fSDavid du Colombier static int	eqpix16(uchar *raw, int p1, int p2);
219a747e4fSDavid du Colombier static int	eqpix32(uchar *raw, int p1, int p2);
229a747e4fSDavid du Colombier static int	eqpix8(uchar *raw, int p1, int p2);
239a747e4fSDavid du Colombier static int	findback(uchar *raw, int stride, int w, int h, int (*eqpix)(uchar*, int, int));
249a747e4fSDavid du Colombier static uchar*	putcorre(uchar *buf, uchar *raw, int p, int pixb, int x, int y, int w, int h);
259a747e4fSDavid du Colombier static uchar*	putrre(uchar *buf, uchar *raw, int p, int pixb, int x, int y, int w, int h);
269a747e4fSDavid du Colombier static void	putpix(Vnc *v, uchar *raw, int p, int pixb);
279a747e4fSDavid du Colombier static int	hexcolors(uchar *raw, int stride, int w, int h, int (*eqpix)(uchar*, int, int), int back, int *fore);
289a747e4fSDavid du Colombier static uchar	*puthexfore(uchar *buf, uchar*, int, int, int x, int y, int w, int h);
299a747e4fSDavid du Colombier static uchar	*puthexcol(uchar *buf, uchar*, int, int, int x, int y, int w, int h);
309a747e4fSDavid du Colombier static void	sendtraw(Vnc *v, uchar *raw, int pixb, int stride, int w, int h);
319a747e4fSDavid du Colombier 
329a747e4fSDavid du Colombier /*
339a747e4fSDavid du Colombier  * default routine, no compression, just the pixels
349a747e4fSDavid du Colombier  */
35*f8e525acSDavid du Colombier int
sendraw(Vncs * v,Rectangle r)369a747e4fSDavid du Colombier sendraw(Vncs *v, Rectangle r)
379a747e4fSDavid du Colombier {
389a747e4fSDavid du Colombier 	int pixb, stride;
399a747e4fSDavid du Colombier 	uchar *raw;
409a747e4fSDavid du Colombier 
41*f8e525acSDavid du Colombier 	if(!rectinrect(r, v->image->r))
429a747e4fSDavid du Colombier 		sysfatal("sending bad rectangle");
439a747e4fSDavid du Colombier 
449a747e4fSDavid du Colombier 	pixb = v->bpp >> 3;
459a747e4fSDavid du Colombier 	if((pixb << 3) != v->bpp)
469a747e4fSDavid du Colombier 		sysfatal("bad pixel math in sendraw");
47*f8e525acSDavid du Colombier 	stride = v->image->width*sizeof(ulong);
489a747e4fSDavid du Colombier 	if(((stride / pixb) * pixb) != stride)
499a747e4fSDavid du Colombier 		sysfatal("bad pixel math in sendraw");
509a747e4fSDavid du Colombier 	stride /= pixb;
519a747e4fSDavid du Colombier 
52*f8e525acSDavid du Colombier 	raw = byteaddr(v->image, r.min);
539a747e4fSDavid du Colombier 
549a747e4fSDavid du Colombier 	vncwrrect(v, r);
559a747e4fSDavid du Colombier 	vncwrlong(v, EncRaw);
569a747e4fSDavid du Colombier 	sendtraw(v, raw, pixb, stride, Dx(r), Dy(r));
57*f8e525acSDavid du Colombier 	return 1;
58*f8e525acSDavid du Colombier }
59*f8e525acSDavid du Colombier 
60*f8e525acSDavid du Colombier int
countraw(Vncs *,Rectangle)61*f8e525acSDavid du Colombier countraw(Vncs*, Rectangle)
62*f8e525acSDavid du Colombier {
63*f8e525acSDavid du Colombier 	return 1;
649a747e4fSDavid du Colombier }
659a747e4fSDavid du Colombier 
669a747e4fSDavid du Colombier /*
679a747e4fSDavid du Colombier  * grab the image for the entire rectangle,
689a747e4fSDavid du Colombier  * then encode each tile
699a747e4fSDavid du Colombier  */
70*f8e525acSDavid du Colombier int
sendhextile(Vncs * v,Rectangle r)719a747e4fSDavid du Colombier sendhextile(Vncs *v, Rectangle r)
729a747e4fSDavid du Colombier {
739a747e4fSDavid du Colombier 	uchar *(*putr)(uchar*, uchar*, int, int, int, int, int, int);
749a747e4fSDavid du Colombier 	int (*eq)(uchar*, int, int);
759a747e4fSDavid du Colombier 	uchar *raw, *buf, *done, *traw;
769a747e4fSDavid du Colombier 	int w, h, stride, pixb, pixlg, nr, bpr, back, fore;
779a747e4fSDavid du Colombier 	int sy, sx, th, tw, oback, ofore, k, nc;
789a747e4fSDavid du Colombier 
799a747e4fSDavid du Colombier 	h = Dy(r);
809a747e4fSDavid du Colombier 	w = Dx(r);
81*f8e525acSDavid du Colombier 	if(h == 0 || w == 0 || !rectinrect(r, v->image->r))
82*f8e525acSDavid du Colombier 		sysfatal("bad rectangle %R in sendhextile %R", r, v->image->r);
839a747e4fSDavid du Colombier 
849a747e4fSDavid du Colombier 	switch(v->bpp){
859a747e4fSDavid du Colombier 	case  8:	pixlg = 0;	eq = eqpix8;	break;
869a747e4fSDavid du Colombier 	case 16:	pixlg = 1;	eq = eqpix16;	break;
879a747e4fSDavid du Colombier 	case 32:	pixlg = 2;	eq = eqpix32;	break;
889a747e4fSDavid du Colombier 	default:
899a747e4fSDavid du Colombier 		sendraw(v, r);
90*f8e525acSDavid du Colombier 		return 1;
919a747e4fSDavid du Colombier 	}
929a747e4fSDavid du Colombier 	pixb = 1 << pixlg;
93*f8e525acSDavid du Colombier 	stride = v->image->width*sizeof(ulong);
949a747e4fSDavid du Colombier 	if(((stride >> pixlg) << pixlg) != stride){
959a747e4fSDavid du Colombier 		sendraw(v, r);
96*f8e525acSDavid du Colombier 		return 1;
979a747e4fSDavid du Colombier 	}
989a747e4fSDavid du Colombier 	stride >>= pixlg;
999a747e4fSDavid du Colombier 
1009a747e4fSDavid du Colombier 	buf = malloc(HextileDim * HextileDim * pixb);
1019a747e4fSDavid du Colombier 	done = malloc(HextileDim * HextileDim);
1029a747e4fSDavid du Colombier 	if(buf == nil || done == nil){
1039a747e4fSDavid du Colombier 		free(buf);
1049a747e4fSDavid du Colombier 		free(done);
1059a747e4fSDavid du Colombier 		sendraw(v, r);
106*f8e525acSDavid du Colombier 		return 1;
1079a747e4fSDavid du Colombier 	}
108*f8e525acSDavid du Colombier 	raw = byteaddr(v->image, r.min);
1099a747e4fSDavid du Colombier 
1109a747e4fSDavid du Colombier 	vncwrrect(v, r);
1119a747e4fSDavid du Colombier 	vncwrlong(v, EncHextile);
1129a747e4fSDavid du Colombier 	oback = -1;
1139a747e4fSDavid du Colombier 	ofore = -1;
1149a747e4fSDavid du Colombier 	for(sy = 0; sy < h; sy += HextileDim){
1159a747e4fSDavid du Colombier 		th = h - sy;
1169a747e4fSDavid du Colombier 		if(th > HextileDim)
1179a747e4fSDavid du Colombier 			th = HextileDim;
1189a747e4fSDavid du Colombier 		for(sx = 0; sx < w; sx += HextileDim){
1199a747e4fSDavid du Colombier 			tw = w - sx;
1209a747e4fSDavid du Colombier 			if(tw > HextileDim)
1219a747e4fSDavid du Colombier 				tw = HextileDim;
1229a747e4fSDavid du Colombier 
1239a747e4fSDavid du Colombier 			traw = raw + ((sy * stride + sx) << pixlg);
1249a747e4fSDavid du Colombier 
1259a747e4fSDavid du Colombier 			back = findback(traw, stride, tw, th, eq);
1269a747e4fSDavid du Colombier 			nc = hexcolors(traw, stride, tw, th, eq, back, &fore);
1279a747e4fSDavid du Colombier 			k = 0;
1289a747e4fSDavid du Colombier 			if(oback < 0 || !(*eq)(raw, back + ((traw - raw) >> pixlg), oback))
1299a747e4fSDavid du Colombier 				k |= HextileBack;
1309a747e4fSDavid du Colombier 			if(nc == 1){
1319a747e4fSDavid du Colombier 				vncwrchar(v, k);
1329a747e4fSDavid du Colombier 				if(k & HextileBack){
1339a747e4fSDavid du Colombier 					oback = back + ((traw - raw) >> pixlg);
1349a747e4fSDavid du Colombier 					putpix(v, raw, oback, pixb);
1359a747e4fSDavid du Colombier 				}
1369a747e4fSDavid du Colombier 				continue;
1379a747e4fSDavid du Colombier 			}
1389a747e4fSDavid du Colombier 			k |= HextileRects;
1399a747e4fSDavid du Colombier 			if(nc == 2){
1409a747e4fSDavid du Colombier 				putr = puthexfore;
1419a747e4fSDavid du Colombier 				bpr = 2;
1429a747e4fSDavid du Colombier 				if(ofore < 0 || !(*eq)(raw, fore + ((traw - raw) >> pixlg), ofore))
1439a747e4fSDavid du Colombier 					k |= HextileFore;
1449a747e4fSDavid du Colombier 			}else{
1459a747e4fSDavid du Colombier 				putr = puthexcol;
1469a747e4fSDavid du Colombier 				bpr = 2 + pixb;
1479a747e4fSDavid du Colombier 				k |= HextileCols;
1489a747e4fSDavid du Colombier 				/* stupid vnc clients smash foreground in this case */
1499a747e4fSDavid du Colombier 				ofore = -1;
1509a747e4fSDavid du Colombier 			}
1519a747e4fSDavid du Colombier 
1529a747e4fSDavid du Colombier 			nr = th * tw << pixlg;
1539a747e4fSDavid du Colombier 			if(k & HextileBack)
1549a747e4fSDavid du Colombier 				nr -= pixb;
1559a747e4fSDavid du Colombier 			if(k & HextileFore)
1569a747e4fSDavid du Colombier 				nr -= pixb;
1579a747e4fSDavid du Colombier 			nr /= bpr;
1589a747e4fSDavid du Colombier 			memset(done, 0, HextileDim * HextileDim);
1599a747e4fSDavid du Colombier 			nr = encrre(traw, stride, tw, th, back, pixb, buf, nr, done, eq, putr);
1609a747e4fSDavid du Colombier 			if(nr < 0){
1619a747e4fSDavid du Colombier 				vncwrchar(v, HextileRaw);
1629a747e4fSDavid du Colombier 				sendtraw(v, traw, pixb, stride, tw, th);
1639a747e4fSDavid du Colombier 				/* stupid vnc clients smash colors in this case */
1649a747e4fSDavid du Colombier 				ofore = -1;
1659a747e4fSDavid du Colombier 				oback = -1;
1669a747e4fSDavid du Colombier 			}else{
1679a747e4fSDavid du Colombier 				vncwrchar(v, k);
1689a747e4fSDavid du Colombier 				if(k & HextileBack){
1699a747e4fSDavid du Colombier 					oback = back + ((traw - raw) >> pixlg);
1709a747e4fSDavid du Colombier 					putpix(v, raw, oback, pixb);
1719a747e4fSDavid du Colombier 				}
1729a747e4fSDavid du Colombier 				if(k & HextileFore){
1739a747e4fSDavid du Colombier 					ofore = fore + ((traw - raw) >> pixlg);
1749a747e4fSDavid du Colombier 					putpix(v, raw, ofore, pixb);
1759a747e4fSDavid du Colombier 				}
1769a747e4fSDavid du Colombier 				vncwrchar(v, nr);
1779a747e4fSDavid du Colombier 				vncwrbytes(v, buf, nr * bpr);
1789a747e4fSDavid du Colombier 			}
1799a747e4fSDavid du Colombier 		}
1809a747e4fSDavid du Colombier 	}
1819a747e4fSDavid du Colombier 	free(buf);
1829a747e4fSDavid du Colombier 	free(done);
183*f8e525acSDavid du Colombier 	return 1;
184*f8e525acSDavid du Colombier }
185*f8e525acSDavid du Colombier 
186*f8e525acSDavid du Colombier int
counthextile(Vncs *,Rectangle)187*f8e525acSDavid du Colombier counthextile(Vncs*, Rectangle)
188*f8e525acSDavid du Colombier {
189*f8e525acSDavid du Colombier 	return 1;
1909a747e4fSDavid du Colombier }
1919a747e4fSDavid du Colombier 
1929a747e4fSDavid du Colombier static int
hexcolors(uchar * raw,int stride,int w,int h,int (* eqpix)(uchar *,int,int),int back,int * rfore)1939a747e4fSDavid du Colombier hexcolors(uchar *raw, int stride, int w, int h, int (*eqpix)(uchar*, int, int), int back, int *rfore)
1949a747e4fSDavid du Colombier {
1959a747e4fSDavid du Colombier 	int s, es, sx, esx, fore;
1969a747e4fSDavid du Colombier 
1979a747e4fSDavid du Colombier 	*rfore = -1;
1989a747e4fSDavid du Colombier 	fore = -1;
1999a747e4fSDavid du Colombier 	es = stride * h;
2009a747e4fSDavid du Colombier 	for(s = 0; s < es; s += stride){
2019a747e4fSDavid du Colombier 		esx = s + w;
2029a747e4fSDavid du Colombier 		for(sx = s; sx < esx; sx++){
2039a747e4fSDavid du Colombier 			if((*eqpix)(raw, back, sx))
2049a747e4fSDavid du Colombier 				continue;
2059a747e4fSDavid du Colombier 			if(fore < 0){
2069a747e4fSDavid du Colombier 				fore = sx;
2079a747e4fSDavid du Colombier 				*rfore = fore;
2089a747e4fSDavid du Colombier 			}else if(!(*eqpix)(raw, fore, sx))
2099a747e4fSDavid du Colombier 				return 3;
2109a747e4fSDavid du Colombier 		}
2119a747e4fSDavid du Colombier 	}
2129a747e4fSDavid du Colombier 
2139a747e4fSDavid du Colombier 	if(fore < 0)
2149a747e4fSDavid du Colombier 		return 1;
2159a747e4fSDavid du Colombier 	return 2;
2169a747e4fSDavid du Colombier }
2179a747e4fSDavid du Colombier 
2189a747e4fSDavid du Colombier static uchar*
puthexcol(uchar * buf,uchar * raw,int p,int pixb,int x,int y,int w,int h)2199a747e4fSDavid du Colombier puthexcol(uchar *buf, uchar *raw, int p, int pixb, int x, int y, int w, int h)
2209a747e4fSDavid du Colombier {
2219a747e4fSDavid du Colombier 	raw += p * pixb;
2229a747e4fSDavid du Colombier 	while(pixb--)
2239a747e4fSDavid du Colombier 		*buf++ = *raw++;
2249a747e4fSDavid du Colombier 	*buf++ = (x << 4) | y;
2259a747e4fSDavid du Colombier 	*buf++ = (w - 1) << 4 | (h - 1);
2269a747e4fSDavid du Colombier 	return buf;
2279a747e4fSDavid du Colombier }
2289a747e4fSDavid du Colombier 
2299a747e4fSDavid du Colombier static uchar*
puthexfore(uchar * buf,uchar *,int,int,int x,int y,int w,int h)2309a747e4fSDavid du Colombier puthexfore(uchar *buf, uchar*, int, int, int x, int y, int w, int h)
2319a747e4fSDavid du Colombier {
2329a747e4fSDavid du Colombier 	*buf++ = (x << 4) | y;
2339a747e4fSDavid du Colombier 	*buf++ = (w - 1) << 4 | (h - 1);
2349a747e4fSDavid du Colombier 	return buf;
2359a747e4fSDavid du Colombier }
2369a747e4fSDavid du Colombier 
2379a747e4fSDavid du Colombier static void
sendtraw(Vnc * v,uchar * raw,int pixb,int stride,int w,int h)2389a747e4fSDavid du Colombier sendtraw(Vnc *v, uchar *raw, int pixb, int stride, int w, int h)
2399a747e4fSDavid du Colombier {
2409a747e4fSDavid du Colombier 	int y;
2419a747e4fSDavid du Colombier 
2429a747e4fSDavid du Colombier 	for(y = 0; y < h; y++)
2439a747e4fSDavid du Colombier 		vncwrbytes(v, &raw[y * stride * pixb], w * pixb);
2449a747e4fSDavid du Colombier }
2459a747e4fSDavid du Colombier 
246*f8e525acSDavid du Colombier static int
rrerects(Rectangle r,int split)2479a747e4fSDavid du Colombier rrerects(Rectangle r, int split)
2489a747e4fSDavid du Colombier {
2499a747e4fSDavid du Colombier 	return ((Dy(r) + split - 1) / split) * ((Dx(r) + split - 1) / split);
2509a747e4fSDavid du Colombier }
2519a747e4fSDavid du Colombier 
252*f8e525acSDavid du Colombier enum
253*f8e525acSDavid du Colombier {
254*f8e525acSDavid du Colombier 	MaxCorreDim	= 48,
255*f8e525acSDavid du Colombier 	MaxRreDim	= 64,
256*f8e525acSDavid du Colombier };
257*f8e525acSDavid du Colombier 
2589a747e4fSDavid du Colombier int
countrre(Vncs *,Rectangle r)259*f8e525acSDavid du Colombier countrre(Vncs*, Rectangle r)
260*f8e525acSDavid du Colombier {
261*f8e525acSDavid du Colombier 	return rrerects(r, MaxRreDim);
262*f8e525acSDavid du Colombier }
263*f8e525acSDavid du Colombier 
264*f8e525acSDavid du Colombier int
countcorre(Vncs *,Rectangle r)265*f8e525acSDavid du Colombier countcorre(Vncs*, Rectangle r)
266*f8e525acSDavid du Colombier {
267*f8e525acSDavid du Colombier 	return rrerects(r, MaxCorreDim);
268*f8e525acSDavid du Colombier }
269*f8e525acSDavid du Colombier 
270*f8e525acSDavid du Colombier static int
_sendrre(Vncs * v,Rectangle r,int split,int compact)271*f8e525acSDavid du Colombier _sendrre(Vncs *v, Rectangle r, int split, int compact)
2729a747e4fSDavid du Colombier {
2739a747e4fSDavid du Colombier 	uchar *raw, *buf, *done;
2749a747e4fSDavid du Colombier 	int w, h, stride, pixb, pixlg, nraw, nr, bpr, back, totr;
2759a747e4fSDavid du Colombier 	int (*eq)(uchar*, int, int);
2769a747e4fSDavid du Colombier 
2779a747e4fSDavid du Colombier 	totr = 0;
2789a747e4fSDavid du Colombier 	h = Dy(r);
2799a747e4fSDavid du Colombier 	while(h > split){
2809a747e4fSDavid du Colombier 		h = r.max.y;
2819a747e4fSDavid du Colombier 		r.max.y = r.min.y + split;
282*f8e525acSDavid du Colombier 		totr += _sendrre(v, r, split, compact);
2839a747e4fSDavid du Colombier 		r.min.y = r.max.y;
2849a747e4fSDavid du Colombier 		r.max.y = h;
2859a747e4fSDavid du Colombier 		h = Dy(r);
2869a747e4fSDavid du Colombier 	}
2879a747e4fSDavid du Colombier 	w = Dx(r);
2889a747e4fSDavid du Colombier 	while(w > split){
2899a747e4fSDavid du Colombier 		w = r.max.x;
2909a747e4fSDavid du Colombier 		r.max.x = r.min.x + split;
291*f8e525acSDavid du Colombier 		totr += _sendrre(v, r, split, compact);
2929a747e4fSDavid du Colombier 		r.min.x = r.max.x;
2939a747e4fSDavid du Colombier 		r.max.x = w;
2949a747e4fSDavid du Colombier 		w = Dx(r);
2959a747e4fSDavid du Colombier 	}
296*f8e525acSDavid du Colombier 	if(h == 0 || w == 0 || !rectinrect(r, v->image->r))
2979a747e4fSDavid du Colombier 		sysfatal("bad rectangle in sendrre");
2989a747e4fSDavid du Colombier 
2999a747e4fSDavid du Colombier 	switch(v->bpp){
3009a747e4fSDavid du Colombier 	case  8:	pixlg = 0;	eq = eqpix8;	break;
3019a747e4fSDavid du Colombier 	case 16:	pixlg = 1;	eq = eqpix16;	break;
3029a747e4fSDavid du Colombier 	case 32:	pixlg = 2;	eq = eqpix32;	break;
3039a747e4fSDavid du Colombier 	default:
3049a747e4fSDavid du Colombier 		sendraw(v, r);
3059a747e4fSDavid du Colombier 		return totr + 1;
3069a747e4fSDavid du Colombier 	}
3079a747e4fSDavid du Colombier 	pixb = 1 << pixlg;
308*f8e525acSDavid du Colombier 	stride = v->image->width*sizeof(ulong);
3099a747e4fSDavid du Colombier 	if(((stride >> pixlg) << pixlg) != stride){
3109a747e4fSDavid du Colombier 		sendraw(v, r);
3119a747e4fSDavid du Colombier 		return totr + 1;
3129a747e4fSDavid du Colombier 	}
3139a747e4fSDavid du Colombier 	stride >>= pixlg;
3149a747e4fSDavid du Colombier 
3159a747e4fSDavid du Colombier 	nraw = w * pixb * h;
3169a747e4fSDavid du Colombier 	buf = malloc(nraw);
3179a747e4fSDavid du Colombier 	done = malloc(w * h);
3189a747e4fSDavid du Colombier 	if(buf == nil || done == nil){
3199a747e4fSDavid du Colombier 		free(buf);
3209a747e4fSDavid du Colombier 		free(done);
3219a747e4fSDavid du Colombier 		sendraw(v, r);
3229a747e4fSDavid du Colombier 		return totr + 1;
3239a747e4fSDavid du Colombier 	}
3249a747e4fSDavid du Colombier 	memset(done, 0, w * h);
3259a747e4fSDavid du Colombier 
326*f8e525acSDavid du Colombier 	raw = byteaddr(v->image, r.min);
3279a747e4fSDavid du Colombier 
3289a747e4fSDavid du Colombier 	if(compact)
3299a747e4fSDavid du Colombier 		bpr = 4 * 1 + pixb;
3309a747e4fSDavid du Colombier 	else
3319a747e4fSDavid du Colombier 		bpr = 4 * 2 + pixb;
3329a747e4fSDavid du Colombier 	nr = (nraw - 4 - pixb) / bpr;
3339a747e4fSDavid du Colombier 	back = findback(raw, stride, w, h, eq);
3349a747e4fSDavid du Colombier 	if(compact)
3359a747e4fSDavid du Colombier 		nr = encrre(raw, stride, w, h, back, pixb, buf, nr, done, eq, putcorre);
3369a747e4fSDavid du Colombier 	else
3379a747e4fSDavid du Colombier 		nr = encrre(raw, stride, w, h, back, pixb, buf, nr, done, eq, putrre);
3389a747e4fSDavid du Colombier 	if(nr < 0){
3399a747e4fSDavid du Colombier 		vncwrrect(v, r);
3409a747e4fSDavid du Colombier 		vncwrlong(v, EncRaw);
3419a747e4fSDavid du Colombier 		sendtraw(v, raw, pixb, stride, w, h);
3429a747e4fSDavid du Colombier 	}else{
3439a747e4fSDavid du Colombier 		vncwrrect(v, r);
3449a747e4fSDavid du Colombier 		if(compact)
3459a747e4fSDavid du Colombier 			vncwrlong(v, EncCorre);
3469a747e4fSDavid du Colombier 		else
3479a747e4fSDavid du Colombier 			vncwrlong(v, EncRre);
3489a747e4fSDavid du Colombier 		vncwrlong(v, nr);
3499a747e4fSDavid du Colombier 		putpix(v, raw, back, pixb);
3509a747e4fSDavid du Colombier 		vncwrbytes(v, buf, nr * bpr);
3519a747e4fSDavid du Colombier 	}
3529a747e4fSDavid du Colombier 	free(buf);
3539a747e4fSDavid du Colombier 	free(done);
3549a747e4fSDavid du Colombier 
3559a747e4fSDavid du Colombier 	return totr + 1;
3569a747e4fSDavid du Colombier }
3579a747e4fSDavid du Colombier 
358*f8e525acSDavid du Colombier int
sendrre(Vncs * v,Rectangle r)359*f8e525acSDavid du Colombier sendrre(Vncs *v, Rectangle r)
360*f8e525acSDavid du Colombier {
361*f8e525acSDavid du Colombier 	return _sendrre(v, r, MaxRreDim, 0);
362*f8e525acSDavid du Colombier }
363*f8e525acSDavid du Colombier 
364*f8e525acSDavid du Colombier int
sendcorre(Vncs * v,Rectangle r)365*f8e525acSDavid du Colombier sendcorre(Vncs *v, Rectangle r)
366*f8e525acSDavid du Colombier {
367*f8e525acSDavid du Colombier 	return _sendrre(v, r, MaxCorreDim, 1);
368*f8e525acSDavid du Colombier }
369*f8e525acSDavid du Colombier 
3709a747e4fSDavid du Colombier static int
encrre(uchar * raw,int stride,int w,int h,int back,int pixb,uchar * buf,int maxr,uchar * done,int (* eqpix)(uchar *,int,int),uchar * (* putr)(uchar *,uchar *,int,int,int,int,int,int))371*f8e525acSDavid du Colombier encrre(uchar *raw, int stride, int w, int h, int back, int pixb, uchar *buf,
372*f8e525acSDavid du Colombier 	int maxr, uchar *done, int (*eqpix)(uchar*, int, int),
373*f8e525acSDavid du Colombier 	uchar *(*putr)(uchar*, uchar*, int, int, int, int, int, int))
3749a747e4fSDavid du Colombier {
3759a747e4fSDavid du Colombier 	int s, es, sx, esx, sy, syx, esyx, rh, rw, y, nr, dsy, dp;
3769a747e4fSDavid du Colombier 
3779a747e4fSDavid du Colombier 	es = stride * h;
3789a747e4fSDavid du Colombier 	y = 0;
3799a747e4fSDavid du Colombier 	nr = 0;
3809a747e4fSDavid du Colombier 	dp = 0;
3819a747e4fSDavid du Colombier 	for(s = 0; s < es; s += stride){
3829a747e4fSDavid du Colombier 		esx = s + w;
3839a747e4fSDavid du Colombier 		for(sx = s; sx < esx; ){
3849a747e4fSDavid du Colombier 			rw = done[dp];
3859a747e4fSDavid du Colombier 			if(rw){
3869a747e4fSDavid du Colombier 				sx += rw;
3879a747e4fSDavid du Colombier 				dp += rw;
3889a747e4fSDavid du Colombier 				continue;
3899a747e4fSDavid du Colombier 			}
3909a747e4fSDavid du Colombier 			if((*eqpix)(raw, back, sx)){
3919a747e4fSDavid du Colombier 				sx++;
3929a747e4fSDavid du Colombier 				dp++;
3939a747e4fSDavid du Colombier 				continue;
3949a747e4fSDavid du Colombier 			}
3959a747e4fSDavid du Colombier 
3969a747e4fSDavid du Colombier 			if(nr >= maxr)
3979a747e4fSDavid du Colombier 				return -1;
3989a747e4fSDavid du Colombier 
3999a747e4fSDavid du Colombier 			/*
4009a747e4fSDavid du Colombier 			 * find the tallest maximally wide uniform colored rectangle
4019a747e4fSDavid du Colombier 			 * with p at the upper left.
4029a747e4fSDavid du Colombier 			 * this isn't an optimal parse, but it's pretty good for text
4039a747e4fSDavid du Colombier 			 */
4049a747e4fSDavid du Colombier 			rw = esx - sx;
4059a747e4fSDavid du Colombier 			rh = 0;
4069a747e4fSDavid du Colombier 			for(sy = sx; sy < es; sy += stride){
4079a747e4fSDavid du Colombier 				if(!(*eqpix)(raw, sx, sy))
4089a747e4fSDavid du Colombier 					break;
4099a747e4fSDavid du Colombier 				esyx = sy + rw;
4109a747e4fSDavid du Colombier 				for(syx = sy + 1; syx < esyx; syx++){
4119a747e4fSDavid du Colombier 					if(!(*eqpix)(raw, sx, syx)){
4129a747e4fSDavid du Colombier 						if(sy == sx)
4139a747e4fSDavid du Colombier 							break;
4149a747e4fSDavid du Colombier 						goto breakout;
4159a747e4fSDavid du Colombier 					}
4169a747e4fSDavid du Colombier 				}
4179a747e4fSDavid du Colombier 				if(sy == sx)
4189a747e4fSDavid du Colombier 					rw = syx - sy;
4199a747e4fSDavid du Colombier 				rh++;
4209a747e4fSDavid du Colombier 			}
4219a747e4fSDavid du Colombier 		breakout:;
4229a747e4fSDavid du Colombier 
4239a747e4fSDavid du Colombier 			nr++;
4249a747e4fSDavid du Colombier 			buf = (*putr)(buf, raw, sx, pixb, sx - s, y, rw, rh);
4259a747e4fSDavid du Colombier 
4269a747e4fSDavid du Colombier 			/*
4279a747e4fSDavid du Colombier 			 * mark all pixels done
4289a747e4fSDavid du Colombier 			 */
4299a747e4fSDavid du Colombier 			dsy = dp;
4309a747e4fSDavid du Colombier 			while(rh--){
4319a747e4fSDavid du Colombier 				esyx = dsy + rw;
4329a747e4fSDavid du Colombier 				for(syx = dsy; syx < esyx; syx++)
4339a747e4fSDavid du Colombier 					done[syx] = esyx - syx;
4349a747e4fSDavid du Colombier 				dsy += w;
4359a747e4fSDavid du Colombier 			}
4369a747e4fSDavid du Colombier 
4379a747e4fSDavid du Colombier 			sx += rw;
4389a747e4fSDavid du Colombier 			dp += rw;
4399a747e4fSDavid du Colombier 		}
4409a747e4fSDavid du Colombier 		y++;
4419a747e4fSDavid du Colombier 	}
4429a747e4fSDavid du Colombier 	return nr;
4439a747e4fSDavid du Colombier }
4449a747e4fSDavid du Colombier 
4459a747e4fSDavid du Colombier /*
4469a747e4fSDavid du Colombier  * estimate the background color
4479a747e4fSDavid du Colombier  * by finding the most frequent character in a small sample
4489a747e4fSDavid du Colombier  */
4499a747e4fSDavid du Colombier static int
findback(uchar * raw,int stride,int w,int h,int (* eqpix)(uchar *,int,int))4509a747e4fSDavid du Colombier findback(uchar *raw, int stride, int w, int h, int (*eqpix)(uchar*, int, int))
4519a747e4fSDavid du Colombier {
4529a747e4fSDavid du Colombier 	enum{
4539a747e4fSDavid du Colombier 		NCol = 6,
4549a747e4fSDavid du Colombier 		NExamine = 4
4559a747e4fSDavid du Colombier 	};
4569a747e4fSDavid du Colombier 	int ccount[NCol], col[NCol], i, wstep, hstep, x, y, pix, c, max, maxc;
4579a747e4fSDavid du Colombier 
4589a747e4fSDavid du Colombier 	wstep = w / NExamine;
4599a747e4fSDavid du Colombier 	if(wstep < 1)
4609a747e4fSDavid du Colombier 		wstep = 1;
4619a747e4fSDavid du Colombier 	hstep = h / NExamine;
4629a747e4fSDavid du Colombier 	if(hstep < 1)
4639a747e4fSDavid du Colombier 		hstep = 1;
4649a747e4fSDavid du Colombier 
4659a747e4fSDavid du Colombier 	for(i = 0; i< NCol; i++)
4669a747e4fSDavid du Colombier 		ccount[i] = 0;
4679a747e4fSDavid du Colombier 	for(y = 0; y < h; y += hstep){
4689a747e4fSDavid du Colombier 		for(x = 0; x < w; x += wstep){
4699a747e4fSDavid du Colombier 			pix = y * stride + x;
4709a747e4fSDavid du Colombier 			for(i = 0; i < NCol; i++){
4719a747e4fSDavid du Colombier 				if(ccount[i] == 0){
4729a747e4fSDavid du Colombier 					ccount[i] = 1;
4739a747e4fSDavid du Colombier 					col[i] = pix;
4749a747e4fSDavid du Colombier 					break;
4759a747e4fSDavid du Colombier 				}
4769a747e4fSDavid du Colombier 				if((*eqpix)(raw, pix, col[i])){
4779a747e4fSDavid du Colombier 					ccount[i]++;
4789a747e4fSDavid du Colombier 					break;
4799a747e4fSDavid du Colombier 				}
4809a747e4fSDavid du Colombier 			}
4819a747e4fSDavid du Colombier 		}
4829a747e4fSDavid du Colombier 	}
4839a747e4fSDavid du Colombier 	maxc = ccount[0];
4849a747e4fSDavid du Colombier 	max = 0;
4859a747e4fSDavid du Colombier 	for(i = 1; i < NCol; i++){
4869a747e4fSDavid du Colombier 		c = ccount[i];
4879a747e4fSDavid du Colombier 		if(!c)
4889a747e4fSDavid du Colombier 			break;
4899a747e4fSDavid du Colombier 		if(c > maxc){
4909a747e4fSDavid du Colombier 			max = i;
4919a747e4fSDavid du Colombier 			maxc = c;
4929a747e4fSDavid du Colombier 		}
4939a747e4fSDavid du Colombier 	}
4949a747e4fSDavid du Colombier 	return col[max];
4959a747e4fSDavid du Colombier }
4969a747e4fSDavid du Colombier 
4979a747e4fSDavid du Colombier static uchar*
putrre(uchar * buf,uchar * raw,int p,int pixb,int x,int y,int w,int h)4989a747e4fSDavid du Colombier putrre(uchar *buf, uchar *raw, int p, int pixb, int x, int y, int w, int h)
4999a747e4fSDavid du Colombier {
5009a747e4fSDavid du Colombier 	raw += p * pixb;
5019a747e4fSDavid du Colombier 	while(pixb--)
5029a747e4fSDavid du Colombier 		*buf++ = *raw++;
5039a747e4fSDavid du Colombier 	*buf++ = x >> 8;
5049a747e4fSDavid du Colombier 	*buf++ = x;
5059a747e4fSDavid du Colombier 	*buf++ = y >> 8;
5069a747e4fSDavid du Colombier 	*buf++ = y;
5079a747e4fSDavid du Colombier 	*buf++ = w >> 8;
5089a747e4fSDavid du Colombier 	*buf++ = w;
5099a747e4fSDavid du Colombier 	*buf++ = h >> 8;
5109a747e4fSDavid du Colombier 	*buf++ = h;
5119a747e4fSDavid du Colombier 	return buf;
5129a747e4fSDavid du Colombier }
5139a747e4fSDavid du Colombier 
5149a747e4fSDavid du Colombier static uchar*
putcorre(uchar * buf,uchar * raw,int p,int pixb,int x,int y,int w,int h)5159a747e4fSDavid du Colombier putcorre(uchar *buf, uchar *raw, int p, int pixb, int x, int y, int w, int h)
5169a747e4fSDavid du Colombier {
5179a747e4fSDavid du Colombier 	raw += p * pixb;
5189a747e4fSDavid du Colombier 	while(pixb--)
5199a747e4fSDavid du Colombier 		*buf++ = *raw++;
5209a747e4fSDavid du Colombier 	*buf++ = x;
5219a747e4fSDavid du Colombier 	*buf++ = y;
5229a747e4fSDavid du Colombier 	*buf++ = w;
5239a747e4fSDavid du Colombier 	*buf++ = h;
5249a747e4fSDavid du Colombier 	return buf;
5259a747e4fSDavid du Colombier }
5269a747e4fSDavid du Colombier 
5279a747e4fSDavid du Colombier static int
eqpix8(uchar * raw,int p1,int p2)5289a747e4fSDavid du Colombier eqpix8(uchar *raw, int p1, int p2)
5299a747e4fSDavid du Colombier {
5309a747e4fSDavid du Colombier 	return raw[p1] == raw[p2];
5319a747e4fSDavid du Colombier }
5329a747e4fSDavid du Colombier 
5339a747e4fSDavid du Colombier static int
eqpix16(uchar * raw,int p1,int p2)5349a747e4fSDavid du Colombier eqpix16(uchar *raw, int p1, int p2)
5359a747e4fSDavid du Colombier {
5369a747e4fSDavid du Colombier 	return ((ushort*)raw)[p1] == ((ushort*)raw)[p2];
5379a747e4fSDavid du Colombier }
5389a747e4fSDavid du Colombier 
5399a747e4fSDavid du Colombier static int
eqpix32(uchar * raw,int p1,int p2)5409a747e4fSDavid du Colombier eqpix32(uchar *raw, int p1, int p2)
5419a747e4fSDavid du Colombier {
5429a747e4fSDavid du Colombier 	return ((ulong*)raw)[p1] == ((ulong*)raw)[p2];
5439a747e4fSDavid du Colombier }
5449a747e4fSDavid du Colombier 
5459a747e4fSDavid du Colombier static void
putpix(Vnc * v,uchar * raw,int p,int pixb)5469a747e4fSDavid du Colombier putpix(Vnc *v, uchar *raw, int p, int pixb)
5479a747e4fSDavid du Colombier {
5489a747e4fSDavid du Colombier 	vncwrbytes(v, raw + p * pixb, pixb);
5499a747e4fSDavid du Colombier }
550