📄 cairo-test.c
字号:
/* * Copyright © 2004 Red Hat, Inc. * * Permission to use, copy, modify, distribute, and sell this software * and its documentation for any purpose is hereby granted without * fee, provided that the above copyright notice appear in all copies * and that both that copyright notice and this permission notice * appear in supporting documentation, and that the name of * Red Hat, Inc. not be used in advertising or publicity pertaining to * distribution of the software without specific, written prior * permission. Red Hat, Inc. makes no representations about the * suitability of this software for any purpose. It is provided "as * is" without express or implied warranty. * * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Author: Carl D. Worth <cworth@cworth.org> */#if HAVE_CONFIG_H#include "config.h"#endif#include <stdio.h>#include <stdlib.h>#include <stdarg.h>#include <ctype.h>#include <setjmp.h>#include <signal.h>#include <assert.h>#ifdef HAVE_UNISTD_H#include <unistd.h>#endif#include <errno.h>#include <string.h>#if HAVE_FCFINI#include <fontconfig/fontconfig.h>#endif#include "cairo-test.h"#include "buffer-diff.h"#include "read-png.h"#include "write-png.h"#include "xmalloc.h"/* This is copied from cairoint.h. That makes it painful to keep in * sync, but the slim stuff makes cairoint.h "hard" to include when * not actually building the cairo library itself. Fortunately, since * we're checking all these values, we do have a safeguard for keeping * them in sync. */typedef enum cairo_internal_surface_type { CAIRO_INTERNAL_SURFACE_TYPE_META = 0x1000, CAIRO_INTERNAL_SURFACE_TYPE_PAGINATED, CAIRO_INTERNAL_SURFACE_TYPE_ANALYSIS, CAIRO_INTERNAL_SURFACE_TYPE_TEST_META, CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK, CAIRO_INTERNAL_SURFACE_TYPE_TEST_PAGINATED} cairo_internal_surface_type_t;#ifdef _MSC_VER#define vsnprintf _vsnprintf#define access _access#define F_OK 0#endif#ifndef FALSE#define FALSE 0#endif#ifndef TRUE#define TRUE !FALSE#endifstatic voidxunlink (const char *pathname);static const char *fail_face = "", *normal_face = "";#define CAIRO_TEST_LOG_SUFFIX ".log"#define CAIRO_TEST_PNG_SUFFIX "-out.png"#define CAIRO_TEST_REF_SUFFIX "-ref.png"#define CAIRO_TEST_DIFF_SUFFIX "-diff.png"#define NUM_DEVICE_OFFSETS 2/* A fake format we use for the flattened ARGB output of the PS and * PDF surfaces. */#define CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED -1/* Static data is messy, but we're coding for tests here, not a * general-purpose library, and it keeps the tests cleaner to avoid a * context object there, (though not a whole lot). */FILE *cairo_test_log_file = NULL;char *srcdir;/* Used to catch crashes in a test, such that we report it as such and * continue testing, although one crasher may already have corrupted memory in * an nonrecoverable fashion. */jmp_buf jmpbuf;voidcairo_test_init (const char *test_name){ char *log_name; xasprintf (&log_name, "%s%s", test_name, CAIRO_TEST_LOG_SUFFIX); xunlink (log_name); cairo_test_log_file = fopen (log_name, "a"); if (cairo_test_log_file == NULL) { fprintf (stderr, "Error opening log file: %s\n", log_name); cairo_test_log_file = stderr; } free (log_name);}voidcairo_test_log (const char *fmt, ...){ va_list va; FILE *file = cairo_test_log_file ? cairo_test_log_file : stderr; va_start (va, fmt); vfprintf (file, fmt, va); va_end (va);}voidxasprintf (char **strp, const char *fmt, ...){#ifdef HAVE_VASPRINTF va_list va; int ret; va_start (va, fmt); ret = vasprintf (strp, fmt, va); va_end (va); if (ret < 0) { cairo_test_log ("Out of memory\n"); exit (1); }#else /* !HAVE_VASNPRINTF */#define BUF_SIZE 1024 va_list va; char buffer[BUF_SIZE]; int ret; va_start (va, fmt); ret = vsnprintf (buffer, sizeof(buffer), fmt, va); va_end (va); if (ret < 0) { cairo_test_log ("Failure in vsnprintf\n"); exit (1); } if (strlen (buffer) == sizeof(buffer) - 1) { cairo_test_log ("Overflowed fixed buffer\n"); exit (1); } *strp = strdup (buffer); if (!*strp) { cairo_test_log ("Out of memory\n"); exit (1); }#endif /* !HAVE_VASNPRINTF */}static voidxunlink (const char *pathname){ if (unlink (pathname) < 0 && errno != ENOENT) { cairo_test_log (" Error: Cannot remove %s: %s\n", pathname, strerror (errno)); exit (1); }}typedef cairo_surface_t *(*cairo_test_create_target_surface_t) (cairo_test_t *test, cairo_content_t content, void **closure);typedef cairo_status_t(*cairo_test_write_to_png_t) (cairo_surface_t *surface, const char *filename);typedef void(*cairo_test_cleanup_target_t) (void *closure);typedef struct _cairo_test_target{ const char *name; cairo_surface_type_t expected_type; cairo_content_t content; cairo_test_create_target_surface_t create_target_surface; cairo_test_write_to_png_t write_to_png; cairo_test_cleanup_target_t cleanup_target; void *closure;} cairo_test_target_t;static char *_cairo_test_content_name (cairo_content_t content){ switch (content) { case CAIRO_CONTENT_COLOR: return "rgb24"; case CAIRO_CONTENT_COLOR_ALPHA: case CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED: return "argb32"; default: assert (0); /* not reached */ return "---"; }}static cairo_surface_t *create_image_surface (cairo_test_t *test, cairo_content_t content, void **closure){ cairo_format_t format; *closure = NULL; if (content == CAIRO_CONTENT_COLOR_ALPHA) { format = CAIRO_FORMAT_ARGB32; } else if (content == CAIRO_CONTENT_COLOR) { format = CAIRO_FORMAT_RGB24; } else { assert (0); /* not reached */ return NULL; } return cairo_image_surface_create (format, test->width, test->height);}#ifdef CAIRO_HAS_TEST_SURFACES#include "test-fallback-surface.h"#include "test-meta-surface.h"#include "test-paginated-surface.h"static cairo_surface_t *create_test_fallback_surface (cairo_test_t *test, cairo_content_t content, void **closure){ *closure = NULL; return _test_fallback_surface_create (content, test->width, test->height);}static cairo_surface_t *create_test_meta_surface (cairo_test_t *test, cairo_content_t content, void **closure){ *closure = NULL; return _test_meta_surface_create (content, test->width, test->height);}static const cairo_user_data_key_t test_paginated_closure_key;typedef struct { unsigned char *data; cairo_content_t content; int width; int height; int stride;} test_paginated_closure_t;static cairo_surface_t *create_test_paginated_surface (cairo_test_t *test, cairo_content_t content, void **closure){ test_paginated_closure_t *tpc; cairo_surface_t *surface; *closure = tpc = xmalloc (sizeof (test_paginated_closure_t)); tpc->content = content; tpc->width = test->width; tpc->height = test->height; tpc->stride = test->width * 4; tpc->data = xcalloc (tpc->stride * test->height, 1); surface = _test_paginated_surface_create_for_data (tpc->data, tpc->content, tpc->width, tpc->height, tpc->stride); cairo_surface_set_user_data (surface, &test_paginated_closure_key, tpc, NULL); return surface;}/* The only reason we go through all these machinations to write a PNG * image is to _really ensure_ that the data actually landed in our * buffer through the paginated surface to the test_paginated_surface. * * If we didn't implement this function then the default * cairo_surface_write_to_png would result in the paginated_surface's * acquire_source_image function replaying the meta-surface to an * intermediate image surface. And in that case the * test_paginated_surface would not be involved and wouldn't be * tested. */static cairo_status_ttest_paginated_write_to_png (cairo_surface_t *surface, const char *filename){ cairo_surface_t *image; cairo_format_t format; test_paginated_closure_t *tpc; tpc = cairo_surface_get_user_data (surface, &test_paginated_closure_key); switch (tpc->content) { case CAIRO_CONTENT_COLOR: format = CAIRO_FORMAT_RGB24; break; case CAIRO_CONTENT_COLOR_ALPHA: format = CAIRO_FORMAT_ARGB32; break; default: assert (0); /* not reached */ return CAIRO_STATUS_NO_MEMORY; } image = cairo_image_surface_create_for_data (tpc->data, format, tpc->width, tpc->height, tpc->stride); cairo_surface_write_to_png (image, filename); cairo_surface_destroy (image); return CAIRO_STATUS_SUCCESS;}static voidcleanup_test_paginated (void *closure){ test_paginated_closure_t *tpc = closure; free (tpc->data); free (tpc);}#endif#ifdef CAIRO_HAS_GLITZ_SURFACE#include <glitz.h>#include <cairo-glitz.h>static const cairo_user_data_key_t glitz_closure_key;typedef struct _glitz_target_closure_base { int width; int height; cairo_content_t content;} glitz_target_closure_base_t;#if CAIRO_CAN_TEST_GLITZ_GLX_SURFACE#include <glitz-glx.h>typedef struct _glitz_glx_target_closure { glitz_target_closure_base_t base; Display *dpy; int scr; Window win;} glitz_glx_target_closure_t;static glitz_surface_t *create_glitz_glx_surface (glitz_format_name_t formatname, int width, int height, glitz_glx_target_closure_t *closure){ Display * dpy = closure->dpy; int scr = closure->scr; glitz_drawable_format_t templ; glitz_drawable_format_t * dformat = NULL; unsigned long mask; glitz_drawable_t * drawable = NULL; glitz_format_t * format; glitz_surface_t * sr; XSizeHints xsh; XSetWindowAttributes xswa; XVisualInfo * vinfo; memset(&templ, 0, sizeof(templ)); templ.color.red_size = 8; templ.color.green_size = 8; templ.color.blue_size = 8; templ.color.alpha_size = 8; templ.color.fourcc = GLITZ_FOURCC_RGB; templ.samples = 1; glitz_glx_init (NULL); mask = GLITZ_FORMAT_SAMPLES_MASK | GLITZ_FORMAT_FOURCC_MASK | GLITZ_FORMAT_RED_SIZE_MASK | GLITZ_FORMAT_GREEN_SIZE_MASK | GLITZ_FORMAT_BLUE_SIZE_MASK; if (formatname == GLITZ_STANDARD_ARGB32) mask |= GLITZ_FORMAT_ALPHA_SIZE_MASK; /* Try for a pbuffer first */ if (!getenv("CAIRO_TEST_FORCE_GLITZ_WINDOW")) dformat = glitz_glx_find_pbuffer_format (dpy, scr, mask, &templ, 0); if (dformat) { closure->win = None; drawable = glitz_glx_create_pbuffer_drawable (dpy, scr, dformat, width, height); if (!drawable) goto FAIL; } else { /* No pbuffer, try window */ dformat = glitz_glx_find_window_format (dpy, scr, mask, &templ, 0); if (!dformat) goto FAIL; vinfo = glitz_glx_get_visual_info_from_format(dpy, DefaultScreen(dpy), dformat); if (!vinfo) goto FAIL; xsh.flags = PSize; xsh.x = 0; xsh.y = 0; xsh.width = width; xsh.height = height; xswa.colormap = XCreateColormap (dpy, RootWindow(dpy, scr), vinfo->visual, AllocNone); closure->win = XCreateWindow (dpy, RootWindow(dpy, scr), xsh.x, xsh.y, xsh.width, xsh.height, 0, vinfo->depth, CopyFromParent, vinfo->visual, CWColormap, &xswa); XFree (vinfo); drawable = glitz_glx_create_drawable_for_window (dpy, scr, dformat, closure->win, width, height); if (!drawable) goto DESTROY_WINDOW; } format = glitz_find_standard_format (drawable, formatname); if (!format) goto DESTROY_DRAWABLE; sr = glitz_surface_create (drawable, format, width, height, 0, NULL); if (!sr) goto DESTROY_DRAWABLE; if (closure->win == None || dformat->doublebuffer) { glitz_surface_attach (sr, drawable, GLITZ_DRAWABLE_BUFFER_BACK_COLOR); } else { XMapWindow (closure->dpy, closure->win); glitz_surface_attach (sr, drawable, GLITZ_DRAWABLE_BUFFER_FRONT_COLOR); } glitz_drawable_destroy (drawable); return sr; DESTROY_DRAWABLE: glitz_drawable_destroy (drawable); DESTROY_WINDOW: if (closure->win) XDestroyWindow (dpy, closure->win); FAIL: return NULL;}static cairo_surface_t *create_cairo_glitz_glx_surface (cairo_test_t *test, cairo_content_t content, void **closure){ int width = test->width;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -