]> Pileus Git - ~andy/gtk/blob - gdk/broadway/broadway.c
[broadway] Import broadway lib
[~andy/gtk] / gdk / broadway / broadway.c
1 #include <string.h>
2 #include <stdint.h>
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <assert.h>
6 #include <errno.h>
7 #include <arpa/inet.h>
8 #include <zlib.h>
9
10 #include "broadway.h"
11
12 /************************************************************************
13  *                Basic helpers                                         *
14  ************************************************************************/
15
16 #define TRUE 1
17 #define FALSE 0
18
19 typedef unsigned char uchar;
20 typedef int boolean;
21
22 static void *
23 bw_malloc(size_t size)
24 {
25   void *ptr;
26
27   ptr = malloc(size);
28   if (ptr == NULL)
29     exit(1);
30
31   return ptr;
32 }
33
34 static void *
35 bw_malloc0(size_t size)
36 {
37   void *ptr;
38
39   ptr = calloc(size, 1);
40   if (ptr == NULL)
41     exit(1);
42
43   return ptr;
44 }
45
46 #define bw_new(struct_type, n_structs) (bw_malloc(sizeof(struct_type) * (n_structs)))
47 #define bw_new0(struct_type, n_structs) (bw_malloc0(sizeof(struct_type) * (n_structs)))
48
49 /************************************************************************
50  *                Base64 implementation, from glib                      *
51  ************************************************************************/
52
53 static const char base64_alphabet[] =
54         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
55
56 static size_t
57 bw_base64_encode_step (const uchar *in,
58                        size_t         len,
59                        boolean      break_lines,
60                        char        *out,
61                        int         *state,
62                        int         *save)
63 {
64   char *outptr;
65   const uchar *inptr;
66
67   if (len <= 0)
68     return 0;
69
70   inptr = in;
71   outptr = out;
72
73   if (len + ((char *) save) [0] > 2)
74     {
75       const uchar *inend = in+len-2;
76       int c1, c2, c3;
77       int already;
78
79       already = *state;
80
81       switch (((char *) save) [0])
82         {
83         case 1:
84           c1 = ((unsigned char *) save) [1];
85           goto skip1;
86         case 2:
87           c1 = ((unsigned char *) save) [1];
88           c2 = ((unsigned char *) save) [2];
89           goto skip2;
90         }
91
92       /*
93        * yes, we jump into the loop, no i'm not going to change it,
94        * it's beautiful!
95        */
96       while (inptr < inend)
97         {
98           c1 = *inptr++;
99         skip1:
100           c2 = *inptr++;
101         skip2:
102           c3 = *inptr++;
103           *outptr++ = base64_alphabet [ c1 >> 2 ];
104           *outptr++ = base64_alphabet [ c2 >> 4 |
105                                         ((c1&0x3) << 4) ];
106           *outptr++ = base64_alphabet [ ((c2 &0x0f) << 2) |
107                                         (c3 >> 6) ];
108           *outptr++ = base64_alphabet [ c3 & 0x3f ];
109           /* this is a bit ugly ... */
110           if (break_lines && (++already) >= 19)
111             {
112               *outptr++ = '\n';
113               already = 0;
114             }
115         }
116
117       ((char *)save)[0] = 0;
118       len = 2 - (inptr - inend);
119       *state = already;
120     }
121
122   if (len>0)
123     {
124       char *saveout;
125
126       /* points to the slot for the next char to save */
127       saveout = & (((char *)save)[1]) + ((char *)save)[0];
128
129       /* len can only be 0 1 or 2 */
130       switch(len)
131         {
132         case 2: *saveout++ = *inptr++;
133         case 1: *saveout++ = *inptr++;
134         }
135       ((char *)save)[0] += len;
136     }
137
138   return outptr - out;
139 }
140
141 static size_t
142 bw_base64_encode_close (boolean  break_lines,
143                         char    *out,
144                         int     *state,
145                         int     *save)
146 {
147   int c1, c2;
148   char *outptr = out;
149
150   c1 = ((unsigned char *) save) [1];
151   c2 = ((unsigned char *) save) [2];
152
153   switch (((char *) save) [0])
154     {
155     case 2:
156       outptr [2] = base64_alphabet[ ( (c2 &0x0f) << 2 ) ];
157       assert (outptr [2] != 0);
158       goto skip;
159     case 1:
160       outptr[2] = '=';
161     skip:
162       outptr [0] = base64_alphabet [ c1 >> 2 ];
163       outptr [1] = base64_alphabet [ c2 >> 4 | ( (c1&0x3) << 4 )];
164       outptr [3] = '=';
165       outptr += 4;
166       break;
167     }
168   if (break_lines)
169     *outptr++ = '\n';
170
171   *save = 0;
172   *state = 0;
173
174   return outptr - out;
175 }
176
177 #if 0
178 static void
179 base64_uint8 (uint8_t v, char *c)
180 {
181   c[0] = base64_alphabet[(v >> 0) & 0x3f];
182   c[1] = base64_alphabet[(v >> 6) & 0x3];
183 }
184 #endif
185
186 static void
187 base64_uint16 (uint32_t v, char *c)
188 {
189   c[0] = base64_alphabet[(v >> 0) & 0x3f];
190   c[1] = base64_alphabet[(v >> 6) & 0x3f];
191   c[2] = base64_alphabet[(v >> 12) & 0xf];
192 }
193
194 #if 0
195 static void
196 base64_uint24 (uint32_t v, char *c)
197 {
198   c[0] = base64_alphabet[(v >> 0) & 0x3f];
199   c[1] = base64_alphabet[(v >> 6) & 0x3f];
200   c[2] = base64_alphabet[(v >> 12) & 0x3f];
201   c[3] = base64_alphabet[(v >> 18) & 0x3f];
202 }
203 #endif
204
205 static void
206 base64_uint32 (uint32_t v, char *c)
207 {
208   c[0] = base64_alphabet[(v >> 0) & 0x3f];
209   c[1] = base64_alphabet[(v >> 6) & 0x3f];
210   c[2] = base64_alphabet[(v >> 12) & 0x3f];
211   c[3] = base64_alphabet[(v >> 18) & 0x3f];
212   c[4] = base64_alphabet[(v >> 24) & 0x3f];
213   c[5] = base64_alphabet[(v >> 30) & 0x2];
214 }
215
216 /************************************************************************
217  *  conversion of raw image data to uncompressed png data: uris         *
218  ************************************************************************/
219
220 /* Table of CRCs of all 8-bit messages. */
221 static unsigned long crc_table[256];
222
223 /* Flag: has the table been computed? Initially false. */
224 static int crc_table_computed = 0;
225
226 /* Make the table for a fast CRC. */
227 static void
228 make_crc_table(void)
229 {
230   unsigned long c;
231   int n, k;
232
233   for (n = 0; n < 256; n++) {
234     c = (unsigned long) n;
235     for (k = 0; k < 8; k++) {
236       if (c & 1)
237         c = 0xedb88320L ^ (c >> 1);
238       else
239         c = c >> 1;
240     }
241     crc_table[n] = c;
242   }
243   crc_table_computed = 1;
244 }
245
246 static unsigned long
247 update_crc(unsigned long crc, unsigned char *buf, int len)
248 {
249   unsigned long c = crc;
250   int n;
251
252   if (!crc_table_computed)
253     make_crc_table();
254   for (n = 0; n < len; n++) {
255     c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8);
256   }
257   return c;
258 }
259
260 static unsigned long
261 crc(unsigned char *buf, int len)
262 {
263   return update_crc(0xffffffffL, buf, len) ^ 0xffffffffL;
264 }
265
266 #define BASE 65521 /* largest prime smaller than 65536 */
267 static unsigned long
268 update_adler32(unsigned long adler, unsigned char *buf, int len)
269 {
270   unsigned long s1 = adler & 0xffff;
271   unsigned long s2 = (adler >> 16) & 0xffff;
272   int n;
273
274   for (n = 0; n < len; n++) {
275     s1 = (s1 + buf[n]) % BASE;
276     s2 = (s2 + s1)     % BASE;
277   }
278   return (s2 << 16) + s1;
279 }
280
281 static char *
282 to_png_rgb (int w, int h, int byte_stride, uint32_t *data)
283 {
284   uchar header[] = {137, 80, 78, 71, 13, 10, 26, 10};
285   uchar ihdr[13+12] = {0, 0, 0, 13, 'I', 'H', 'D', 'R',
286                         /* w: */ 0, 0, 0, 0, /* h: */ 0,0,0,0,
287                         /* bpp: */ 8, /* color type: */ 2,
288                         0, 0, 0};
289   uchar idat_start[8] = { /* len: */0, 0, 0, 0,   'I', 'D', 'A', 'T' };
290   uchar iend[12] = {0, 0, 0, 0, 'I', 'E', 'N', 'D', 0xae, 0x42, 0x60, 0x82};
291   size_t data_size, row_size;
292   char row_header[6];
293   uint8_t *png, *p, *p_row, *p_idat;
294   uint32_t *row;
295   unsigned long adler;
296   uint32_t pixel;
297   size_t png_size;
298   int x, y;
299   char *url, *url_base64;
300   int state = 0, outlen;
301   int save = 0;
302
303   *(uint32_t *)&ihdr[8] = htonl(w);
304   *(uint32_t *)&ihdr[12] = htonl(h);
305   *(uint32_t *)&ihdr[21] = htonl(crc(&ihdr[4], 13 + 4));
306
307   row_size = 1 + w * 3;
308   row_header[0] = 0;
309   row_header[1] = row_size & 0xff;
310   row_header[2] = (row_size >> 8) & 0xff;
311   row_header[3] = ~row_header[1];
312   row_header[4] = ~row_header[2];
313   row_header[5] = 0;
314
315   data_size = 2 + (6 + w * 3) * h + 4;
316
317   *(uint32_t *)&idat_start[0] = htonl(data_size);
318
319   png_size = sizeof(header) + sizeof(ihdr) + 12 + data_size + sizeof(iend);
320   png = bw_malloc (png_size);
321
322   p = png;
323   memcpy (p, header, sizeof(header));
324   p += sizeof(header);
325   memcpy (p, ihdr, sizeof(ihdr));
326   p += sizeof(ihdr);
327   memcpy (p, idat_start, sizeof(idat_start));
328   p += sizeof(idat_start);
329
330   /* IDAT data:
331
332      zlib header:  0x78, 0x01 ,
333      h * scanline: row_header[] + width * r,g,b
334      checksum: adler32
335   */
336
337   p_idat = p - 4;
338
339   /* zlib header */
340   *p++ = 0x78;
341   *p++ = 0x01;
342
343   adler = 1;
344
345   /* scanline data */
346   for (y = 0; y < h; y++) {
347     if (y == h - 1)
348       row_header[0] = 1; /* final block */
349     memcpy (p, row_header, sizeof(row_header));
350     p += sizeof(row_header);
351     p_row = p - 1;
352     row = data;
353     data += byte_stride / 4;
354     for (x = 0; x < w; x++) {
355       pixel = *row++;
356       *p++ = (pixel >> 16) & 0xff; /* red */
357       *p++ = (pixel >> 8) & 0xff; /* green */
358       *p++ = (pixel >> 0) & 0xff; /* blue */
359     }
360     adler = update_adler32(adler, p_row, p - p_row);
361   }
362
363   /* adler32 */
364   *(uint32_t *)p = htonl(adler);
365   p += 4;
366   *(uint32_t *)p = htonl(crc(p_idat, p - p_idat));
367   p += 4;
368
369   memcpy (p, iend, sizeof(iend));
370   p += sizeof(iend);
371
372   assert(p - png == png_size);
373
374   url = bw_malloc (strlen("data:image/png;base64,") +
375                    ((png_size / 3 + 1) * 4 + 4) + 1);
376   strcpy (url, "data:image/png;base64,");
377
378   url_base64 = url + strlen("data:image/png;base64,");
379   outlen = bw_base64_encode_step (png, png_size, FALSE, url_base64, &state, &save);
380   outlen += bw_base64_encode_close (FALSE, url_base64 + outlen, &state, &save);
381   url_base64[outlen] = 0;
382
383   free (png);
384
385   return url;
386 }
387
388 static char *
389 to_png_rgba (int w, int h, int byte_stride, uint32_t *data)
390 {
391   uchar header[] = {137, 80, 78, 71, 13, 10, 26, 10};
392   uchar ihdr[13+12] = {0, 0, 0, 13, 'I', 'H', 'D', 'R',
393                         /* w: */ 0, 0, 0, 0, /* h: */ 0,0,0,0,
394                         /* bpp: */ 8, /* color type: */ 6,
395                         0, 0, 0};
396   uchar idat_start[8] = { /* len: */0, 0, 0, 0,   'I', 'D', 'A', 'T' };
397   uchar iend[12] = {0, 0, 0, 0, 'I', 'E', 'N', 'D', 0xae, 0x42, 0x60, 0x82};
398   size_t data_size, row_size;
399   char row_header[6];
400   uint8_t *png, *p, *p_row, *p_idat;
401   uint32_t *row;
402   unsigned long adler;
403   uint32_t pixel;
404   size_t png_size;
405   int x, y;
406   char *url, *url_base64;
407   int state = 0, outlen;
408   int save = 0;
409
410   *(uint32_t *)&ihdr[8] = htonl(w);
411   *(uint32_t *)&ihdr[12] = htonl(h);
412   *(uint32_t *)&ihdr[21] = htonl(crc(&ihdr[4], 13 + 4));
413
414   row_size = 1 + w * 4;
415   row_header[0] = 0;
416   row_header[1] = row_size & 0xff;
417   row_header[2] = (row_size >> 8) & 0xff;
418   row_header[3] = ~row_header[1];
419   row_header[4] = ~row_header[2];
420   row_header[5] = 0;
421
422   data_size = 2 + (6 + w * 4) * h + 4;
423
424   *(uint32_t *)&idat_start[0] = htonl(data_size);
425
426   png_size = sizeof(header) + sizeof(ihdr) + 12 + data_size + sizeof(iend);
427   png = bw_malloc (png_size);
428
429   p = png;
430   memcpy (p, header, sizeof(header));
431   p += sizeof(header);
432   memcpy (p, ihdr, sizeof(ihdr));
433   p += sizeof(ihdr);
434   memcpy (p, idat_start, sizeof(idat_start));
435   p += sizeof(idat_start);
436
437   /* IDAT data:
438
439      zlib header:  0x78, 0x01 ,
440      h * scanline: row_header[] + width * r,g,b,a
441      checksum: adler32
442   */
443
444   p_idat = p - 4;
445
446   /* zlib header */
447   *p++ = 0x78;
448   *p++ = 0x01;
449
450   adler = 1;
451
452   /* scanline data */
453   for (y = 0; y < h; y++) {
454     if (y == h - 1)
455       row_header[0] = 1; /* final block */
456     memcpy (p, row_header, sizeof(row_header));
457     p += sizeof(row_header);
458     p_row = p - 1;
459     row = data;
460     data += byte_stride / 4;
461     for (x = 0; x < w; x++) {
462       pixel = *row++;
463       *p++ = (pixel >> 16) & 0xff; /* red */
464       *p++ = (pixel >> 8) & 0xff; /* green */
465       *p++ = (pixel >> 0) & 0xff; /* blue */
466       *p++ = (pixel >> 24) & 0xff; /* alpha */
467     }
468     adler = update_adler32(adler, p_row, p - p_row);
469   }
470
471   /* adler32 */
472   *(uint32_t *)p = htonl(adler);
473   p += 4;
474   *(uint32_t *)p = htonl(crc(p_idat, p - p_idat));
475   p += 4;
476
477   memcpy (p, iend, sizeof(iend));
478   p += sizeof(iend);
479
480   assert(p - png == png_size);
481
482   url = bw_malloc (strlen("data:image/png;base64,") +
483                    ((png_size / 3 + 1) * 4 + 4) + 1);
484   strcpy (url, "data:image/png;base64,");
485
486   url_base64 = url + strlen("data:image/png;base64,");
487   outlen = bw_base64_encode_step (png, png_size, FALSE, url_base64, &state, &save);
488   outlen += bw_base64_encode_close (FALSE, url_base64 + outlen, &state, &save);
489   url_base64[outlen] = 0;
490
491   free (png);
492
493   return url;
494 }
495
496 #if 0
497 static char *
498 to_png_a (int w, int h, int byte_stride, uint8_t *data)
499 {
500   uchar header[] = {137, 80, 78, 71, 13, 10, 26, 10};
501   uchar ihdr[13+12] = {0, 0, 0, 13, 'I', 'H', 'D', 'R',
502                         /* w: */ 0, 0, 0, 0, /* h: */ 0,0,0,0,
503                         /* bpp: */ 8, /* color type: */ 4,
504                         0, 0, 0};
505   uchar idat_start[8] = { /* len: */0, 0, 0, 0,   'I', 'D', 'A', 'T' };
506   uchar iend[12] = {0, 0, 0, 0, 'I', 'E', 'N', 'D', 0xae, 0x42, 0x60, 0x82};
507   size_t data_size, row_size;
508   char row_header[6];
509   uint8_t *png, *p, *p_row, *p_idat;
510   uint8_t *row;
511   unsigned long adler;
512   uint32_t pixel;
513   size_t png_size;
514   int x, y;
515   char *url, *url_base64;
516   int state = 0, outlen;
517   int save = 0;
518
519   *(uint32_t *)&ihdr[8] = htonl(w);
520   *(uint32_t *)&ihdr[12] = htonl(h);
521   *(uint32_t *)&ihdr[21] = htonl(crc(&ihdr[4], 13 + 4));
522
523   row_size = 1 + w * 2;
524   row_header[0] = 0;
525   row_header[1] = row_size & 0xff;
526   row_header[2] = (row_size >> 8) & 0xff;
527   row_header[3] = ~row_header[1];
528   row_header[4] = ~row_header[2];
529   row_header[5] = 0;
530
531   data_size = 2 + (6 + w * 2) * h + 4;
532
533   *(uint32_t *)&idat_start[0] = htonl(data_size);
534
535   png_size = sizeof(header) + sizeof(ihdr) + 12 + data_size + sizeof(iend);
536   png = bw_malloc (png_size);
537
538   p = png;
539   memcpy (p, header, sizeof(header));
540   p += sizeof(header);
541   memcpy (p, ihdr, sizeof(ihdr));
542   p += sizeof(ihdr);
543   memcpy (p, idat_start, sizeof(idat_start));
544   p += sizeof(idat_start);
545
546   /* IDAT data:
547
548      zlib header:  0x78, 0x01 ,
549      h * scanline: row_header[] + width * r,g,b,a
550      checksum: adler32
551   */
552
553   p_idat = p - 4;
554
555   /* zlib header */
556   *p++ = 0x78;
557   *p++ = 0x01;
558
559   adler = 1;
560
561   /* scanline data */
562   for (y = 0; y < h; y++) {
563     if (y == h - 1)
564       row_header[0] = 1; /* final block */
565     memcpy (p, row_header, sizeof(row_header));
566     p += sizeof(row_header);
567     p_row = p - 1;
568     row = data;
569     data += byte_stride / 4;
570     for (x = 0; x < w; x++) {
571       pixel = *row++;
572       *p++ = 0x00; /* gray */
573       *p++ = pixel; /* alpha */
574     }
575     adler = update_adler32(adler, p_row, p - p_row);
576   }
577
578   /* adler32 */
579   *(uint32_t *)p = htonl(adler);
580   p += 4;
581   *(uint32_t *)p = htonl(crc(p_idat, p - p_idat));
582   p += 4;
583
584   memcpy (p, iend, sizeof(iend));
585   p += sizeof(iend);
586
587   assert(p - png == png_size);
588
589   url = bw_malloc (strlen("data:image/png;base64,") +
590                   ((png_size / 3 + 1) * 4 + 4) + 1);
591   strcpy (url, "data:image/png;base64,");
592
593   url_base64 = url + strlen("data:image/png;base64,");
594   outlen = bw_base64_encode_step (png, png_size, FALSE, url_base64, &state, &save);
595   outlen += bw_base64_encode_close (FALSE, url_base64 + outlen, &state, &save);
596   url_base64[outlen] = 0;
597
598   free (png);
599
600   return url;
601 }
602 #endif
603
604 /************************************************************************
605  *                Basic I/O primitives                                  *
606  ************************************************************************/
607
608 struct BroadwayClient {
609   int fd;
610   gzFile *zfd;
611 } ;
612
613 static void
614 broadway_client_write_raw (BroadwayClient *client,
615                            const void *buf, size_t count)
616 {
617   ssize_t res;
618   int errsave;
619   const char *ptr = (const char *)buf;
620
621   while (count > 0)
622     {
623       res = write(client->fd, ptr, count);
624       if (res == -1)
625         {
626           errsave = errno;
627           if (errsave == EINTR)
628             continue;
629           fprintf(stderr, "Error on write_raw to client %d\n", errsave);
630           exit(1);
631         }
632       if (res == 0)
633         {
634           fprintf(stderr, "Short write_raw to client\n");
635           exit(1);
636         }
637       count -= res;
638       ptr += res;
639     }
640 }
641
642 static void
643 broadway_client_write (BroadwayClient *client,
644                        const void *buf, size_t count)
645 {
646   ssize_t res;
647   const char *ptr = (const char *)buf;
648
649   while (count > 0)
650     {
651       res = gzwrite(client->zfd, ptr, count);
652       if (res == -1)
653         {
654           fprintf(stderr, "Error on write to client\n");
655           exit(1);
656         }
657       if (res == 0)
658         {
659           fprintf(stderr, "Short write to client\n");
660           exit(1);
661         }
662       count -= res;
663       ptr += res;
664     }
665 }
666
667 static void
668 broadway_client_write_header (BroadwayClient *client)
669 {
670   char *header;
671
672   header =
673     "Content-type: multipart/x-mixed-replace;boundary=x\r\n"
674     "Content-Encoding: gzip\r\n"
675     "\r\n";
676   broadway_client_write_raw (client,
677                              header, strlen (header));
678 }
679
680 static void
681 send_boundary (BroadwayClient *client)
682 {
683   char *boundary =
684     "--x\r\n"
685     "\r\n";
686
687   broadway_client_write (client, boundary, strlen (boundary));
688 }
689
690 BroadwayClient *
691 broadway_client_new(int fd)
692 {
693   BroadwayClient *client;
694
695   client = bw_new0 (BroadwayClient, 1);
696
697   client->fd = fd;
698
699   broadway_client_write_header (client);
700
701   client->zfd = gzdopen(fd, "wb");
702
703   /* Need an initial multipart boundary */
704   send_boundary (client);
705
706   return client;
707 }
708
709 void
710 broadway_client_flush (BroadwayClient *client)
711 {
712   send_boundary (client);
713   gzflush (client->zfd, Z_SYNC_FLUSH);
714 }
715
716
717 /************************************************************************
718  *                     Core rendering operations                        *
719  ************************************************************************/
720
721 void
722 broadway_client_copy_rectangles (BroadwayClient *client,  int id,
723                                  BroadwayRect *rects, int n_rects,
724                                  int dx, int dy)
725 {
726   char *buf;
727   int len, i, p;
728
729   len = 1 + 3 + 3 + 3*4*n_rects + 3 + 3;
730
731   buf = bw_malloc (len);
732   p = 0;
733   buf[p++] = 'b';
734   base64_uint16(id, &buf[p]); p +=3;
735   base64_uint16(n_rects, &buf[p]); p +=3;
736   for (i = 0; i < n_rects; i++)
737     {
738       base64_uint16(rects[i].x, &buf[p]); p +=3;
739       base64_uint16(rects[i].y, &buf[p]); p +=3;
740       base64_uint16(rects[i].width, &buf[p]); p +=3;
741       base64_uint16(rects[i].height, &buf[p]); p +=3;
742     }
743   base64_uint16(dx, &buf[p]); p +=3;
744   base64_uint16(dy, &buf[p]); p +=3;
745
746   broadway_client_write (client, buf, len);
747   free (buf);
748 }
749
750 void
751 broadway_client_new_surface(BroadwayClient *client,  int id, int x, int y, int w, int h)
752 {
753   char buf[16];
754
755   buf[0] = 's';
756   base64_uint16(id, &buf[1]);
757   base64_uint16(x, &buf[4]);
758   base64_uint16(y, &buf[7]);
759   base64_uint16(w, &buf[10]);
760   base64_uint16(h, &buf[13]);
761
762   broadway_client_write (client, buf, 16);
763 }
764
765 void
766 broadway_client_show_surface(BroadwayClient *client,  int id)
767 {
768   char buf[4];
769
770   buf[0] = 'S';
771   base64_uint16(id, &buf[1]);
772
773   broadway_client_write (client, buf, 4);
774 }
775
776 void
777 broadway_client_hide_surface(BroadwayClient *client,  int id)
778 {
779   char buf[4];
780
781   buf[0] = 'H';
782   base64_uint16(id, &buf[1]);
783
784   broadway_client_write (client, buf, 4);
785 }
786
787 void
788 broadway_client_destroy_surface(BroadwayClient *client,  int id)
789 {
790   char buf[4];
791
792   buf[0] = 'd';
793   base64_uint16(id, &buf[1]);
794
795   broadway_client_write (client, buf, 4);
796 }
797
798 void
799 broadway_client_move_surface(BroadwayClient *client,  int id, int x, int y)
800 {
801   char buf[10];
802
803   buf[0] = 'm';
804   base64_uint16(id, &buf[1]);
805   base64_uint16(x, &buf[4]);
806   base64_uint16(y, &buf[7]);
807
808   broadway_client_write (client, buf, 10);
809 }
810
811 void
812 broadway_client_put_rgb (BroadwayClient *client,  int id, int x, int y,
813                          int w, int h, int byte_stride, void *data)
814 {
815   char buf[16];
816   size_t len;
817   char *url;
818
819   buf[0] = 'i';
820   base64_uint16(id, &buf[1]);
821   base64_uint16(x, &buf[4]);
822   base64_uint16(y, &buf[7]);
823
824   url = to_png_rgb (w, h, byte_stride, (uint32_t*)data);
825   len = strlen (url);
826   base64_uint32(len, &buf[10]);
827
828   broadway_client_write (client, buf, 16);
829
830   broadway_client_write (client, url, len);
831
832   free (url);
833 }
834
835 static void
836 rgb_autocrop (unsigned char *data,
837               int byte_stride,
838               int *x_arg, int *y_arg,
839               int *w_arg, int *h_arg)
840 {
841   unsigned char *line;
842   int w, h;
843   int x, y, xx, yy;
844   boolean non_zero;
845
846   x = *x_arg;
847   y = *y_arg;
848   w = *w_arg;
849   h = *h_arg;
850
851   while (h > 0)
852     {
853       line = data + y * byte_stride + x * 4;
854
855       non_zero = FALSE;
856       for (xx = 0; xx < w; xx++)
857         {
858           if (line[1] != 0 || line[2] != 0 || line[3] != 0) {
859             non_zero = TRUE;
860             break;
861           }
862           line += 4;
863         }
864
865       if (non_zero)
866         break;
867
868       y++;
869       h--;
870     }
871
872   while (h > 0)
873     {
874       line = data + (y + h - 1) * byte_stride + x * 4;
875
876       non_zero = FALSE;
877       for (xx = 0; xx < w; xx++)
878         {
879           if (line[1] != 0 || line[2] != 0 || line[3] != 0) {
880             non_zero = TRUE;
881             break;
882           }
883           line += 4;
884         }
885
886       if (non_zero)
887         break;
888       h--;
889     }
890
891   while (w > 0)
892     {
893       line = data + y * byte_stride + x * 4;
894
895       non_zero = FALSE;
896       for (yy = 0; yy < h; yy++)
897         {
898           if (line[1] != 0 || line[2] != 0 || line[3] != 0) {
899             non_zero = TRUE;
900             break;
901           }
902           line += byte_stride;
903         }
904
905       if (non_zero)
906         break;
907
908       x++;
909       w--;
910     }
911
912   while (w > 0)
913     {
914       line = data + y * byte_stride + (x + w - 1) * 4;
915
916       non_zero = FALSE;
917       for (yy = 0; yy < h; yy++)
918         {
919           if (line[1] != 0 || line[2] != 0 || line[3] != 0) {
920             non_zero = TRUE;
921             break;
922           }
923           line += byte_stride;
924         }
925
926       if (non_zero)
927         break;
928       w--;
929     }
930
931     *x_arg = x;
932     *y_arg = y;
933     *w_arg = w;
934     *h_arg = h;
935 }
936
937 void
938 broadway_client_put_delta_rgb (BroadwayClient *client,  int id, int dest_x, int dest_y,
939                                int w, int h, int byte_stride, void *data)
940 {
941   char buf[16];
942   size_t len;
943   char *url;
944   int src_x, src_y;
945
946   src_x = 0;
947   src_y = 0;
948
949   rgb_autocrop (data,
950                 byte_stride,
951                 &src_x, &src_y, &w, &h);
952   data = (uint8_t *)data + src_x * 4 + src_y * byte_stride;
953
954   buf[0] = 'D';
955   base64_uint16(id, &buf[1]);
956   base64_uint16(dest_x + src_x, &buf[4]);
957   base64_uint16(dest_y + src_y, &buf[7]);
958
959   url = to_png_rgb (w, h, byte_stride, (uint32_t*)data);
960   len = strlen (url);
961   base64_uint32(len, &buf[10]);
962
963   broadway_client_write (client, buf, 16);
964
965   broadway_client_write (client, url, len);
966
967   free (url);
968 }
969
970 void
971 broadway_client_put_rgba (BroadwayClient *client,  int id, int x, int y,
972                           int w, int h, int byte_stride, void *data)
973 {
974   char buf[16];
975   size_t len;
976   char *url;
977
978   buf[0] = 'i';
979   base64_uint16(id, &buf[1]);
980   base64_uint16(x, &buf[4]);
981   base64_uint16(y, &buf[7]);
982
983   url = to_png_rgba (w, h, byte_stride, (uint32_t*)data);
984   len = strlen (url);
985   base64_uint32(len, &buf[10]);
986
987   broadway_client_write (client, buf, 16);
988
989   broadway_client_write (client, url, len);
990
991   free (url);
992 }
993
994 #if 0
995 static void
996 send_image_a (BroadwayClient *client,  int id, int x, int y,
997               int w, int h, int byte_stride, uint8_t *data)
998 {
999   char buf[16];
1000   size_t len;
1001   char *url;
1002
1003   buf[0] = 'i';
1004   base64_uint16(id, &buf[1]);
1005   base64_uint16(x, &buf[4]);
1006   base64_uint16(y, &buf[7]);
1007
1008   url = to_png_a (w, h, byte_stride, data);
1009   len = strlen (url);
1010   base64_uint32(len, &buf[10]);
1011
1012   broadway_client_write (client, buf, 16);
1013
1014   broadway_client_write (client, url, len);
1015
1016   free (url);
1017 }
1018 #endif