summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2009-07-03 18:26:50 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2009-07-03 18:26:50 +0100
commit6003ab77e1ebefadb97338de0e7da4a76d973b1a (patch)
treee375335dac3abfdd3e75cb18a317824556de84f6
parent2a9903dbbfeb3fe843f0d618d15674b37a29f3a9 (diff)
Export meta-surface
The meta-surface is a vital tool to record a trace of drawing commands in-memory. As such it is used throughout cairo. The value of such a surface is immediately obvious and should be applicable for many applications. The first such case is by cairo-test-trace which wants to record the entire graph of drawing commands that affect a surface in the event of a failure.
-rw-r--r--NEWS27
-rw-r--r--boilerplate/Makefile.win32.features8
-rw-r--r--boilerplate/cairo-boilerplate.c12
-rw-r--r--build/Makefile.win32.features-h1
-rw-r--r--build/configure.ac.features1
-rw-r--r--configure.ac4
-rw-r--r--perf/cairo-perf.c6
-rw-r--r--src/Makefile.win32.features8
-rw-r--r--src/cairo-meta-surface-private.h14
-rw-r--r--src/cairo-meta-surface.c202
-rw-r--r--src/cairo-paginated-surface.c16
-rw-r--r--src/cairo-pdf-surface.c2
-rw-r--r--src/cairo-ps-surface.c2
-rw-r--r--src/cairo-script-surface.c10
-rw-r--r--src/cairo-surface.c2
-rw-r--r--src/cairo-svg-surface.c8
-rw-r--r--src/cairo-type3-glyph-surface.c8
-rw-r--r--src/cairo-types-private.h3
-rw-r--r--src/cairo-user-font.c7
-rw-r--r--src/cairo-win32-printing-surface.c2
-rw-r--r--src/cairo.h22
-rw-r--r--src/test-meta-surface.c16
-rw-r--r--src/test-meta-surface.h8
-rw-r--r--test/cairo-test-trace.c58
-rw-r--r--test/get-clip.c5
25 files changed, 296 insertions, 156 deletions
diff --git a/NEWS b/NEWS
index e23c58b5..4072acae 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,30 @@
+Snapshot 1.9.4 (2009-07-xx)
+===========================
+API additions:
+
+ cairo_meta_surface_create()
+ cairo_meta_surface_ink_extents()
+ cairo_meta_surface_replay()
+
+ Finally exporting the internal meta-surface so that applications
+ have a method to record and replay a sequence of drawing commands.
+
+New utilities:
+
+ cairo-test-trace
+
+ A companion to cairo-perf-trace, this utility replays a trace against
+ multiple targets in parallel and looks for differences in the output,
+ and then records any drawing commands that cause a failure.
+ Future plans:
+ Further minimisation of the fail trace using "delta debugging".
+ More control over test/reference targets.
+
+New experimental backends:
+
+ QT
+
+
Snapshot 1.9.2 (2009-06-12)
===========================
API additions:
diff --git a/boilerplate/Makefile.win32.features b/boilerplate/Makefile.win32.features
index e80bf034..33eaf5fd 100644
--- a/boilerplate/Makefile.win32.features
+++ b/boilerplate/Makefile.win32.features
@@ -234,6 +234,14 @@ enabled_cairo_boilerplate_headers += $(cairo_boilerplate_image_headers)
enabled_cairo_boilerplate_private += $(cairo_boilerplate_image_private)
enabled_cairo_boilerplate_sources += $(cairo_boilerplate_image_sources)
+supported_cairo_boilerplate_headers += $(cairo_boilerplate_meta_headers)
+all_cairo_boilerplate_headers += $(cairo_boilerplate_meta_headers)
+all_cairo_boilerplate_private += $(cairo_boilerplate_meta_private)
+all_cairo_boilerplate_sources += $(cairo_boilerplate_meta_sources)
+enabled_cairo_boilerplate_headers += $(cairo_boilerplate_meta_headers)
+enabled_cairo_boilerplate_private += $(cairo_boilerplate_meta_private)
+enabled_cairo_boilerplate_sources += $(cairo_boilerplate_meta_sources)
+
supported_cairo_boilerplate_headers += $(cairo_boilerplate_user_headers)
all_cairo_boilerplate_headers += $(cairo_boilerplate_user_headers)
all_cairo_boilerplate_private += $(cairo_boilerplate_user_private)
diff --git a/boilerplate/cairo-boilerplate.c b/boilerplate/cairo-boilerplate.c
index 285b23aa..af6f9fa8 100644
--- a/boilerplate/cairo-boilerplate.c
+++ b/boilerplate/cairo-boilerplate.c
@@ -526,7 +526,7 @@ static const cairo_boilerplate_target_t targets[] =
},
{
"win32-printing", "win32", ".ps", NULL,
- CAIRO_INTERNAL_SURFACE_TYPE_META, CAIRO_CONTENT_COLOR, 0,
+ CAIRO_SURFACE_TYPE_META, CAIRO_CONTENT_COLOR, 0,
_cairo_boilerplate_win32_printing_create_surface,
NULL, NULL,
_cairo_boilerplate_win32_printing_get_image_surface,
@@ -613,7 +613,7 @@ static const cairo_boilerplate_target_t targets[] =
},
{
"ps2", "ps", ".ps", NULL,
- CAIRO_INTERNAL_SURFACE_TYPE_META, CAIRO_CONTENT_COLOR, 0,
+ CAIRO_SURFACE_TYPE_META, CAIRO_CONTENT_COLOR, 0,
_cairo_boilerplate_ps2_create_surface,
_cairo_boilerplate_ps_force_fallbacks,
_cairo_boilerplate_ps_finish_surface,
@@ -636,7 +636,7 @@ static const cairo_boilerplate_target_t targets[] =
},
{
"ps3", "ps", ".ps", NULL,
- CAIRO_INTERNAL_SURFACE_TYPE_META, CAIRO_CONTENT_COLOR, 0,
+ CAIRO_SURFACE_TYPE_META, CAIRO_CONTENT_COLOR, 0,
_cairo_boilerplate_ps3_create_surface,
_cairo_boilerplate_ps_force_fallbacks,
_cairo_boilerplate_ps_finish_surface,
@@ -661,7 +661,7 @@ static const cairo_boilerplate_target_t targets[] =
},
{
"pdf", "pdf", ".pdf", NULL,
- CAIRO_INTERNAL_SURFACE_TYPE_META, CAIRO_CONTENT_COLOR, 0,
+ CAIRO_SURFACE_TYPE_META, CAIRO_CONTENT_COLOR, 0,
_cairo_boilerplate_pdf_create_surface,
_cairo_boilerplate_pdf_force_fallbacks,
_cairo_boilerplate_pdf_finish_surface,
@@ -703,7 +703,7 @@ static const cairo_boilerplate_target_t targets[] =
},
{
"svg11", "svg", NULL, NULL,
- CAIRO_INTERNAL_SURFACE_TYPE_META, CAIRO_CONTENT_COLOR, 1,
+ CAIRO_SURFACE_TYPE_META, CAIRO_CONTENT_COLOR, 1,
_cairo_boilerplate_svg11_create_surface,
_cairo_boilerplate_svg_force_fallbacks,
_cairo_boilerplate_svg_finish_surface,
@@ -725,7 +725,7 @@ static const cairo_boilerplate_target_t targets[] =
},
{
"svg12", "svg", NULL, NULL,
- CAIRO_INTERNAL_SURFACE_TYPE_META, CAIRO_CONTENT_COLOR, 1,
+ CAIRO_SURFACE_TYPE_META, CAIRO_CONTENT_COLOR, 1,
_cairo_boilerplate_svg12_create_surface,
_cairo_boilerplate_svg_force_fallbacks,
_cairo_boilerplate_svg_finish_surface,
diff --git a/build/Makefile.win32.features-h b/build/Makefile.win32.features-h
index 3cfc5424..fd5f05d8 100644
--- a/build/Makefile.win32.features-h
+++ b/build/Makefile.win32.features-h
@@ -69,5 +69,6 @@ ifeq ($(CAIRO_HAS_TEST_SURFACES),1)
@echo "#define CAIRO_HAS_TEST_SURFACES 1" >> src/cairo-features.h
endif
@echo "#define CAIRO_HAS_IMAGE_SURFACE 1" >> src/cairo-features.h
+ @echo "#define CAIRO_HAS_META_SURFACE 1" >> src/cairo-features.h
@echo "#define CAIRO_HAS_USER_FONT 1" >> src/cairo-features.h
@echo "#endif" >> src/cairo-features.h
diff --git a/build/configure.ac.features b/build/configure.ac.features
index d3d321fd..3f866801 100644
--- a/build/configure.ac.features
+++ b/build/configure.ac.features
@@ -361,6 +361,7 @@ AC_DEFUN([CAIRO_REPORT],
echo ""
echo "The following surface backends:"
echo " Image: yes (always builtin)"
+ echo " Meta: yes (always builtin)"
echo " Xlib: $use_xlib"
echo " Xlib Xrender: $use_xlib_xrender"
echo " Qt: $use_qt"
diff --git a/configure.ac b/configure.ac
index 06b7fa83..4f8f1b27 100644
--- a/configure.ac
+++ b/configure.ac
@@ -472,6 +472,10 @@ CAIRO_ENABLE_SURFACE_BACKEND(image, image, always, [
dnl ===========================================================================
+CAIRO_ENABLE_SURFACE_BACKEND(meta, meta, always)
+
+dnl ===========================================================================
+
CAIRO_ENABLE_FONT_BACKEND(user, user, always)
dnl ===========================================================================
diff --git a/perf/cairo-perf.c b/perf/cairo-perf.c
index 35a89b56..cf757f73 100644
--- a/perf/cairo-perf.c
+++ b/perf/cairo-perf.c
@@ -68,7 +68,7 @@ const cairo_perf_case_t perf_cases[];
static cairo_bool_t
target_is_measurable (const cairo_boilerplate_target_t *target)
{
- switch (target->expected_type) {
+ switch ((int) target->expected_type) {
case CAIRO_SURFACE_TYPE_IMAGE:
if (strcmp (target->name, "pdf") == 0 ||
strcmp (target->name, "ps") == 0)
@@ -102,9 +102,7 @@ target_is_measurable (const cairo_boilerplate_target_t *target)
case CAIRO_SURFACE_TYPE_QT:
#endif
return TRUE;
- case CAIRO_SURFACE_TYPE_PDF:
- case CAIRO_SURFACE_TYPE_PS:
- case CAIRO_SURFACE_TYPE_SVG:
+
default:
return FALSE;
}
diff --git a/src/Makefile.win32.features b/src/Makefile.win32.features
index ac8d570e..6b989a80 100644
--- a/src/Makefile.win32.features
+++ b/src/Makefile.win32.features
@@ -316,6 +316,14 @@ enabled_cairo_headers += $(cairo_image_headers)
enabled_cairo_private += $(cairo_image_private)
enabled_cairo_sources += $(cairo_image_sources)
+supported_cairo_headers += $(cairo_meta_headers)
+all_cairo_headers += $(cairo_meta_headers)
+all_cairo_private += $(cairo_meta_private)
+all_cairo_sources += $(cairo_meta_sources)
+enabled_cairo_headers += $(cairo_meta_headers)
+enabled_cairo_private += $(cairo_meta_private)
+enabled_cairo_sources += $(cairo_meta_sources)
+
supported_cairo_headers += $(cairo_user_headers)
all_cairo_headers += $(cairo_user_headers)
all_cairo_private += $(cairo_user_private)
diff --git a/src/cairo-meta-surface-private.h b/src/cairo-meta-surface-private.h
index 8d5e096e..f0c95c19 100644
--- a/src/cairo-meta-surface-private.h
+++ b/src/cairo-meta-surface-private.h
@@ -150,8 +150,9 @@ typedef struct _cairo_meta_surface {
/* A meta-surface is logically unbounded, but when used as a
* source we need to render it to an image, so we need a size at
* which to create that image. */
- int width_pixels;
- int height_pixels;
+ double width_pixels;
+ double height_pixels;
+ cairo_rectangle_int_t extents;
cairo_array_t commands;
cairo_surface_t *commands_owner;
@@ -160,18 +161,13 @@ typedef struct _cairo_meta_surface {
int replay_start_idx;
} cairo_meta_surface_t;
-cairo_private cairo_surface_t *
-_cairo_meta_surface_create (cairo_content_t content,
- int width_pixels,
- int height_pixels);
+slim_hidden_proto (cairo_meta_surface_create);
+slim_hidden_proto (cairo_meta_surface_replay);
cairo_private cairo_int_status_t
_cairo_meta_surface_get_path (cairo_surface_t *surface,
cairo_path_fixed_t *path);
-cairo_private cairo_status_t
-_cairo_meta_surface_replay (cairo_surface_t *surface,
- cairo_surface_t *target);
cairo_private cairo_status_t
_cairo_meta_surface_replay_analyze_meta_pattern (cairo_surface_t *surface,
diff --git a/src/cairo-meta-surface.c b/src/cairo-meta-surface.c
index 9f60007a..3c2b74ee 100644
--- a/src/cairo-meta-surface.c
+++ b/src/cairo-meta-surface.c
@@ -42,7 +42,9 @@
* level of paint, mask, stroke, fill, and show_text_glyphs). The meta
* surface can then be "replayed" against any target surface with:
*
- * _cairo_meta_surface_replay (meta, target);
+ * <informalexample><programlisting>
+ * cairo_meta_surface_replay (meta, target);
+ * </programlisting></informalexample>
*
* after which the results in target will be identical to the results
* that would have been obtained if the original operations applied to
@@ -57,6 +59,7 @@
*/
#include "cairoint.h"
+#include "cairo-analysis-surface-private.h"
#include "cairo-meta-surface-private.h"
#include "cairo-clip-private.h"
@@ -73,13 +76,38 @@ static const cairo_surface_backend_t cairo_meta_surface_backend;
*
* XXX: The naming of "pixels" in the size here is a misnomer. It's
* actually a size in whatever device-space units are desired (again,
- * according to the intended replay target). This should likely also
- * be changed to use doubles not ints.
+ * according to the intended replay target).
*/
+
+/**
+ * cairo_meta_surface_create:
+ * @content: the content of the meta surface
+ * @width_pixels: width of the surface, in pixels
+ * @height_pixels: height of the surface, in pixels
+ *
+ * Creates a meta-surface which can be used to record all drawing operations
+ * at the highest level (that is, the level of paint, mask, stroke, fill
+ * and show_text_glyphs). The meta surface can then be "replayed" against
+ * any target surface with:
+ *
+ * <informalexample><programlisting>
+ * cairo_meta_surface_replay (meta, target);
+ * </programlisting></informalexample>
+ *
+ * after which the results in target will be identical to the results
+ * that would have been obtained if the original operations applied to
+ * the meta surface had instead been applied to the target surface.
+ *
+ * The recording phase of the meta surface is careful to snapshot all
+ * necessary objects (paths, patterns, etc.), in order to achieve
+ * accurate replay.
+ *
+ * Since 1.10
+ **/
cairo_surface_t *
-_cairo_meta_surface_create (cairo_content_t content,
- int width_pixels,
- int height_pixels)
+cairo_meta_surface_create (cairo_content_t content,
+ double width_pixels,
+ double height_pixels)
{
cairo_meta_surface_t *meta;
@@ -94,6 +122,29 @@ _cairo_meta_surface_create (cairo_content_t content,
meta->width_pixels = width_pixels;
meta->height_pixels = height_pixels;
+ /* unbounded -> 'infinite' extents */
+ if (width_pixels < 0) {
+ meta->extents.x = CAIRO_RECT_INT_MIN;
+ meta->extents.width = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN;
+ } else {
+ meta->extents.x = 0;
+ if (ceil (width_pixels) > CAIRO_RECT_INT_MAX)
+ meta->extents.width = CAIRO_RECT_INT_MAX;
+ else
+ meta->extents.width = ceil (width_pixels);
+ }
+
+ if (height_pixels < 0) {
+ meta->extents.y = CAIRO_RECT_INT_MIN;
+ meta->extents.height = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN;
+ } else {
+ meta->extents.y = 0;
+ if (ceil (height_pixels) > CAIRO_RECT_INT_MAX)
+ meta->extents.height = CAIRO_RECT_INT_MAX;
+ else
+ meta->extents.height = ceil (height_pixels);
+ }
+
_cairo_array_init (&meta->commands, sizeof (cairo_command_t *));
meta->commands_owner = NULL;
@@ -102,6 +153,7 @@ _cairo_meta_surface_create (cairo_content_t content,
return &meta->base;
}
+slim_hidden_def (cairo_meta_surface_create);
static cairo_surface_t *
_cairo_meta_surface_create_similar (void *abstract_surface,
@@ -109,7 +161,7 @@ _cairo_meta_surface_create_similar (void *abstract_surface,
int width,
int height)
{
- return _cairo_meta_surface_create (content, width, height);
+ return cairo_meta_surface_create (content, width, height);
}
static cairo_status_t
@@ -193,10 +245,10 @@ _cairo_meta_surface_acquire_source_image (void *abstract_surface,
cairo_surface_t *image;
image = _cairo_image_surface_create_with_content (surface->content,
- surface->width_pixels,
- surface->height_pixels);
+ ceil (surface->width_pixels),
+ ceil (surface->height_pixels));
- status = _cairo_meta_surface_replay (&surface->base, image);
+ status = cairo_meta_surface_replay (&surface->base, image);
if (unlikely (status)) {
cairo_surface_destroy (image);
return status;
@@ -216,6 +268,16 @@ _cairo_meta_surface_release_source_image (void *abstract_surface,
cairo_surface_destroy (&image->base);
}
+static void
+_draw_command_init (cairo_command_header_t *command,
+ cairo_command_type_t type,
+ cairo_meta_surface_t *meta)
+{
+ command->type = type;
+ command->region = CAIRO_META_REGION_ALL;
+ command->extents = meta->extents;
+}
+
static cairo_int_status_t
_cairo_meta_surface_paint (void *abstract_surface,
cairo_operator_t op,
@@ -230,12 +292,7 @@ _cairo_meta_surface_paint (void *abstract_surface,
if (unlikely (command == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- command->header.type = CAIRO_COMMAND_PAINT;
- command->header.region = CAIRO_META_REGION_ALL;
- command->header.extents.x = 0;
- command->header.extents.y = 0;
- command->header.extents.width = meta->width_pixels;
- command->header.extents.height = meta->height_pixels;
+ _draw_command_init (&command->header, CAIRO_COMMAND_PAINT, meta);
command->op = op;
status = _cairo_pattern_init_snapshot (&command->source.base, source);
@@ -276,12 +333,7 @@ _cairo_meta_surface_mask (void *abstract_surface,
if (unlikely (command == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- command->header.type = CAIRO_COMMAND_MASK;
- command->header.region = CAIRO_META_REGION_ALL;
- command->header.extents.x = 0;
- command->header.extents.y = 0;
- command->header.extents.width = meta->width_pixels;
- command->header.extents.height = meta->height_pixels;
+ _draw_command_init (&command->header, CAIRO_COMMAND_MASK, meta);
command->op = op;
status = _cairo_pattern_init_snapshot (&command->source.base, source);
@@ -327,12 +379,7 @@ _cairo_meta_surface_stroke (void *abstract_surface,
if (unlikely (command == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- command->header.type = CAIRO_COMMAND_STROKE;
- command->header.region = CAIRO_META_REGION_ALL;
- command->header.extents.x = 0;
- command->header.extents.y = 0;
- command->header.extents.width = meta->width_pixels;
- command->header.extents.height = meta->height_pixels;
+ _draw_command_init (&command->header, CAIRO_COMMAND_STROKE, meta);
command->op = op;
status = _cairo_pattern_init_snapshot (&command->source.base, source);
@@ -387,12 +434,7 @@ _cairo_meta_surface_fill (void *abstract_surface,
if (unlikely (command == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- command->header.type = CAIRO_COMMAND_FILL;
- command->header.region = CAIRO_META_REGION_ALL;
- command->header.extents.x = 0;
- command->header.extents.y = 0;
- command->header.extents.width = meta->width_pixels;
- command->header.extents.height = meta->height_pixels;
+ _draw_command_init (&command->header, CAIRO_COMMAND_FILL, meta);
command->op = op;
status = _cairo_pattern_init_snapshot (&command->source.base, source);
@@ -450,12 +492,7 @@ _cairo_meta_surface_show_text_glyphs (void *abstract_surface,
if (unlikely (command == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- command->header.type = CAIRO_COMMAND_SHOW_TEXT_GLYPHS;
- command->header.region = CAIRO_META_REGION_ALL;
- command->header.extents.x = 0;
- command->header.extents.y = 0;
- command->header.extents.width = meta->width_pixels;
- command->header.extents.height = meta->height_pixels;
+ _draw_command_init (&command->header, CAIRO_COMMAND_SHOW_TEXT_GLYPHS, meta);
command->op = op;
status = _cairo_pattern_init_snapshot (&command->source.base, source);
@@ -601,7 +638,7 @@ _cairo_meta_surface_intersect_clip_path (void *dst,
/* Currently, we're using as the "size" of a meta surface the largest
* surface size against which the meta-surface is expected to be
- * replayed, (as passed in to _cairo_meta_surface_create).
+ * replayed, (as passed in to cairo_meta_surface_create()).
*/
static cairo_int_status_t
_cairo_meta_surface_get_extents (void *abstract_surface,
@@ -609,13 +646,13 @@ _cairo_meta_surface_get_extents (void *abstract_surface,
{
cairo_meta_surface_t *surface = abstract_surface;
- if (surface->width_pixels == -1 && surface->height_pixels == -1)
+ if (surface->width_pixels < 0 || surface->height_pixels < 0)
return CAIRO_INT_STATUS_UNSUPPORTED;
rectangle->x = 0;
rectangle->y = 0;
- rectangle->width = surface->width_pixels;
- rectangle->height = surface->height_pixels;
+ rectangle->width = ceil (surface->width_pixels);
+ rectangle->height = ceil (surface->height_pixels);
return CAIRO_STATUS_SUCCESS;
}
@@ -635,7 +672,7 @@ _cairo_surface_is_meta (const cairo_surface_t *surface)
}
static const cairo_surface_backend_t cairo_meta_surface_backend = {
- CAIRO_INTERNAL_SURFACE_TYPE_META,
+ CAIRO_SURFACE_TYPE_META,
_cairo_meta_surface_create_similar,
_cairo_meta_surface_finish,
_cairo_meta_surface_acquire_source_image,
@@ -1000,15 +1037,30 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface,
return _cairo_surface_set_error (surface, status);
}
+/**
+ * cairo_meta_surface_replay:
+ * @surface: the #cairo_meta_surface_t
+ * @target: a target #cairo_surface_t onto which to replay the operations
+ * @width_pixels: width of the surface, in pixels
+ * @height_pixels: height of the surface, in pixels
+ *
+ * A meta surface can be "replayed" against any target surface,
+ * after which the results in target will be identical to the results
+ * that would have been obtained if the original operations applied to
+ * the meta surface had instead been applied to the target surface.
+ *
+ * Since 1.10
+ **/
cairo_status_t
-_cairo_meta_surface_replay (cairo_surface_t *surface,
- cairo_surface_t *target)
+cairo_meta_surface_replay (cairo_surface_t *surface,
+ cairo_surface_t *target)
{
return _cairo_meta_surface_replay_internal (surface,
target,
CAIRO_META_REPLAY,
CAIRO_META_REGION_ALL);
}
+slim_hidden_def (cairo_meta_surface_replay);
/* Replay meta to surface. When the return status of each operation is
* one of %CAIRO_STATUS_SUCCESS, %CAIRO_INT_STATUS_UNSUPPORTED, or
@@ -1036,3 +1088,59 @@ _cairo_meta_surface_replay_region (cairo_surface_t *surface,
CAIRO_META_REPLAY,
region);
}
+
+/**
+ * cairo_meta_surface_ink_extents:
+ * @surface: a #cairo_meta_surface_t
+ * @x0: the x-coordinate of the top-left of the ink bounding box
+ * @y0: the y-coordinate of the top-left of the ink bounding box
+ * @width: the width of the ink bounding box
+ * @height: the height of the ink bounding box
+ *
+ * Measures the extents of the operations stored within the meta-surface.
+ * This is useful to compute the required size of an image surface (or
+ * equivalent) into which to replay the full sequence of drawing operaitions.
+ *
+ * Since: 1.10
+ **/
+void
+cairo_meta_surface_ink_extents (cairo_surface_t *surface,
+ double *x0,
+ double *y0,
+ double *width,
+ double *height)
+{
+ cairo_surface_t *null_surface;
+ cairo_surface_t *analysis_surface;
+ cairo_status_t status;
+ cairo_box_t bbox;
+
+ memset (&bbox, 0, sizeof (bbox));
+
+ if (! _cairo_surface_is_meta (surface)) {
+ _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+ goto DONE;
+ }
+
+ null_surface = _cairo_null_surface_create (CAIRO_CONTENT_COLOR_ALPHA);
+ analysis_surface = _cairo_analysis_surface_create (null_surface, -1, -1);
+ cairo_surface_destroy (null_surface);
+
+ status = analysis_surface->status;
+ if (unlikely (status))
+ goto DONE;
+
+ status = cairo_meta_surface_replay (surface, analysis_surface);
+ _cairo_analysis_surface_get_bounding_box (analysis_surface, &bbox);
+ cairo_surface_destroy (analysis_surface);
+
+DONE:
+ if (x0)
+ *x0 = _cairo_fixed_to_double (bbox.p1.x);
+ if (y0)
+ *y0 = _cairo_fixed_to_double (bbox.p1.y);
+ if (width)
+ *width = _cairo_fixed_to_double (bbox.p2.x - bbox.p1.x);
+ if (height)
+ *height = _cairo_fixed_to_double (bbox.p2.y - bbox.p1.y);
+}
diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c
index b84fbffe..033df35a 100644
--- a/src/cairo-paginated-surface.c
+++ b/src/cairo-paginated-surface.c
@@ -97,7 +97,7 @@ _cairo_paginated_surface_create (cairo_surface_t *target,
surface->backend = backend;
- surface->meta = _cairo_meta_surface_create (content, width, height);
+ surface->meta = cairo_meta_surface_create (content, width, height);
status = cairo_surface_status (surface->meta);
if (unlikely (status))
goto FAIL_CLEANUP_SURFACE;
@@ -148,8 +148,8 @@ _cairo_paginated_surface_set_size (cairo_surface_t *surface,
paginated_surface->height = height;
cairo_surface_destroy (paginated_surface->meta);
- paginated_surface->meta = _cairo_meta_surface_create (paginated_surface->content,
- width, height);
+ paginated_surface->meta = cairo_meta_surface_create (paginated_surface->content,
+ width, height);
status = cairo_surface_status (paginated_surface->meta);
if (unlikely (status))
return _cairo_surface_set_error (surface, status);
@@ -222,7 +222,7 @@ _cairo_paginated_surface_acquire_source_image (void *abstract_surface,
extents.width,
extents.height);
- status = _cairo_meta_surface_replay (surface->meta, image);
+ status = cairo_meta_surface_replay (surface->meta, image);
if (unlikely (status)) {
cairo_surface_destroy (image);
return status;
@@ -266,7 +266,7 @@ _paint_fallback_image (cairo_paginated_surface_t *surface,
* so we have to do the scaling manually. */
cairo_surface_set_device_offset (image, -x*x_scale, -y*y_scale);
- status = _cairo_meta_surface_replay (surface->meta, image);
+ status = cairo_meta_surface_replay (surface->meta, image);
if (unlikely (status))
goto CLEANUP_IMAGE;
@@ -481,9 +481,9 @@ _cairo_paginated_surface_show_page (void *abstract_surface)
cairo_surface_destroy (surface->meta);
- surface->meta = _cairo_meta_surface_create (surface->content,
- surface->width,
- surface->height);
+ surface->meta = cairo_meta_surface_create (surface->content,
+ surface->width,
+ surface->height);
status = cairo_surface_status (surface->meta);
if (unlikely (status))
return status;
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 88b17440..6be6245e 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -1475,7 +1475,7 @@ _cairo_pdf_surface_create_similar (void *abstract_surface,
int width,
int height)
{
- return _cairo_meta_surface_create (content, width, height);
+ return cairo_meta_surface_create (content, width, height);
}
static void
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index fde161d6..cfe730cb 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -1294,7 +1294,7 @@ _cairo_ps_surface_create_similar (void *abstract_surface,
int width,
int height)
{
- return _cairo_meta_surface_create (content, width, height);
+ return cairo_meta_surface_create (content, width, height);
}
static cairo_status_t
diff --git a/src/cairo-script-surface.c b/src/cairo-script-surface.c
index dad849f0..6d150698 100644
--- a/src/cairo-script-surface.c
+++ b/src/cairo-script-surface.c
@@ -840,7 +840,7 @@ _emit_meta_surface_pattern (cairo_script_surface_t *surface,
if (unlikely (status))
return status;
- status = _cairo_meta_surface_replay (source, analysis_surface);
+ status = cairo_meta_surface_replay (source, analysis_surface);
_cairo_analysis_surface_get_bounding_box (analysis_surface, &bbox);
cairo_surface_destroy (analysis_surface);
if (unlikely (status))
@@ -862,7 +862,7 @@ _emit_meta_surface_pattern (cairo_script_surface_t *surface,
_content_to_string (source->content));
target_push (similar);
- status = _cairo_meta_surface_replay (source, &similar->base);
+ status = cairo_meta_surface_replay (source, &similar->base);
if (unlikely (status)) {
cairo_surface_destroy (&similar->base);
return status;
@@ -1145,7 +1145,7 @@ _emit_surface_pattern (cairo_script_surface_t *surface,
source = surface_pattern->surface;
switch ((int) source->type) {
- case CAIRO_INTERNAL_SURFACE_TYPE_META:
+ case CAIRO_SURFACE_TYPE_META:
return _emit_meta_surface_pattern (surface, pattern);
case CAIRO_SURFACE_TYPE_SCRIPT:
return _emit_script_surface_pattern (surface, pattern);
@@ -2216,8 +2216,8 @@ _emit_scaled_glyph_vector (cairo_script_surface_t *surface,
old_cr = surface->cr;
_cairo_script_implicit_context_init (&surface->cr);
- status = _cairo_meta_surface_replay (scaled_glyph->meta_surface,
- &surface->base);
+ status = cairo_meta_surface_replay (scaled_glyph->meta_surface,
+ &surface->base);
surface->cr = old_cr;
_cairo_output_stream_puts (surface->ctx->stream, "} set set\n");
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index fd35c12f..55aee0e6 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -1517,7 +1517,7 @@ _cairo_surface_clone_similar (cairo_surface_t *surface,
cairo_surface_set_device_offset (similar, -src_x, -src_y);
- status = _cairo_meta_surface_replay (src, similar);
+ status = cairo_meta_surface_replay (src, similar);
if (unlikely (status)) {
cairo_surface_destroy (similar);
return status;
diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index d74e1f89..15e36845 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -856,7 +856,7 @@ _cairo_svg_surface_create_similar (void *abstract_src,
int width,
int height)
{
- return _cairo_meta_surface_create (content, width, height);
+ return cairo_meta_surface_create (content, width, height);
}
static cairo_status_t
@@ -1217,7 +1217,7 @@ _cairo_svg_surface_emit_meta_surface (cairo_svg_document_t *document,
document->owner->x_fallback_resolution,
document->owner->y_fallback_resolution);
- status = _cairo_meta_surface_replay (&meta->base, paginated_surface);
+ status = cairo_meta_surface_replay (&meta->base, paginated_surface);
if (unlikely (status)) {
cairo_surface_destroy (&meta->base);
cairo_surface_destroy (paginated_surface);
@@ -1334,8 +1334,8 @@ _cairo_svg_surface_emit_composite_meta_pattern (cairo_output_stream_t *output,
"patternUnits=\"userSpaceOnUse\" "
"width=\"%d\" height=\"%d\"",
pattern_id,
- meta_surface->width_pixels,
- meta_surface->height_pixels);
+ (int) ceil (meta_surface->width_pixels),
+ (int) ceil (meta_surface->height_pixels));
_cairo_svg_surface_emit_transform (output, " patternTransform", &p2u, parent_matrix);
_cairo_output_stream_printf (output, ">\n");
}
diff --git a/src/cairo-type3-glyph-surface.c b/src/cairo-type3-glyph-surface.c
index 104da53d..6e725960 100644
--- a/src/cairo-type3-glyph-surface.c
+++ b/src/cairo-type3-glyph-surface.c
@@ -425,8 +425,8 @@ _cairo_type3_glyph_surface_analyze_glyph (void *abstract_surface,
goto cleanup;
}
- status = _cairo_meta_surface_replay (scaled_glyph->meta_surface,
- &surface->base);
+ status = cairo_meta_surface_replay (scaled_glyph->meta_surface,
+ &surface->base);
if (unlikely (status))
goto cleanup;
@@ -520,8 +520,8 @@ _cairo_type3_glyph_surface_emit_glyph (void *abstract_surface,
_cairo_type3_glyph_surface_set_stream (surface, mem_stream);
_cairo_output_stream_printf (surface->stream, "q\n");
- status = _cairo_meta_surface_replay (scaled_glyph->meta_surface,
- &surface->base);
+ status = cairo_meta_surface_replay (scaled_glyph->meta_surface,
+ &surface->base);
status2 = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status == CAIRO_STATUS_SUCCESS)
diff --git a/src/cairo-types-private.h b/src/cairo-types-private.h
index 1edd24f2..2ed3264b 100644
--- a/src/cairo-types-private.h
+++ b/src/cairo-types-private.h
@@ -162,8 +162,7 @@ typedef enum _cairo_int_status {
} cairo_int_status_t;
typedef enum _cairo_internal_surface_type {
- CAIRO_INTERNAL_SURFACE_TYPE_META = 0x1000,
- CAIRO_INTERNAL_SURFACE_TYPE_PAGINATED,
+ CAIRO_INTERNAL_SURFACE_TYPE_PAGINATED = 0x1000,
CAIRO_INTERNAL_SURFACE_TYPE_ANALYSIS,
CAIRO_INTERNAL_SURFACE_TYPE_TEST_META,
CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
diff --git a/src/cairo-user-font.c b/src/cairo-user-font.c
index 5ab9751d..1adfd7d6 100644
--- a/src/cairo-user-font.c
+++ b/src/cairo-user-font.c
@@ -85,7 +85,7 @@ _cairo_user_scaled_font_create_meta_context (cairo_user_scaled_font_t *scaled_fo
CAIRO_CONTENT_COLOR_ALPHA :
CAIRO_CONTENT_ALPHA;
- meta_surface = _cairo_meta_surface_create (content, -1, -1);
+ meta_surface = cairo_meta_surface_create (content, -1, -1);
cr = cairo_create (meta_surface);
cairo_surface_destroy (meta_surface);
@@ -158,8 +158,7 @@ _cairo_user_scaled_glyph_init (void *abstract_font,
_cairo_analysis_surface_set_ctm (analysis_surface,
&scaled_font->extent_scale);
- status = _cairo_meta_surface_replay (meta_surface,
- analysis_surface);
+ status = cairo_meta_surface_replay (meta_surface, analysis_surface);
_cairo_analysis_surface_get_bounding_box (analysis_surface, &bbox);
cairo_surface_destroy (analysis_surface);
@@ -214,7 +213,7 @@ _cairo_user_scaled_glyph_init (void *abstract_font,
cairo_surface_set_device_offset (surface,
- _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x),
- _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y));
- status = _cairo_meta_surface_replay (meta_surface, surface);
+ status = cairo_meta_surface_replay (meta_surface, surface);
if (unlikely (status)) {
cairo_surface_destroy(surface);
diff --git a/src/cairo-win32-printing-surface.c b/src/cairo-win32-printing-surface.c
index e7ff3bb6..9025bfa7 100644
--- a/src/cairo-win32-printing-surface.c
+++ b/src/cairo-win32-printing-surface.c
@@ -1607,7 +1607,7 @@ _cairo_win32_printing_surface_create_similar (void *abstract_surface,
int width,
int height)
{
- return _cairo_meta_surface_create (content, width, height);
+ return cairo_meta_surface_create (content, width, height);
}
static cairo_int_status_t
diff --git a/src/cairo.h b/src/cairo.h
index 37ccdc3c..8f7e5338 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -1890,6 +1890,7 @@ cairo_surface_status (cairo_surface_t *surface);
* @CAIRO_SURFACE_TYPE_QUARTZ_IMAGE: The surface is of type quartz_image
* @CAIRO_SURFACE_TYPE_SCRIPT: The surface is of type script, since 1.10
* @CAIRO_SURFACE_TYPE_QT: The surface is of type Qt, since 1.10
+ * @CAIRO_SURFACE_TYPE_META: The surface is a meta-type, 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
@@ -1930,7 +1931,8 @@ typedef enum _cairo_surface_type {
CAIRO_SURFACE_TYPE_WIN32_PRINTING,
CAIRO_SURFACE_TYPE_QUARTZ_IMAGE,
CAIRO_SURFACE_TYPE_SCRIPT,
- CAIRO_SURFACE_TYPE_QT
+ CAIRO_SURFACE_TYPE_QT,
+ CAIRO_SURFACE_TYPE_META
} cairo_surface_type_t;
cairo_public cairo_surface_type_t
@@ -2108,6 +2110,24 @@ cairo_image_surface_create_from_png_stream (cairo_read_func_t read_func,
#endif
+/* Meta-surface functions */
+
+cairo_public cairo_surface_t *
+cairo_meta_surface_create (cairo_content_t content,
+ double width_pixels,
+ double height_pixels);
+
+cairo_public void
+cairo_meta_surface_ink_extents (cairo_surface_t *surface,
+ double *x0,
+ double *y0,
+ double *width,
+ double *height);
+
+cairo_public cairo_status_t
+cairo_meta_surface_replay (cairo_surface_t *surface,
+ cairo_surface_t *target);
+
/* Pattern creation functions */
cairo_public cairo_pattern_t *
diff --git a/src/test-meta-surface.c b/src/test-meta-surface.c
index 7af5df7f..80e56f31 100644
--- a/src/test-meta-surface.c
+++ b/src/test-meta-surface.c
@@ -136,7 +136,7 @@ _test_meta_surface_show_page (void *abstract_surface)
return status;
}
- status = _cairo_meta_surface_replay (surface->meta, surface->image);
+ status = cairo_meta_surface_replay (surface->meta, surface->image);
if (status)
return status;
@@ -338,7 +338,7 @@ _cairo_test_meta_surface_create (cairo_content_t content,
_cairo_surface_init (&surface->base, &test_meta_surface_backend,
content);
- surface->meta = _cairo_meta_surface_create (content, width, height);
+ surface->meta = cairo_meta_surface_create (content, width, height);
status = cairo_surface_status (surface->meta);
if (status)
goto FAIL;
@@ -356,15 +356,3 @@ _cairo_test_meta_surface_create (cairo_content_t content,
return _cairo_surface_create_in_error (status);
}
slim_hidden_def (_cairo_test_meta_surface_create);
-
-cairo_status_t
-_cairo_test_meta_surface_replay (cairo_surface_t *abstract_surface,
- cairo_surface_t *target)
-{
- test_meta_surface_t *surface = (test_meta_surface_t *) abstract_surface;
-
- if (abstract_surface->backend != &test_meta_surface_backend)
- return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
-
- return _cairo_meta_surface_replay (surface->meta, target);
-}
diff --git a/src/test-meta-surface.h b/src/test-meta-surface.h
index a251fd4e..4cd27d86 100644
--- a/src/test-meta-surface.h
+++ b/src/test-meta-surface.h
@@ -42,12 +42,8 @@ CAIRO_BEGIN_DECLS
cairo_surface_t *
_cairo_test_meta_surface_create (cairo_content_t content,
- int width,
- int height);
-
-cairo_status_t
-_cairo_test_meta_surface_replay (cairo_surface_t *abstract_surface,
- cairo_surface_t *target);
+ int width,
+ int height);
CAIRO_END_DECLS
diff --git a/test/cairo-test-trace.c b/test/cairo-test-trace.c
index 18e1934b..bee0551d 100644
--- a/test/cairo-test-trace.c
+++ b/test/cairo-test-trace.c
@@ -64,9 +64,6 @@
#include <cairo-script.h>
#endif
-/* XXX give me a real meta surface! */
-#include <test-meta-surface.h>
-
/* For basename */
#ifdef HAVE_LIBGEN_H
#include <libgen.h>
@@ -603,9 +600,6 @@ cleanup_recorder (void *arg)
cairo_surface_finish (thread->surface);
cairo_surface_destroy (thread->surface);
- if (thread->target->cleanup)
- thread->target->cleanup (thread->closure);
-
close (thread->sk);
free (thread);
}
@@ -628,9 +622,7 @@ record (void *arg)
* 2. Runs in the same process, but separate thread.
*/
static pid_t
-spawn_recorder (const char *socket_path,
- const cairo_boilerplate_target_t *target,
- const char *trace)
+spawn_recorder (const char *socket_path, const char *trace)
{
test_runner_thread_t *thread;
pthread_t id;
@@ -653,18 +645,13 @@ spawn_recorder (const char *socket_path,
}
thread->base = NULL;
- thread->target = target;
+ thread->target = NULL;
thread->contexts = NULL;
thread->context_id = 0;
thread->trace = trace;
- thread->surface = target->create_surface (NULL,
- target->content,
- 1, 1,
- 1, 1,
- CAIRO_BOILERPLATE_MODE_TEST,
- 0,
- &thread->closure);
+ thread->surface = cairo_meta_surface_create (CAIRO_CONTENT_COLOR_ALPHA,
+ 0, 0);
if (thread->surface == NULL) {
cleanup_recorder (thread);
return -1;
@@ -853,7 +840,7 @@ static void
write_images (const char *trace, struct slave *slave, int num_slaves)
{
while (num_slaves--) {
- if (slave->image != NULL) {
+ if (slave->image != NULL && ! slave->is_meta) {
char *filename;
xasprintf (&filename, "%s-%s-fail.png",
@@ -887,7 +874,7 @@ write_trace (const char *trace, struct slave *slave)
slave->height);
free (filename);
- status = _cairo_test_meta_surface_replay (slave->image, script);
+ status = cairo_meta_surface_replay (slave->image, script);
cairo_surface_destroy (script);
#endif
}
@@ -1179,6 +1166,7 @@ target_is_measurable (const cairo_boilerplate_target_t *target)
case CAIRO_SURFACE_TYPE_SCRIPT:
case CAIRO_SURFACE_TYPE_SVG:
case CAIRO_SURFACE_TYPE_WIN32_PRINTING:
+ case CAIRO_SURFACE_TYPE_META:
default:
return FALSE;
}
@@ -1243,8 +1231,9 @@ _test_trace (test_runner_t *test,
struct error_info *error)
{
const char *shm_path = SHM_PATH_XXX;
- const cairo_boilerplate_target_t *target, *image, *meta;
+ const cairo_boilerplate_target_t *target, *image;
struct slave *slaves, *s;
+ pid_t slave;
char socket_dir[] = "/tmp/cairo-test-trace.XXXXXX";
char *socket_path;
int sk, fd;
@@ -1280,29 +1269,22 @@ _test_trace (test_runner_t *test,
#if HAVE_PTHREAD_H
/* set-up a meta-surface to reconstruct errors */
- meta = cairo_boilerplate_get_target_by_name ("test-meta",
- CAIRO_CONTENT_COLOR_ALPHA);
- if (meta != NULL) {
- pid_t slave;
-
- slave = spawn_recorder (socket_path, meta, trace);
- if (slave < 0) {
- fprintf (stderr, "Unable to create meta surface\n");
- goto cleanup_sk;
- }
-
- s->pid = slave;
- s->is_meta = TRUE;
- s->target = meta;
- s->fd = -1;
- s->reference = NULL;
- s++;
+ slave = spawn_recorder (socket_path, trace);
+ if (slave < 0) {
+ fprintf (stderr, "Unable to create meta surface\n");
+ goto cleanup_sk;
}
+
+ s->pid = slave;
+ s->is_meta = TRUE;
+ s->target = NULL;
+ s->fd = -1;
+ s->reference = NULL;
+ s++;
#endif
/* spawn slave processes to run the trace */
for (i = 0; i < test->num_targets; i++) {
- pid_t slave;
const cairo_boilerplate_target_t *reference;
struct slave *master;
diff --git a/test/get-clip.c b/test/get-clip.c
index 1a07f012..c7414b4a 100644
--- a/test/get-clip.c
+++ b/test/get-clip.c
@@ -132,10 +132,15 @@ draw (cairo_t *cr, int width, int height)
uses_clip_rects = TRUE;
break;
case CAIRO_SURFACE_TYPE_QUARTZ:
+ case CAIRO_SURFACE_TYPE_QUARTZ_IMAGE:
case CAIRO_SURFACE_TYPE_PDF:
case CAIRO_SURFACE_TYPE_PS:
case CAIRO_SURFACE_TYPE_SVG:
case CAIRO_SURFACE_TYPE_OS2:
+ case CAIRO_SURFACE_TYPE_WIN32_PRINTING:
+ case CAIRO_SURFACE_TYPE_SCRIPT:
+ case CAIRO_SURFACE_TYPE_QT:
+ case CAIRO_SURFACE_TYPE_META:
default:
uses_clip_rects = FALSE;
break;