diff options
Diffstat (limited to 'libs/cairo-1.16.0/util/cairo-sphinx/sphinx.c')
-rw-r--r-- | libs/cairo-1.16.0/util/cairo-sphinx/sphinx.c | 1545 |
1 files changed, 0 insertions, 1545 deletions
diff --git a/libs/cairo-1.16.0/util/cairo-sphinx/sphinx.c b/libs/cairo-1.16.0/util/cairo-sphinx/sphinx.c deleted file mode 100644 index 238d400..0000000 --- a/libs/cairo-1.16.0/util/cairo-sphinx/sphinx.c +++ /dev/null @@ -1,1545 +0,0 @@ -/* - * The intention for sphinx is for detection of rendering errors inside - * applications by simultaneously rendering on to the target device and on - * an image surface and comparing the two. If it found a discrepancy, it - * would then dump the trace that reproduces the error. (Then apply - * delta-debugging to reduce that down to a minimal trace.) - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <stdio.h> -#include <stdlib.h> -#include <sys/stat.h> -#include <sys/mman.h> -#include <sys/socket.h> -#include <sys/poll.h> -#include <sys/un.h> -#include <unistd.h> -#include <fcntl.h> -#include <signal.h> -#include <errno.h> -#include <assert.h> -#include <pthread.h> - -#include <cairo.h> -#include <cairo-script.h> -#include <cairo-script-interpreter.h> -#include <cairo-boilerplate.h> - -#include <glib.h> /* for checksumming */ - -#ifndef CAIRO_HAS_REAL_PTHREAD -# error "cairo-sphinx needs real pthreads" -#endif - -#ifndef MAP_NORESERVE -#define MAP_NORESERVE 0 -#endif - -#define DATA_SIZE (256 << 20) -#define SHM_PATH_XXX "/shmem-cairo-sphinx" - -struct client { - int sk; - const cairo_boilerplate_target_t *target; - cairo_surface_t *surface; - void *base; - - cairo_script_interpreter_t *csi; - struct context_closure { - struct context_closure *next; - unsigned long id; - cairo_t *context; - cairo_surface_t *surface; - cairo_surface_t *original; - } *contexts; - - unsigned long context_id; -}; - -struct surface_tag { - long width, height; -}; -static const cairo_user_data_key_t surface_tag; - -static int -client_socket (const char *socket_path); - -static int -writen (int fd, const void *ptr, int len) -{ -#if 1 - const uint8_t *data = ptr; - while (len) { - int ret = write (fd, data, len); - if (ret < 0) { - switch (errno) { - case EAGAIN: - case EINTR: - continue; - default: - return FALSE; - } - } else if (ret == 0) { - return FALSE; - } else { - data += ret; - len -= ret; - } - } - return TRUE; -#else - int ret = send (fd, ptr, len, 0); - return ret == len; -#endif -} - -static int -readn (int fd, void *ptr, int len) -{ -#if 0 - uint8_t *data = ptr; - while (len) { - int ret = read (fd, data, len); - if (ret < 0) { - switch (errno) { - case EAGAIN: - case EINTR: - continue; - default: - return FALSE; - } - } else if (ret == 0) { - return FALSE; - } else { - data += ret; - len -= ret; - } - } - return TRUE; -#else - int ret = recv (fd, ptr, len, MSG_WAITALL); - return ret == len; -#endif -} -static int -open_devnull_to_fd (int want_fd, int flags) -{ - int error; - int got_fd; - - close (want_fd); - - got_fd = open("/dev/null", flags | O_CREAT, 0700); - if (got_fd == -1) - return -1; - - error = dup2 (got_fd, want_fd); - close (got_fd); - - return error; -} - -static int -daemonize (void) -{ - void (*oldhup) (int); - - /* Let the parent go. */ - switch (fork ()) { - case -1: return -1; - case 0: break; - default: _exit (0); - } - - /* Become session leader. */ - if (setsid () == -1) - return -1; - - /* Refork to yield session leadership. */ - oldhup = signal (SIGHUP, SIG_IGN); - switch (fork ()) { - case -1: return -1; - case 0: break; - default: _exit (0); - } - signal (SIGHUP, oldhup); - - /* Establish stdio. */ - if (open_devnull_to_fd (0, O_RDONLY) == -1) - return -1; - if (open_devnull_to_fd (1, O_WRONLY | O_APPEND) == -1) - return -1; - if (dup2 (1, 2) == -1) - return -1; - - return 0; -} - -static int -server_socket (const char *socket_path) -{ - long flags; - struct sockaddr_un addr; - int sk; - - unlink (socket_path); - - sk = socket (PF_UNIX, SOCK_STREAM, 0); - if (sk == -1) - return -1; - - memset (&addr, 0, sizeof (addr)); - addr.sun_family = AF_UNIX; - strcpy (addr.sun_path, socket_path); - if (bind (sk, (struct sockaddr *) &addr, sizeof (addr)) == -1) { - close (sk); - return -1; - } - - flags = fcntl (sk, F_GETFL); - if (flags == -1 || fcntl (sk, F_SETFL, flags | O_NONBLOCK) == -1) { - close (sk); - return -1; - } - - if (listen (sk, 5) == -1) { - close (sk); - return -1; - } - - return sk; -} - -static int -readline (int fd, char *line, int max) -{ - int len = 0; - do { - int ret = read (fd, &line[len], 1); - if (ret <= 0) - return -1; - } while (line[len] != '\n' && ++len < max); - line[len] = '\0'; - return len; -} - -struct clients { - int count, size; - int complete; - - cairo_surface_t *recording; - unsigned long serial; - - struct client_info { - int sk; - int trace; - unsigned long image_serial; - cairo_surface_t *image; - char *name; - char *target; - char *reference; - - uint8_t *out_buf; - int out_len; - int out_size; - } *clients; - const char *shm_path; - unsigned long offset; - uint8_t *base; -}; - -static void * -clients_shm (const char *shm_path) -{ - void *base; - int fd; - - shm_unlink (shm_path); - fd = shm_open (shm_path, O_RDWR | O_EXCL | O_CREAT, 0777); - if (fd == -1) - return MAP_FAILED; - - if (ftruncate (fd, DATA_SIZE) == -1) { - close (fd); - return MAP_FAILED; - } - - base = mmap (NULL, DATA_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - close (fd); - - return base; -} - -static int -clients_init (struct clients *clients) -{ - clients->count = 0; - clients->complete = 0; - clients->size = 4; - clients->clients = xmalloc (clients->size * sizeof (struct client_info)); - - clients->shm_path = SHM_PATH_XXX; - clients->base = clients_shm (clients->shm_path); - if (clients->base == MAP_FAILED) - return -1; - clients->offset = 0; - - clients->recording = NULL; - clients->serial = 0; - - return 0; -} - -static void -clients_add_command (struct clients *clients, int fd, char *info) -{ - struct client_info *c; - char buf[1024]; - int len; - char *str; - - if (clients->count == clients->size) { - clients->size *= 2; - clients->clients = xrealloc (clients->clients, - clients->size * sizeof (struct client_info)); - } - - c = &clients->clients[clients->count++]; - c->sk = fd; - c->trace = -1; - c->image_serial = 0; - c->image = NULL; - c->name = c->target = c->reference = NULL; - - c->out_size = 8192; - c->out_buf = xmalloc (c->out_size); - c->out_len = 0; - - str = strstr (info, "name="); - if (str != NULL) { - char *sp = strchr (str + 5, ' '); - int len; - if (sp) - len = sp - str - 5; - else - len = strlen (str + 5); - c->name = xmalloc (len + 1); - memcpy (c->name, str + 5, len); - c->name[len] = '\0'; - } - - str = strstr (info, "target="); - if (str != NULL) { - char *sp = strchr (str + 7, ' '); - int len; - if (sp) - len = sp - str - 7; - else - len = strlen (str + 7); - c->target = xmalloc (len + 1); - memcpy (c->target, str + 7, len); - c->target[len] = '\0'; - } - - str = strstr (info, "reference="); - if (str != NULL) { - char *sp = strchr (str + 10, ' '); - int len; - if (sp) - len = sp - str - 10; - else - len = strlen (str + 10); - c->reference = xmalloc (len + 1); - memcpy (c->reference, str + 10, len); - c->reference[len] = '\0'; - } - - len = sprintf (buf, "%s\n", clients->shm_path); - writen (fd, buf, len); -} - -static void -clients_add_trace (struct clients *clients, int fd, char *info) -{ - char *str, *sp; - char *name; - int i; - - str = strstr (info, "name="); - assert (str != NULL); - sp = strchr (str + 5, ' '); - if (sp) - i = sp - str - 5; - else - i = strlen (str + 5); - - name = xmalloc (i + 1); - memcpy (name, str + 5, i); - name[i] = '\0'; - - for (i = 0; i < clients->count; i++) { - struct client_info *c = &clients->clients[i]; - if (strcmp (name, c->name) == 0) { - c->trace = fd; - break; - } - } - - free (name); -} - -static int -clients_image (struct clients *clients, int fd, char *info) -{ - struct client_info *c = NULL; - int format, width, height, stride, size; - int i; - - for (i = 0; i < clients->count; i++) { - if (clients->clients[i].sk == fd) { - c = &clients->clients[i]; - break; - } - } - - if (c == NULL) - return 0; - - if (sscanf (info, "%lu %d %d %d %d", - &c->image_serial, &format, &width, &height, &stride) != 5) - { - return 0; - } - - size = height * stride; - size = (size + 4095) & -4096; - assert (clients->offset + size <= DATA_SIZE); - - c->image = - cairo_image_surface_create_for_data (clients->base + clients->offset, - format, width, height, stride); - - if (! writen (fd, &clients->offset, sizeof (clients->offset))) - return 0; - - clients->offset += size; - - return 1; -} - -static int -u8_cmp (const void *A, const void *B) -{ - const uint8_t *a = A, *b = B; - return (int) *a - (int) *b; -} - -static uint8_t -median (uint8_t *values, int count) -{ - /* XXX could use a fast median here if we cared */ - qsort (values, count, 1, u8_cmp); - return values[count/2]; -} - -static uint32_t -get_pixel32 (int x, int y, const uint8_t *data, int stride) -{ - return ((uint32_t *)(data + y * stride))[x]; -} - -static uint8_t -get_median_32 (int x, int y, int channel, - const uint8_t *data, int width, int height, int stride) -{ - uint8_t neighbourhood[25]; - int cnt = 0; - int xx, yy; - - for (yy = y - 2; yy <= y + 2; yy++) { - if (yy < 0) - continue; - if (yy >= height) - continue; - - for (xx = x - 2; xx <= x + 2; xx++) { - if (xx < 0) - continue; - if (xx >= width) - continue; - - neighbourhood[cnt++] = (get_pixel32 (xx, yy, data, stride) >> (channel*8)) & 0xff; - } - } - - return median (neighbourhood, cnt); -} - -static uint8_t -get_pixel8 (int x, int y, const uint8_t *data, int stride) -{ - return data[y * stride + x]; -} - -static uint8_t -get_median_8 (int x, int y, const uint8_t *data, int width, int height, int stride) -{ - uint8_t neighbourhood[25]; - int cnt = 0; - int xx, yy; - - for (yy = y - 2; yy <= y + 2; yy++) { - if (yy < 0) - continue; - if (yy >= height) - continue; - - for (xx = x - 2; xx <= x + 2; xx++) { - if (xx < 0) - continue; - if (xx >= width) - continue; - - neighbourhood[cnt++] = get_pixel8 (xx, yy, data, stride); - } - } - - return median (neighbourhood, cnt); -} - -static cairo_bool_t -compare_images (cairo_surface_t *a, - cairo_surface_t *b) -{ - int width, height, stride; - const uint8_t *aa, *bb; - int x, y; - - if (cairo_surface_status (a) || cairo_surface_status (b)) - return FALSE; - - if (cairo_surface_get_type (a) != cairo_surface_get_type (b)) - return FALSE; - - if (cairo_image_surface_get_format (a) != cairo_image_surface_get_format (b)) - return FALSE; - - if (cairo_image_surface_get_width (a) != cairo_image_surface_get_width (b)) - return FALSE; - - if (cairo_image_surface_get_height (a) != cairo_image_surface_get_height (b)) - return FALSE; - - if (cairo_image_surface_get_stride (a) != cairo_image_surface_get_stride (b)) - return FALSE; - - - width = cairo_image_surface_get_width (a); - height = cairo_image_surface_get_height (a); - stride = cairo_image_surface_get_stride (a); - - aa = cairo_image_surface_get_data (a); - bb = cairo_image_surface_get_data (b); - switch (cairo_image_surface_get_format (a)) { - case CAIRO_FORMAT_ARGB32: - for (y = 0; y < height; y++) { - const uint32_t *ua = (uint32_t *) aa; - const uint32_t *ub = (uint32_t *) bb; - for (x = 0; x < width; x++) { - if (ua[x] != ub[x]) { - int channel; - - for (channel = 0; channel < 4; channel++) { - unsigned va, vb, diff; - - va = (ua[x] >> (channel*8)) & 0xff; - vb = (ub[x] >> (channel*8)) & 0xff; - diff = abs (va - vb); - if (diff > 1) { - va = get_median_32 (x, y, channel, aa, width, height, stride); - vb = get_median_32 (x, y, channel, bb, width, height, stride); - diff = abs (va - vb); - if (diff > 1) - return FALSE; - } - } - } - } - aa += stride; - bb += stride; - } - break; - - case CAIRO_FORMAT_RGB24: - for (y = 0; y < height; y++) { - const uint32_t *ua = (uint32_t *) aa; - const uint32_t *ub = (uint32_t *) bb; - for (x = 0; x < width; x++) { - if ((ua[x] & 0x00ffffff) != (ub[x] & 0x00ffffff)) { - int channel; - - for (channel = 0; channel < 3; channel++) { - unsigned va, vb, diff; - - va = (ua[x] >> (channel*8)) & 0xff; - vb = (ub[x] >> (channel*8)) & 0xff; - diff = abs (va - vb); - if (diff > 1) { - va = get_median_32 (x, y, channel, aa, width, height, stride); - vb = get_median_32 (x, y, channel, bb, width, height, stride); - diff = abs (va - vb); - if (diff > 1) - return FALSE; - } - } - } - } - aa += stride; - bb += stride; - } - break; - - case CAIRO_FORMAT_A8: - for (y = 0; y < height; y++) { - for (x = 0; x < width; x++) { - if (aa[x] != bb[x]) { - unsigned diff = abs (aa[x] - bb[x]); - if (diff > 1) { - uint8_t va, vb; - - va = get_median_8 (x, y, aa, width, height, stride); - vb = get_median_8 (x, y, bb, width, height, stride); - diff = abs (va - vb); - if (diff > 1) - return FALSE; - } - - } - } - aa += stride; - bb += stride; - } - break; - - case CAIRO_FORMAT_A1: - width /= 8; - for (y = 0; y < height; y++) { - if (memcmp (aa, bb, width)) - return FALSE; - aa += stride; - bb += stride; - } - break; - - case CAIRO_FORMAT_INVALID: - case CAIRO_FORMAT_RGB16_565: /* XXX */ - break; - } - - return TRUE; -} - -static int -check_images (struct clients *clients) -{ - int i, j; - - for (i = 0; i < clients->count; i++) { - struct client_info *c = &clients->clients[i]; - - if (c->reference == NULL) - continue; - - for (j = 0; j < clients->count; j++) { - struct client_info *ref = &clients->clients[j]; - - if (strcmp (c->reference, ref->name)) - continue; - - if (! compare_images (c->image, ref->image)) - return 0; - } - } - - return 1; -} - -static gchar * -checksum (const char *filename) -{ - gchar *str = NULL; - gchar *data; - gsize len; - - if (g_file_get_contents (filename, &data, &len, NULL)) { - str = g_compute_checksum_for_data (G_CHECKSUM_SHA1, (guchar *) data, len); - g_free (data); - } - - return str; -} - -static void -write_trace (struct clients *clients) -{ - cairo_device_t *ctx; - gchar *csum; - char buf[4096]; - int i; - - mkdir ("output", 0777); - - ctx = cairo_script_create ("output/cairo-sphinx.trace"); - cairo_script_from_recording_surface (ctx, clients->recording); - cairo_device_destroy (ctx); - - csum = checksum ("output/cairo-sphinx.trace"); - - sprintf (buf, "output/%s.trace", csum); - if (! g_file_test (buf, G_FILE_TEST_EXISTS)) { - rename ("output/cairo-sphinx.trace", buf); - - sprintf (buf, "output/%s.recording.png", csum); - cairo_surface_write_to_png (clients->recording, buf); - - for (i = 0; i < clients->count; i++) { - struct client_info *c = &clients->clients[i]; - if (c->image != NULL) { - sprintf (buf, "output/%s.%s.png", csum, c->name); - cairo_surface_write_to_png (c->image, buf); - } - } - } -} - -static void -clients_complete (struct clients *clients, int fd) -{ - int i; - - for (i = 0; i < clients->count; i++) { - if (clients->clients[i].sk == fd) { - break; - } - } - if (i == clients->count) - return; - - if (++clients->complete != clients->count) - return; - - clients->offset = 0; - clients->complete = 0; - - if (! check_images (clients)) - write_trace (clients); - - /* ack */ - for (i = 0; i < clients->count; i++) { - struct client_info *c = &clients->clients[i]; - - cairo_surface_destroy (c->image); - c->image = NULL; - - if (! writen (c->sk, &clients->serial, sizeof (clients->serial))) - continue; - - c->image_serial = 0; - } - - clients->recording = NULL; - clients->serial = 0; -} - -static void -clients_recording (struct clients *clients, int fd, char *info) -{ - sscanf (info, "%p %lu", &clients->recording, &clients->serial); - clients_complete (clients, fd); -} - -static void -clients_remove (struct clients *clients, int fd) -{ - int i, j; - - for (i = 0; i < clients->count; i++) { - struct client_info *c = &clients->clients[i]; - if (c->sk == fd) { - free (c->out_buf); - break; - } - } - - for (j = i++; i < clients->count; i++) - clients->clients[j] = clients->clients[i]; - - clients->count = j; -} - -static void -clients_send_trace (struct clients *clients, - const char * const line, const int len) -{ - int i; - - for (i = 0; i < clients->count; i++) { - struct client_info *c = &clients->clients[i]; - int ret, rem = len; - - if (c->trace == -1) - continue; - - if (c->out_len) { - ret = write (c->trace, c->out_buf, c->out_len); - if (ret > 0) { - c->out_len -= ret; - if (c->out_len) - memmove (c->out_buf, c->out_buf + ret, c->out_len); - } - } - - if (! c->out_len) { - ret = write (c->trace, line, rem); - if (ret > 0) - rem -= ret; - } - - if (rem) { - if (c->out_len + rem > c->out_size) { - c->out_size *= 2; - c->out_buf = xrealloc (c->out_buf, c->out_size); - } - - memcpy (c->out_buf + c->out_len, line, rem); - c->out_len += rem; - } - } -} - -static void -clients_fini (struct clients *clients) -{ - shm_unlink (clients->shm_path); - munmap (clients->base, DATA_SIZE); - free (clients->clients); -} - -static int -nonblocking (int fd) -{ - long flags; - - flags = fcntl (fd, F_GETFL); - if (flags == -1) - return -1; - - return fcntl (fd, F_SETFL, flags | O_NONBLOCK); -} - -static void * -request_image (struct client *c, - struct context_closure *closure, - cairo_format_t format, - int width, int height, int stride) -{ - char buf[1024]; - unsigned long offset = -1; - int len; - - assert (format != CAIRO_FORMAT_INVALID); - - len = sprintf (buf, ".image %lu %d %d %d %d\n", - closure->id, format, width, height, stride); - writen (c->sk, buf, len); - - readn (c->sk, &offset, sizeof (offset)); - if (offset == (unsigned long) -1) - return NULL; - - return (uint8_t *) c->base + offset; -} - -static cairo_format_t -format_for_content (cairo_content_t content) -{ - switch (content) { - case CAIRO_CONTENT_ALPHA: - return CAIRO_FORMAT_A8; - case CAIRO_CONTENT_COLOR: - return CAIRO_FORMAT_RGB24; - default: - case CAIRO_CONTENT_COLOR_ALPHA: - return CAIRO_FORMAT_ARGB32; - } -} - -static void -get_surface_size (cairo_surface_t *surface, - int *width, int *height, - cairo_format_t *format) -{ - if (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE) { - *width = cairo_image_surface_get_width (surface); - *height = cairo_image_surface_get_height (surface); - *format = cairo_image_surface_get_format (surface); - } else { - struct surface_tag *tag; - - tag = cairo_surface_get_user_data (surface, &surface_tag); - if (tag != NULL) { - *width = tag->width; - *height = tag->height; - } else { - double x0, x1, y0, y1; - cairo_t *cr; - - /* presumably created using cairo_surface_create_similar() */ - cr = cairo_create (surface); - cairo_clip_extents (cr, &x0, &y0, &x1, &y1); - cairo_destroy (cr); - - tag = xmalloc (sizeof (*tag)); - *width = tag->width = ceil (x1 - x0); - *height = tag->height = ceil (y1 - y0); - - if (cairo_surface_set_user_data (surface, &surface_tag, tag, free)) - exit (-1); - } - } -} - - -static void -send_surface (struct client *c, - struct context_closure *closure) -{ - cairo_surface_t *source = closure->surface; - cairo_surface_t *image; - cairo_format_t format = CAIRO_FORMAT_INVALID; - cairo_t *cr; - int width, height, stride; - void *data; - unsigned long serial; - - get_surface_size (source, &width, &height, &format); - if (format == CAIRO_FORMAT_INVALID) - format = format_for_content (cairo_surface_get_content (source)); - - stride = cairo_format_stride_for_width (format, width); - - data = request_image (c, closure, format, width, height, stride); - if (data == NULL) - exit (-1); - - image = cairo_image_surface_create_for_data (data, - format, - width, height, - stride); - cr = cairo_create (image); - cairo_surface_destroy (image); - - cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); - cairo_set_source_surface (cr, source, 0, 0); - cairo_paint (cr); - cairo_destroy (cr); - - /* signal completion */ - writen (c->sk, ".complete\n", strlen (".complete\n")); - - /* wait for image check */ - serial = 0; - readn (c->sk, &serial, sizeof (serial)); - if (serial != closure->id) - exit (-1); -} - -static void -send_recording (struct client *c, - struct context_closure *closure) -{ - cairo_surface_t *source = closure->surface; - char buf[1024]; - int len; - unsigned long serial; - - assert (cairo_surface_get_type (source) == CAIRO_SURFACE_TYPE_RECORDING); - len = sprintf (buf, ".recording %p %lu\n", source, closure->id); - writen (c->sk, buf, len); - - /* wait for image check */ - - serial = 0; - readn (c->sk, &serial, sizeof (serial)); - if (serial != closure->id) - exit (-1); -} - -static cairo_surface_t * -_surface_create (void *closure, - cairo_content_t content, - double width, double height, - long uid) -{ - struct client *c = closure; - cairo_surface_t *surface; - - surface = cairo_surface_create_similar (c->surface, - content, width, height); - if (cairo_surface_get_type (surface) != CAIRO_SURFACE_TYPE_IMAGE) { - struct surface_tag *tag; - - tag = xmalloc (sizeof (*tag)); - tag->width = width; - tag->height = height; - if (cairo_surface_set_user_data (surface, &surface_tag, tag, free)) - exit (-1); - } - - return surface; -} - -static cairo_t * -_context_create (void *closure, cairo_surface_t *surface) -{ - struct client *c = closure; - struct context_closure *l; - cairo_bool_t foreign = FALSE; - - l = xmalloc (sizeof (*l)); - l->next = c->contexts; - l->surface = surface; - l->original = cairo_surface_reference (surface); - l->id = ++c->context_id; - if (l->id == 0) - l->id = ++c->context_id; - c->contexts = l; - - /* record everything, including writes to images */ - if (c->target == NULL) { - if (cairo_surface_get_type (surface) != CAIRO_SURFACE_TYPE_RECORDING) { - cairo_format_t format; - int width, height; - - get_surface_size (surface, &width, &height, &format); - l->surface = cairo_surface_create_similar (c->surface, - cairo_surface_get_content (surface), - width, height); - foreign = TRUE; - } - } - - l->context = cairo_create (l->surface); - if (foreign) { - cairo_set_source_surface (l->context, surface, 0, 0); - cairo_paint (l->context); - } - - return l->context; -} - -static void -_context_destroy (void *closure, void *ptr) -{ - struct client *c = closure; - struct context_closure *l, **prev = &c->contexts; - - while ((l = *prev) != NULL) { - if (l->context == ptr) { - if (cairo_surface_status (l->surface) == CAIRO_STATUS_SUCCESS) { - if (c->target == NULL) - send_recording (c, l); - else - send_surface (c, l); - } else { - exit (-1); - } - - cairo_surface_destroy (l->original); - *prev = l->next; - free (l); - return; - } - prev = &l->next; - } -} - -static void * -recorder (void *arg) -{ - struct client client; - const cairo_script_interpreter_hooks_t hooks = { - .closure = &client, - .surface_create = _surface_create, - .context_create = _context_create, - .context_destroy = _context_destroy, - }; - char *buf; - int buf_size; - int len = 0, ret; - struct pollfd pfd; - - client.target = NULL; - client.sk = client_socket ("/tmp/cairo-sphinx"); - if (client.sk < 0) - return NULL; - - buf_size = 65536; - buf = xmalloc (buf_size); - - len = sprintf (buf, "client-command target=recording name=.recorder\n"); - if (! writen (client.sk, buf, len)) - return NULL; - - /* drain the shm_path */ - len = readline (client.sk, buf, buf_size); - - pfd.fd = client_socket ("/tmp/cairo-sphinx"); - if (pfd.fd < 0) - return NULL; - - len = sprintf (buf, "client-trace name=.recorder\n"); - if (! writen (pfd.fd, buf, len)) - return NULL; - - client.surface = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, - NULL); - - client.context_id = 0; - client.csi = cairo_script_interpreter_create (); - cairo_script_interpreter_install_hooks (client.csi, &hooks); - - nonblocking (pfd.fd); - pfd.events = POLLIN; - len = 0; - while (poll (&pfd, 1, -1) > 0) { - while ((ret = read (pfd.fd, buf + len, buf_size - len)) > 0) { - int end; - - if (ret == buf_size - len) { - buf_size *= 2; - buf = xrealloc (buf, buf_size); - } - len += ret; - - for (end = len; end > 0 && buf[--end] != '\n'; ) - ; - if (end > 0) { - buf[end] = '\0'; - cairo_script_interpreter_feed_string (client.csi, buf, end); - - len -= end + 1; - if (len) - memmove (buf, buf + end + 1, len); - } - } - if (ret == 0) - break; - if (! (errno == EAGAIN || errno == EINTR)) - break; - } - - cairo_script_interpreter_finish (client.csi); - cairo_script_interpreter_destroy (client.csi); - - cairo_surface_destroy (client.surface); - return NULL; -} - -static int -do_server (const char *path) -{ - pthread_t thread; - struct clients clients; - char line[4096]; - struct pollfd *pfd; - int num_pfd, size_pfd; - int n, cnt, ret = 1; - int sk, source = -1; - int waiter = -1, waiter_count = 0; - int len; - - signal (SIGPIPE, SIG_IGN); - - if (clients_init (&clients) < 0) { - fprintf (stderr, "Failed to initialise clients structure\n"); - return -1; - } - - sk = server_socket (path); - if (sk < 0) { - fprintf (stderr, "Failed to create server socket\n"); - return 1; - } - - if (daemonize () < 0) - return 1; - - if (pthread_create (&thread, NULL, recorder, NULL) < 0) { - fprintf (stderr, "Failed to create spawn recording thread\n"); - return 1; - } - - size_pfd = 4; - pfd = xmalloc (sizeof (*pfd) * size_pfd); - pfd[0].fd = sk; - pfd[0].events = POLLIN; - num_pfd = 1; - - while ((cnt = poll (pfd, num_pfd, -1)) > 0) { - int have_source; - - if (pfd[0].revents) { - while ((sk = accept (pfd[0].fd, NULL, NULL)) != -1) { - len = readline (sk, line, sizeof (line)); - if (strcmp (line, "source") == 0) { - - if (source != -1) - exit (1); - - source = sk; - if (nonblocking (sk) < 0) { - close (sk); - continue; - } - } else if (strncmp (line, "client-command", 14) == 0) { - if (source == -1) - clients_add_command (&clients, sk, line); - } else if (strncmp (line, "client-trace", 12) == 0) { - if (source == -1) { - clients_add_trace (&clients, sk, line); - if (nonblocking (sk) < 0) { - close (sk); - continue; - } - - if (clients.count == waiter_count) { - for (n = 1; n < num_pfd; n++) { - if (pfd[n].fd == waiter) { - pfd[n].fd = -1; - break; - } - } - close (waiter); - waiter_count = -1; - } - } - } else if (strncmp (line, "wait", 4) == 0) { - int count = atoi (line + 5) + 1; - if (clients.count == count) { - close (sk); - continue; - } else { - waiter = sk; - waiter_count = count; - } - } - - if (num_pfd == size_pfd) { - size_pfd *= 2; - pfd = xrealloc (pfd, sizeof (*pfd) * size_pfd); - } - - pfd[num_pfd].fd = sk; - pfd[num_pfd].events = POLLIN; - pfd[num_pfd].revents = 0; - num_pfd++; - } - cnt--; - } - - have_source = 0; - for (n = 1; cnt && n < num_pfd; n++) { - if (! pfd[n].revents) - continue; - cnt--; - - if (pfd[n].fd == -1) - continue; - - if (source == pfd[n].fd) { - have_source = n; - } else { - len = readline (pfd[n].fd, line, sizeof (line)); - if (len < 0) { - clients_remove (&clients, pfd[n].fd); - close (pfd[n].fd); - pfd[n].fd = -1; - continue; - } - - if (strncmp (line, ".image", 6) == 0) { - if (! clients_image (&clients, pfd[n].fd, line + 7)) { - clients_remove (&clients, pfd[n].fd); - close (pfd[n].fd); - pfd[n].fd = -1; - continue; - } - } else if (strncmp (line, ".complete", 9) == 0) { - clients_complete (&clients, pfd[n].fd); - } else if (strncmp (line, ".recording", 10) == 0) { - clients_recording (&clients, pfd[n].fd, line + 6); - } else { - printf ("do_command (%s)\n", line); - } - } - } - - if (have_source) { - do { - len = read (source, line, sizeof (line)); - if (len > 0) { - clients_send_trace (&clients, line, len); - } else if (len == 0) { - close (source); - pfd[have_source].fd = source = -1; - goto done; - } else - break; - } while (1); - } - - for (n = cnt = 1; n < num_pfd; n++) { - if (pfd[n].fd != -1) { - if (cnt != n) - pfd[cnt] = pfd[n]; - cnt++; - } - } - num_pfd = cnt; - } - -done: - ret = 0; - for (n = 0; n < num_pfd; n++) { - if (pfd[n].fd != -1) - close (pfd[n].fd); - } - free (pfd); - clients_fini (&clients); - - return ret; -} - -static void * -client_shm (const char *shm_path) -{ - void *base; - int fd; - - fd = shm_open (shm_path, O_RDWR, 0); - if (fd == -1) - return MAP_FAILED; - - base = mmap (NULL, DATA_SIZE, - PROT_READ | PROT_WRITE, - MAP_SHARED | MAP_NORESERVE, - fd, 0); - close (fd); - - return base; -} - -static int -client_socket (const char *socket_path) -{ - struct sockaddr_un addr; - int sk; - - sk = socket (PF_UNIX, SOCK_STREAM, 0); - if (sk == -1) - return -1; - - memset (&addr, 0, sizeof (addr)); - addr.sun_family = AF_UNIX; - strcpy (addr.sun_path, socket_path); - - if (connect (sk, (struct sockaddr *) &addr, sizeof (addr)) == -1) - return -1; - - return sk; -} - -static int -do_client (int fd, - const char *target, - const char *name, - const char *reference, - cairo_content_t content) -{ - struct client client; - const cairo_script_interpreter_hooks_t hooks = { - .closure = &client, - .surface_create = _surface_create, - .context_create = _context_create, - .context_destroy = _context_destroy, - }; - void *closure; - char *buf; - int buf_size; - int len = 0, ret; - struct pollfd pfd; - - client.sk = fd; - client.target = cairo_boilerplate_get_target_by_name (target, content); - client.context_id = 0; - - client.surface = client.target->create_surface (NULL, content, 1, 1, 1, 1, - CAIRO_BOILERPLATE_MODE_TEST, - &closure); - if (client.surface == NULL) { - fprintf (stderr, "Failed to create target surface: %s.\n", - client.target->name); - return 1; - } - - buf_size = 65536; - buf = xmalloc (buf_size); - - if (reference != NULL) { - len = sprintf (buf, - "client-command name=%s target=%s reference=%s\n", - name, target, reference); - } else { - len = sprintf (buf, - "client-command name=%s target=%s\n", - name, target); - } - if (! writen (fd, buf, len)) - return 1; - - len = readline (fd, buf, buf_size); - client.base = client_shm (buf); - if (client.base == MAP_FAILED) { - fprintf (stderr, "Failed to map shared memory segment '%s'.\n", buf); - return 1; - } - - if (daemonize () < 0) - return 1; - - pfd.fd = client_socket ("/tmp/cairo-sphinx"); - if (pfd.fd < 0) - return 1; - - len = sprintf (buf, "client-trace name=%s\n", name); - if (! writen (pfd.fd, buf, len)) - return 1; - - client.csi = cairo_script_interpreter_create (); - cairo_script_interpreter_install_hooks (client.csi, &hooks); - - nonblocking (pfd.fd); - pfd.events = POLLIN; - len = 0; - while (poll (&pfd, 1, -1) > 0) { - while ((ret = read (pfd.fd, buf + len, buf_size - len)) > 0) { - int end; - - if (ret == buf_size - len) { - buf_size *= 2; - buf = xrealloc (buf, buf_size); - } - len += ret; - - for (end = len; end > 0 && buf[--end] != '\n'; ) - ; - if (end > 0) { - buf[end] = '\0'; - cairo_script_interpreter_feed_string (client.csi, buf, end); - - len -= end + 1; - if (len) - memmove (buf, buf + end + 1, len); - } - } - if (ret == 0) - break; - if (! (errno == EAGAIN || errno == EINTR)) - break; - } - - cairo_script_interpreter_finish (client.csi); - cairo_script_interpreter_destroy (client.csi); - - cairo_surface_destroy (client.surface); - close (fd); - - return 0; -} - -static int -do_exec (int fd, char **argv) -{ - char buf[4096]; - - if (*argv == NULL) - return 0; - - snprintf (buf, sizeof (buf), "%s/cairo-trace.so", LIBDIR); - setenv ("LD_PRELOAD", buf, 1); - - snprintf (buf, sizeof (buf), "0"); - setenv ("CAIRO_TRACE_LINE_INFO", buf, 1); - - snprintf (buf, sizeof (buf), "%d", fd); - setenv ("CAIRO_TRACE_FD", buf, 1); - putenv (buf); - - return execvp (argv[0], argv); -} - -static int -do_wait (int fd) -{ - char buf; - int ret = read (fd, &buf, 1); - return ret != 0; -} - -int -main (int argc, char **argv) -{ - char buf[4096]; - int len; - int fd; - - if (argc == 1) - return do_server ("/tmp/cairo-sphinx"); - - fd = client_socket ("/tmp/cairo-sphinx"); - if (fd < 0) - return 1; - - if (strcmp (argv[1], "client") == 0) { - return do_client (fd, argv[2], argv[3], argv[4], - CAIRO_CONTENT_COLOR_ALPHA); - } - - if (strcmp (argv[1], "wait") == 0) { - len = snprintf (buf, sizeof (buf), "wait %s\n", argv[2]); - if (! writen (fd, buf, len)) - return 1; - - return do_wait (fd); - } - - if (strcmp (argv[1], "exec") == 0) { - len = snprintf (buf, sizeof (buf), "source\n"); - if (! writen (fd, buf, len)) - return 1; - - return do_exec (fd, argv+2); - } - - if (strcmp (argv[1], "replay") == 0) { - len = snprintf (buf, sizeof (buf), "replay %s\n", argv[2]); - return ! writen (fd, buf, len); - } - - return 0; -} |