10 /************************************************************************
12 ************************************************************************/
14 static const char base64_alphabet[] =
15 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
17 #if 0 /* Unused for now */
19 base64_uint8 (guint8 v, char *c)
21 c[0] = base64_alphabet[(v >> 0) & 0x3f];
22 c[1] = base64_alphabet[(v >> 6) & 0x3];
27 base64_uint16 (guint32 v, char *c)
29 c[0] = base64_alphabet[(v >> 0) & 0x3f];
30 c[1] = base64_alphabet[(v >> 6) & 0x3f];
31 c[2] = base64_alphabet[(v >> 12) & 0xf];
36 base64_uint24 (guint32 v, char *c)
38 c[0] = base64_alphabet[(v >> 0) & 0x3f];
39 c[1] = base64_alphabet[(v >> 6) & 0x3f];
40 c[2] = base64_alphabet[(v >> 12) & 0x3f];
41 c[3] = base64_alphabet[(v >> 18) & 0x3f];
46 base64_uint32 (guint32 v, char *c)
48 c[0] = base64_alphabet[(v >> 0) & 0x3f];
49 c[1] = base64_alphabet[(v >> 6) & 0x3f];
50 c[2] = base64_alphabet[(v >> 12) & 0x3f];
51 c[3] = base64_alphabet[(v >> 18) & 0x3f];
52 c[4] = base64_alphabet[(v >> 24) & 0x3f];
53 c[5] = base64_alphabet[(v >> 30) & 0x2];
56 /***********************************************************
57 * conversion of raw image data to png data: uris *
58 ***********************************************************/
61 write_png_data (void *closure,
62 const unsigned char *data,
63 unsigned int data_len)
65 GString *buf = closure;
67 g_string_append_len (buf, (char *)data, data_len);
69 return CAIRO_STATUS_SUCCESS;
73 to_png_rgb (GString *buf, int w, int h, int byte_stride, guint32 *data)
75 cairo_surface_t *surface;
77 surface = cairo_image_surface_create_for_data ((guchar *)data,
78 CAIRO_FORMAT_RGB24, w, h, byte_stride);
80 cairo_surface_write_to_png_stream (surface, write_png_data, buf);
81 cairo_surface_destroy (surface);
85 to_png_rgba (GString *buf, int w, int h, int byte_stride, guint32 *data)
87 cairo_surface_t *surface;
89 surface = cairo_image_surface_create_for_data ((guchar *)data,
90 CAIRO_FORMAT_ARGB32, w, h, byte_stride);
92 cairo_surface_write_to_png_stream (surface, write_png_data, buf);
93 cairo_surface_destroy (surface);
102 static cairo_status_t
103 write_png_url (void *closure,
104 const unsigned char *data,
105 unsigned int data_len)
107 struct PngTarget *target = closure;
110 old_len = target->buf->len;
111 g_string_set_size (target->buf,
112 old_len + (data_len / 3 + 1) * 4 + 4);
114 res = g_base64_encode_step (data, data_len, FALSE,
115 target->buf->str + old_len,
116 &target->state, &target->save);
118 g_string_set_size (target->buf, old_len + res);
120 return CAIRO_STATUS_SUCCESS;
124 to_png_url_rgb (GString *buf, int w, int h, int byte_stride, guint32 *data)
126 cairo_surface_t *surface;
127 struct PngTarget target;
134 g_string_append (buf, "data:image/png;base64,");
136 surface = cairo_image_surface_create_for_data ((guchar *)data,
137 CAIRO_FORMAT_RGB24, w, h, byte_stride);
139 cairo_surface_write_to_png_stream (surface, write_png_url, &target);
140 cairo_surface_destroy (surface);
144 g_string_set_size (buf, old_len + 4);
145 res = g_base64_encode_close (FALSE,
147 &target.state, &target.save);
148 g_string_set_size (buf, old_len + res);
152 to_png_url_rgba (GString *buf, int w, int h, int byte_stride, guint32 *data)
154 cairo_surface_t *surface;
155 struct PngTarget target;
162 g_string_append (buf, "data:image/png;base64,");
164 surface = cairo_image_surface_create_for_data ((guchar *)data,
165 CAIRO_FORMAT_ARGB32, w, h, byte_stride);
167 cairo_surface_write_to_png_stream (surface, write_png_url, &target);
168 cairo_surface_destroy (surface);
172 g_string_set_size (buf, old_len + 4);
173 res = g_base64_encode_close (FALSE,
175 &target.state, &target.save);
176 g_string_set_size (buf, old_len + res);
181 to_png_a (int w, int h, int byte_stride, guint8 *data)
183 cairo_surface_t *surface;
184 struct PngTarget target;
187 target.url = g_string_new ("data:image/png;base64,");
191 surface = cairo_image_surface_create_for_data (data,
192 CAIRO_FORMAT_A8, w, h, byte_stride);
194 cairo_surface_write_to_png_stream (surface, write_png_url, &target);
196 old_len = target.url->len;
198 g_string_set_size (target.url, old_len + 4);
199 res = g_base64_encode_close (FALSE,
200 target.url->str + old_len,
201 &target.state, &target.save);
202 g_string_set_size (target.url, old_len + res);
204 return g_string_free (target.url, FALSE);
208 /************************************************************************
209 * Basic I/O primitives *
210 ************************************************************************/
212 struct BroadwayOutput {
217 gboolean proto_v7_plus;
222 broadway_output_send_cmd (BroadwayOutput *output,
223 gboolean fin, BroadwayWSOpCode code,
224 const void *buf, gsize count)
226 gboolean mask = FALSE;
230 gboolean mid_header = count > 125 && count <= 65535;
231 gboolean long_header = count > 65535;
233 /* NB. big-endian spec => bit 0 == MSB */
234 header[0] = ( (fin ? 0x80 : 0) | (code & 0x0f) );
235 header[1] = ( (mask ? 0x80 : 0) |
236 (mid_header ? 126 : long_header ? 127 : count) );
240 *(guint16 *)(header + p) = GUINT16_TO_BE( (guint16)count );
243 else if (long_header)
245 *(guint64 *)(header + p) = GUINT64_TO_BE( count );
248 // FIXME: if we are paranoid we should 'mask' the data
249 // FIXME: we should really emit these as a single write
250 g_output_stream_write_all (output->out, header, p, NULL, NULL, NULL);
251 g_output_stream_write_all (output->out, buf, count, NULL, NULL, NULL);
255 broadway_output_send_cmd_pre_v7 (BroadwayOutput *output,
256 const void *buf, gsize count)
258 g_output_stream_write_all (output->out, "\0", 1, NULL, NULL, NULL);
259 g_output_stream_write_all (output->out, buf, count, NULL, NULL, NULL);
260 g_output_stream_write_all (output->out, "\xff", 1, NULL, NULL, NULL);
263 void broadway_output_pong (BroadwayOutput *output)
265 if (output->proto_v7_plus)
266 broadway_output_send_cmd (output, TRUE, BROADWAY_WS_CNX_PONG, NULL, 0);
270 broadway_output_flush (BroadwayOutput *output)
272 if (output->buf->len == 0)
275 if (!output->proto_v7_plus)
276 broadway_output_send_cmd_pre_v7 (output, output->buf->str, output->buf->len);
277 else if (output->binary)
278 broadway_output_send_cmd (output, TRUE, BROADWAY_WS_BINARY,
279 output->buf->str, output->buf->len);
281 broadway_output_send_cmd (output, TRUE, BROADWAY_WS_TEXT,
282 output->buf->str, output->buf->len);
284 g_string_set_size (output->buf, 0);
286 return !output->error;
291 broadway_output_new (GOutputStream *out, guint32 serial,
292 gboolean proto_v7_plus, gboolean binary)
294 BroadwayOutput *output;
296 output = g_new0 (BroadwayOutput, 1);
298 output->out = g_object_ref (out);
299 output->buf = g_string_new ("");
300 output->serial = serial;
301 output->proto_v7_plus = proto_v7_plus;
302 output->binary = binary;
308 broadway_output_free (BroadwayOutput *output)
310 g_object_unref (output->out);
315 broadway_output_get_next_serial (BroadwayOutput *output)
317 return output->serial;
321 /************************************************************************
322 * Core rendering operations *
323 ************************************************************************/
326 append_char (BroadwayOutput *output, char c)
328 g_string_append_c (output->buf, c);
332 append_bool (BroadwayOutput *output, gboolean val)
335 g_string_append_c (output->buf, val ? 1: 0);
337 g_string_append_c (output->buf, val ? '1': '0');
341 append_flags (BroadwayOutput *output, guint32 val)
344 g_string_append_c (output->buf, val);
346 g_string_append_c (output->buf, val + '0');
351 append_uint16 (BroadwayOutput *output, guint32 v)
353 gsize old_len = output->buf->len;
357 guint8 *buf = (guint8 *)output->buf->str + old_len;
359 g_string_set_size (output->buf, old_len + 2);
360 buf[0] = (v >> 0) & 0xff;
361 buf[1] = (v >> 8) & 0xff;
365 g_string_set_size (output->buf, old_len + 3);
366 base64_uint16 (v, output->buf->str + old_len);
371 append_uint32 (BroadwayOutput *output, guint32 v)
373 gsize old_len = output->buf->len;
377 guint8 *buf = (guint8 *)output->buf->str + old_len;
379 g_string_set_size (output->buf, old_len + 4);
380 buf[0] = (v >> 0) & 0xff;
381 buf[1] = (v >> 8) & 0xff;
382 buf[2] = (v >> 16) & 0xff;
383 buf[3] = (v >> 24) & 0xff;
387 g_string_set_size (output->buf, old_len + 6);
388 base64_uint32 (v, output->buf->str + old_len);
393 overwrite_uint32 (BroadwayOutput *output, gsize pos, guint32 v)
397 guint8 *buf = (guint8 *)output->buf->str + pos;
399 buf[0] = (v >> 0) & 0xff;
400 buf[1] = (v >> 8) & 0xff;
401 buf[2] = (v >> 16) & 0xff;
402 buf[3] = (v >> 24) & 0xff;
406 base64_uint32 (v, output->buf->str + pos);
412 write_header(BroadwayOutput *output, char op)
414 append_char (output, op);
415 append_uint32 (output, output->serial++);
419 broadway_output_copy_rectangles (BroadwayOutput *output, int id,
420 BroadwayRect *rects, int n_rects,
425 write_header (output, 'b');
426 append_uint16 (output, id);
427 append_uint16 (output, n_rects);
428 for (i = 0; i < n_rects; i++)
430 append_uint16 (output, rects[i].x);
431 append_uint16 (output, rects[i].y);
432 append_uint16 (output, rects[i].width);
433 append_uint16 (output, rects[i].height);
435 append_uint16 (output, dx);
436 append_uint16 (output, dy);
440 broadway_output_grab_pointer (BroadwayOutput *output,
442 gboolean owner_event)
444 write_header (output, 'g');
445 append_uint16 (output, id);
446 append_bool (output, owner_event);
450 broadway_output_ungrab_pointer (BroadwayOutput *output)
454 serial = output->serial;
455 write_header (output, 'u');
461 broadway_output_new_surface(BroadwayOutput *output,
462 int id, int x, int y, int w, int h,
465 write_header (output, 's');
466 append_uint16 (output, id);
467 append_uint16 (output, x);
468 append_uint16 (output, y);
469 append_uint16 (output, w);
470 append_uint16 (output, h);
471 append_bool (output, is_temp);
475 broadway_output_show_surface(BroadwayOutput *output, int id)
477 write_header (output, 'S');
478 append_uint16 (output, id);
482 broadway_output_hide_surface(BroadwayOutput *output, int id)
484 write_header (output, 'H');
485 append_uint16 (output, id);
489 broadway_output_destroy_surface(BroadwayOutput *output, int id)
491 write_header (output, 'd');
492 append_uint16 (output, id);
497 broadway_output_move_resize_surface (BroadwayOutput *output,
508 if (!has_pos && !has_size)
511 write_header (output, 'm');
512 val = (!!has_pos) | ((!!has_size) << 1);
513 append_uint16 (output, id);
514 append_flags (output, val);
517 append_uint16 (output, x);
518 append_uint16 (output, y);
522 append_uint16 (output, w);
523 append_uint16 (output, h);
528 broadway_output_set_transient_for (BroadwayOutput *output,
532 write_header (output, 'p');
533 append_uint16 (output, id);
534 append_uint16 (output, parent_id);
539 broadway_output_put_rgb (BroadwayOutput *output, int id, int x, int y,
540 int w, int h, int byte_stride, void *data)
542 gsize size_start, image_start, len;
544 write_header (output, 'i');
546 append_uint16 (output, id);
547 append_uint16 (output, x);
548 append_uint16 (output, y);
550 size_start = output->buf->len;
551 append_uint32 (output, 0);
553 image_start = output->buf->len;
555 to_png_rgb (output->buf, w, h, byte_stride, (guint32*)data);
557 to_png_url_rgb (output->buf, w, h, byte_stride, (guint32*)data);
559 len = output->buf->len - image_start;
561 overwrite_uint32 (output, size_start, len);
570 is_any_x_set (unsigned char *data,
571 int box_x1, int box_x2,
572 int x1, int x2, int y, int *x_set,
587 ptr = (guint32 *)(data + y * byte_stride + x1 * 4);
604 #define EXTEND_X_FUZZ 10
605 #define EXTEND_Y_FUZZ 10
608 extend_x_range (unsigned char *data,
609 int box_x1, int box_y1,
610 int box_x2, int box_y2,
611 int *x1, int *x2, int y,
617 while (is_any_x_set (data, box_x1, box_x2, *x1 - EXTEND_X_FUZZ, *x1, y, &new_x, byte_stride))
623 while (is_any_x_set (data, box_x1, box_x2, *x2, *x2 + EXTEND_X_FUZZ, y, &new_x, byte_stride))
633 extend_y_range (unsigned char *data,
634 int box_x1, int box_y1,
635 int box_x2, int box_y2,
636 int x1, int x2, int *y,
647 y2 = *y + EXTEND_Y_FUZZ;
651 for (yy = y2; yy > *y + 1; yy--)
653 if (is_any_x_set (data, box_x1, box_x2, x1, x2, yy - 1, NULL, byte_stride))
670 rgba_find_rects_extents (unsigned char *data,
671 int box_x1, int box_y1,
672 int box_x2, int box_y2,
677 int x1, x2, y1, y2, yy;
687 /* Expand maximally for all known rows */
692 for (yy = y1; yy < y2; yy++)
693 extended |= extend_x_range (data,
701 while (extend_y_range(data,
714 rgba_find_rects_sub (unsigned char *data,
715 int box_x1, int box_y1,
716 int box_x2, int box_y2,
719 int *n_rects, int *alloc_rects)
725 if (box_x1 == box_x2 || box_y1 == box_y2)
728 for (y = box_y1; y < box_y2; y++)
730 line = (guint32 *)(data + y * byte_stride + box_x1 * 4);
732 for (x = box_x1; x < box_x2; x++)
736 rgba_find_rects_extents (data,
737 box_x1, box_y1, box_x2, box_y2,
738 x, y, &rect, byte_stride);
739 if (*n_rects == *alloc_rects)
742 *rects = g_renew (BroadwayBox, *rects, *alloc_rects);
744 (*rects)[*n_rects] = rect;
746 rgba_find_rects_sub (data,
750 rects, n_rects, alloc_rects);
751 rgba_find_rects_sub (data,
755 rects, n_rects, alloc_rects);
756 rgba_find_rects_sub (data,
760 rects, n_rects, alloc_rects);
769 rgba_find_rects (unsigned char *data,
770 int w, int h, int byte_stride,
777 rects = g_new (BroadwayBox, alloc_rects);
780 rgba_find_rects_sub (data,
781 0, 0, w, h, byte_stride,
782 &rects, n_rects, &alloc_rects);
788 broadway_output_put_rgba (BroadwayOutput *output, int id, int x, int y,
789 int w, int h, int byte_stride, void *data)
793 gsize size_start, image_start, len;
795 rects = rgba_find_rects (data, w, h, byte_stride, &n_rects);
797 for (i = 0; i < n_rects; i++)
801 write_header (output, 'i');
802 append_uint16 (output, id);
803 append_uint16 (output, x + rects[i].x1);
804 append_uint16 (output, y + rects[i].y1);
806 size_start = output->buf->len;
807 append_uint32 (output, 0);
809 image_start = output->buf->len;
811 subdata = (guint8 *)data + rects[i].x1 * 4 + rects[i].y1 * byte_stride;
813 to_png_rgba (output->buf, rects[i].x2 - rects[i].x1,
814 rects[i].y2 - rects[i].y1,
815 byte_stride, (guint32*)subdata);
817 to_png_url_rgba (output->buf, rects[i].x2 - rects[i].x1,
818 rects[i].y2 - rects[i].y1,
819 byte_stride, (guint32*)subdata);
821 len = output->buf->len - image_start;
823 overwrite_uint32 (output, size_start, len);
830 broadway_output_surface_flush (BroadwayOutput *output,
833 write_header (output, 'f');
834 append_uint16 (output, id);