diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2009-07-03 18:26:50 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2009-07-03 18:26:50 +0100 |
commit | 6003ab77e1ebefadb97338de0e7da4a76d973b1a (patch) | |
tree | e375335dac3abfdd3e75cb18a317824556de84f6 | |
parent | 2a9903dbbfeb3fe843f0d618d15674b37a29f3a9 (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-- | NEWS | 27 | ||||
-rw-r--r-- | boilerplate/Makefile.win32.features | 8 | ||||
-rw-r--r-- | boilerplate/cairo-boilerplate.c | 12 | ||||
-rw-r--r-- | build/Makefile.win32.features-h | 1 | ||||
-rw-r--r-- | build/configure.ac.features | 1 | ||||
-rw-r--r-- | configure.ac | 4 | ||||
-rw-r--r-- | perf/cairo-perf.c | 6 | ||||
-rw-r--r-- | src/Makefile.win32.features | 8 | ||||
-rw-r--r-- | src/cairo-meta-surface-private.h | 14 | ||||
-rw-r--r-- | src/cairo-meta-surface.c | 202 | ||||
-rw-r--r-- | src/cairo-paginated-surface.c | 16 | ||||
-rw-r--r-- | src/cairo-pdf-surface.c | 2 | ||||
-rw-r--r-- | src/cairo-ps-surface.c | 2 | ||||
-rw-r--r-- | src/cairo-script-surface.c | 10 | ||||
-rw-r--r-- | src/cairo-surface.c | 2 | ||||
-rw-r--r-- | src/cairo-svg-surface.c | 8 | ||||
-rw-r--r-- | src/cairo-type3-glyph-surface.c | 8 | ||||
-rw-r--r-- | src/cairo-types-private.h | 3 | ||||
-rw-r--r-- | src/cairo-user-font.c | 7 | ||||
-rw-r--r-- | src/cairo-win32-printing-surface.c | 2 | ||||
-rw-r--r-- | src/cairo.h | 22 | ||||
-rw-r--r-- | src/test-meta-surface.c | 16 | ||||
-rw-r--r-- | src/test-meta-surface.h | 8 | ||||
-rw-r--r-- | test/cairo-test-trace.c | 58 | ||||
-rw-r--r-- | test/get-clip.c | 5 |
25 files changed, 296 insertions, 156 deletions
@@ -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; |