]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/vnc/draw.c
fix utf and rune handling in preparation for 32bit runes
[plan9front.git] / sys / src / cmd / vnc / draw.c
1 #include "vnc.h"
2 #include "vncv.h"
3
4 static struct {
5         char    *name;
6         int     num;
7 } enctab[] = {
8         "copyrect",     EncCopyRect,
9         "corre",        EncCorre,
10         "hextile",      EncHextile,
11         "raw",          EncRaw,
12         "rre",          EncRre,
13         "mousewarp",    EncMouseWarp,
14 };
15
16 static  uchar   *pixbuf;
17 static  uchar   *linebuf;
18 static  int     vpixb;
19 static  int     pixb;
20 static  void    (*pixcp)(uchar*, uchar*);
21
22 static void
23 vncrdcolor(Vnc *v, uchar *color)
24 {
25         vncrdbytes(v, color, vpixb);
26
27         if(cvtpixels)
28                 (*cvtpixels)(color, color, 1);
29 }
30
31 void
32 sendencodings(Vnc *v)
33 {
34         char *f[10];
35         int enc[10], nenc, i, j, nf;
36
37         nf = tokenize(encodings, f, nelem(f));
38         nenc = 0;
39         for(i=0; i<nf; i++){
40                 for(j=0; j<nelem(enctab); j++)
41                         if(strcmp(f[i], enctab[j].name) == 0)
42                                 break;
43                 if(j == nelem(enctab)){
44                         print("warning: unknown encoding %s\n", f[i]);
45                         continue;
46                 }
47                 enc[nenc++] = enctab[j].num;
48         }
49
50         vnclock(v);
51         vncwrchar(v, MSetEnc);
52         vncwrchar(v, 0);
53         vncwrshort(v, nenc);
54         for(i=0; i<nenc; i++)
55                 vncwrlong(v, enc[i]);
56         vncflush(v);
57         vncunlock(v);
58 }
59
60 void
61 requestupdate(Vnc *v, int incremental)
62 {
63         int x, y;
64
65         lockdisplay(display);
66         x = Dx(screen->r);
67         y = Dy(screen->r);
68         unlockdisplay(display);
69         if(x > v->dim.x)
70                 x = v->dim.x;
71         if(y > v->dim.y)
72                 y = v->dim.y;
73         vnclock(v);
74         vncwrchar(v, MFrameReq);
75         vncwrchar(v, incremental);
76         vncwrrect(v, Rpt(ZP, Pt(x, y)));
77         vncflush(v);
78         vncunlock(v);
79 }
80
81 static Rectangle
82 clippixbuf(Rectangle r, int maxx, int maxy)
83 {
84         int y, h, stride1, stride2;
85
86         if(r.min.x > maxx || r.min.y > maxy){
87                 r.max.x = 0;
88                 return r;
89         }
90         if(r.max.y > maxy)
91                 r.max.y = maxy;
92         if(r.max.x <= maxx)
93                 return r;
94
95         stride2 = Dx(r) * pixb;
96         r.max.x = maxx;
97         stride1 = Dx(r) * pixb;
98         h = Dy(r);
99         for(y = 0; y < h; y++)
100                 memmove(&pixbuf[y * stride1], &pixbuf[y * stride2], stride1);
101
102         return r;
103 }
104
105 /* must be called with display locked */
106 static void
107 updatescreen(Rectangle r)
108 {
109         int b, bb;
110
111         lockdisplay(display);
112         if(r.max.x > Dx(screen->r) || r.max.y > Dy(screen->r)){
113                 r = clippixbuf(r, Dx(screen->r), Dy(screen->r));
114                 if(r.max.x == 0){
115                         unlockdisplay(display);
116                         return;
117                 }
118         }
119
120         /*
121          * assume load image fails only because of resize
122          */
123         b = Dx(r) * pixb * Dy(r);
124         bb = loadimage(screen, rectaddpt(r, screen->r.min), pixbuf, b);
125         if(bb != b && verbose)
126                 fprint(2, "loadimage %d on %R for %R returned %d: %r\n", b, rectaddpt(r, screen->r.min), screen->r, bb);
127         unlockdisplay(display);
128 }
129
130 static void
131 fillrect(Rectangle r, int stride, uchar *color)
132 {
133         int x, xe, y, off;
134
135         y = r.min.y;
136         off = y * stride;
137         for(; y < r.max.y; y++){
138                 xe = off + r.max.x * pixb;
139                 for(x = off + r.min.x * pixb; x < xe; x += pixb)
140                         (*pixcp)(&pixbuf[x], color);
141                 off += stride;
142         }
143 }
144
145 static void
146 loadbuf(Vnc *v, Rectangle r, int stride)
147 {
148         int off, y;
149
150         if(cvtpixels){
151                 y = r.min.y;
152                 off = y * stride;
153                 for(; y < r.max.y; y++){
154                         vncrdbytes(v, linebuf, Dx(r) * vpixb);
155                         (*cvtpixels)(&pixbuf[off + r.min.x * pixb], linebuf, Dx(r));
156                         off += stride;
157                 }
158         }else{
159                 y = r.min.y;
160                 off = y * stride;
161                 for(; y < r.max.y; y++){
162                         vncrdbytes(v, &pixbuf[off + r.min.x * pixb], Dx(r) * pixb);
163                         off += stride;
164                 }
165         }
166 }
167
168 static Rectangle
169 hexrect(ushort u)
170 {
171         int x, y, w, h;
172
173         x = u>>12;
174         y = (u>>8)&15;
175         w = ((u>>4)&15)+1;
176         h = (u&15)+1;
177
178         return Rect(x, y, x+w, y+h);
179 }
180
181
182 static void
183 dohextile(Vnc *v, Rectangle r, int stride)
184 {
185         ulong bg, fg, c;
186         int enc, nsub, sx, sy, w, h, th, tw;
187         Rectangle sr, ssr;
188
189         fg = bg = 0;
190         h = Dy(r);
191         w = Dx(r);
192         for(sy = 0; sy < h; sy += HextileDim){
193                 th = h - sy;
194                 if(th > HextileDim)
195                         th = HextileDim;
196                 for(sx = 0; sx < w; sx += HextileDim){
197                         tw = w - sx;
198                         if(tw > HextileDim)
199                                 tw = HextileDim;
200
201                         sr = Rect(sx, sy, sx + tw, sy + th);
202                         enc = vncrdchar(v);
203                         if(enc & HextileRaw){
204                                 loadbuf(v, sr, stride);
205                                 continue;
206                         }
207
208                         if(enc & HextileBack)
209                                 vncrdcolor(v, (uchar*)&bg);
210                         fillrect(sr, stride, (uchar*)&bg);
211
212                         if(enc & HextileFore)
213                                 vncrdcolor(v, (uchar*)&fg);
214
215                         if(enc & HextileRects){
216                                 nsub = vncrdchar(v);
217                                 (*pixcp)((uchar*)&c, (uchar*)&fg);
218                                 while(nsub-- > 0){
219                                         if(enc & HextileCols)
220                                                 vncrdcolor(v, (uchar*)&c);
221                                         ssr = rectaddpt(hexrect(vncrdshort(v)), sr.min);
222                                         fillrect(ssr, stride, (uchar*)&c);
223                                 }
224                         }
225                 }
226         }
227 }
228
229 static void
230 dorectangle(Vnc *v)
231 {
232         ulong type;
233         long n, stride;
234         ulong color;
235         Point p;
236         Rectangle r, subr, maxr;
237
238         r = vncrdrect(v);
239         if(r.min.x == r.max.x || r.min.y == r.max.y)
240                 return;
241         if(!rectinrect(r, Rpt(ZP, v->dim)))
242                 sysfatal("bad rectangle from server: %R not in %R", r, Rpt(ZP, v->dim));
243         stride = Dx(r) * pixb;
244         type = vncrdlong(v);
245         switch(type){
246         default:
247                 sysfatal("bad rectangle encoding from server");
248                 break;
249         case EncRaw:
250                 loadbuf(v, Rpt(ZP, Pt(Dx(r), Dy(r))), stride);
251                 updatescreen(r);
252                 break;
253
254         case EncCopyRect:
255                 p = vncrdpoint(v);
256                 lockdisplay(display);
257                 p = addpt(p, screen->r.min);
258                 r = rectaddpt(r, screen->r.min);
259                 draw(screen, r, screen, nil, p);
260                 unlockdisplay(display);
261                 break;
262
263         case EncRre:
264         case EncCorre:
265                 maxr = Rpt(ZP, Pt(Dx(r), Dy(r)));
266                 n = vncrdlong(v);
267                 vncrdcolor(v, (uchar*)&color);
268                 fillrect(maxr, stride, (uchar*)&color);
269                 while(n-- > 0){
270                         vncrdcolor(v, (uchar*)&color);
271                         if(type == EncRre)
272                                 subr = vncrdrect(v);
273                         else
274                                 subr = vncrdcorect(v);
275                         if(!rectinrect(subr, maxr))
276                                 sysfatal("bad encoding from server");
277                         fillrect(subr, stride, (uchar*)&color);
278                 }
279                 updatescreen(r);
280                 break;
281
282         case EncHextile:
283                 dohextile(v, r, stride);
284                 updatescreen(r);
285                 break;
286
287         case EncMouseWarp:
288                 mousewarp(r.min);
289                 break;
290         }
291 }
292
293 static void
294 pixcp8(uchar *dst, uchar *src)
295 {
296         *dst = *src;
297 }
298
299 static void
300 pixcp16(uchar *dst, uchar *src)
301 {
302         *(ushort*)dst = *(ushort*)src;
303 }
304
305 static void
306 pixcp32(uchar *dst, uchar *src)
307 {
308         *(ulong*)dst = *(ulong*)src;
309 }
310
311 static void
312 pixcp24(uchar *dst, uchar *src)
313 {
314         dst[0] = src[0];
315         dst[1] = src[1];
316         dst[2] = src[2];
317 }
318
319 static int
320 calcpixb(int bpp)
321 {
322         if(bpp / 8 * 8 != bpp)
323                 sysfatal("can't handle your screen");
324         return bpp / 8;
325 }
326
327 void
328 readfromserver(Vnc *v)
329 {
330         uchar type;
331         uchar junk[100];
332         long n;
333
334         vpixb = calcpixb(v->bpp);
335         pixb = calcpixb(screen->depth);
336         switch(pixb){
337         case 1:
338                 pixcp = pixcp8;
339                 break;
340         case 2:
341                 pixcp = pixcp16;
342                 break;
343         case 3:
344                 pixcp = pixcp24;
345                 break;
346         case 4:
347                 pixcp = pixcp32;
348                 break;
349         default:
350                 sysfatal("can't handle your screen: bad depth %d", pixb);
351         }
352         linebuf = malloc(v->dim.x * vpixb);
353         pixbuf = malloc(v->dim.x * pixb * v->dim.y);
354         if(linebuf == nil || pixbuf == nil)
355                 sysfatal("can't allocate pix decompression storage");
356         for(;;){
357                 type = vncrdchar(v);
358                 switch(type){
359                 default:
360                         sysfatal("bad message from server");
361                         break;
362                 case MFrameUpdate:
363                         vncrdchar(v);
364                         n = vncrdshort(v);
365                         while(n-- > 0)
366                                 dorectangle(v);
367                         flushimage(display, 1);
368                         requestupdate(v, 1);
369                         break;
370
371                 case MSetCmap:
372                         vncrdbytes(v, junk, 3);
373                         n = vncrdshort(v);
374                         vncgobble(v, n*3*2);
375                         break;
376
377                 case MBell:
378                         break;
379
380                 case MSAck:
381                         break;
382
383                 case MSCut:
384                         vncrdbytes(v, junk, 3);
385                         n = vncrdlong(v);
386                         writesnarf(v, n);
387                         break;
388                 }
389         }
390 }