diff --git a/ChangeLog b/ChangeLog index 2f6a31a50..6f67623e8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,35 @@ +2005-12-21 Carl Worth + + * src/Makefile.am: + * src/cairo-paginated-surface-private.h: + * src/cairo-paginated-surface.c: (_cairo_paginated_surface_create), + (_cairo_paginated_surface_create_similar), + (_cairo_paginated_surface_finish), + (_cairo_paginated_surface_acquire_source_image), + (_cairo_paginated_surface_release_source_image), + (_cairo_paginated_surface_show_page), + (_cairo_paginated_surface_intersect_clip_path), + (_cairo_paginated_surface_get_extents), + (_cairo_paginated_surface_paint), (_cairo_paginated_surface_mask), + (_cairo_paginated_surface_stroke), (_cairo_paginated_surface_fill), + (_cairo_paginated_surface_show_glyphs), + (_cairo_paginated_surface_snapshot): Add a private + cairo_paginated_surface_t which builds on top of the meta surface + and is intended to provide an easy interface with common + functionality for the various paginated surface types (ps, pdf, + etc.). + + * src/test-paginated-surface.c: + (_test_paginated_surface_create_for_data): + * src/test-paginated-surface.h: + * test/cairo-test.c: (create_test_paginated_surface), + (test_paginated_write_to_png), (cleanup_test_paginated), + (cairo_test_expecting): Add test_paginated_surface_t which is + another test surface enabled with --enable-test-surfaces. The + test_meta_surface code served as the basis for + cairo_paginated_surface_t so that test surface may be entirely + superfluous now. + 2005-12-21 Carl Worth Here is a cleaner implementation of the _cairo_array_t change diff --git a/src/Makefile.am b/src/Makefile.am index 687d968d4..4a4a139fc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -22,7 +22,8 @@ endif if CAIRO_HAS_TEST_SURFACES libcairo_test_sources = test-fallback-surface.c test-fallback-surface.h \ - test-meta-surface.c test-meta-surface.h + test-meta-surface.c test-meta-surface.h \ + test-paginated-surface.c test-paginated-surface.h endif if CAIRO_HAS_XLIB_SURFACE @@ -164,6 +165,8 @@ libcairo_la_SOURCES = \ cairo-wideint.h \ cairo-meta-surface.c \ cairo-meta-surface-private.h \ + cairo-paginated-surface.c \ + cairo-paginated-surface-private.h \ $(libcairo_atsui_sources) \ $(libcairo_ft_sources) \ $(libcairo_ps_sources) \ diff --git a/src/cairo-paginated-surface-private.h b/src/cairo-paginated-surface-private.h new file mode 100644 index 000000000..ccec6047b --- /dev/null +++ b/src/cairo-paginated-surface-private.h @@ -0,0 +1,46 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc + * + * 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 Red Hat, Inc. + * + * Contributor(s): + * Carl Worth + */ + +#ifndef CAIRO_PAGINATED_SURFACE_H +#define CAIRO_PAGINATED_SURFACE_H + +#include "cairoint.h" + +cairo_private cairo_surface_t * +_cairo_paginated_surface_create (cairo_surface_t *target, + int width, + int height); + +#endif /* CAIRO_PAGINATED_SURFACE_H */ diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c new file mode 100644 index 000000000..d576b91b5 --- /dev/null +++ b/src/cairo-paginated-surface.c @@ -0,0 +1,337 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc + * + * 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 Red Hat, Inc. + * + * Contributor(s): + * Carl Worth + */ + +/* The paginated surface layer exists to provide as much code sharing + * as possible for the various paginated surface backends in cairo + * (PostScript, PDF, etc.). + * + * The concept is that a surface which uses a paginated surface merely + * needs to implement backend operations which it can accurately + * provide, (and return CAIRO_INT_STATUS_UNSUPPORTED or leave backend + * function pointers NULL otherwise). The paginated surface is the + * responsible for collecting operations that aren't supported, + * replaying them against the image surface, and then supplying the + * resulting images to the target surface. + * + * When created, a paginated surface accepts the target surface to + * which the final drawing will eventually be performed. The paginated + * surface then uses cairo_meta_surface_t to record all drawing + * operations up until each show_page operation. + * + * At the time of show_page, the paginated surface replays the meta + * surface against the target surface and maintains regions of the + * result that will come from the nativ surface and regions that will + * need to come from image fallbacks. It then replays the necessary + * portions against image surface and provides those results to the + * target surface through existing interfaces. + * + * This way the target surface is never even aware of any distinction + * between native drawing operations vs. results that are supplied by + * image fallbacks. Instead the surface need only implement as much of + * the surface backend interface as it can do correctly, and let the + * paginated surface take care of all the messy details. + */ + +#include "cairoint.h" + +#include "cairo-paginated-surface-private.h" +#include "cairo-meta-surface-private.h" + +typedef struct _cairo_paginated_surface { + cairo_surface_t base; + + /* The target surface to hold the final result. */ + cairo_surface_t *target; + + /* A cairo_meta_surface to record all operations. To be replayed + * against target, and also against image surface as necessary for + * fallbacks. */ + cairo_surface_t *meta; + +} cairo_paginated_surface_t; + +const cairo_private cairo_surface_backend_t cairo_paginated_surface_backend; + +static cairo_int_status_t +_cairo_paginated_surface_show_page (void *abstract_surface); + +cairo_surface_t * +_cairo_paginated_surface_create (cairo_surface_t *target, + int width, + int height) +{ + cairo_paginated_surface_t *surface; + + surface = malloc (sizeof (cairo_paginated_surface_t)); + if (surface == NULL) + goto FAIL; + + _cairo_surface_init (&surface->base, &cairo_paginated_surface_backend); + + surface->target = target; + + surface->meta = _cairo_meta_surface_create (width, height); + if (cairo_surface_status (surface->meta)) + goto FAIL_CLEANUP_SURFACE; + + return &surface->base; + + FAIL_CLEANUP_SURFACE: + free (surface); + FAIL: + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_surface_t*) &_cairo_surface_nil; +} + +static cairo_surface_t * +_cairo_paginated_surface_create_similar (void *abstract_surface, + cairo_content_t content, + int width, + int height) +{ + return _cairo_meta_surface_create (width, height); +} + +static cairo_status_t +_cairo_paginated_surface_finish (void *abstract_surface) +{ + cairo_paginated_surface_t *surface = abstract_surface; + + cairo_surface_destroy (surface->meta); + + cairo_surface_destroy (surface->target); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_paginated_surface_acquire_source_image (void *abstract_surface, + cairo_image_surface_t **image_out, + void **image_extra) +{ + cairo_paginated_surface_t *surface = abstract_surface; + cairo_surface_t *image; + cairo_rectangle_t extents; + + _cairo_surface_get_extents (surface->target, &extents); + + image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + extents.width, extents.height); + + _cairo_meta_surface_replay (surface->meta, image); + + *image_out = (cairo_image_surface_t*) image; + *image_extra = NULL; + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_paginated_surface_release_source_image (void *abstract_surface, + cairo_image_surface_t *image, + void *image_extra) +{ + cairo_surface_destroy (&image->base); +} + +static cairo_int_status_t +_cairo_paginated_surface_show_page (void *abstract_surface) +{ + cairo_paginated_surface_t *surface = abstract_surface; + + _cairo_meta_surface_replay (surface->meta, surface->target); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_paginated_surface_intersect_clip_path (void *abstract_surface, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias) +{ + cairo_paginated_surface_t *surface = abstract_surface; + + return _cairo_surface_intersect_clip_path (surface->meta, + path, fill_rule, + tolerance, antialias); +} + +static cairo_int_status_t +_cairo_paginated_surface_get_extents (void *abstract_surface, + cairo_rectangle_t *rectangle) +{ + cairo_paginated_surface_t *surface = abstract_surface; + + return _cairo_surface_get_extents (surface->target, rectangle); +} + +static cairo_int_status_t +_cairo_paginated_surface_paint (void *abstract_surface, + cairo_operator_t op, + cairo_pattern_t *source) +{ + cairo_paginated_surface_t *surface = abstract_surface; + + return _cairo_surface_paint (surface->meta, op, source); +} + +static cairo_int_status_t +_cairo_paginated_surface_mask (void *abstract_surface, + cairo_operator_t op, + cairo_pattern_t *source, + cairo_pattern_t *mask) +{ + cairo_paginated_surface_t *surface = abstract_surface; + + return _cairo_surface_mask (surface->meta, op, source, mask); +} + +static cairo_int_status_t +_cairo_paginated_surface_stroke (void *abstract_surface, + cairo_operator_t op, + cairo_pattern_t *source, + cairo_path_fixed_t *path, + cairo_stroke_style_t *style, + cairo_matrix_t *ctm, + cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias) +{ + cairo_paginated_surface_t *surface = abstract_surface; + + return _cairo_surface_stroke (surface->meta, op, source, + path, style, + ctm, ctm_inverse, + tolerance, antialias); +} + +static cairo_int_status_t +_cairo_paginated_surface_fill (void *abstract_surface, + cairo_operator_t op, + cairo_pattern_t *source, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias) +{ + cairo_paginated_surface_t *surface = abstract_surface; + + return _cairo_surface_fill (surface->meta, op, source, + path, fill_rule, + tolerance, antialias); +} + +static cairo_int_status_t +_cairo_paginated_surface_show_glyphs (void *abstract_surface, + cairo_operator_t op, + cairo_pattern_t *source, + const cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font) +{ + cairo_paginated_surface_t *surface = abstract_surface; + + return _cairo_surface_show_glyphs (surface->meta, op, source, + glyphs, num_glyphs, + scaled_font); +} + +static cairo_surface_t * +_cairo_paginated_surface_snapshot (void *abstract_other) +{ + cairo_paginated_surface_t *other = abstract_other; + + /* XXX: Just making a snapshot of other->meta is what we really + * want. But this currently triggers a bug somewhere (the "mask" + * test from the test suite segfaults). + * + * For now, we'll create a new image surface and replay onto + * that. It would be tempting to replay into other->image and then + * return a snapshot of that, but that will cause the self-copy + * test to fail, (since our replay will be affected by a clip that + * should not have any effect on the use of the resulting snapshot + * as a source). + */ + +#if 0 + return _cairo_surface_snapshot (other->meta); +#else + cairo_rectangle_t extents; + cairo_surface_t *surface; + + _cairo_surface_get_extents (other->target, &extents); + + surface = cairo_surface_create_similar (other->target, + CAIRO_CONTENT_COLOR_ALPHA, + extents.width, + extents.height); + + _cairo_meta_surface_replay (other->meta, surface); + + return surface; +#endif +} + +const cairo_surface_backend_t cairo_paginated_surface_backend = { + _cairo_paginated_surface_create_similar, + _cairo_paginated_surface_finish, + _cairo_paginated_surface_acquire_source_image, + _cairo_paginated_surface_release_source_image, + NULL, /* acquire_dest_image */ + NULL, /* release_dest_image */ + NULL, /* clone_similar */ + NULL, /* composite */ + NULL, /* fill_rectangles */ + NULL, /* composite_trapezoids */ + NULL, /* copy_page */ + _cairo_paginated_surface_show_page, + NULL, /* set_clip_region */ + _cairo_paginated_surface_intersect_clip_path, + _cairo_paginated_surface_get_extents, + NULL, /* old_show_glyphs */ + NULL, /* get_font_options */ + NULL, /* flush */ + NULL, /* mark_dirty_rectangle */ + NULL, /* scaled_font_fini */ + NULL, /* scaled_glyph_fini */ + _cairo_paginated_surface_paint, + _cairo_paginated_surface_mask, + _cairo_paginated_surface_stroke, + _cairo_paginated_surface_fill, + _cairo_paginated_surface_show_glyphs, + _cairo_paginated_surface_snapshot +}; diff --git a/src/test-paginated-surface.c b/src/test-paginated-surface.c new file mode 100644 index 000000000..2a1510915 --- /dev/null +++ b/src/test-paginated-surface.c @@ -0,0 +1,67 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc + * + * 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 Red Hat, Inc. + * + * Contributor(s): + * Carl Worth + */ + +/* This isn't a "real" surface, but just something to be used by the + * test suite to help exercise the paginated-surface paths in cairo. + * + * The defining feature of this backend is that it uses a paginated + * surface to record all operations, and then replays everything to an + * image surface. + * + * It's possible that this code might serve as a good starting point + * for someone working on bringing up a new paginated-surface-based + * backend. + */ + +#include "test-paginated-surface.h" + +#include "cairoint.h" + +#include "cairo-paginated-surface-private.h" + +cairo_surface_t * +_test_paginated_surface_create_for_data (unsigned char *data, + cairo_format_t format, + int width, + int height, + int stride) +{ + cairo_surface_t *target; + + target = cairo_image_surface_create_for_data (data, format, + width, height, stride); + + return _cairo_paginated_surface_create (target, width, height); +} diff --git a/src/test-paginated-surface.h b/src/test-paginated-surface.h new file mode 100644 index 000000000..f00a33631 --- /dev/null +++ b/src/test-paginated-surface.h @@ -0,0 +1,52 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc + * + * 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 Red Hat, Inc. + * + * Contributor(s): + * Carl Worth + */ + +#ifndef TEST_PAGINATED_SURFACE_H +#define TEST_PAGINATED_SURFACE_H + +#include "cairo.h" + +CAIRO_BEGIN_DECLS + +cairo_surface_t * +_test_paginated_surface_create_for_data (unsigned char *data, + cairo_format_t format, + int width, + int height, + int stride); + +CAIRO_END_DECLS + +#endif /* TEST_PAGINATED_SURFACE_H */ diff --git a/test/cairo-test.c b/test/cairo-test.c index ac6298b4d..e6c67e1bb 100644 --- a/test/cairo-test.c +++ b/test/cairo-test.c @@ -190,6 +190,7 @@ create_image_surface (cairo_test_t *test, cairo_format_t format, #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_format_t format, @@ -207,6 +208,86 @@ create_test_meta_surface (cairo_test_t *test, cairo_format_t format, return _test_meta_surface_create (format, test->width, test->height); } +static const cairo_user_data_key_t test_paginated_closure_key; + +typedef struct { + unsigned char *data; + cairo_format_t format; + int width; + int height; + int stride; +} test_paginated_closure_t; + +static cairo_surface_t * +create_test_paginated_surface (cairo_test_t *test, cairo_format_t format, + void **closure) +{ + test_paginated_closure_t *tpc; + cairo_surface_t *surface; + + *closure = tpc = xmalloc (sizeof (test_paginated_closure_t)); + + tpc->format = format; + 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->format, + 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_t +test_paginated_write_to_png (cairo_surface_t *surface, + const char *filename) +{ + cairo_surface_t *image; + test_paginated_closure_t *tpc; + + tpc = cairo_surface_get_user_data (surface, &test_paginated_closure_key); + + image = cairo_image_surface_create_for_data (tpc->data, + tpc->format, + tpc->width, + tpc->height, + tpc->stride); + + cairo_surface_write_to_png (image, filename); + + cairo_surface_destroy (image); + + return CAIRO_STATUS_SUCCESS; +} + +static void +cleanup_test_paginated (void *closure) +{ + test_paginated_closure_t *tpc = closure; + + free (tpc->data); + free (tpc); +} + #endif #ifdef CAIRO_HAS_GLITZ_SURFACE @@ -1299,6 +1380,10 @@ cairo_test_expecting (cairo_test_t *test, cairo_test_draw_function_t draw, create_test_fallback_surface, cairo_surface_write_to_png, NULL }, { "test-meta", CAIRO_FORMAT_ARGB32, create_test_meta_surface, cairo_surface_write_to_png, NULL }, + { "test-paginated", CAIRO_FORMAT_ARGB32, + create_test_paginated_surface, + test_paginated_write_to_png, + cleanup_test_paginated }, #endif #ifdef CAIRO_HAS_GLITZ_SURFACE #if CAIRO_CAN_TEST_GLITZ_GLX_SURFACE