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