[gtk+/broadway: 10/71] [broadway] Import broadway lib



commit 7f0e43c0fd21dbe220f46cf930ef728a43719736
Author: Alexander Larsson <alexl redhat com>
Date:   Tue Nov 16 12:42:53 2010 +0100

    [broadway] Import broadway lib
    
    We put this in gtk+ for now since it will be synced initially, but
    it avoids using glib so that it can be used lower in the stack if
    required (e.g. in cairo later).

 gdk/broadway/Makefile.am     |   11 +-
 gdk/broadway/broadway-demo.c |  228 ++++++++++
 gdk/broadway/broadway.c      | 1018 ++++++++++++++++++++++++++++++++++++++++++
 gdk/broadway/broadway.h      |   55 +++
 4 files changed, 1311 insertions(+), 1 deletions(-)
---
diff --git a/gdk/broadway/Makefile.am b/gdk/broadway/Makefile.am
index 5e88720..9fe6b26 100644
--- a/gdk/broadway/Makefile.am
+++ b/gdk/broadway/Makefile.am
@@ -14,7 +14,11 @@ INCLUDES =			\
 
 LDADDS = $(GDK_DEP_LIBS)
 
-noinst_LTLIBRARIES = libgdk-broadway.la
+noinst_LTLIBRARIES = libbroadway.la libgdk-broadway.la
+
+libbroadway_la_SOURCES =		\
+	broadway.h			\
+	broadway.c
 
 libgdk_broadway_la_SOURCES =		\
 	gdkapplaunchcontext-broadway.c \
@@ -46,4 +50,9 @@ libgdk_broadway_la_SOURCES =		\
 	gdkwindow-broadway.h	\
 	gdkprivate-broadway.h
 
+libgdk_broadway_la_LIBADD = libbroadway.la
+
+noinst_PROGRAMS = broadway-demo
+broadway_demo_LDADD = -lz -lcairo libbroadway.la
+
 -include $(top_srcdir)/git.mk
diff --git a/gdk/broadway/broadway-demo.c b/gdk/broadway/broadway-demo.c
new file mode 100644
index 0000000..0c4cd1c
--- /dev/null
+++ b/gdk/broadway/broadway-demo.c
@@ -0,0 +1,228 @@
+/* Build with
+   gcc -lm -lz -O2 -Wall `pkg-config --libs --cflags cairo`  -o broadway broadway.c demo.c
+*/
+
+#include "broadway.h"
+#include <math.h>
+#include <unistd.h>
+#include <cairo.h>
+
+static void
+diff_surfaces (cairo_surface_t *surface,
+	       cairo_surface_t *old_surface)
+{
+  unsigned char *data, *old_data;
+  unsigned char *line, *old_line;
+  int w, h, stride, old_stride;
+  int x, y;
+
+  data = cairo_image_surface_get_data (surface);
+  old_data = cairo_image_surface_get_data (old_surface);
+
+  w = cairo_image_surface_get_width (surface);
+  h = cairo_image_surface_get_height (surface);
+
+  stride = cairo_image_surface_get_stride (surface);
+  old_stride = cairo_image_surface_get_stride (old_surface);
+
+  for (y = 0; y < h; y++)
+    {
+      line = data;
+      old_line = old_data;
+
+      for (x = 0; x < w; x++)
+	{
+	  int j;
+	  for (j = 0; j < 4; j++)
+	    old_line[j] = line[j] - old_line[j];
+	  line += 4;
+	  old_line += 4;
+	}
+
+      data += stride;
+      old_data += old_stride;
+    }
+}
+
+static void
+snippet(cairo_t *cr, int i)
+{
+  if (1)
+    {
+      cairo_save(cr);
+      cairo_rotate (cr, i * 0.002);
+      /* a custom shape that could be wrapped in a function */
+      double x0      = 25.6,   /* parameters like cairo_rectangle */
+	y0      = 25.6,
+	rect_width  = 204.8,
+	rect_height = 204.8,
+	radius = 102.4;   /* and an approximate curvature radius */
+
+      double x1,y1;
+
+      x1=x0+rect_width;
+      y1=y0+rect_height;
+      if (rect_width/2<radius) {
+	if (rect_height/2<radius) {
+	  cairo_move_to  (cr, x0, (y0 + y1)/2);
+	  cairo_curve_to (cr, x0 ,y0, x0, y0, (x0 + x1)/2, y0);
+	  cairo_curve_to (cr, x1, y0, x1, y0, x1, (y0 + y1)/2);
+	  cairo_curve_to (cr, x1, y1, x1, y1, (x1 + x0)/2, y1);
+	  cairo_curve_to (cr, x0, y1, x0, y1, x0, (y0 + y1)/2);
+	} else {
+	  cairo_move_to  (cr, x0, y0 + radius);
+	  cairo_curve_to (cr, x0 ,y0, x0, y0, (x0 + x1)/2, y0);
+	  cairo_curve_to (cr, x1, y0, x1, y0, x1, y0 + radius);
+	  cairo_line_to (cr, x1 , y1 - radius);
+	  cairo_curve_to (cr, x1, y1, x1, y1, (x1 + x0)/2, y1);
+	  cairo_curve_to (cr, x0, y1, x0, y1, x0, y1- radius);
+	}
+      } else {
+	if (rect_height/2<radius) {
+	  cairo_move_to  (cr, x0, (y0 + y1)/2);
+	  cairo_curve_to (cr, x0 , y0, x0 , y0, x0 + radius, y0);
+	  cairo_line_to (cr, x1 - radius, y0);
+	  cairo_curve_to (cr, x1, y0, x1, y0, x1, (y0 + y1)/2);
+	  cairo_curve_to (cr, x1, y1, x1, y1, x1 - radius, y1);
+	  cairo_line_to (cr, x0 + radius, y1);
+	  cairo_curve_to (cr, x0, y1, x0, y1, x0, (y0 + y1)/2);
+	} else {
+	  cairo_move_to  (cr, x0, y0 + radius);
+	  cairo_curve_to (cr, x0 , y0, x0 , y0, x0 + radius, y0);
+	  cairo_line_to (cr, x1 - radius, y0);
+	  cairo_curve_to (cr, x1, y0, x1, y0, x1, y0 + radius);
+	  cairo_line_to (cr, x1 , y1 - radius);
+	  cairo_curve_to (cr, x1, y1, x1, y1, x1 - radius, y1);
+	  cairo_line_to (cr, x0 + radius, y1);
+	  cairo_curve_to (cr, x0, y1, x0, y1, x0, y1- radius);
+	}
+      }
+      cairo_close_path (cr);
+
+      cairo_set_source_rgb (cr, 0.5, 0.5, 1);
+      cairo_fill_preserve (cr);
+      cairo_set_source_rgba (cr, 0.5, 0, 0, 0.5);
+      cairo_set_line_width (cr, 10.0);
+      cairo_stroke (cr);
+      cairo_restore(cr);
+    }
+  if (1)
+    {
+      double xc = 128.0;
+      double yc = 128.0;
+      double radius = 100.0;
+      double angle1 = (45.0 + i * 5)  * (M_PI/180.0);  /* angles are specified */
+      double angle2 = (180.0 + i * 5) * (M_PI/180.0);  /* in radians           */
+
+      cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
+
+      cairo_set_line_width (cr, 10.0);
+      cairo_arc (cr, xc, yc, radius, angle1, angle2);
+      cairo_stroke (cr);
+
+      /* draw helping lines */
+      cairo_set_source_rgba (cr, 1, 0.2, 0.2, 0.6);
+      cairo_set_line_width (cr, 6.0);
+
+      cairo_arc (cr, xc, yc, 10.0, 0, 2*M_PI);
+      cairo_fill (cr);
+
+      cairo_arc (cr, xc, yc, radius, angle1, angle1);
+      cairo_line_to (cr, xc, yc);
+      cairo_arc (cr, xc, yc, radius, angle2, angle2);
+      cairo_line_to (cr, xc, yc);
+      cairo_stroke (cr);
+    }
+}
+
+static void
+demo2 (BroadwayClient *client)
+{
+  cairo_t *cr;
+  cairo_surface_t *surface, *old_surface;
+  BroadwayRect rects[2];
+  double da = 0;
+  int i;
+
+  broadway_client_new_surface(client,  0, 100, 100, 800, 600);
+
+  surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+					800, 600);
+  old_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+					    800, 600);
+
+  cr = cairo_create (old_surface);
+  cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
+  cairo_rectangle (cr, 0, 0, 800, 600);
+  cairo_fill (cr);
+  cairo_destroy (cr);
+
+  for (i = 0; i < 100; i++)
+    {
+      cr = cairo_create (surface);
+
+      cairo_set_source_rgb (cr, 0.8, 0.8, 0.8);
+
+      cairo_rectangle (cr, 0, 0, 800, 600);
+      cairo_fill (cr);
+
+      snippet(cr, i);
+
+      cairo_destroy (cr);
+
+      if (i == 0)
+	{
+	  broadway_client_put_rgb (client, 0, 0, 0, 800, 600, 800*4,
+				   cairo_image_surface_get_data(surface)
+				   );
+	  broadway_client_show_surface (client,  0);
+	}
+      else
+	{
+	  diff_surfaces (surface,
+			 old_surface);
+	  broadway_client_put_delta_rgb (client, 0, 0, 0, 800, 600, 800*4,
+					 cairo_image_surface_get_data(old_surface));
+	}
+      broadway_client_move_surface (client, 0, 100 + i, 100 + i);
+
+      rects[0].x = 500;
+      rects[0].y = 0;
+      rects[0].width = 100;
+      rects[0].height = 100;
+      rects[1].x = 600;
+      rects[1].y = 100;
+      rects[1].width = 100;
+      rects[1].height = 100;
+      broadway_client_copy_rectangles (client,
+				       0,
+				       rects, 2,
+				       400, 0);
+
+      broadway_client_flush (client);
+
+      cr = cairo_create (old_surface);
+      cairo_set_source_surface (cr, surface, 0, 0);
+      cairo_paint (cr);
+      cairo_destroy (cr);
+
+      da += 10;
+      usleep (50 * 1000);
+  }
+
+
+  cairo_surface_destroy (surface);
+  broadway_client_destroy_surface(client,  0);
+  broadway_client_flush (client);
+}
+
+int
+main (int argc, char *argv[])
+{
+  BroadwayClient *client;
+
+  client = broadway_client_new (STDOUT_FILENO);
+  demo2(client);
+
+  return 0;
+}
diff --git a/gdk/broadway/broadway.c b/gdk/broadway/broadway.c
new file mode 100644
index 0000000..9d4fb35
--- /dev/null
+++ b/gdk/broadway/broadway.c
@@ -0,0 +1,1018 @@
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+#include <arpa/inet.h>
+#include <zlib.h>
+
+#include "broadway.h"
+
+/************************************************************************
+ *                Basic helpers                                         *
+ ************************************************************************/
+
+#define TRUE 1
+#define FALSE 0
+
+typedef unsigned char uchar;
+typedef int boolean;
+
+static void *
+bw_malloc(size_t size)
+{
+  void *ptr;
+
+  ptr = malloc(size);
+  if (ptr == NULL)
+    exit(1);
+
+  return ptr;
+}
+
+static void *
+bw_malloc0(size_t size)
+{
+  void *ptr;
+
+  ptr = calloc(size, 1);
+  if (ptr == NULL)
+    exit(1);
+
+  return ptr;
+}
+
+#define bw_new(struct_type, n_structs) (bw_malloc(sizeof(struct_type) * (n_structs)))
+#define bw_new0(struct_type, n_structs) (bw_malloc0(sizeof(struct_type) * (n_structs)))
+
+/************************************************************************
+ *                Base64 implementation, from glib                      *
+ ************************************************************************/
+
+static const char base64_alphabet[] =
+	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static size_t
+bw_base64_encode_step (const uchar *in,
+		       size_t         len,
+		       boolean      break_lines,
+		       char        *out,
+		       int         *state,
+		       int         *save)
+{
+  char *outptr;
+  const uchar *inptr;
+
+  if (len <= 0)
+    return 0;
+
+  inptr = in;
+  outptr = out;
+
+  if (len + ((char *) save) [0] > 2)
+    {
+      const uchar *inend = in+len-2;
+      int c1, c2, c3;
+      int already;
+
+      already = *state;
+
+      switch (((char *) save) [0])
+        {
+        case 1:
+          c1 = ((unsigned char *) save) [1];
+          goto skip1;
+        case 2:
+          c1 = ((unsigned char *) save) [1];
+          c2 = ((unsigned char *) save) [2];
+          goto skip2;
+        }
+
+      /*
+       * yes, we jump into the loop, no i'm not going to change it,
+       * it's beautiful!
+       */
+      while (inptr < inend)
+        {
+          c1 = *inptr++;
+        skip1:
+          c2 = *inptr++;
+        skip2:
+          c3 = *inptr++;
+          *outptr++ = base64_alphabet [ c1 >> 2 ];
+          *outptr++ = base64_alphabet [ c2 >> 4 |
+                                        ((c1&0x3) << 4) ];
+          *outptr++ = base64_alphabet [ ((c2 &0x0f) << 2) |
+                                        (c3 >> 6) ];
+          *outptr++ = base64_alphabet [ c3 & 0x3f ];
+          /* this is a bit ugly ... */
+          if (break_lines && (++already) >= 19)
+            {
+              *outptr++ = '\n';
+              already = 0;
+            }
+        }
+
+      ((char *)save)[0] = 0;
+      len = 2 - (inptr - inend);
+      *state = already;
+    }
+
+  if (len>0)
+    {
+      char *saveout;
+
+      /* points to the slot for the next char to save */
+      saveout = & (((char *)save)[1]) + ((char *)save)[0];
+
+      /* len can only be 0 1 or 2 */
+      switch(len)
+        {
+        case 2: *saveout++ = *inptr++;
+        case 1: *saveout++ = *inptr++;
+        }
+      ((char *)save)[0] += len;
+    }
+
+  return outptr - out;
+}
+
+static size_t
+bw_base64_encode_close (boolean  break_lines,
+			char    *out,
+			int     *state,
+			int     *save)
+{
+  int c1, c2;
+  char *outptr = out;
+
+  c1 = ((unsigned char *) save) [1];
+  c2 = ((unsigned char *) save) [2];
+
+  switch (((char *) save) [0])
+    {
+    case 2:
+      outptr [2] = base64_alphabet[ ( (c2 &0x0f) << 2 ) ];
+      assert (outptr [2] != 0);
+      goto skip;
+    case 1:
+      outptr[2] = '=';
+    skip:
+      outptr [0] = base64_alphabet [ c1 >> 2 ];
+      outptr [1] = base64_alphabet [ c2 >> 4 | ( (c1&0x3) << 4 )];
+      outptr [3] = '=';
+      outptr += 4;
+      break;
+    }
+  if (break_lines)
+    *outptr++ = '\n';
+
+  *save = 0;
+  *state = 0;
+
+  return outptr - out;
+}
+
+#if 0
+static void
+base64_uint8 (uint8_t v, char *c)
+{
+  c[0] = base64_alphabet[(v >> 0) & 0x3f];
+  c[1] = base64_alphabet[(v >> 6) & 0x3];
+}
+#endif
+
+static void
+base64_uint16 (uint32_t v, char *c)
+{
+  c[0] = base64_alphabet[(v >> 0) & 0x3f];
+  c[1] = base64_alphabet[(v >> 6) & 0x3f];
+  c[2] = base64_alphabet[(v >> 12) & 0xf];
+}
+
+#if 0
+static void
+base64_uint24 (uint32_t v, char *c)
+{
+  c[0] = base64_alphabet[(v >> 0) & 0x3f];
+  c[1] = base64_alphabet[(v >> 6) & 0x3f];
+  c[2] = base64_alphabet[(v >> 12) & 0x3f];
+  c[3] = base64_alphabet[(v >> 18) & 0x3f];
+}
+#endif
+
+static void
+base64_uint32 (uint32_t v, char *c)
+{
+  c[0] = base64_alphabet[(v >> 0) & 0x3f];
+  c[1] = base64_alphabet[(v >> 6) & 0x3f];
+  c[2] = base64_alphabet[(v >> 12) & 0x3f];
+  c[3] = base64_alphabet[(v >> 18) & 0x3f];
+  c[4] = base64_alphabet[(v >> 24) & 0x3f];
+  c[5] = base64_alphabet[(v >> 30) & 0x2];
+}
+
+/************************************************************************
+ *  conversion of raw image data to uncompressed png data: uris         *
+ ************************************************************************/
+
+/* Table of CRCs of all 8-bit messages. */
+static unsigned long crc_table[256];
+
+/* Flag: has the table been computed? Initially false. */
+static int crc_table_computed = 0;
+
+/* Make the table for a fast CRC. */
+static void
+make_crc_table(void)
+{
+  unsigned long c;
+  int n, k;
+
+  for (n = 0; n < 256; n++) {
+    c = (unsigned long) n;
+    for (k = 0; k < 8; k++) {
+      if (c & 1)
+	c = 0xedb88320L ^ (c >> 1);
+      else
+	c = c >> 1;
+    }
+    crc_table[n] = c;
+  }
+  crc_table_computed = 1;
+}
+
+static unsigned long
+update_crc(unsigned long crc, unsigned char *buf, int len)
+{
+  unsigned long c = crc;
+  int n;
+
+  if (!crc_table_computed)
+    make_crc_table();
+  for (n = 0; n < len; n++) {
+    c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8);
+  }
+  return c;
+}
+
+static unsigned long
+crc(unsigned char *buf, int len)
+{
+  return update_crc(0xffffffffL, buf, len) ^ 0xffffffffL;
+}
+
+#define BASE 65521 /* largest prime smaller than 65536 */
+static unsigned long
+update_adler32(unsigned long adler, unsigned char *buf, int len)
+{
+  unsigned long s1 = adler & 0xffff;
+  unsigned long s2 = (adler >> 16) & 0xffff;
+  int n;
+
+  for (n = 0; n < len; n++) {
+    s1 = (s1 + buf[n]) % BASE;
+    s2 = (s2 + s1)     % BASE;
+  }
+  return (s2 << 16) + s1;
+}
+
+static char *
+to_png_rgb (int w, int h, int byte_stride, uint32_t *data)
+{
+  uchar header[] = {137, 80, 78, 71, 13, 10, 26, 10};
+  uchar ihdr[13+12] = {0, 0, 0, 13, 'I', 'H', 'D', 'R',
+			/* w: */ 0, 0, 0, 0, /* h: */ 0,0,0,0,
+			/* bpp: */ 8, /* color type: */ 2,
+			0, 0, 0};
+  uchar idat_start[8] = { /* len: */0, 0, 0, 0,   'I', 'D', 'A', 'T' };
+  uchar iend[12] = {0, 0, 0, 0, 'I', 'E', 'N', 'D', 0xae, 0x42, 0x60, 0x82};
+  size_t data_size, row_size;
+  char row_header[6];
+  uint8_t *png, *p, *p_row, *p_idat;
+  uint32_t *row;
+  unsigned long adler;
+  uint32_t pixel;
+  size_t png_size;
+  int x, y;
+  char *url, *url_base64;
+  int state = 0, outlen;
+  int save = 0;
+
+  *(uint32_t *)&ihdr[8] = htonl(w);
+  *(uint32_t *)&ihdr[12] = htonl(h);
+  *(uint32_t *)&ihdr[21] = htonl(crc(&ihdr[4], 13 + 4));
+
+  row_size = 1 + w * 3;
+  row_header[0] = 0;
+  row_header[1] = row_size & 0xff;
+  row_header[2] = (row_size >> 8) & 0xff;
+  row_header[3] = ~row_header[1];
+  row_header[4] = ~row_header[2];
+  row_header[5] = 0;
+
+  data_size = 2 + (6 + w * 3) * h + 4;
+
+  *(uint32_t *)&idat_start[0] = htonl(data_size);
+
+  png_size = sizeof(header) + sizeof(ihdr) + 12 + data_size + sizeof(iend);
+  png = bw_malloc (png_size);
+
+  p = png;
+  memcpy (p, header, sizeof(header));
+  p += sizeof(header);
+  memcpy (p, ihdr, sizeof(ihdr));
+  p += sizeof(ihdr);
+  memcpy (p, idat_start, sizeof(idat_start));
+  p += sizeof(idat_start);
+
+  /* IDAT data:
+
+     zlib header:  0x78, 0x01 ,
+     h * scanline: row_header[] + width * r,g,b
+     checksum: adler32
+  */
+
+  p_idat = p - 4;
+
+  /* zlib header */
+  *p++ = 0x78;
+  *p++ = 0x01;
+
+  adler = 1;
+
+  /* scanline data */
+  for (y = 0; y < h; y++) {
+    if (y == h - 1)
+      row_header[0] = 1; /* final block */
+    memcpy (p, row_header, sizeof(row_header));
+    p += sizeof(row_header);
+    p_row = p - 1;
+    row = data;
+    data += byte_stride / 4;
+    for (x = 0; x < w; x++) {
+      pixel = *row++;
+      *p++ = (pixel >> 16) & 0xff; /* red */
+      *p++ = (pixel >> 8) & 0xff; /* green */
+      *p++ = (pixel >> 0) & 0xff; /* blue */
+    }
+    adler = update_adler32(adler, p_row, p - p_row);
+  }
+
+  /* adler32 */
+  *(uint32_t *)p = htonl(adler);
+  p += 4;
+  *(uint32_t *)p = htonl(crc(p_idat, p - p_idat));
+  p += 4;
+
+  memcpy (p, iend, sizeof(iend));
+  p += sizeof(iend);
+
+  assert(p - png == png_size);
+
+  url = bw_malloc (strlen("data:image/png;base64,") +
+		   ((png_size / 3 + 1) * 4 + 4) + 1);
+  strcpy (url, "data:image/png;base64,");
+
+  url_base64 = url + strlen("data:image/png;base64,");
+  outlen = bw_base64_encode_step (png, png_size, FALSE, url_base64, &state, &save);
+  outlen += bw_base64_encode_close (FALSE, url_base64 + outlen, &state, &save);
+  url_base64[outlen] = 0;
+
+  free (png);
+
+  return url;
+}
+
+static char *
+to_png_rgba (int w, int h, int byte_stride, uint32_t *data)
+{
+  uchar header[] = {137, 80, 78, 71, 13, 10, 26, 10};
+  uchar ihdr[13+12] = {0, 0, 0, 13, 'I', 'H', 'D', 'R',
+			/* w: */ 0, 0, 0, 0, /* h: */ 0,0,0,0,
+			/* bpp: */ 8, /* color type: */ 6,
+			0, 0, 0};
+  uchar idat_start[8] = { /* len: */0, 0, 0, 0,   'I', 'D', 'A', 'T' };
+  uchar iend[12] = {0, 0, 0, 0, 'I', 'E', 'N', 'D', 0xae, 0x42, 0x60, 0x82};
+  size_t data_size, row_size;
+  char row_header[6];
+  uint8_t *png, *p, *p_row, *p_idat;
+  uint32_t *row;
+  unsigned long adler;
+  uint32_t pixel;
+  size_t png_size;
+  int x, y;
+  char *url, *url_base64;
+  int state = 0, outlen;
+  int save = 0;
+
+  *(uint32_t *)&ihdr[8] = htonl(w);
+  *(uint32_t *)&ihdr[12] = htonl(h);
+  *(uint32_t *)&ihdr[21] = htonl(crc(&ihdr[4], 13 + 4));
+
+  row_size = 1 + w * 4;
+  row_header[0] = 0;
+  row_header[1] = row_size & 0xff;
+  row_header[2] = (row_size >> 8) & 0xff;
+  row_header[3] = ~row_header[1];
+  row_header[4] = ~row_header[2];
+  row_header[5] = 0;
+
+  data_size = 2 + (6 + w * 4) * h + 4;
+
+  *(uint32_t *)&idat_start[0] = htonl(data_size);
+
+  png_size = sizeof(header) + sizeof(ihdr) + 12 + data_size + sizeof(iend);
+  png = bw_malloc (png_size);
+
+  p = png;
+  memcpy (p, header, sizeof(header));
+  p += sizeof(header);
+  memcpy (p, ihdr, sizeof(ihdr));
+  p += sizeof(ihdr);
+  memcpy (p, idat_start, sizeof(idat_start));
+  p += sizeof(idat_start);
+
+  /* IDAT data:
+
+     zlib header:  0x78, 0x01 ,
+     h * scanline: row_header[] + width * r,g,b,a
+     checksum: adler32
+  */
+
+  p_idat = p - 4;
+
+  /* zlib header */
+  *p++ = 0x78;
+  *p++ = 0x01;
+
+  adler = 1;
+
+  /* scanline data */
+  for (y = 0; y < h; y++) {
+    if (y == h - 1)
+      row_header[0] = 1; /* final block */
+    memcpy (p, row_header, sizeof(row_header));
+    p += sizeof(row_header);
+    p_row = p - 1;
+    row = data;
+    data += byte_stride / 4;
+    for (x = 0; x < w; x++) {
+      pixel = *row++;
+      *p++ = (pixel >> 16) & 0xff; /* red */
+      *p++ = (pixel >> 8) & 0xff; /* green */
+      *p++ = (pixel >> 0) & 0xff; /* blue */
+      *p++ = (pixel >> 24) & 0xff; /* alpha */
+    }
+    adler = update_adler32(adler, p_row, p - p_row);
+  }
+
+  /* adler32 */
+  *(uint32_t *)p = htonl(adler);
+  p += 4;
+  *(uint32_t *)p = htonl(crc(p_idat, p - p_idat));
+  p += 4;
+
+  memcpy (p, iend, sizeof(iend));
+  p += sizeof(iend);
+
+  assert(p - png == png_size);
+
+  url = bw_malloc (strlen("data:image/png;base64,") +
+		   ((png_size / 3 + 1) * 4 + 4) + 1);
+  strcpy (url, "data:image/png;base64,");
+
+  url_base64 = url + strlen("data:image/png;base64,");
+  outlen = bw_base64_encode_step (png, png_size, FALSE, url_base64, &state, &save);
+  outlen += bw_base64_encode_close (FALSE, url_base64 + outlen, &state, &save);
+  url_base64[outlen] = 0;
+
+  free (png);
+
+  return url;
+}
+
+#if 0
+static char *
+to_png_a (int w, int h, int byte_stride, uint8_t *data)
+{
+  uchar header[] = {137, 80, 78, 71, 13, 10, 26, 10};
+  uchar ihdr[13+12] = {0, 0, 0, 13, 'I', 'H', 'D', 'R',
+			/* w: */ 0, 0, 0, 0, /* h: */ 0,0,0,0,
+			/* bpp: */ 8, /* color type: */ 4,
+			0, 0, 0};
+  uchar idat_start[8] = { /* len: */0, 0, 0, 0,   'I', 'D', 'A', 'T' };
+  uchar iend[12] = {0, 0, 0, 0, 'I', 'E', 'N', 'D', 0xae, 0x42, 0x60, 0x82};
+  size_t data_size, row_size;
+  char row_header[6];
+  uint8_t *png, *p, *p_row, *p_idat;
+  uint8_t *row;
+  unsigned long adler;
+  uint32_t pixel;
+  size_t png_size;
+  int x, y;
+  char *url, *url_base64;
+  int state = 0, outlen;
+  int save = 0;
+
+  *(uint32_t *)&ihdr[8] = htonl(w);
+  *(uint32_t *)&ihdr[12] = htonl(h);
+  *(uint32_t *)&ihdr[21] = htonl(crc(&ihdr[4], 13 + 4));
+
+  row_size = 1 + w * 2;
+  row_header[0] = 0;
+  row_header[1] = row_size & 0xff;
+  row_header[2] = (row_size >> 8) & 0xff;
+  row_header[3] = ~row_header[1];
+  row_header[4] = ~row_header[2];
+  row_header[5] = 0;
+
+  data_size = 2 + (6 + w * 2) * h + 4;
+
+  *(uint32_t *)&idat_start[0] = htonl(data_size);
+
+  png_size = sizeof(header) + sizeof(ihdr) + 12 + data_size + sizeof(iend);
+  png = bw_malloc (png_size);
+
+  p = png;
+  memcpy (p, header, sizeof(header));
+  p += sizeof(header);
+  memcpy (p, ihdr, sizeof(ihdr));
+  p += sizeof(ihdr);
+  memcpy (p, idat_start, sizeof(idat_start));
+  p += sizeof(idat_start);
+
+  /* IDAT data:
+
+     zlib header:  0x78, 0x01 ,
+     h * scanline: row_header[] + width * r,g,b,a
+     checksum: adler32
+  */
+
+  p_idat = p - 4;
+
+  /* zlib header */
+  *p++ = 0x78;
+  *p++ = 0x01;
+
+  adler = 1;
+
+  /* scanline data */
+  for (y = 0; y < h; y++) {
+    if (y == h - 1)
+      row_header[0] = 1; /* final block */
+    memcpy (p, row_header, sizeof(row_header));
+    p += sizeof(row_header);
+    p_row = p - 1;
+    row = data;
+    data += byte_stride / 4;
+    for (x = 0; x < w; x++) {
+      pixel = *row++;
+      *p++ = 0x00; /* gray */
+      *p++ = pixel; /* alpha */
+    }
+    adler = update_adler32(adler, p_row, p - p_row);
+  }
+
+  /* adler32 */
+  *(uint32_t *)p = htonl(adler);
+  p += 4;
+  *(uint32_t *)p = htonl(crc(p_idat, p - p_idat));
+  p += 4;
+
+  memcpy (p, iend, sizeof(iend));
+  p += sizeof(iend);
+
+  assert(p - png == png_size);
+
+  url = bw_malloc (strlen("data:image/png;base64,") +
+		  ((png_size / 3 + 1) * 4 + 4) + 1);
+  strcpy (url, "data:image/png;base64,");
+
+  url_base64 = url + strlen("data:image/png;base64,");
+  outlen = bw_base64_encode_step (png, png_size, FALSE, url_base64, &state, &save);
+  outlen += bw_base64_encode_close (FALSE, url_base64 + outlen, &state, &save);
+  url_base64[outlen] = 0;
+
+  free (png);
+
+  return url;
+}
+#endif
+
+/************************************************************************
+ *                Basic I/O primitives                                  *
+ ************************************************************************/
+
+struct BroadwayClient {
+  int fd;
+  gzFile *zfd;
+} ;
+
+static void
+broadway_client_write_raw (BroadwayClient *client,
+			   const void *buf, size_t count)
+{
+  ssize_t res;
+  int errsave;
+  const char *ptr = (const char *)buf;
+
+  while (count > 0)
+    {
+      res = write(client->fd, ptr, count);
+      if (res == -1)
+	{
+	  errsave = errno;
+	  if (errsave == EINTR)
+	    continue;
+	  fprintf(stderr, "Error on write_raw to client %d\n", errsave);
+	  exit(1);
+	}
+      if (res == 0)
+	{
+	  fprintf(stderr, "Short write_raw to client\n");
+	  exit(1);
+	}
+      count -= res;
+      ptr += res;
+    }
+}
+
+static void
+broadway_client_write (BroadwayClient *client,
+		       const void *buf, size_t count)
+{
+  ssize_t res;
+  const char *ptr = (const char *)buf;
+
+  while (count > 0)
+    {
+      res = gzwrite(client->zfd, ptr, count);
+      if (res == -1)
+	{
+	  fprintf(stderr, "Error on write to client\n");
+	  exit(1);
+	}
+      if (res == 0)
+	{
+	  fprintf(stderr, "Short write to client\n");
+	  exit(1);
+	}
+      count -= res;
+      ptr += res;
+    }
+}
+
+static void
+broadway_client_write_header (BroadwayClient *client)
+{
+  char *header;
+
+  header =
+    "Content-type: multipart/x-mixed-replace;boundary=x\r\n"
+    "Content-Encoding: gzip\r\n"
+    "\r\n";
+  broadway_client_write_raw (client,
+			     header, strlen (header));
+}
+
+static void
+send_boundary (BroadwayClient *client)
+{
+  char *boundary =
+    "--x\r\n"
+    "\r\n";
+
+  broadway_client_write (client, boundary, strlen (boundary));
+}
+
+BroadwayClient *
+broadway_client_new(int fd)
+{
+  BroadwayClient *client;
+
+  client = bw_new0 (BroadwayClient, 1);
+
+  client->fd = fd;
+
+  broadway_client_write_header (client);
+
+  client->zfd = gzdopen(fd, "wb");
+
+  /* Need an initial multipart boundary */
+  send_boundary (client);
+
+  return client;
+}
+
+void
+broadway_client_flush (BroadwayClient *client)
+{
+  send_boundary (client);
+  gzflush (client->zfd, Z_SYNC_FLUSH);
+}
+
+
+/************************************************************************
+ *                     Core rendering operations                        *
+ ************************************************************************/
+
+void
+broadway_client_copy_rectangles (BroadwayClient *client,  int id,
+				 BroadwayRect *rects, int n_rects,
+				 int dx, int dy)
+{
+  char *buf;
+  int len, i, p;
+
+  len = 1 + 3 + 3 + 3*4*n_rects + 3 + 3;
+
+  buf = bw_malloc (len);
+  p = 0;
+  buf[p++] = 'b';
+  base64_uint16(id, &buf[p]); p +=3;
+  base64_uint16(n_rects, &buf[p]); p +=3;
+  for (i = 0; i < n_rects; i++)
+    {
+      base64_uint16(rects[i].x, &buf[p]); p +=3;
+      base64_uint16(rects[i].y, &buf[p]); p +=3;
+      base64_uint16(rects[i].width, &buf[p]); p +=3;
+      base64_uint16(rects[i].height, &buf[p]); p +=3;
+    }
+  base64_uint16(dx, &buf[p]); p +=3;
+  base64_uint16(dy, &buf[p]); p +=3;
+
+  broadway_client_write (client, buf, len);
+  free (buf);
+}
+
+void
+broadway_client_new_surface(BroadwayClient *client,  int id, int x, int y, int w, int h)
+{
+  char buf[16];
+
+  buf[0] = 's';
+  base64_uint16(id, &buf[1]);
+  base64_uint16(x, &buf[4]);
+  base64_uint16(y, &buf[7]);
+  base64_uint16(w, &buf[10]);
+  base64_uint16(h, &buf[13]);
+
+  broadway_client_write (client, buf, 16);
+}
+
+void
+broadway_client_show_surface(BroadwayClient *client,  int id)
+{
+  char buf[4];
+
+  buf[0] = 'S';
+  base64_uint16(id, &buf[1]);
+
+  broadway_client_write (client, buf, 4);
+}
+
+void
+broadway_client_hide_surface(BroadwayClient *client,  int id)
+{
+  char buf[4];
+
+  buf[0] = 'H';
+  base64_uint16(id, &buf[1]);
+
+  broadway_client_write (client, buf, 4);
+}
+
+void
+broadway_client_destroy_surface(BroadwayClient *client,  int id)
+{
+  char buf[4];
+
+  buf[0] = 'd';
+  base64_uint16(id, &buf[1]);
+
+  broadway_client_write (client, buf, 4);
+}
+
+void
+broadway_client_move_surface(BroadwayClient *client,  int id, int x, int y)
+{
+  char buf[10];
+
+  buf[0] = 'm';
+  base64_uint16(id, &buf[1]);
+  base64_uint16(x, &buf[4]);
+  base64_uint16(y, &buf[7]);
+
+  broadway_client_write (client, buf, 10);
+}
+
+void
+broadway_client_put_rgb (BroadwayClient *client,  int id, int x, int y,
+			 int w, int h, int byte_stride, void *data)
+{
+  char buf[16];
+  size_t len;
+  char *url;
+
+  buf[0] = 'i';
+  base64_uint16(id, &buf[1]);
+  base64_uint16(x, &buf[4]);
+  base64_uint16(y, &buf[7]);
+
+  url = to_png_rgb (w, h, byte_stride, (uint32_t*)data);
+  len = strlen (url);
+  base64_uint32(len, &buf[10]);
+
+  broadway_client_write (client, buf, 16);
+
+  broadway_client_write (client, url, len);
+
+  free (url);
+}
+
+static void
+rgb_autocrop (unsigned char *data,
+	      int byte_stride,
+	      int *x_arg, int *y_arg,
+	      int *w_arg, int *h_arg)
+{
+  unsigned char *line;
+  int w, h;
+  int x, y, xx, yy;
+  boolean non_zero;
+
+  x = *x_arg;
+  y = *y_arg;
+  w = *w_arg;
+  h = *h_arg;
+
+  while (h > 0)
+    {
+      line = data + y * byte_stride + x * 4;
+
+      non_zero = FALSE;
+      for (xx = 0; xx < w; xx++)
+	{
+	  if (line[1] != 0 || line[2] != 0 || line[3] != 0) {
+	    non_zero = TRUE;
+	    break;
+	  }
+	  line += 4;
+	}
+
+      if (non_zero)
+	break;
+
+      y++;
+      h--;
+    }
+
+  while (h > 0)
+    {
+      line = data + (y + h - 1) * byte_stride + x * 4;
+
+      non_zero = FALSE;
+      for (xx = 0; xx < w; xx++)
+	{
+	  if (line[1] != 0 || line[2] != 0 || line[3] != 0) {
+	    non_zero = TRUE;
+	    break;
+	  }
+	  line += 4;
+	}
+
+      if (non_zero)
+	break;
+      h--;
+    }
+
+  while (w > 0)
+    {
+      line = data + y * byte_stride + x * 4;
+
+      non_zero = FALSE;
+      for (yy = 0; yy < h; yy++)
+	{
+	  if (line[1] != 0 || line[2] != 0 || line[3] != 0) {
+	    non_zero = TRUE;
+	    break;
+	  }
+	  line += byte_stride;
+	}
+
+      if (non_zero)
+	break;
+
+      x++;
+      w--;
+    }
+
+  while (w > 0)
+    {
+      line = data + y * byte_stride + (x + w - 1) * 4;
+
+      non_zero = FALSE;
+      for (yy = 0; yy < h; yy++)
+	{
+	  if (line[1] != 0 || line[2] != 0 || line[3] != 0) {
+	    non_zero = TRUE;
+	    break;
+	  }
+	  line += byte_stride;
+	}
+
+      if (non_zero)
+	break;
+      w--;
+    }
+
+    *x_arg = x;
+    *y_arg = y;
+    *w_arg = w;
+    *h_arg = h;
+}
+
+void
+broadway_client_put_delta_rgb (BroadwayClient *client,  int id, int dest_x, int dest_y,
+			       int w, int h, int byte_stride, void *data)
+{
+  char buf[16];
+  size_t len;
+  char *url;
+  int src_x, src_y;
+
+  src_x = 0;
+  src_y = 0;
+
+  rgb_autocrop (data,
+		byte_stride,
+		&src_x, &src_y, &w, &h);
+  data = (uint8_t *)data + src_x * 4 + src_y * byte_stride;
+
+  buf[0] = 'D';
+  base64_uint16(id, &buf[1]);
+  base64_uint16(dest_x + src_x, &buf[4]);
+  base64_uint16(dest_y + src_y, &buf[7]);
+
+  url = to_png_rgb (w, h, byte_stride, (uint32_t*)data);
+  len = strlen (url);
+  base64_uint32(len, &buf[10]);
+
+  broadway_client_write (client, buf, 16);
+
+  broadway_client_write (client, url, len);
+
+  free (url);
+}
+
+void
+broadway_client_put_rgba (BroadwayClient *client,  int id, int x, int y,
+			  int w, int h, int byte_stride, void *data)
+{
+  char buf[16];
+  size_t len;
+  char *url;
+
+  buf[0] = 'i';
+  base64_uint16(id, &buf[1]);
+  base64_uint16(x, &buf[4]);
+  base64_uint16(y, &buf[7]);
+
+  url = to_png_rgba (w, h, byte_stride, (uint32_t*)data);
+  len = strlen (url);
+  base64_uint32(len, &buf[10]);
+
+  broadway_client_write (client, buf, 16);
+
+  broadway_client_write (client, url, len);
+
+  free (url);
+}
+
+#if 0
+static void
+send_image_a (BroadwayClient *client,  int id, int x, int y,
+	      int w, int h, int byte_stride, uint8_t *data)
+{
+  char buf[16];
+  size_t len;
+  char *url;
+
+  buf[0] = 'i';
+  base64_uint16(id, &buf[1]);
+  base64_uint16(x, &buf[4]);
+  base64_uint16(y, &buf[7]);
+
+  url = to_png_a (w, h, byte_stride, data);
+  len = strlen (url);
+  base64_uint32(len, &buf[10]);
+
+  broadway_client_write (client, buf, 16);
+
+  broadway_client_write (client, url, len);
+
+  free (url);
+}
+#endif
diff --git a/gdk/broadway/broadway.h b/gdk/broadway/broadway.h
new file mode 100644
index 0000000..8ae0d6d
--- /dev/null
+++ b/gdk/broadway/broadway.h
@@ -0,0 +1,55 @@
+typedef struct BroadwayClient BroadwayClient;
+
+typedef struct  {
+    int x, y;
+    int width, height;
+} BroadwayRect;
+
+BroadwayClient *broadway_client_new             (int             fd);
+void            broadway_client_flush           (BroadwayClient *client);
+void            broadway_client_new_surface     (BroadwayClient *client,
+						 int             id,
+						 int             x,
+						 int             y,
+						 int             w,
+						 int             h);
+void            broadway_client_show_surface    (BroadwayClient *client,
+						 int             id);
+void            broadway_client_hide_surface    (BroadwayClient *client,
+						 int             id);
+void            broadway_client_destroy_surface (BroadwayClient *client,
+						 int             id);
+void            broadway_client_move_surface    (BroadwayClient *client,
+						 int             id,
+						 int             x,
+						 int             y);
+void            broadway_client_put_rgb         (BroadwayClient *client,
+						 int             id,
+						 int             x,
+						 int             y,
+						 int             w,
+						 int             h,
+						 int             byte_stride,
+						 void           *data);
+void            broadway_client_put_rgba        (BroadwayClient *client,
+						 int             id,
+						 int             x,
+						 int             y,
+						 int             w,
+						 int             h,
+						 int             byte_stride,
+						 void           *data);
+void            broadway_client_put_delta_rgb   (BroadwayClient *client,
+						 int             id,
+						 int             dest_x,
+						 int             dest_y,
+						 int             w,
+						 int             h,
+						 int             byte_stride,
+						 void           *data);
+void            broadway_client_copy_rectangles (BroadwayClient *client,
+						 int             id,
+						 BroadwayRect   *rects,
+						 int             n_rects,
+						 int             dx,
+						 int             dy);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]