Back to index

lightning-sunbird  0.9+nobinonly
cairo_test.c
Go to the documentation of this file.
00001 /*
00002  * Copyright © 2004 Red Hat, Inc.
00003  *
00004  * Permission to use, copy, modify, distribute, and sell this software
00005  * and its documentation for any purpose is hereby granted without
00006  * fee, provided that the above copyright notice appear in all copies
00007  * and that both that copyright notice and this permission notice
00008  * appear in supporting documentation, and that the name of
00009  * Red Hat, Inc. not be used in advertising or publicity pertaining to
00010  * distribution of the software without specific, written prior
00011  * permission. Red Hat, Inc. makes no representations about the
00012  * suitability of this software for any purpose.  It is provided "as
00013  * is" without express or implied warranty.
00014  *
00015  * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
00016  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
00017  * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
00018  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
00019  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
00020  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
00021  * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00022  *
00023  * Author: Carl D. Worth <cworth@cworth.org>
00024  */
00025 
00026 #include <stdio.h>
00027 #include <stdlib.h>
00028 #include <stdarg.h>
00029 #include <unistd.h>
00030 #include <errno.h>
00031 #include <string.h>
00032 
00033 #include "cairo_test.h"
00034 
00035 #include "buffer_diff.h"
00036 #include "read_png.h"
00037 #include "write_png.h"
00038 #include "xmalloc.h"
00039 
00040 #define CAIRO_TEST_LOG_SUFFIX ".log"
00041 #define CAIRO_TEST_PNG_SUFFIX "-out.png"
00042 #define CAIRO_TEST_REF_SUFFIX "-ref.png"
00043 #define CAIRO_TEST_DIFF_SUFFIX "-diff.png"
00044 
00045 static void
00046 xasprintf (char **strp, const char *fmt, ...)
00047 {
00048 #ifdef HAVE_VASPRINTF    
00049     va_list va;
00050     int ret;
00051     
00052     va_start (va, fmt);
00053     ret = vasprintf (strp, fmt, va);
00054     va_end (va);
00055 
00056     if (ret < 0) {
00057        fprintf (stderr, "Out of memory\n");
00058        exit (1);
00059     }
00060 #else /* !HAVE_VASNPRINTF */
00061 #define BUF_SIZE 1024
00062     va_list va;
00063     char buffer[BUF_SIZE];
00064     int ret;
00065     
00066     va_start (va, fmt);
00067     ret = vsnprintf (buffer, sizeof(buffer), fmt, va);
00068     va_end (va);
00069 
00070     if (ret < 0) {
00071        fprintf (stderr, "Failure in vsnprintf\n");
00072        exit (1);
00073     }
00074     
00075     if (strlen (buffer) == sizeof(buffer) - 1) {
00076        fprintf (stderr, "Overflowed fixed buffer\n");
00077        exit (1);
00078     }
00079     
00080     *strp = strdup (buffer);
00081     if (!*strp) {
00082        fprintf (stderr, "Out of memory\n");
00083        exit (1);
00084     }
00085 #endif /* !HAVE_VASNPRINTF */
00086 }
00087 
00088 static void
00089 xunlink (const char *pathname)
00090 {
00091     if (unlink (pathname) < 0 && errno != ENOENT) {
00092        fprintf (stderr, "  Error: Cannot remove %s: %s\n",
00093                pathname, strerror (errno));
00094        exit (1);
00095     }
00096 }
00097 
00098 cairo_test_status_t
00099 cairo_test (cairo_test_t *test, cairo_test_draw_function_t draw)
00100 {
00101     cairo_t *cr;
00102     int stride;
00103     unsigned char *png_buf, *ref_buf, *diff_buf;
00104     char *log_name, *png_name, *ref_name, *diff_name;
00105     char *srcdir;
00106     int pixels_changed;
00107     int ref_width, ref_height, ref_stride;
00108     read_png_status_t png_status;
00109     cairo_test_status_t ret;
00110     FILE *png_file;
00111     FILE *log_file;
00112 
00113     /* The cairo part of the test is the easiest part */
00114     cr = cairo_create ();
00115 
00116     stride = 4 * test->width;
00117 
00118     png_buf = xcalloc (stride * test->height, 1);
00119     diff_buf = xcalloc (stride * test->height, 1);
00120 
00121     cairo_set_target_image (cr, png_buf, CAIRO_FORMAT_ARGB32,
00122                          test->width, test->height, stride);
00123 
00124     (draw) (cr, test->width, test->height);
00125 
00126     cairo_destroy (cr);
00127 
00128     /* Skip image check for tests with no image (width,height == 0,0) */
00129     if (test->width == 0 || test->height == 0) {
00130        free (png_buf);
00131        free (diff_buf);
00132        return CAIRO_TEST_SUCCESS;
00133     }
00134 
00135     /* Then we've got a bunch of string manipulation and file I/O for the check */
00136     srcdir = getenv ("srcdir");
00137     if (!srcdir)
00138        srcdir = ".";
00139     xasprintf (&log_name, "%s%s", test->name, CAIRO_TEST_LOG_SUFFIX);
00140     xasprintf (&png_name, "%s%s", test->name, CAIRO_TEST_PNG_SUFFIX);
00141     xasprintf (&ref_name, "%s/%s%s", srcdir, test->name, CAIRO_TEST_REF_SUFFIX);
00142     xasprintf (&diff_name, "%s%s", test->name, CAIRO_TEST_DIFF_SUFFIX);
00143 
00144     png_file = fopen (png_name, "w");
00145     write_png_argb32 (png_buf, png_file, test->width, test->height, stride);
00146     fclose (png_file);
00147 
00148     xunlink (log_name);
00149 
00150     ref_buf = NULL;
00151     png_status = (read_png_argb32 (ref_name, &ref_buf, &ref_width, &ref_height, &ref_stride));
00152     if (png_status) {
00153        log_file = fopen (log_name, "a");
00154        switch (png_status)
00155        {
00156        case READ_PNG_FILE_NOT_FOUND:
00157            fprintf (log_file, "Error: No reference image found: %s\n", ref_name);
00158            break;
00159        case READ_PNG_FILE_NOT_PNG:
00160            fprintf (log_file, "Error: %s is not a png image\n", ref_name);
00161            break;
00162        default:
00163            fprintf (log_file, "Error: Failed to read %s\n", ref_name);
00164        }
00165        fclose (log_file);
00166               
00167        ret = CAIRO_TEST_FAILURE;
00168        goto BAIL;
00169     } else {
00170     }
00171 
00172     if (test->width != ref_width || test->height != ref_height) {
00173        log_file = fopen (log_name, "a");
00174        fprintf (log_file,
00175                "Error: Image size mismatch: (%dx%d) vs. (%dx%d)\n"
00176                "       for %s vs %s\n",
00177                test->width, test->height,
00178                ref_width, ref_height,
00179                png_name, ref_name);
00180        fclose (log_file);
00181 
00182        ret = CAIRO_TEST_FAILURE;
00183        goto BAIL;
00184     }
00185 
00186     pixels_changed = buffer_diff (png_buf, ref_buf, diff_buf,
00187                               test->width, test->height, stride);
00188     if (pixels_changed) {
00189        log_file = fopen (log_name, "a");
00190        fprintf (log_file, "Error: %d pixels differ from reference image %s\n",
00191                pixels_changed, ref_name);
00192        png_file = fopen (diff_name, "w");
00193        write_png_argb32 (diff_buf, png_file, test->width, test->height, stride);
00194        fclose (png_file);
00195        fclose (log_file);
00196 
00197        ret = CAIRO_TEST_FAILURE;
00198        goto BAIL;
00199     } else {
00200        xunlink (diff_name);
00201     }
00202 
00203     ret = CAIRO_TEST_SUCCESS;
00204 
00205 BAIL:
00206     free (png_buf);
00207     free (ref_buf);
00208     free (diff_buf);
00209     free (log_name);
00210     free (png_name);
00211     free (ref_name);
00212     free (diff_name);
00213 
00214     return ret;
00215 }
00216 
00217 cairo_pattern_t *
00218 cairo_test_create_png_pattern (cairo_t *cr, const char *filename)
00219 {
00220     cairo_surface_t *image;
00221     cairo_pattern_t *pattern;
00222     unsigned char *buffer;
00223     int w, h, stride;
00224     read_png_status_t status;
00225     char *srcdir = getenv ("srcdir");
00226 
00227     status = read_png_argb32 (filename, &buffer, &w,&h, &stride);
00228     if (status != READ_PNG_SUCCESS) {
00229        if (srcdir) {
00230            char *srcdir_filename;
00231            xasprintf (&srcdir_filename, "%s/%s", srcdir, filename);
00232            status = read_png_argb32 (srcdir_filename, &buffer, &w,&h, &stride);
00233            free (srcdir_filename);
00234        }
00235     }
00236     if (status != READ_PNG_SUCCESS)
00237        return NULL;
00238 
00239     image = cairo_surface_create_for_image (buffer, CAIRO_FORMAT_ARGB32,
00240                                        w, h, stride);
00241 
00242     cairo_surface_set_repeat (image, 1);
00243 
00244     pattern = cairo_pattern_create_for_surface (image);
00245 
00246     return pattern;
00247 }