12 /************************************************************************
14 ************************************************************************/
19 typedef unsigned char uchar;
23 bw_malloc(size_t size)
35 bw_malloc0(size_t size)
39 ptr = calloc(size, 1);
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)))
49 /************************************************************************
50 * Base64 implementation, from glib *
51 ************************************************************************/
53 static const char base64_alphabet[] =
54 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
57 bw_base64_encode_step (const uchar *in,
73 if (len + ((char *) save) [0] > 2)
75 const uchar *inend = in+len-2;
81 switch (((char *) save) [0])
84 c1 = ((unsigned char *) save) [1];
87 c1 = ((unsigned char *) save) [1];
88 c2 = ((unsigned char *) save) [2];
93 * yes, we jump into the loop, no i'm not going to change it,
103 *outptr++ = base64_alphabet [ c1 >> 2 ];
104 *outptr++ = base64_alphabet [ c2 >> 4 |
106 *outptr++ = base64_alphabet [ ((c2 &0x0f) << 2) |
108 *outptr++ = base64_alphabet [ c3 & 0x3f ];
109 /* this is a bit ugly ... */
110 if (break_lines && (++already) >= 19)
117 ((char *)save)[0] = 0;
118 len = 2 - (inptr - inend);
126 /* points to the slot for the next char to save */
127 saveout = & (((char *)save)[1]) + ((char *)save)[0];
129 /* len can only be 0 1 or 2 */
132 case 2: *saveout++ = *inptr++;
133 case 1: *saveout++ = *inptr++;
135 ((char *)save)[0] += len;
142 bw_base64_encode_close (boolean break_lines,
150 c1 = ((unsigned char *) save) [1];
151 c2 = ((unsigned char *) save) [2];
153 switch (((char *) save) [0])
156 outptr [2] = base64_alphabet[ ( (c2 &0x0f) << 2 ) ];
157 assert (outptr [2] != 0);
162 outptr [0] = base64_alphabet [ c1 >> 2 ];
163 outptr [1] = base64_alphabet [ c2 >> 4 | ( (c1&0x3) << 4 )];
179 base64_uint8 (uint8_t v, char *c)
181 c[0] = base64_alphabet[(v >> 0) & 0x3f];
182 c[1] = base64_alphabet[(v >> 6) & 0x3];
187 base64_uint16 (uint32_t v, char *c)
189 c[0] = base64_alphabet[(v >> 0) & 0x3f];
190 c[1] = base64_alphabet[(v >> 6) & 0x3f];
191 c[2] = base64_alphabet[(v >> 12) & 0xf];
196 base64_uint24 (uint32_t v, char *c)
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];
206 base64_uint32 (uint32_t v, char *c)
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];
216 /************************************************************************
217 * conversion of raw image data to uncompressed png data: uris *
218 ************************************************************************/
220 /* Table of CRCs of all 8-bit messages. */
221 static unsigned long crc_table[256];
223 /* Flag: has the table been computed? Initially false. */
224 static int crc_table_computed = 0;
226 /* Make the table for a fast CRC. */
233 for (n = 0; n < 256; n++) {
234 c = (unsigned long) n;
235 for (k = 0; k < 8; k++) {
237 c = 0xedb88320L ^ (c >> 1);
243 crc_table_computed = 1;
247 update_crc(unsigned long crc, unsigned char *buf, int len)
249 unsigned long c = crc;
252 if (!crc_table_computed)
254 for (n = 0; n < len; n++) {
255 c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8);
261 crc(unsigned char *buf, int len)
263 return update_crc(0xffffffffL, buf, len) ^ 0xffffffffL;
266 #define BASE 65521 /* largest prime smaller than 65536 */
268 update_adler32(unsigned long adler, unsigned char *buf, int len)
270 unsigned long s1 = adler & 0xffff;
271 unsigned long s2 = (adler >> 16) & 0xffff;
274 for (n = 0; n < len; n++) {
275 s1 = (s1 + buf[n]) % BASE;
276 s2 = (s2 + s1) % BASE;
278 return (s2 << 16) + s1;
282 to_png_rgb (int w, int h, int byte_stride, uint32_t *data)
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,
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;
293 uint8_t *png, *p, *p_row, *p_idat;
299 char *url, *url_base64;
300 int state = 0, outlen;
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));
307 row_size = 1 + w * 3;
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];
315 data_size = 2 + (6 + w * 3) * h + 4;
317 *(uint32_t *)&idat_start[0] = htonl(data_size);
319 png_size = sizeof(header) + sizeof(ihdr) + 12 + data_size + sizeof(iend);
320 png = bw_malloc (png_size);
323 memcpy (p, header, sizeof(header));
325 memcpy (p, ihdr, sizeof(ihdr));
327 memcpy (p, idat_start, sizeof(idat_start));
328 p += sizeof(idat_start);
332 zlib header: 0x78, 0x01 ,
333 h * scanline: row_header[] + width * r,g,b
346 for (y = 0; y < h; y++) {
348 row_header[0] = 1; /* final block */
349 memcpy (p, row_header, sizeof(row_header));
350 p += sizeof(row_header);
353 data += byte_stride / 4;
354 for (x = 0; x < w; x++) {
356 *p++ = (pixel >> 16) & 0xff; /* red */
357 *p++ = (pixel >> 8) & 0xff; /* green */
358 *p++ = (pixel >> 0) & 0xff; /* blue */
360 adler = update_adler32(adler, p_row, p - p_row);
364 *(uint32_t *)p = htonl(adler);
366 *(uint32_t *)p = htonl(crc(p_idat, p - p_idat));
369 memcpy (p, iend, sizeof(iend));
372 assert(p - png == png_size);
374 url = bw_malloc (strlen("data:image/png;base64,") +
375 ((png_size / 3 + 1) * 4 + 4) + 1);
376 strcpy (url, "data:image/png;base64,");
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;
389 to_png_rgba (int w, int h, int byte_stride, uint32_t *data)
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,
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;
400 uint8_t *png, *p, *p_row, *p_idat;
406 char *url, *url_base64;
407 int state = 0, outlen;
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));
414 row_size = 1 + w * 4;
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];
422 data_size = 2 + (6 + w * 4) * h + 4;
424 *(uint32_t *)&idat_start[0] = htonl(data_size);
426 png_size = sizeof(header) + sizeof(ihdr) + 12 + data_size + sizeof(iend);
427 png = bw_malloc (png_size);
430 memcpy (p, header, sizeof(header));
432 memcpy (p, ihdr, sizeof(ihdr));
434 memcpy (p, idat_start, sizeof(idat_start));
435 p += sizeof(idat_start);
439 zlib header: 0x78, 0x01 ,
440 h * scanline: row_header[] + width * r,g,b,a
453 for (y = 0; y < h; y++) {
455 row_header[0] = 1; /* final block */
456 memcpy (p, row_header, sizeof(row_header));
457 p += sizeof(row_header);
460 data += byte_stride / 4;
461 for (x = 0; x < w; x++) {
463 *p++ = (pixel >> 16) & 0xff; /* red */
464 *p++ = (pixel >> 8) & 0xff; /* green */
465 *p++ = (pixel >> 0) & 0xff; /* blue */
466 *p++ = (pixel >> 24) & 0xff; /* alpha */
468 adler = update_adler32(adler, p_row, p - p_row);
472 *(uint32_t *)p = htonl(adler);
474 *(uint32_t *)p = htonl(crc(p_idat, p - p_idat));
477 memcpy (p, iend, sizeof(iend));
480 assert(p - png == png_size);
482 url = bw_malloc (strlen("data:image/png;base64,") +
483 ((png_size / 3 + 1) * 4 + 4) + 1);
484 strcpy (url, "data:image/png;base64,");
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;
498 to_png_a (int w, int h, int byte_stride, uint8_t *data)
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,
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;
509 uint8_t *png, *p, *p_row, *p_idat;
515 char *url, *url_base64;
516 int state = 0, outlen;
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));
523 row_size = 1 + w * 2;
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];
531 data_size = 2 + (6 + w * 2) * h + 4;
533 *(uint32_t *)&idat_start[0] = htonl(data_size);
535 png_size = sizeof(header) + sizeof(ihdr) + 12 + data_size + sizeof(iend);
536 png = bw_malloc (png_size);
539 memcpy (p, header, sizeof(header));
541 memcpy (p, ihdr, sizeof(ihdr));
543 memcpy (p, idat_start, sizeof(idat_start));
544 p += sizeof(idat_start);
548 zlib header: 0x78, 0x01 ,
549 h * scanline: row_header[] + width * r,g,b,a
562 for (y = 0; y < h; y++) {
564 row_header[0] = 1; /* final block */
565 memcpy (p, row_header, sizeof(row_header));
566 p += sizeof(row_header);
569 data += byte_stride / 4;
570 for (x = 0; x < w; x++) {
572 *p++ = 0x00; /* gray */
573 *p++ = pixel; /* alpha */
575 adler = update_adler32(adler, p_row, p - p_row);
579 *(uint32_t *)p = htonl(adler);
581 *(uint32_t *)p = htonl(crc(p_idat, p - p_idat));
584 memcpy (p, iend, sizeof(iend));
587 assert(p - png == png_size);
589 url = bw_malloc (strlen("data:image/png;base64,") +
590 ((png_size / 3 + 1) * 4 + 4) + 1);
591 strcpy (url, "data:image/png;base64,");
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;
604 /************************************************************************
605 * Basic I/O primitives *
606 ************************************************************************/
608 struct BroadwayClient {
614 broadway_client_write_raw (BroadwayClient *client,
615 const void *buf, size_t count)
619 const char *ptr = (const char *)buf;
623 res = write(client->fd, ptr, count);
627 if (errsave == EINTR)
629 fprintf(stderr, "Error on write_raw to client %d\n", errsave);
634 fprintf(stderr, "Short write_raw to client\n");
643 broadway_client_write (BroadwayClient *client,
644 const void *buf, size_t count)
647 const char *ptr = (const char *)buf;
651 res = gzwrite(client->zfd, ptr, count);
654 fprintf(stderr, "Error on write to client\n");
659 fprintf(stderr, "Short write to client\n");
668 broadway_client_write_header (BroadwayClient *client)
673 "Content-type: multipart/x-mixed-replace;boundary=x\r\n"
674 "Content-Encoding: gzip\r\n"
676 broadway_client_write_raw (client,
677 header, strlen (header));
681 send_boundary (BroadwayClient *client)
687 broadway_client_write (client, boundary, strlen (boundary));
691 broadway_client_new(int fd)
693 BroadwayClient *client;
695 client = bw_new0 (BroadwayClient, 1);
699 broadway_client_write_header (client);
701 client->zfd = gzdopen(fd, "wb");
703 /* Need an initial multipart boundary */
704 send_boundary (client);
710 broadway_client_flush (BroadwayClient *client)
712 send_boundary (client);
713 gzflush (client->zfd, Z_SYNC_FLUSH);
717 /************************************************************************
718 * Core rendering operations *
719 ************************************************************************/
722 broadway_client_copy_rectangles (BroadwayClient *client, int id,
723 BroadwayRect *rects, int n_rects,
729 len = 1 + 3 + 3 + 3*4*n_rects + 3 + 3;
731 buf = bw_malloc (len);
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++)
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;
743 base64_uint16(dx, &buf[p]); p +=3;
744 base64_uint16(dy, &buf[p]); p +=3;
746 broadway_client_write (client, buf, len);
751 broadway_client_new_surface(BroadwayClient *client, int id, int x, int y, int w, int h)
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]);
762 broadway_client_write (client, buf, 16);
766 broadway_client_show_surface(BroadwayClient *client, int id)
771 base64_uint16(id, &buf[1]);
773 broadway_client_write (client, buf, 4);
777 broadway_client_hide_surface(BroadwayClient *client, int id)
782 base64_uint16(id, &buf[1]);
784 broadway_client_write (client, buf, 4);
788 broadway_client_destroy_surface(BroadwayClient *client, int id)
793 base64_uint16(id, &buf[1]);
795 broadway_client_write (client, buf, 4);
799 broadway_client_move_surface(BroadwayClient *client, int id, int x, int y)
804 base64_uint16(id, &buf[1]);
805 base64_uint16(x, &buf[4]);
806 base64_uint16(y, &buf[7]);
808 broadway_client_write (client, buf, 10);
812 broadway_client_put_rgb (BroadwayClient *client, int id, int x, int y,
813 int w, int h, int byte_stride, void *data)
820 base64_uint16(id, &buf[1]);
821 base64_uint16(x, &buf[4]);
822 base64_uint16(y, &buf[7]);
824 url = to_png_rgb (w, h, byte_stride, (uint32_t*)data);
826 base64_uint32(len, &buf[10]);
828 broadway_client_write (client, buf, 16);
830 broadway_client_write (client, url, len);
836 rgb_autocrop (unsigned char *data,
838 int *x_arg, int *y_arg,
839 int *w_arg, int *h_arg)
853 line = data + y * byte_stride + x * 4;
856 for (xx = 0; xx < w; xx++)
858 if (line[1] != 0 || line[2] != 0 || line[3] != 0) {
874 line = data + (y + h - 1) * byte_stride + x * 4;
877 for (xx = 0; xx < w; xx++)
879 if (line[1] != 0 || line[2] != 0 || line[3] != 0) {
893 line = data + y * byte_stride + x * 4;
896 for (yy = 0; yy < h; yy++)
898 if (line[1] != 0 || line[2] != 0 || line[3] != 0) {
914 line = data + y * byte_stride + (x + w - 1) * 4;
917 for (yy = 0; yy < h; yy++)
919 if (line[1] != 0 || line[2] != 0 || line[3] != 0) {
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)
951 &src_x, &src_y, &w, &h);
952 data = (uint8_t *)data + src_x * 4 + src_y * byte_stride;
955 base64_uint16(id, &buf[1]);
956 base64_uint16(dest_x + src_x, &buf[4]);
957 base64_uint16(dest_y + src_y, &buf[7]);
959 url = to_png_rgb (w, h, byte_stride, (uint32_t*)data);
961 base64_uint32(len, &buf[10]);
963 broadway_client_write (client, buf, 16);
965 broadway_client_write (client, url, len);
971 broadway_client_put_rgba (BroadwayClient *client, int id, int x, int y,
972 int w, int h, int byte_stride, void *data)
979 base64_uint16(id, &buf[1]);
980 base64_uint16(x, &buf[4]);
981 base64_uint16(y, &buf[7]);
983 url = to_png_rgba (w, h, byte_stride, (uint32_t*)data);
985 base64_uint32(len, &buf[10]);
987 broadway_client_write (client, buf, 16);
989 broadway_client_write (client, url, len);
996 send_image_a (BroadwayClient *client, int id, int x, int y,
997 int w, int h, int byte_stride, uint8_t *data)
1004 base64_uint16(id, &buf[1]);
1005 base64_uint16(x, &buf[4]);
1006 base64_uint16(y, &buf[7]);
1008 url = to_png_a (w, h, byte_stride, data);
1010 base64_uint32(len, &buf[10]);
1012 broadway_client_write (client, buf, 16);
1014 broadway_client_write (client, url, len);