Add CairoScript backend.

A new meta-surface backend for serialising drawing operations to a
CairoScript file. The principal use (as currently envisaged) is to provide
a round-trip testing mechanism for CairoScript - i.e. we can generate
script files for every test in the suite and check that we can replay them
with perfect fidelity. (Obviously this does not provide complete coverage
of CairoScript's syntax, but should give reasonable coverage over the
operators.)
This commit is contained in:
Chris Wilson 2008-11-04 10:45:34 +00:00
parent 47a56e0850
commit a856371bef
32 changed files with 3540 additions and 41 deletions

View file

@ -36,6 +36,9 @@ cairo_boilerplate_ps_sources = cairo-boilerplate-ps.c
cairo_boilerplate_quartz_private = cairo-boilerplate-quartz-private.h
cairo_boilerplate_quartz_sources = cairo-boilerplate-quartz.c
cairo_boilerplate_script_private = cairo-boilerplate-script-private.h
cairo_boilerplate_script_sources = cairo-boilerplate-script.c
cairo_boilerplate_sdl_private = cairo-boilerplate-sdl-private.h
cairo_boilerplate_sdl_sources = cairo-boilerplate-sdl.c

View file

@ -0,0 +1,57 @@
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
/*
* Copyright © 2008 Chris Wilson
*
* 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: Chris Wilson <chris@chris-wilson.co.uk>
*/
#ifndef _CAIRO_BOILERPLATE_SCRIPT_PRIVATE_H_
#define _CAIRO_BOILERPLATE_SCRIPT_PRIVATE_H_
cairo_surface_t *
_cairo_boilerplate_script_create_surface (const char *name,
cairo_content_t content,
int width,
int height,
int max_width,
int max_height,
cairo_boilerplate_mode_t mode,
int id,
void **closure);
cairo_status_t
_cairo_boilerplate_script_finish_surface (cairo_surface_t *surface);
cairo_status_t
_cairo_boilerplate_script_surface_write_to_png (cairo_surface_t *surface,
const char *filename);
cairo_surface_t *
_cairo_boilerplate_script_get_image_surface (cairo_surface_t *surface,
int page,
int width,
int height);
void
_cairo_boilerplate_script_cleanup (void *closure);
#endif

View file

@ -0,0 +1,125 @@
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
/*
* Copyright © Chris Wilson
*
* 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
* Chris Wilson not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. Chris Wilson makes no representations about the
* suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL CHRIS WILSON 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: Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairo-boilerplate.h"
#include "cairo-boilerplate-script-private.h"
#include "cairo-script.h"
cairo_user_data_key_t script_closure_key;
typedef struct _script_target_closure {
char *filename;
int width;
int height;
} script_target_closure_t;
cairo_surface_t *
_cairo_boilerplate_script_create_surface (const char *name,
cairo_content_t content,
int width,
int height,
int max_width,
int max_height,
cairo_boilerplate_mode_t mode,
int id,
void **closure)
{
script_target_closure_t *ptc;
cairo_surface_t *surface;
cairo_status_t status;
*closure = ptc = xmalloc (sizeof (script_target_closure_t));
ptc->width = width;
ptc->height = height;
xasprintf (&ptc->filename, "%s.out.cs", name);
xunlink (ptc->filename);
surface = cairo_script_surface_create (ptc->filename, width, height);
status = cairo_surface_set_user_data (surface,
&script_closure_key, ptc, NULL);
if (status == CAIRO_STATUS_SUCCESS)
return surface;
cairo_surface_destroy (surface);
surface = cairo_boilerplate_surface_create_in_error (status);
free (ptc->filename);
free (ptc);
return surface;
}
cairo_status_t
_cairo_boilerplate_script_finish_surface (cairo_surface_t *surface)
{
cairo_surface_finish (surface);
return cairo_surface_status (surface);
}
cairo_status_t
_cairo_boilerplate_script_surface_write_to_png (cairo_surface_t *surface,
const char *filename)
{
return CAIRO_STATUS_WRITE_ERROR;
}
static cairo_surface_t *
_cairo_boilerplate_script_convert_to_image (cairo_surface_t *surface,
int page)
{
script_target_closure_t *ptc = cairo_surface_get_user_data (surface,
&script_closure_key);
return cairo_boilerplate_convert_to_image (ptc->filename, page);
}
cairo_surface_t *
_cairo_boilerplate_script_get_image_surface (cairo_surface_t *surface,
int page,
int width,
int height)
{
cairo_surface_t *image;
image = _cairo_boilerplate_script_convert_to_image (surface, page);
cairo_surface_set_device_offset (image,
cairo_image_surface_get_width (image) - width,
cairo_image_surface_get_height (image) - height);
surface = _cairo_boilerplate_get_image_surface (image, 0, width, height);
cairo_surface_destroy (image);
return surface;
}
void
_cairo_boilerplate_script_cleanup (void *closure)
{
script_target_closure_t *ptc = closure;
free (ptc->filename);
free (ptc);
}

View file

@ -47,6 +47,9 @@
#if CAIRO_HAS_QUARTZ_SURFACE
#include "cairo-boilerplate-quartz-private.h"
#endif
#if CAIRO_HAS_SCRIPT_SURFACE
#include "cairo-boilerplate-script-private.h"
#endif
#if CAIRO_HAS_SDL_SURFACE
#include "cairo-boilerplate-sdl-private.h"
#endif
@ -603,6 +606,19 @@ static cairo_boilerplate_target_t targets[] =
NULL, TRUE, TRUE
},
#endif
#if CAIRO_HAS_SCRIPT_SURFACE
{
"script", "script", ".cs",
CAIRO_SURFACE_TYPE_SCRIPT, CAIRO_CONTENT_COLOR_ALPHA, 0,
_cairo_boilerplate_script_create_surface,
NULL,
_cairo_boilerplate_script_finish_surface,
_cairo_boilerplate_script_get_image_surface,
_cairo_boilerplate_script_surface_write_to_png,
_cairo_boilerplate_script_cleanup,
NULL, FALSE
},
#endif
#if CAIRO_HAS_SVG_SURFACE && CAIRO_CAN_TEST_SVG_SURFACE
/* It seems we should be able to round-trip SVG content perfectly
* through librsvg and cairo, but for some mysterious reason, some

View file

@ -367,6 +367,7 @@ AC_DEFUN([CAIRO_REPORT],
echo " XCB: $use_xcb"
echo " Win32: $use_win32"
echo " OS2: $use_os2"
echo " CairoScript: $use_script"
echo " PostScript: $use_ps"
echo " PDF: $use_pdf"
echo " SVG: $use_svg"
@ -389,6 +390,7 @@ AC_DEFUN([CAIRO_REPORT],
echo " test surfaces: $use_test_surfaces"
echo " ps testing: $test_ps"
echo " pdf testing: $test_pdf"
echo " cs testing: $test_script"
echo " svg testing: $test_svg"
if test x"$use_win32" = "xyes"; then
echo " win32 printing testing: $test_win32_printing"

View file

@ -236,6 +236,22 @@ CAIRO_ENABLE_SURFACE_BACKEND(directfb, directfb, no, [
dnl ===========================================================================
CAIRO_ENABLE_SURFACE_BACKEND(script, script, no, [
test_script="yes"
csi_CFLAGS=
csi_LIBS=-lcairo-script-interpreter
if test "x$test_script" = "xyes"; then
AC_DEFINE([CAIRO_CAN_TEST_SCRIPT_SURFACE], 1,
[Define to 1 if the CairoScript backend can be tested])
else
AC_MSG_WARN([CairoScript backend will not be tested])
fi
AC_SUBST(csi_CFLAGS)
AC_SUBST(csi_LIBS)
])
dnl ===========================================================================
# We use pkg-config to look for freetype2, but fall back to
# freetype-config if it fails. We prefer pkg-config, since we can
# then just put freetype2 >= $FREETYPE_MIN_VERSION in

View file

@ -194,6 +194,7 @@ cairo_<emphasis>backend</emphasis>_surface_create().
@CAIRO_SURFACE_TYPE_WIN32_PRINTING:
@CAIRO_SURFACE_TYPE_QUARTZ_IMAGE:
@CAIRO_SURFACE_TYPE_SDL:
@CAIRO_SURFACE_TYPE_SCRIPT:
<!-- ##### FUNCTION cairo_surface_get_type ##### -->
<para>

View file

@ -249,3 +249,6 @@ cairo_directfb_sources = cairo-directfb-surface.c
cairo_sdl_headers = cairo-sdl.h
cairo_sdl_sources = cairo-sdl-surface.c
cairo_script_headers = cairo-script.h
cairo_script_sources = cairo-script-surface.c

View file

@ -124,6 +124,7 @@ _cairo_base85_stream_create (cairo_output_stream_t *output)
_cairo_output_stream_init (&stream->base,
_cairo_base85_stream_write,
NULL,
_cairo_base85_stream_close);
stream->output = output;
stream->pending = 0;

View file

@ -118,7 +118,7 @@ _cairo_cache_insert (cairo_cache_t *cache,
cairo_cache_entry_t *entry);
cairo_private void
_cairo_cache_foreach (cairo_cache_t *cache,
_cairo_cache_foreach (cairo_cache_t *cache,
cairo_cache_callback_func_t cache_callback,
void *closure);

View file

@ -44,7 +44,7 @@ _cairo_cache_remove (cairo_cache_t *cache,
static void
_cairo_cache_shrink_to_accommodate (cairo_cache_t *cache,
unsigned long additional);
unsigned long additional);
static cairo_status_t
_cairo_cache_init (cairo_cache_t *cache,
@ -66,25 +66,20 @@ _cairo_cache_init (cairo_cache_t *cache,
return CAIRO_STATUS_SUCCESS;
}
static void
_cairo_cache_pluck (void *entry, void *closure)
{
_cairo_cache_remove (closure, entry);
}
static void
_cairo_cache_fini (cairo_cache_t *cache)
{
cairo_cache_entry_t *entry;
/* We have to manually remove all entries from the cache ourselves
* rather than relying on _cairo_hash_table_destroy() to do that
* since otherwise the cache->entry_destroy callback would not get
* called on each entry. */
while (1) {
entry = _cairo_hash_table_random_entry (cache->hash_table, NULL);
if (entry == NULL)
break;
_cairo_cache_remove (cache, entry);
}
_cairo_hash_table_foreach (cache->hash_table,
_cairo_cache_pluck,
cache);
assert (cache->size == 0);
_cairo_hash_table_destroy (cache->hash_table);
cache->size = 0;
}
/**
@ -354,8 +349,20 @@ unsigned long
_cairo_hash_string (const char *c)
{
/* This is the djb2 hash. */
unsigned long hash = 5381;
unsigned long hash = _CAIRO_HASH_INIT_VALUE;
while (c && *c)
hash = ((hash << 5) + hash) + *c++;
return hash;
}
unsigned long
_cairo_hash_bytes (unsigned long hash,
const void *ptr,
unsigned int length)
{
const uint8_t *bytes = ptr;
/* This is the djb2 hash. */
while (length--)
hash = ((hash << 5) + hash) + *bytes++;
return hash;
}

View file

@ -128,6 +128,7 @@ _cairo_deflate_stream_create (cairo_output_stream_t *output)
_cairo_output_stream_init (&stream->base,
_cairo_deflate_stream_write,
NULL,
_cairo_deflate_stream_close);
stream->output = output;

View file

@ -2739,6 +2739,18 @@ _cairo_ft_scaled_font_is_vertical (cairo_scaled_font_t *scaled_font)
return FALSE;
}
unsigned int
_cairo_ft_scaled_font_get_load_flags (cairo_scaled_font_t *scaled_font)
{
cairo_ft_scaled_font_t *ft_scaled_font;
if (! _cairo_scaled_font_is_ft (scaled_font))
return 0;
ft_scaled_font = (cairo_ft_scaled_font_t *) scaled_font;
return ft_scaled_font->ft_options.load_flags;
}
void
_cairo_ft_font_reset_static_data (void)
{

View file

@ -64,6 +64,9 @@ _cairo_ft_unscaled_font_unlock_face (cairo_ft_unscaled_font_t *unscaled);
cairo_private cairo_bool_t
_cairo_ft_scaled_font_is_vertical (cairo_scaled_font_t *scaled_font);
cairo_private unsigned int
_cairo_ft_scaled_font_get_load_flags (cairo_scaled_font_t *scaled_font);
CAIRO_END_DECLS
#endif /* CAIRO_HAS_FT_FONT */

View file

@ -1056,7 +1056,8 @@ _cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
path,
gstate->fill_rule,
gstate->tolerance,
gstate->antialias, NULL);
gstate->antialias,
NULL);
if (pattern == &pattern_stack.base)
_cairo_pattern_fini (&pattern_stack.base);

View file

@ -43,14 +43,20 @@
#include <stdio.h>
#include <stdarg.h>
typedef cairo_status_t (*cairo_output_stream_write_func_t) (cairo_output_stream_t *output_stream,
const unsigned char *data,
unsigned int length);
typedef cairo_status_t
(*cairo_output_stream_write_func_t) (cairo_output_stream_t *output_stream,
const unsigned char *data,
unsigned int length);
typedef cairo_status_t (*cairo_output_stream_close_func_t) (cairo_output_stream_t *output_stream);
typedef cairo_status_t
(*cairo_output_stream_flush_func_t) (cairo_output_stream_t *output_stream);
typedef cairo_status_t
(*cairo_output_stream_close_func_t) (cairo_output_stream_t *output_stream);
struct _cairo_output_stream {
cairo_output_stream_write_func_t write_func;
cairo_output_stream_flush_func_t flush_func;
cairo_output_stream_close_func_t close_func;
unsigned long position;
cairo_status_t status;
@ -62,6 +68,7 @@ extern const cairo_private cairo_output_stream_t _cairo_output_stream_nil;
cairo_private void
_cairo_output_stream_init (cairo_output_stream_t *stream,
cairo_output_stream_write_func_t write_func,
cairo_output_stream_flush_func_t flush_func,
cairo_output_stream_close_func_t close_func);
cairo_private cairo_status_t
@ -93,6 +100,10 @@ _cairo_output_stream_create (cairo_write_func_t write_func,
cairo_private cairo_output_stream_t *
_cairo_output_stream_create_in_error (cairo_status_t status);
/* Tries to flush any buffer maintained by the stream or its delegates. */
cairo_private cairo_status_t
_cairo_output_stream_flush (cairo_output_stream_t *stream);
/* Returns the final status value associated with this object, just
* before its last gasp. This final status value will capture any
* status failure returned by the stream's close_func as well. */

View file

@ -70,9 +70,11 @@
void
_cairo_output_stream_init (cairo_output_stream_t *stream,
cairo_output_stream_write_func_t write_func,
cairo_output_stream_flush_func_t flush_func,
cairo_output_stream_close_func_t close_func)
{
stream->write_func = write_func;
stream->flush_func = flush_func;
stream->close_func = close_func;
stream->position = 0;
stream->status = CAIRO_STATUS_SUCCESS;
@ -87,6 +89,7 @@ _cairo_output_stream_fini (cairo_output_stream_t *stream)
const cairo_output_stream_t _cairo_output_stream_nil = {
NULL, /* write_func */
NULL, /* flush_func */
NULL, /* close_func */
0, /* position */
CAIRO_STATUS_NO_MEMORY,
@ -95,6 +98,7 @@ const cairo_output_stream_t _cairo_output_stream_nil = {
static const cairo_output_stream_t _cairo_output_stream_nil_write_error = {
NULL, /* write_func */
NULL, /* flush_func */
NULL, /* close_func */
0, /* position */
CAIRO_STATUS_WRITE_ERROR,
@ -148,7 +152,8 @@ _cairo_output_stream_create (cairo_write_func_t write_func,
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
_cairo_output_stream_init (&stream->base, closure_write, closure_close);
_cairo_output_stream_init (&stream->base,
closure_write, NULL, closure_close);
stream->write_func = write_func;
stream->close_func = close_func;
stream->closure = closure;
@ -173,12 +178,36 @@ _cairo_output_stream_create_in_error (cairo_status_t status)
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
_cairo_output_stream_init (stream, NULL, NULL);
_cairo_output_stream_init (stream, NULL, NULL, NULL);
stream->status = status;
return stream;
}
cairo_status_t
_cairo_output_stream_flush (cairo_output_stream_t *stream)
{
cairo_status_t status;
if (stream->closed)
return stream->status;
if (stream == &_cairo_output_stream_nil ||
stream == &_cairo_output_stream_nil_write_error)
{
return stream->status;
}
if (stream->flush_func) {
status = stream->flush_func (stream);
/* Don't overwrite a pre-existing status failure. */
if (stream->status == CAIRO_STATUS_SUCCESS)
stream->status = status;
}
return stream->status;
}
cairo_status_t
_cairo_output_stream_close (cairo_output_stream_t *stream)
{
@ -574,7 +603,8 @@ _cairo_output_stream_create_for_file (FILE *file)
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
_cairo_output_stream_init (&stream->base, stdio_write, stdio_flush);
_cairo_output_stream_init (&stream->base,
stdio_write, stdio_flush, stdio_flush);
stream->file = file;
return &stream->base;
@ -608,7 +638,8 @@ _cairo_output_stream_create_for_filename (const char *filename)
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
_cairo_output_stream_init (&stream->base, stdio_write, stdio_close);
_cairo_output_stream_init (&stream->base,
stdio_write, stdio_flush, stdio_close);
stream->file = file;
return &stream->base;
@ -650,7 +681,7 @@ _cairo_memory_stream_create (void)
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
_cairo_output_stream_init (&stream->base, memory_write, memory_close);
_cairo_output_stream_init (&stream->base, memory_write, NULL, memory_close);
_cairo_array_init (&stream->array, 1);
return &stream->base;
@ -727,7 +758,7 @@ _cairo_null_stream_create (void)
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
_cairo_output_stream_init (stream, null_write, NULL);
_cairo_output_stream_init (stream, null_write, NULL, NULL);
return stream;
}

View file

@ -37,6 +37,7 @@
#define CAIRO_PATH_FIXED_PRIVATE_H
#include "cairo-types-private.h"
#include "cairo-compiler-private.h"
enum cairo_path_op {
CAIRO_PATH_OP_MOVE_TO = 0,
@ -77,4 +78,14 @@ struct _cairo_path_fixed {
cairo_path_buf_fixed_t buf_head;
};
cairo_private unsigned long
_cairo_path_fixed_hash (const cairo_path_fixed_t *path);
cairo_private unsigned long
_cairo_path_fixed_size (const cairo_path_fixed_t *path);
cairo_private cairo_bool_t
_cairo_path_fixed_equal (const cairo_path_fixed_t *a,
const cairo_path_fixed_t *b);
#endif /* CAIRO_PATH_FIXED_PRIVATE_H */

View file

@ -144,6 +144,170 @@ _cairo_path_fixed_init_copy (cairo_path_fixed_t *path,
return CAIRO_STATUS_SUCCESS;
}
unsigned long
_cairo_path_fixed_hash (const cairo_path_fixed_t *path)
{
unsigned long hash = 0;
const cairo_path_buf_t *buf;
int num_points, num_ops;
hash = _cairo_hash_bytes (hash,
&path->current_point,
sizeof (path->current_point));
hash = _cairo_hash_bytes (hash,
&path->last_move_point,
sizeof (path->last_move_point));
num_ops = path->buf_head.base.num_ops;
num_points = path->buf_head.base.num_points;
for (buf = path->buf_head.base.next;
buf != NULL;
buf = buf->next)
{
hash = _cairo_hash_bytes (hash, buf->op,
buf->num_ops * sizeof (buf->op[0]));
hash = _cairo_hash_bytes (hash, buf->points,
buf->num_points * sizeof (buf->points[0]));
num_ops += buf->num_ops;
num_points += buf->num_points;
}
hash = _cairo_hash_bytes (hash, &num_ops, sizeof (num_ops));
hash = _cairo_hash_bytes (hash, &num_points, sizeof (num_points));
return hash;
}
unsigned long
_cairo_path_fixed_size (const cairo_path_fixed_t *path)
{
const cairo_path_buf_t *buf;
int num_points, num_ops;
num_ops = path->buf_head.base.num_ops;
num_points = path->buf_head.base.num_points;
for (buf = path->buf_head.base.next;
buf != NULL;
buf = buf->next)
{
num_ops += buf->num_ops;
num_points += buf->num_points;
}
return num_ops * sizeof (buf->op[0]) +
num_points * sizeof (buf->points[0]);
}
cairo_bool_t
_cairo_path_fixed_equal (const cairo_path_fixed_t *a,
const cairo_path_fixed_t *b)
{
const cairo_path_buf_t *buf_a, *buf_b;
const cairo_path_op_t *ops_a, *ops_b;
const cairo_point_t *points_a, *points_b;
int num_points_a, num_ops_a;
int num_points_b, num_ops_b;
if (a == b)
return TRUE;
if (a != NULL) {
num_ops_a = a->buf_head.base.num_ops;
num_points_a = a->buf_head.base.num_points;
for (buf_a = a->buf_head.base.next;
buf_a != NULL;
buf_a = buf_a->next)
{
num_ops_a += buf_a->num_ops;
num_points_a += buf_a->num_points;
}
} else
num_ops_a = num_points_a = 0;
if (b != NULL) {
num_ops_b = b->buf_head.base.num_ops;
num_points_b = b->buf_head.base.num_points;
for (buf_b = b->buf_head.base.next;
buf_b != NULL;
buf_b = buf_b->next)
{
num_ops_b += buf_b->num_ops;
num_points_b += buf_b->num_points;
}
} else
num_ops_b = num_points_b = 0;
if (num_ops_a == 0 && num_ops_b == 0)
return TRUE;
if (num_ops_a != num_ops_b || num_points_a != num_points_b)
return FALSE;
assert (a != NULL && b != NULL);
buf_a = &a->buf_head.base;
num_points_a = buf_a->num_points;
num_ops_a = buf_a->num_ops;
ops_a = buf_a->op;
points_a = buf_a->points;
buf_b = &b->buf_head.base;
num_points_b = buf_b->num_points;
num_ops_b = buf_b->num_ops;
ops_b = buf_b->op;
points_b = buf_b->points;
while (TRUE) {
int num_ops = MIN (num_ops_a, num_ops_b);
int num_points = MIN (num_points_a, num_points_b);
if (memcmp (ops_a, ops_b, num_ops * sizeof (cairo_path_op_t)))
return FALSE;
if (memcmp (points_a, points_b, num_points * sizeof (cairo_point_t)))
return FALSE;
num_ops_a -= num_ops;
ops_a += num_ops;
num_points_a -= num_points;
points_a += num_points;
if (num_ops_a == 0 || num_points_a == 0) {
if (num_ops_a || num_points_a)
return FALSE;
buf_a = buf_a->next;
if (buf_a == NULL)
break;
num_points_a = buf_a->num_points;
num_ops_a = buf_a->num_ops;
ops_a = buf_a->op;
points_a = buf_a->points;
}
num_ops_b -= num_ops;
ops_b += num_ops;
num_points_b -= num_points;
points_b += num_points;
if (num_ops_b == 0 || num_points_b == 0) {
if (num_ops_b || num_points_b)
return FALSE;
buf_b = buf_b->next;
if (buf_b == NULL)
break;
num_points_b = buf_b->num_points;
num_ops_b = buf_b->num_ops;
ops_b = buf_b->op;
points_b = buf_b->points;
}
}
return TRUE;
}
cairo_path_fixed_t *
_cairo_path_fixed_create (void)
{

View file

@ -2293,6 +2293,261 @@ _cairo_pattern_get_extents (const cairo_pattern_t *pattern,
return CAIRO_STATUS_SUCCESS;
}
static unsigned long
_cairo_solid_pattern_hash (unsigned long hash,
const cairo_pattern_t *pattern)
{
const cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern;
hash = _cairo_hash_bytes (hash, &solid->content, sizeof (solid->content));
hash = _cairo_hash_bytes (hash, &solid->color, sizeof (solid->color));
return hash;
}
static unsigned long
_cairo_gradient_color_stops_hash (unsigned long hash,
const cairo_gradient_pattern_t *gradient)
{
unsigned int n;
hash = _cairo_hash_bytes (hash,
&gradient->n_stops,
sizeof (gradient->n_stops));
for (n = 0; n < gradient->n_stops; n++) {
hash = _cairo_hash_bytes (hash,
&gradient->stops[n].offset,
sizeof (double));
hash = _cairo_hash_bytes (hash,
&gradient->stops[n].color,
sizeof (cairo_color_t));
}
return hash;
}
static unsigned long
_cairo_linear_pattern_hash (unsigned long hash,
const cairo_pattern_t *pattern)
{
const cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) pattern;
hash = _cairo_hash_bytes (hash, &linear->p1, sizeof (linear->p1));
hash = _cairo_hash_bytes (hash, &linear->p2, sizeof (linear->p2));
return _cairo_gradient_color_stops_hash (hash, &linear->base);
}
static unsigned long
_cairo_radial_pattern_hash (unsigned long hash, const cairo_pattern_t *pattern)
{
const cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) pattern;
hash = _cairo_hash_bytes (hash, &radial->c1, sizeof (radial->c1));
hash = _cairo_hash_bytes (hash, &radial->r1, sizeof (radial->r1));
hash = _cairo_hash_bytes (hash, &radial->c2, sizeof (radial->c2));
hash = _cairo_hash_bytes (hash, &radial->r2, sizeof (radial->r2));
return _cairo_gradient_color_stops_hash (hash, &radial->base);
}
static unsigned long
_cairo_surface_pattern_hash (unsigned long hash,
const cairo_pattern_t *pattern)
{
/* XXX requires cow-snapshots */
return hash;
}
unsigned long
_cairo_pattern_hash (const cairo_pattern_t *pattern)
{
unsigned long hash = _CAIRO_HASH_INIT_VALUE;
if (pattern->status)
return 0;
hash = _cairo_hash_bytes (hash, &pattern->type, sizeof (pattern->type));
hash = _cairo_hash_bytes (hash, &pattern->matrix, sizeof (pattern->matrix));
hash = _cairo_hash_bytes (hash, &pattern->filter, sizeof (pattern->filter));
hash = _cairo_hash_bytes (hash, &pattern->extend, sizeof (pattern->extend));
switch (pattern->type) {
case CAIRO_PATTERN_TYPE_SOLID:
return _cairo_solid_pattern_hash (hash, pattern);
case CAIRO_PATTERN_TYPE_LINEAR:
return _cairo_linear_pattern_hash (hash, pattern);
case CAIRO_PATTERN_TYPE_RADIAL:
return _cairo_radial_pattern_hash (hash, pattern);
case CAIRO_PATTERN_TYPE_SURFACE:
return _cairo_surface_pattern_hash (hash, pattern);
default:
ASSERT_NOT_REACHED;
return FALSE;
}
}
static unsigned long
_cairo_gradient_pattern_color_stops_size (const cairo_pattern_t *pattern)
{
cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t *) pattern;
return gradient->n_stops * (sizeof (double) + sizeof (cairo_color_t));
}
unsigned long
_cairo_pattern_size (const cairo_pattern_t *pattern)
{
if (pattern->status)
return 0;
/* XXX */
switch (pattern->type) {
case CAIRO_PATTERN_TYPE_SOLID:
return sizeof (cairo_solid_pattern_t);
break;
case CAIRO_PATTERN_TYPE_SURFACE:
return sizeof (cairo_surface_pattern_t);
break;
case CAIRO_PATTERN_TYPE_LINEAR:
return sizeof (cairo_linear_pattern_t) +
_cairo_gradient_pattern_color_stops_size (pattern);
break;
case CAIRO_PATTERN_TYPE_RADIAL:
return sizeof (cairo_radial_pattern_t) +
_cairo_gradient_pattern_color_stops_size (pattern);
default:
ASSERT_NOT_REACHED;
return 0;
}
}
static cairo_bool_t
_cairo_solid_pattern_equal (const cairo_pattern_t *A,
const cairo_pattern_t *B)
{
const cairo_solid_pattern_t *a = (cairo_solid_pattern_t *) A;
const cairo_solid_pattern_t *b = (cairo_solid_pattern_t *) B;
if (a->content != b->content)
return FALSE;
return _cairo_color_equal (&a->color, &b->color);
}
static cairo_bool_t
_cairo_gradient_color_stops_equal (const cairo_gradient_pattern_t *a,
const cairo_gradient_pattern_t *b)
{
unsigned int n;
if (a->n_stops != b->n_stops)
return FALSE;
for (n = 0; n < a->n_stops; n++) {
if (a->stops[n].offset != b->stops[n].offset)
return FALSE;
if (! _cairo_color_equal (&a->stops[n].color, &b->stops[n].color))
return FALSE;
}
return TRUE;
}
static cairo_bool_t
_cairo_linear_pattern_equal (const cairo_pattern_t *A,
const cairo_pattern_t *B)
{
const cairo_linear_pattern_t *a = (cairo_linear_pattern_t *) A;
const cairo_linear_pattern_t *b = (cairo_linear_pattern_t *) B;
if (a->p1.x != b->p1.x)
return FALSE;
if (a->p1.y != b->p1.y)
return FALSE;
if (a->p2.x != b->p2.x)
return FALSE;
if (a->p2.y != b->p2.y)
return FALSE;
return _cairo_gradient_color_stops_equal (&a->base, &b->base);
}
static cairo_bool_t
_cairo_radial_pattern_equal (const cairo_pattern_t *A,
const cairo_pattern_t *B)
{
const cairo_radial_pattern_t *a = (cairo_radial_pattern_t *) A;
const cairo_radial_pattern_t *b = (cairo_radial_pattern_t *) B;
if (a->c1.x != b->c1.x)
return FALSE;
if (a->c1.y != b->c1.y)
return FALSE;
if (a->r1 != b->r1)
return FALSE;
if (a->c2.x != b->c2.x)
return FALSE;
if (a->c2.y != b->c2.y)
return FALSE;
if (a->r2 != b->r2)
return FALSE;
return _cairo_gradient_color_stops_equal (&a->base, &b->base);
}
static cairo_bool_t
_cairo_surface_pattern_equal (const cairo_pattern_t *A,
const cairo_pattern_t *B)
{
/* XXX requires cow-snapshots */
return FALSE;
}
cairo_bool_t
_cairo_pattern_equal (const cairo_pattern_t *a, const cairo_pattern_t *b)
{
if (a->status || b->status)
return FALSE;
if (a->type != b->type)
return FALSE;
if (memcmp (&a->matrix, &b->matrix, sizeof (cairo_matrix_t)))
return FALSE;
if (a->filter != b->filter)
return FALSE;
if (a->extend != b->extend)
return FALSE;
switch (a->type) {
case CAIRO_PATTERN_TYPE_SOLID:
return _cairo_solid_pattern_equal (a, b);
case CAIRO_PATTERN_TYPE_LINEAR:
return _cairo_linear_pattern_equal (a, b);
case CAIRO_PATTERN_TYPE_RADIAL:
return _cairo_radial_pattern_equal (a, b);
case CAIRO_PATTERN_TYPE_SURFACE:
return _cairo_surface_pattern_equal (a, b);
default:
ASSERT_NOT_REACHED;
return FALSE;
}
}
/**
* cairo_pattern_get_rgba
* @pattern: a #cairo_pattern_t

View file

@ -300,6 +300,7 @@ _word_wrap_stream_create (cairo_output_stream_t *output, int max_column)
_cairo_output_stream_init (&stream->base,
_word_wrap_stream_write,
NULL,
_word_wrap_stream_close);
stream->output = output;
stream->max_column = max_column;

View file

@ -1740,6 +1740,7 @@ _string_array_stream_create (cairo_output_stream_t *output)
_cairo_output_stream_init (&stream->base,
_string_array_stream_write,
NULL,
_string_array_stream_close);
stream->output = output;
stream->column = 0;
@ -1766,6 +1767,7 @@ _base85_array_stream_create (cairo_output_stream_t *output)
_cairo_output_stream_init (&stream->base,
_string_array_stream_write,
NULL,
_string_array_stream_close);
stream->output = output;
stream->column = 0;

View file

@ -94,10 +94,11 @@ struct _cairo_scaled_font {
cairo_bool_t finished;
/* "live" scaled_font members */
cairo_matrix_t scale; /* font space => device space */
cairo_matrix_t scale_inverse; /* device space => font space */
double max_scale; /* maximum x/y expansion of scale */
cairo_font_extents_t extents; /* user space */
cairo_matrix_t scale; /* font space => device space */
cairo_matrix_t scale_inverse; /* device space => font space */
double max_scale; /* maximum x/y expansion of scale */
cairo_font_extents_t extents; /* user space */
cairo_font_extents_t fs_extents; /* font space */
/* The mutex protects modification to all subsequent fields. */
cairo_mutex_t mutex;

View file

@ -201,6 +201,7 @@ static const cairo_scaled_font_t _cairo_scaled_font_nil = {
{ 1., 0., 0., 1., 0, 0}, /* scale_inverse */
1., /* max_scale */
{ 0., 0., 0., 0., 0. }, /* extents */
{ 0., 0., 0., 0., 0. }, /* fs_extents */
CAIRO_MUTEX_NIL_INITIALIZER,/* mutex */
NULL, /* glyphs */
NULL, /* surface_backend */
@ -691,6 +692,8 @@ _cairo_scaled_font_set_metrics (cairo_scaled_font_t *scaled_font,
cairo_status_t status;
double font_scale_x, font_scale_y;
scaled_font->fs_extents = *fs_metrics;
status = _cairo_matrix_compute_basis_scale_factors (&scaled_font->font_matrix,
&font_scale_x, &font_scale_y,
1);
@ -2210,6 +2213,8 @@ _cairo_scaled_glyph_set_metrics (cairo_scaled_glyph_t *scaled_glyph,
double min_device_x = 0.0, max_device_x = 0.0, min_device_y = 0.0, max_device_y = 0.0;
double device_x_advance, device_y_advance;
scaled_glyph->fs_metrics = *fs_metrics;
for (hm = 0.0; hm <= 1.0; hm += 1.0)
for (wm = 0.0; wm <= 1.0; wm += 1.0) {
double x, y;

2598
src/cairo-script-surface.c Normal file

File diff suppressed because it is too large Load diff

74
src/cairo-script.h Normal file
View file

@ -0,0 +1,74 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2008 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Chris Wilson
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#ifndef CAIRO_SCRIPT_H
#define CAIRO_SCRIPT_H
#include "cairo.h"
#if CAIRO_HAS_SCRIPT_SURFACE
CAIRO_BEGIN_DECLS
cairo_public cairo_surface_t *
cairo_script_surface_create (const char *filename,
double width,
double height);
cairo_public cairo_surface_t *
cairo_script_surface_create_for_stream (cairo_write_func_t write_func,
void *closure,
double width,
double height);
typedef enum {
CAIRO_SCRIPT_MODE_BINARY,
CAIRO_SCRIPT_MODE_ASCII
} cairo_script_mode_t;
cairo_public void
cairo_script_surface_set_mode (cairo_surface_t *surface,
cairo_script_mode_t mode);
cairo_public cairo_script_mode_t
cairo_script_surface_get_mode (cairo_surface_t *surface);
CAIRO_END_DECLS
#else /*CAIRO_HAS_SCRIPT_SURFACE*/
# error Cairo was not compiled with support for the CairoScript backend
#endif /*CAIRO_HAS_SCRIPT_SURFACE*/
#endif /*CAIRO_SCRIPT_H*/

View file

@ -44,6 +44,7 @@
#include "cairo-reference-count-private.h"
typedef struct _cairo_array cairo_array_t;
typedef struct _cairo_backend cairo_backend_t;
typedef struct _cairo_cache cairo_cache_t;
typedef struct _cairo_clip cairo_clip_t;
typedef struct _cairo_clip_path cairo_clip_path_t;

View file

@ -1876,6 +1876,7 @@ cairo_surface_status (cairo_surface_t *surface);
* @CAIRO_SURFACE_TYPE_WIN32_PRINTING: The surface is a win32 printing surface
* @CAIRO_SURFACE_TYPE_QUARTZ_IMAGE: The surface is of type quartz_image
* @CAIRO_SURFACE_TYPE_SDL: The surface is of type SDL, since 1.10
* @CAIRO_SURFACE_TYPE_SCRIPT: The surface is of type script, since 1.10
*
* #cairo_surface_type_t is used to describe the type of a given
* surface. The surface types are also known as "backends" or "surface
@ -1915,7 +1916,8 @@ typedef enum _cairo_surface_type {
CAIRO_SURFACE_TYPE_OS2,
CAIRO_SURFACE_TYPE_WIN32_PRINTING,
CAIRO_SURFACE_TYPE_QUARTZ_IMAGE,
CAIRO_SURFACE_TYPE_SDL
CAIRO_SURFACE_TYPE_SDL,
CAIRO_SURFACE_TYPE_SCRIPT
} cairo_surface_type_t;
cairo_public cairo_surface_type_t

View file

@ -322,9 +322,16 @@ _cairo_user_data_array_set_data (cairo_user_data_array_t *array,
void *user_data,
cairo_destroy_func_t destroy);
#define _CAIRO_HASH_INIT_VALUE 5381
cairo_private unsigned long
_cairo_hash_string (const char *c);
cairo_private unsigned long
_cairo_hash_bytes (unsigned long hash,
const void *bytes,
unsigned int length);
/*
* A #cairo_unscaled_font_t is just an opaque handle we use in the
* glyph cache.
@ -339,6 +346,7 @@ typedef struct _cairo_scaled_glyph {
cairo_cache_entry_t cache_entry; /* hash is glyph index */
cairo_scaled_font_t *scaled_font; /* font the glyph lives in */
cairo_text_extents_t metrics; /* user-space metrics */
cairo_text_extents_t fs_metrics; /* font-space metrics */
cairo_box_t bbox; /* device-space bounds */
int16_t x_advance; /* device-space rounded X advance */
int16_t y_advance; /* device-space rounded Y advance */
@ -2386,6 +2394,16 @@ cairo_private cairo_status_t
_cairo_pattern_get_extents (const cairo_pattern_t *pattern,
cairo_rectangle_int_t *extents);
cairo_private unsigned long
_cairo_pattern_hash (const cairo_pattern_t *pattern);
cairo_private unsigned long
_cairo_pattern_size (const cairo_pattern_t *pattern);
cairo_private cairo_bool_t
_cairo_pattern_equal (const cairo_pattern_t *a,
const cairo_pattern_t *b);
cairo_private void
_cairo_pattern_reset_static_data (void);

View file

@ -1170,10 +1170,10 @@ png_flatten_LDADD = $(top_builddir)/src/libcairo.la $(CAIRO_LDADD)
if BUILD_ANY2PPM
check_PROGRAMS += any2ppm
any2ppm_CFLAGS = $(POPPLER_CFLAGS) $(LIBRSVG_CFLAGS) $(LIBSPECTRE_CFLAGS)
any2ppm_CFLAGS = $(POPPLER_CFLAGS) $(LIBRSVG_CFLAGS) $(LIBSPECTRE_CFLAGS) $(csi_CFLAGS)
# add LDADD, so poppler/librsvg uses "our" cairo
any2ppm_LDFLAGS = $(CAIRO_TEST_UNDEFINED_LDFLAGS)
any2ppm_LDADD = $(top_builddir)/src/libcairo.la $(CAIRO_LDADD) $(POPPLER_LIBS) $(LIBRSVG_LIBS) $(LIBSPECTRE_LIBS)
any2ppm_LDADD = $(top_builddir)/src/libcairo.la $(CAIRO_LDADD) $(POPPLER_LIBS) $(LIBRSVG_LIBS) $(LIBSPECTRE_LIBS) $(csi_LIBS)
endif
if CAIRO_CAN_TEST_PDF_SURFACE

View file

@ -63,6 +63,10 @@
#include <cairo.h>
#if CAIRO_CAN_TEST_SCRIPT_SURFACE
#include <cairo-script-interpreter.h>
#endif
#if CAIRO_CAN_TEST_PDF_SURFACE
#include <poppler.h>
#endif
@ -160,7 +164,21 @@ write_ppm (cairo_surface_t *surface, int fd)
int width, height, stride;
int i, j;
data = cairo_image_surface_get_data (surface);
height = cairo_image_surface_get_height (surface);
width = cairo_image_surface_get_width (surface);
stride = cairo_image_surface_get_stride (surface);
format = cairo_image_surface_get_format (surface);
if (format == CAIRO_FORMAT_ARGB32) {
/* see if we can convert to a standard ppm type and trim a few bytes */
cairo_bool_t uses_alpha = FALSE;
const unsigned char *alpha = data;
for (j = height * stride; j-- && uses_alpha == FALSE; alpha += 4)
uses_alpha = *alpha != 0xff;
if (! uses_alpha)
format = CAIRO_FORMAT_RGB24;
}
switch (format) {
case CAIRO_FORMAT_ARGB32:
/* XXX need true alpha for svg */
@ -177,11 +195,6 @@ write_ppm (cairo_surface_t *surface, int fd)
return "unhandled image format";
}
data = cairo_image_surface_get_data (surface);
height = cairo_image_surface_get_height (surface);
width = cairo_image_surface_get_width (surface);
stride = cairo_image_surface_get_stride (surface);
len = sprintf (buf, "%s %d %d 255\n", format_str, width, height);
for (j = 0; j < height; j++) {
const unsigned int *row = (unsigned int *) (data + stride * j);
@ -220,6 +233,69 @@ write_ppm (cairo_surface_t *surface, int fd)
return NULL;
}
#if CAIRO_CAN_TEST_SCRIPT_SURFACE
static cairo_surface_t *
_create_image (void *closure,
double width, double height,
csi_object_t *dictionary)
{
cairo_surface_t **out = closure;
cairo_surface_t *surface;
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
return *out = cairo_surface_reference (surface);
}
static const char *
_cairo_script_render_page (const char *filename,
cairo_surface_t **surface_out)
{
cairo_script_interpreter_t *csi;
cairo_surface_t *surface = NULL;
cairo_status_t status;
csi = csi_create ();
csi_set_surface_create_function (csi, _create_image, &surface);
csi_run (csi, filename);
status = csi_destroy (csi);
if (status || surface == NULL) {
cairo_surface_destroy (surface);
return "cairo-script interpreter failed";
}
status = cairo_surface_status (surface);
if (status) {
cairo_surface_destroy (surface);
return cairo_status_to_string (status);
}
*surface_out = surface;
return NULL;
}
static const char *
cs_convert (char **argv, int fd)
{
const char *err;
cairo_surface_t *surface = NULL; /* silence compiler warning */
err = _cairo_script_render_page (argv[0], &surface);
if (err != NULL)
return err;
err = write_ppm (surface, fd);
cairo_surface_destroy (surface);
return err;
}
#else
static const char *
cs_convert (char **argv, int fd)
{
return "compiled without CairoScript support.";
}
#endif
#if CAIRO_CAN_TEST_PDF_SURFACE
/* adapted from pdf2png.c */
static const char *
@ -453,6 +529,7 @@ convert (char **argv, int fd)
const char *type;
const char *(*func) (char **, int);
} converters[] = {
{ "cs", cs_convert },
{ "pdf", pdf_convert },
{ "ps", ps_convert },
{ "svg", svg_convert },

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB