8 #include <sys/socket.h>
9 #include <netinet/in.h>
10 #include <netinet/tcp.h>
14 /************************************************************************
16 ************************************************************************/
18 static const char base64_alphabet[] =
19 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
21 #if 0 /* Unused for now */
23 base64_uint8 (guint8 v, char *c)
25 c[0] = base64_alphabet[(v >> 0) & 0x3f];
26 c[1] = base64_alphabet[(v >> 6) & 0x3];
31 base64_uint16 (guint32 v, char *c)
33 c[0] = base64_alphabet[(v >> 0) & 0x3f];
34 c[1] = base64_alphabet[(v >> 6) & 0x3f];
35 c[2] = base64_alphabet[(v >> 12) & 0xf];
40 base64_uint24 (guint32 v, char *c)
42 c[0] = base64_alphabet[(v >> 0) & 0x3f];
43 c[1] = base64_alphabet[(v >> 6) & 0x3f];
44 c[2] = base64_alphabet[(v >> 12) & 0x3f];
45 c[3] = base64_alphabet[(v >> 18) & 0x3f];
50 base64_uint32 (guint32 v, char *c)
52 c[0] = base64_alphabet[(v >> 0) & 0x3f];
53 c[1] = base64_alphabet[(v >> 6) & 0x3f];
54 c[2] = base64_alphabet[(v >> 12) & 0x3f];
55 c[3] = base64_alphabet[(v >> 18) & 0x3f];
56 c[4] = base64_alphabet[(v >> 24) & 0x3f];
57 c[5] = base64_alphabet[(v >> 30) & 0x2];
60 /************************************************************************
61 * conversion of raw image data to uncompressed png data: uris *
62 ************************************************************************/
64 /* Table of CRCs of all 8-bit messages. */
65 static unsigned long crc_table[256];
67 /* Flag: has the table been computed? Initially false. */
68 static int crc_table_computed = 0;
70 /* Make the table for a fast CRC. */
77 for (n = 0; n < 256; n++) {
78 c = (unsigned long) n;
79 for (k = 0; k < 8; k++) {
81 c = 0xedb88320L ^ (c >> 1);
87 crc_table_computed = 1;
91 update_crc(unsigned long crc, unsigned char *buf, int len)
93 unsigned long c = crc;
96 if (!crc_table_computed)
98 for (n = 0; n < len; n++) {
99 c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8);
105 crc(unsigned char *buf, int len)
107 return update_crc(0xffffffffL, buf, len) ^ 0xffffffffL;
110 #define BASE 65521 /* largest prime smaller than 65536 */
112 update_adler32(unsigned long adler, unsigned char *buf, int len)
114 unsigned long s1 = adler & 0xffff;
115 unsigned long s2 = (adler >> 16) & 0xffff;
118 for (n = 0; n < len; n++) {
119 s1 = (s1 + buf[n]) % BASE;
120 s2 = (s2 + s1) % BASE;
122 return (s2 << 16) + s1;
126 to_png_rgb (int w, int h, int byte_stride, guint32 *data)
128 guchar header[] = {137, 80, 78, 71, 13, 10, 26, 10};
129 guchar ihdr[13+12] = {0, 0, 0, 13, 'I', 'H', 'D', 'R',
130 /* w: */ 0, 0, 0, 0, /* h: */ 0,0,0,0,
131 /* bpp: */ 8, /* color type: */ 2,
133 guchar idat_start[8] = { /* len: */0, 0, 0, 0, 'I', 'D', 'A', 'T' };
134 guchar iend[12] = {0, 0, 0, 0, 'I', 'E', 'N', 'D', 0xae, 0x42, 0x60, 0x82};
135 gsize data_size, row_size;
137 guint8 *png, *p, *p_row, *p_idat;
143 char *url, *url_base64;
144 int state = 0, outlen;
147 *(guint32 *)&ihdr[8] = GUINT32_TO_BE(w);
148 *(guint32 *)&ihdr[12] = GUINT32_TO_BE(h);
149 *(guint32 *)&ihdr[21] = GUINT32_TO_BE(crc(&ihdr[4], 13 + 4));
151 row_size = 1 + w * 3;
153 row_header[1] = row_size & 0xff;
154 row_header[2] = (row_size >> 8) & 0xff;
155 row_header[3] = ~row_header[1];
156 row_header[4] = ~row_header[2];
159 data_size = 2 + (6 + w * 3) * h + 4;
161 *(guint32 *)&idat_start[0] = GUINT32_TO_BE(data_size);
163 png_size = sizeof(header) + sizeof(ihdr) + 12 + data_size + sizeof(iend);
164 png = g_malloc (png_size);
167 memcpy (p, header, sizeof(header));
169 memcpy (p, ihdr, sizeof(ihdr));
171 memcpy (p, idat_start, sizeof(idat_start));
172 p += sizeof(idat_start);
176 zlib header: 0x78, 0x01 ,
177 h * scanline: row_header[] + width * r,g,b
190 for (y = 0; y < h; y++) {
192 row_header[0] = 1; /* final block */
193 memcpy (p, row_header, sizeof(row_header));
194 p += sizeof(row_header);
197 data += byte_stride / 4;
198 for (x = 0; x < w; x++) {
200 *p++ = (pixel >> 16) & 0xff; /* red */
201 *p++ = (pixel >> 8) & 0xff; /* green */
202 *p++ = (pixel >> 0) & 0xff; /* blue */
204 adler = update_adler32(adler, p_row, p - p_row);
208 *(guint32 *)p = GUINT32_TO_BE(adler);
210 *(guint32 *)p = GUINT32_TO_BE(crc(p_idat, p - p_idat));
213 memcpy (p, iend, sizeof(iend));
216 assert(p - png == png_size);
218 url = g_malloc (strlen("data:image/png;base64,") +
219 ((png_size / 3 + 1) * 4 + 4) + 1);
220 strcpy (url, "data:image/png;base64,");
222 url_base64 = url + strlen("data:image/png;base64,");
223 outlen = g_base64_encode_step (png, png_size, FALSE, url_base64, &state, &save);
224 outlen += g_base64_encode_close (FALSE, url_base64 + outlen, &state, &save);
225 url_base64[outlen] = 0;
233 to_png_rgba (int w, int h, int byte_stride, guint32 *data)
235 guchar header[] = {137, 80, 78, 71, 13, 10, 26, 10};
236 guchar ihdr[13+12] = {0, 0, 0, 13, 'I', 'H', 'D', 'R',
237 /* w: */ 0, 0, 0, 0, /* h: */ 0,0,0,0,
238 /* bpp: */ 8, /* color type: */ 6,
240 guchar idat_start[8] = { /* len: */0, 0, 0, 0, 'I', 'D', 'A', 'T' };
241 guchar iend[12] = {0, 0, 0, 0, 'I', 'E', 'N', 'D', 0xae, 0x42, 0x60, 0x82};
242 gsize data_size, row_size;
244 guint8 *png, *p, *p_row, *p_idat;
250 char *url, *url_base64;
251 int state = 0, outlen;
254 *(guint32 *)&ihdr[8] = GUINT32_TO_BE(w);
255 *(guint32 *)&ihdr[12] = GUINT32_TO_BE(h);
256 *(guint32 *)&ihdr[21] = GUINT32_TO_BE(crc(&ihdr[4], 13 + 4));
258 row_size = 1 + w * 4;
260 row_header[1] = row_size & 0xff;
261 row_header[2] = (row_size >> 8) & 0xff;
262 row_header[3] = ~row_header[1];
263 row_header[4] = ~row_header[2];
266 data_size = 2 + (6 + w * 4) * h + 4;
268 *(guint32 *)&idat_start[0] = GUINT32_TO_BE(data_size);
270 png_size = sizeof(header) + sizeof(ihdr) + 12 + data_size + sizeof(iend);
271 png = g_malloc (png_size);
274 memcpy (p, header, sizeof(header));
276 memcpy (p, ihdr, sizeof(ihdr));
278 memcpy (p, idat_start, sizeof(idat_start));
279 p += sizeof(idat_start);
283 zlib header: 0x78, 0x01 ,
284 h * scanline: row_header[] + width * r,g,b,a
297 for (y = 0; y < h; y++) {
299 row_header[0] = 1; /* final block */
300 memcpy (p, row_header, sizeof(row_header));
301 p += sizeof(row_header);
304 data += byte_stride / 4;
305 for (x = 0; x < w; x++) {
307 *p++ = (pixel >> 16) & 0xff; /* red */
308 *p++ = (pixel >> 8) & 0xff; /* green */
309 *p++ = (pixel >> 0) & 0xff; /* blue */
310 *p++ = (pixel >> 24) & 0xff; /* alpha */
312 adler = update_adler32(adler, p_row, p - p_row);
316 *(guint32 *)p = GUINT32_TO_BE(adler);
318 *(guint32 *)p = GUINT32_TO_BE(crc(p_idat, p - p_idat));
321 memcpy (p, iend, sizeof(iend));
324 assert(p - png == png_size);
326 url = g_malloc (strlen("data:image/png;base64,") +
327 ((png_size / 3 + 1) * 4 + 4) + 1);
328 strcpy (url, "data:image/png;base64,");
330 url_base64 = url + strlen("data:image/png;base64,");
331 outlen = g_base64_encode_step (png, png_size, FALSE, url_base64, &state, &save);
332 outlen += g_base64_encode_close (FALSE, url_base64 + outlen, &state, &save);
333 url_base64[outlen] = 0;
342 to_png_a (int w, int h, int byte_stride, guint8 *data)
344 guchar header[] = {137, 80, 78, 71, 13, 10, 26, 10};
345 guchar ihdr[13+12] = {0, 0, 0, 13, 'I', 'H', 'D', 'R',
346 /* w: */ 0, 0, 0, 0, /* h: */ 0,0,0,0,
347 /* bpp: */ 8, /* color type: */ 4,
349 guchar idat_start[8] = { /* len: */0, 0, 0, 0, 'I', 'D', 'A', 'T' };
350 guchar iend[12] = {0, 0, 0, 0, 'I', 'E', 'N', 'D', 0xae, 0x42, 0x60, 0x82};
351 gsize data_size, row_size;
353 guint8 *png, *p, *p_row, *p_idat;
359 char *url, *url_base64;
360 int state = 0, outlen;
363 *(guint32 *)&ihdr[8] = GUINT32_TO_BE(w);
364 *(guint32 *)&ihdr[12] = GUINT32_TO_BE(h);
365 *(guint32 *)&ihdr[21] = GUINT32_TO_BE(crc(&ihdr[4], 13 + 4));
367 row_size = 1 + w * 2;
369 row_header[1] = row_size & 0xff;
370 row_header[2] = (row_size >> 8) & 0xff;
371 row_header[3] = ~row_header[1];
372 row_header[4] = ~row_header[2];
375 data_size = 2 + (6 + w * 2) * h + 4;
377 *(guint32 *)&idat_start[0] = GUINT32_TO_BE(data_size);
379 png_size = sizeof(header) + sizeof(ihdr) + 12 + data_size + sizeof(iend);
380 png = g_malloc (png_size);
383 memcpy (p, header, sizeof(header));
385 memcpy (p, ihdr, sizeof(ihdr));
387 memcpy (p, idat_start, sizeof(idat_start));
388 p += sizeof(idat_start);
392 zlib header: 0x78, 0x01 ,
393 h * scanline: row_header[] + width * r,g,b,a
406 for (y = 0; y < h; y++) {
408 row_header[0] = 1; /* final block */
409 memcpy (p, row_header, sizeof(row_header));
410 p += sizeof(row_header);
413 data += byte_stride / 4;
414 for (x = 0; x < w; x++) {
416 *p++ = 0x00; /* gray */
417 *p++ = pixel; /* alpha */
419 adler = update_adler32(adler, p_row, p - p_row);
423 *(guint32 *)p = GUINT32_TO_BE(adler);
425 *(guint32 *)p = GUINT32_TO_BE(crc(p_idat, p - p_idat));
428 memcpy (p, iend, sizeof(iend));
431 assert(p - png == png_size);
433 url = g_malloc (strlen("data:image/png;base64,") +
434 ((png_size / 3 + 1) * 4 + 4) + 1);
435 strcpy (url, "data:image/png;base64,");
437 url_base64 = url + strlen("data:image/png;base64,");
438 outlen = g_base64_encode_step (png, png_size, FALSE, url_base64, &state, &save);
439 outlen += g_base64_encode_close (FALSE, url_base64 + outlen, &state, &save);
440 url_base64[outlen] = 0;
448 /************************************************************************
449 * Basic I/O primitives *
450 ************************************************************************/
452 struct BroadwayOutput {
460 broadway_output_write_raw (BroadwayOutput *output,
461 const void *buf, gsize count)
465 const char *ptr = (const char *)buf;
472 res = write(output->fd, ptr, count);
476 if (errsave == EINTR)
478 output->error = TRUE;
483 output->error = TRUE;
492 broadway_output_write (BroadwayOutput *output,
493 const void *buf, gsize count)
496 const char *ptr = (const char *)buf;
503 res = gzwrite(output->zfd, ptr, count);
506 output->error = TRUE;
511 output->error = TRUE;
520 broadway_output_write_header (BroadwayOutput *output)
525 "HTTP/1.1 200 OK\r\n"
526 "Content-type: multipart/x-mixed-replace;boundary=x\r\n"
527 "Content-Encoding: gzip\r\n"
529 broadway_output_write_raw (output,
530 header, strlen (header));
534 send_boundary (BroadwayOutput *output)
540 broadway_output_write (output, boundary, strlen (boundary));
544 broadway_output_new(int fd, guint32 serial)
546 BroadwayOutput *output;
549 output = g_new0 (BroadwayOutput, 1);
552 output->serial = serial;
554 setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
556 broadway_output_write_header (output);
558 output->zfd = gzdopen(fd, "wb");
560 /* Need an initial multipart boundary */
561 send_boundary (output);
567 broadway_output_free (BroadwayOutput *output)
570 gzclose (output->zfd);
577 broadway_output_get_next_serial (BroadwayOutput *output)
579 return output->serial;
583 broadway_output_flush (BroadwayOutput *output)
585 send_boundary (output);
586 gzflush (output->zfd, Z_SYNC_FLUSH);
587 return !output->error;
591 /************************************************************************
592 * Core rendering operations *
593 ************************************************************************/
595 #define HEADER_LEN (1+6)
598 append_uint16 (guint32 v, char *buf, int *p)
600 base64_uint16 (v, &buf[*p]);
605 append_uint32 (guint32 v, char *buf, int *p)
607 base64_uint32 (v, &buf[*p]);
612 write_header(BroadwayOutput *output, char *buf, char op)
618 append_uint32 (output->serial++, buf, &p);
624 broadway_output_copy_rectangles (BroadwayOutput *output, int id,
625 BroadwayRect *rects, int n_rects,
631 len = HEADER_LEN + 3 + 3 + 3*4*n_rects + 3 + 3;
633 buf = g_malloc (len);
634 p = write_header (output, buf, 'b');
635 append_uint16 (id, buf, &p);
636 append_uint16 (n_rects, buf, &p);
637 for (i = 0; i < n_rects; i++)
639 append_uint16 (rects[i].x, buf, &p);
640 append_uint16 (rects[i].y, buf, &p);
641 append_uint16 (rects[i].width, buf, &p);
642 append_uint16 (rects[i].height, buf, &p);
644 append_uint16 (dx, buf, &p);
645 append_uint16 (dy, buf, &p);
649 broadway_output_write (output, buf, len);
654 broadway_output_grab_pointer (BroadwayOutput *output,
656 gboolean owner_event)
658 char buf[HEADER_LEN + 3 + 1];
661 p = write_header (output, buf, 'g');
662 append_uint16 (id, buf, &p);
663 buf[p++] = owner_event ? '1': '0';
665 assert (p == sizeof (buf));
667 broadway_output_write (output, buf, sizeof (buf));
671 broadway_output_ungrab_pointer (BroadwayOutput *output)
673 char buf[HEADER_LEN];
677 serial = output->serial;
678 p = write_header (output, buf, 'u');
680 assert (p == sizeof (buf));
682 broadway_output_write (output, buf, sizeof (buf));
688 broadway_output_new_surface(BroadwayOutput *output,
689 int id, int x, int y, int w, int h,
692 char buf[HEADER_LEN + 16];
695 p = write_header (output, buf, 's');
696 append_uint16 (id, buf, &p);
697 append_uint16 (x, buf, &p);
698 append_uint16 (y, buf, &p);
699 append_uint16 (w, buf, &p);
700 append_uint16 (h, buf, &p);
701 buf[p++] = is_temp ? '1' : '0';
703 assert (p == sizeof (buf));
705 broadway_output_write (output, buf, sizeof (buf));
709 broadway_output_show_surface(BroadwayOutput *output, int id)
711 char buf[HEADER_LEN + 3];
714 p = write_header (output, buf, 'S');
715 append_uint16 (id, buf, &p);
717 assert (p == sizeof (buf));
719 broadway_output_write (output, buf, sizeof (buf));
723 broadway_output_hide_surface(BroadwayOutput *output, int id)
725 char buf[HEADER_LEN + 3];
728 p = write_header (output, buf, 'H');
729 append_uint16 (id, buf, &p);
731 assert (p == sizeof (buf));
733 broadway_output_write (output, buf, sizeof (buf));
737 broadway_output_destroy_surface(BroadwayOutput *output, int id)
739 char buf[HEADER_LEN + 3];
742 p = write_header (output, buf, 'd');
743 append_uint16 (id, buf, &p);
745 assert (p == sizeof (buf));
747 broadway_output_write (output, buf, sizeof (buf));
751 broadway_output_move_surface(BroadwayOutput *output, int id, int x, int y)
753 char buf[HEADER_LEN + 9];
756 p = write_header (output, buf, 'm');
758 append_uint16 (id, buf, &p);
759 append_uint16 (x, buf, &p);
760 append_uint16 (y, buf, &p);
762 assert (p == sizeof (buf));
764 broadway_output_write (output, buf, sizeof (buf));
768 broadway_output_resize_surface(BroadwayOutput *output, int id, int w, int h)
770 char buf[HEADER_LEN + 9];
773 p = write_header (output, buf, 'r');
775 append_uint16 (id, buf, &p);
776 append_uint16 (w, buf, &p);
777 append_uint16 (h, buf, &p);
779 assert (p == sizeof (buf));
781 broadway_output_write (output, buf, sizeof (buf));
785 broadway_output_set_transient_for (BroadwayOutput *output,
789 char buf[HEADER_LEN + 6];
792 p = write_header (output, buf, 'p');
794 append_uint16 (id, buf, &p);
795 append_uint16 (parent_id, buf, &p);
797 assert (p == sizeof (buf));
799 broadway_output_write (output, buf, sizeof (buf));
804 broadway_output_put_rgb (BroadwayOutput *output, int id, int x, int y,
805 int w, int h, int byte_stride, void *data)
807 char buf[HEADER_LEN + 15];
812 p = write_header (output, buf, 'i');
814 append_uint16 (id, buf, &p);
815 append_uint16 (x, buf, &p);
816 append_uint16 (y, buf, &p);
818 url = to_png_rgb (w, h, byte_stride, (guint32*)data);
820 append_uint32 (len, buf, &p);
822 assert (p == sizeof (buf));
824 broadway_output_write (output, buf, sizeof (buf));
826 broadway_output_write (output, url, len);
837 is_any_x_set (unsigned char *data,
838 int box_x1, int box_x2,
839 int x1, int x2, int y, int *x_set,
854 ptr = (guint32 *)(data + y * byte_stride + x1 * 4);
871 #define EXTEND_X_FUZZ 10
872 #define EXTEND_Y_FUZZ 10
875 extend_x_range (unsigned char *data,
876 int box_x1, int box_y1,
877 int box_x2, int box_y2,
878 int *x1, int *x2, int y,
884 while (is_any_x_set (data, box_x1, box_x2, *x1 - EXTEND_X_FUZZ, *x1, y, &new_x, byte_stride))
890 while (is_any_x_set (data, box_x1, box_x2, *x2, *x2 + EXTEND_X_FUZZ, y, &new_x, byte_stride))
900 extend_y_range (unsigned char *data,
901 int box_x1, int box_y1,
902 int box_x2, int box_y2,
903 int x1, int x2, int *y,
914 y2 = *y + EXTEND_Y_FUZZ;
918 for (yy = y2; yy > *y + 1; yy--)
920 if (is_any_x_set (data, box_x1, box_x2, x1, x2, yy - 1, NULL, byte_stride))
937 rgba_find_rects_extents (unsigned char *data,
938 int box_x1, int box_y1,
939 int box_x2, int box_y2,
944 int x1, x2, y1, y2, yy;
954 /* Expand maximally for all known rows */
959 for (yy = y1; yy < y2; yy++)
960 extended |= extend_x_range (data,
968 while (extend_y_range(data,
981 rgba_find_rects_sub (unsigned char *data,
982 int box_x1, int box_y1,
983 int box_x2, int box_y2,
986 int *n_rects, int *alloc_rects)
992 if (box_x1 == box_x2 || box_y1 == box_y2)
995 for (y = box_y1; y < box_y2; y++)
997 line = (guint32 *)(data + y * byte_stride + box_x1 * 4);
999 for (x = box_x1; x < box_x2; x++)
1003 rgba_find_rects_extents (data,
1004 box_x1, box_y1, box_x2, box_y2,
1005 x, y, &rect, byte_stride);
1006 if (*n_rects == *alloc_rects)
1008 (*alloc_rects) *= 2;
1009 *rects = g_renew (BroadwayBox, *rects, *alloc_rects);
1011 (*rects)[*n_rects] = rect;
1013 rgba_find_rects_sub (data,
1017 rects, n_rects, alloc_rects);
1018 rgba_find_rects_sub (data,
1022 rects, n_rects, alloc_rects);
1023 rgba_find_rects_sub (data,
1027 rects, n_rects, alloc_rects);
1035 static BroadwayBox *
1036 rgba_find_rects (unsigned char *data,
1037 int w, int h, int byte_stride,
1044 rects = g_new (BroadwayBox, alloc_rects);
1047 rgba_find_rects_sub (data,
1048 0, 0, w, h, byte_stride,
1049 &rects, n_rects, &alloc_rects);
1055 broadway_output_put_rgba (BroadwayOutput *output, int id, int x, int y,
1056 int w, int h, int byte_stride, void *data)
1058 char buf[HEADER_LEN + 15];
1065 rects = rgba_find_rects (data, w, h, byte_stride, &n_rects);
1067 for (i = 0; i < n_rects; i++)
1069 subdata = (guint8 *)data + rects[i].x1 * 4 + rects[i].y1 * byte_stride;
1071 p = write_header (output, buf, 'i');
1072 append_uint16 (id, buf, &p);
1073 append_uint16 (x + rects[i].x1, buf, &p);
1074 append_uint16 (y + rects[i].y1, buf, &p);
1076 url = to_png_rgba (rects[i].x2 - rects[i].x1,
1077 rects[i].y2 - rects[i].y1,
1078 byte_stride, (guint32*)subdata);
1080 append_uint32 (len, buf, &p);
1082 assert (p == sizeof (buf));
1084 broadway_output_write (output, buf, sizeof (buf));
1086 broadway_output_write (output, url, len);
1095 broadway_output_surface_flush (BroadwayOutput *output,
1098 char buf[HEADER_LEN + 3];
1101 p = write_header (output, buf, 'f');
1102 append_uint16 (id, buf, &p);
1104 assert (p == sizeof (buf));
1106 broadway_output_write (output, buf, sizeof (buf));
1111 send_image_a (BroadwayOutput *output, int id, int x, int y,
1112 int w, int h, int byte_stride, guint8 *data)
1114 char buf[HEADER_LEN + 15];
1118 p = write_header (output, buf, 'i');
1119 append_uint16 (id, buf, &p);
1120 append_uint16 (x, buf, &p);
1121 append_uint16 (y, buf, &p);
1123 url = to_png_a (w, h, byte_stride, data);
1125 append_uint32 (len, buf, &p);
1127 assert (p == sizeof (buf));
1129 broadway_output_write (output, buf, sizeof (buf));
1131 broadway_output_write (output, url, len);