diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2011-08-02 22:31:49 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2011-08-15 00:16:09 +0100 |
commit | 2220693a40a4f8d13603b3fb29273ec59fd433bc (patch) | |
tree | aec5bf4af07b2a2c2c0d96069e028bdcdec953e9 | |
parent | eed1f2efdf36173e23b7177bb34ab9a5f015fb2a (diff) |
Introduce cairo_mime_surface_t
The mime surface is a user-callback surface designed for interfacing
cairo with an opaque data source. For instance, in a web browser, the
incoming page may be laid out and rendered to a recording surface before
all the image data has finished being downloaded. In this circumstance
we need to pass a place holder to cairo and to supply the image data
later upon demand.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r-- | boilerplate/Makefile.win32.features | 10 | ||||
-rw-r--r-- | build/Makefile.win32.features-h | 1 | ||||
-rw-r--r-- | build/configure.ac.features | 1 | ||||
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | src/Makefile.sources | 1 | ||||
-rw-r--r-- | src/Makefile.win32.features | 10 | ||||
-rw-r--r-- | src/cairo-mime-surface.c | 411 | ||||
-rw-r--r-- | src/cairo.c | 11 | ||||
-rw-r--r-- | src/cairo.h | 89 | ||||
-rw-r--r-- | test/Makefile.refs | 1 | ||||
-rw-r--r-- | test/Makefile.sources | 1 | ||||
-rw-r--r-- | test/mime-surface.c | 174 | ||||
-rw-r--r-- | test/mime-surface.ref.png | bin | 0 -> 1209 bytes | |||
-rw-r--r-- | util/cairo-trace/trace.c | 49 |
14 files changed, 739 insertions, 21 deletions
diff --git a/boilerplate/Makefile.win32.features b/boilerplate/Makefile.win32.features index 793d1f40..8b6a6733 100644 --- a/boilerplate/Makefile.win32.features +++ b/boilerplate/Makefile.win32.features @@ -398,6 +398,16 @@ enabled_cairo_boilerplate_private += $(cairo_boilerplate_image_private) enabled_cairo_boilerplate_cxx_sources += $(cairo_boilerplate_image_cxx_sources) enabled_cairo_boilerplate_sources += $(cairo_boilerplate_image_sources) +supported_cairo_boilerplate_headers += $(cairo_boilerplate_mime_headers) +all_cairo_boilerplate_headers += $(cairo_boilerplate_mime_headers) +all_cairo_boilerplate_private += $(cairo_boilerplate_mime_private) +all_cairo_boilerplate_cxx_sources += $(cairo_boilerplate_mime_cxx_sources) +all_cairo_boilerplate_sources += $(cairo_boilerplate_mime_sources) +enabled_cairo_boilerplate_headers += $(cairo_boilerplate_mime_headers) +enabled_cairo_boilerplate_private += $(cairo_boilerplate_mime_private) +enabled_cairo_boilerplate_cxx_sources += $(cairo_boilerplate_mime_cxx_sources) +enabled_cairo_boilerplate_sources += $(cairo_boilerplate_mime_sources) + supported_cairo_boilerplate_headers += $(cairo_boilerplate_recording_headers) all_cairo_boilerplate_headers += $(cairo_boilerplate_recording_headers) all_cairo_boilerplate_private += $(cairo_boilerplate_recording_private) diff --git a/build/Makefile.win32.features-h b/build/Makefile.win32.features-h index e49ad6e6..84d65f4f 100644 --- a/build/Makefile.win32.features-h +++ b/build/Makefile.win32.features-h @@ -99,6 +99,7 @@ ifeq ($(CAIRO_HAS_TEST_SURFACES),1) @echo "#define CAIRO_HAS_TEST_SURFACES 1" >> $(top_srcdir)/src/cairo-features.h endif @echo "#define CAIRO_HAS_IMAGE_SURFACE 1" >> $(top_srcdir)/src/cairo-features.h + @echo "#define CAIRO_HAS_MIME_SURFACE 1" >> $(top_srcdir)/src/cairo-features.h @echo "#define CAIRO_HAS_RECORDING_SURFACE 1" >> $(top_srcdir)/src/cairo-features.h @echo "#define CAIRO_HAS_OBSERVER_SURFACE 1" >> $(top_srcdir)/src/cairo-features.h ifeq ($(CAIRO_HAS_TEE_SURFACE),1) diff --git a/build/configure.ac.features b/build/configure.ac.features index 4f774e30..faa762ca 100644 --- a/build/configure.ac.features +++ b/build/configure.ac.features @@ -366,6 +366,7 @@ AC_DEFUN([CAIRO_REPORT], echo " Image: yes (always builtin)" echo " Recording: yes (always builtin)" echo " Observer: yes (always builtin)" + echo " Mime: yes (always builtin)" echo " Tee: $use_tee" echo " XML: $use_xml" echo " Skia: $use_skia" diff --git a/configure.ac b/configure.ac index fc14341d..71f8bf3a 100644 --- a/configure.ac +++ b/configure.ac @@ -620,6 +620,7 @@ CAIRO_ENABLE_SURFACE_BACKEND(image, image, always, [ dnl =========================================================================== +CAIRO_ENABLE_SURFACE_BACKEND(mime, mime, always) CAIRO_ENABLE_SURFACE_BACKEND(recording, recording, always) CAIRO_ENABLE_SURFACE_BACKEND(observer, observer, always) CAIRO_ENABLE_SURFACE_BACKEND(tee, tee, no) diff --git a/src/Makefile.sources b/src/Makefile.sources index a47a0108..2b563f23 100644 --- a/src/Makefile.sources +++ b/src/Makefile.sources @@ -151,6 +151,7 @@ cairo_sources = \ cairo-lzw.c \ cairo-matrix.c \ cairo-mesh-pattern-rasterizer.c \ + cairo-mime-surface.c \ cairo-misc.c \ cairo-mutex.c \ cairo-observer.c \ diff --git a/src/Makefile.win32.features b/src/Makefile.win32.features index db769efd..4b90d649 100644 --- a/src/Makefile.win32.features +++ b/src/Makefile.win32.features @@ -520,6 +520,16 @@ enabled_cairo_private += $(cairo_image_private) enabled_cairo_cxx_sources += $(cairo_image_cxx_sources) enabled_cairo_sources += $(cairo_image_sources) +supported_cairo_headers += $(cairo_mime_headers) +all_cairo_headers += $(cairo_mime_headers) +all_cairo_private += $(cairo_mime_private) +all_cairo_cxx_sources += $(cairo_mime_cxx_sources) +all_cairo_sources += $(cairo_mime_sources) +enabled_cairo_headers += $(cairo_mime_headers) +enabled_cairo_private += $(cairo_mime_private) +enabled_cairo_cxx_sources += $(cairo_mime_cxx_sources) +enabled_cairo_sources += $(cairo_mime_sources) + supported_cairo_headers += $(cairo_recording_headers) all_cairo_headers += $(cairo_recording_headers) all_cairo_private += $(cairo_recording_private) diff --git a/src/cairo-mime-surface.c b/src/cairo-mime-surface.c new file mode 100644 index 00000000..f23c451a --- /dev/null +++ b/src/cairo-mime-surface.c @@ -0,0 +1,411 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2011 Intel Corporation + * + * 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, 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): + * Chris Wilson <chris@chris-wilson.co.uk> + */ + +/** + * SECTION:cairo-mime-surface + * @Title: Callback Surfaces + * @Short_Description: Allows the user to provide a callback to supply image + * data upon demand + * @See_Also: #cairo_surface_t + * + * The mime surfaces provide the ability to render from arbitrary sources + * not necessarily resident nor immediately usable by Cairo. The user is + * given the ability to insert a placeholder surface which can be used + * with a pattern and then later supply the actual pixel data upon demand. + * This deferred source is given both the sample region for the operation + * along with the destination surface such that they may be taken into + * account when creating the actual surface to use as the source of pixel + * data. + * + * The reason why it is called the mime surface is two-fold. First it came + * about as an extension of the mime-data property to handle deferred + * image decoding when rendering to pixel buffers (as opposed to the pass- + * through support in PDF and friends.) And then to further rationalise + * the name, it is a surface that mimics a real source without ever + * holding onto to any pixels of its own - a mime surface. + * + * The mime-surface callback interface consists of 4 functions. The principal + * pair are the acquire/release callbacks which are called when pixel data + * is required for an operation (along with the target surface and the sample + * extents). The callee must supply a surface that covers the sample area and + * set the actual extents of the returned surface in the output rectangle + * parameter. The surface does not necessarily have to be an image surface, + * but it is expected that an image surface is likely to be the most + * convenient for uploading pixel data. (Use + * cairo_surface_create_similar_image() to create an image surface that is + * optimised for uploading to the target.) The release callback is + * subsequently called when the returned surface is no longer needed (before + * the operation completes, within the lifetime of the source). + * + * The other pair of functions are to aide with lifetime management of the + * surface with respect to patterns and other users. The destroy callback + * allows for the caller to cleanup the associated data when the last + * reference to surface is destroyed. The snapshot callback is triggered + * when there is an immutable surface pattern referencing the mime-surface + * and the mime-surface will be be invalidated. (Since the mime-surface is + * read-only and a reference will be held by the pattern, this can only be + * triggered through an explicit cairo_surface_finish().) In this + * circumstance, we need to clone the source in order to preserve the pixel + * data for later use (i.e. we have recorded the pattern). The snapshot + * callback provides an interface for the caller to clone the mime-surface + * in an efficient manner. The returned surface may be of any type so long + * as it holds all pixel data and remains accessible. + */ + +/** + * CAIRO_HAS_MIME_SURFACE: + * + * Defined if the mime surface backend is available. + * The mime surface backend is always built in. + * + * @Since: 1.12 + */ + +#include "cairoint.h" +#include "cairo-error-private.h" +#include "cairo-image-surface-private.h" + +typedef struct _cairo_mime_surface { + cairo_surface_t base; + + cairo_rectangle_int_t extents; + + cairo_mime_surface_acquire_t acquire; + cairo_mime_surface_release_t release; + cairo_mime_surface_snapshot_t snapshot; + cairo_mime_surface_destroy_t destroy; + + /* an explicit pre-allocated member in preference to the general user-data */ + void *user_data; +} cairo_mime_surface_t; + +static cairo_status_t +_cairo_mime_surface_finish (void *abstract_surface) +{ + cairo_mime_surface_t *surface = abstract_surface; + + if (surface->destroy) + surface->destroy (&surface->base, surface->user_data); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_bool_t +_cairo_mime_surface_get_extents (void *abstract_surface, + cairo_rectangle_int_t *rectangle) +{ + cairo_mime_surface_t *surface = abstract_surface; + + *rectangle = surface->extents; + return TRUE; +} + +static cairo_status_t +_cairo_mime_surface_acquire_source_image (void *abstract_surface, + //cairo_surface_t *target, + cairo_image_surface_t **image_out, + void **image_extra) +{ + cairo_mime_surface_t *mime = abstract_surface; + cairo_surface_t *acquired; + cairo_surface_t *dummy_target; + cairo_rectangle_int_t extents; + + if (mime->acquire == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* Force the callee to populate the extents rectangle */ + memset (&extents, 0, sizeof (extents)); + + /* Masquerade for a flexible user-interface */ + dummy_target = _cairo_image_surface_create_with_content (mime->base.content, 0, 0); + acquired = mime->acquire (&mime->base, mime->user_data, + dummy_target, &mime->extents, &extents); + cairo_surface_destroy (dummy_target); + + if (acquired == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* The callee must have supplied us with all the image data */ + assert (extents.width == mime->extents.width && extents.height == mime->extents.height); + + if (! _cairo_surface_is_image (acquired)) { + cairo_status_t status; + void *extra = NULL; + + status = _cairo_surface_acquire_source_image (acquired, image_out, &extra); + if (unlikely (status)) { + cairo_surface_destroy (acquired); + return status; + } + + assert (extra == NULL); + *image_extra = acquired; + } else { + *image_out = (cairo_image_surface_t *) acquired; + *image_extra = NULL; + } + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_mime_surface_release_source_image (void *abstract_surface, + cairo_image_surface_t *image, + void *image_extra) +{ + cairo_mime_surface_t *mime = abstract_surface; + + if (image_extra) { + cairo_surface_destroy (&image->base); + image = image_extra; + } + + if (mime->release) + mime->release (&mime->base, mime->user_data, &image->base); +} + +static cairo_surface_t * +_cairo_mime_surface_snapshot (void *abstract_surface) +{ + cairo_mime_surface_t *mime = abstract_surface; + + if (mime->snapshot == NULL) + return NULL; + + return mime->snapshot (&mime->base, mime->user_data); +} + +static const cairo_surface_backend_t cairo_mime_surface_backend = { + CAIRO_SURFACE_TYPE_MIME, + _cairo_mime_surface_finish, + + NULL, /* Read-only */ + + NULL, /* create similar */ + NULL, /* create similar image */ + NULL, /* map to image */ + NULL, /* unmap image */ + + _cairo_mime_surface_acquire_source_image, + _cairo_mime_surface_release_source_image, + NULL, /* acquire_dest_image */ + NULL, /* release_dest_image */ + NULL, /* clone_similar */ + NULL, /* composite */ + NULL, /* fill_rectangles */ + NULL, /* composite_trapezoids */ + NULL, /* create_span_renderer */ + NULL, /* check_span_renderer */ + NULL, /* copy_page */ + NULL, /* show_page */ + _cairo_mime_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 */ + + + NULL, /* paint */ + NULL, /* mask */ + NULL, /* stroke */ + NULL, /* fill */ + NULL, /* glyphs */ + + _cairo_mime_surface_snapshot, +}; + +cairo_surface_t * +cairo_mime_surface_create (void *data, cairo_content_t content, int width, int height) +{ + cairo_mime_surface_t *surface; + + if (width < 0 || height < 0) + return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_SIZE); + + if (! CAIRO_CONTENT_VALID (content)) + return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_CONTENT); + + surface = calloc (1, sizeof (*surface)); + if (unlikely (surface == NULL)) + return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY); + + _cairo_surface_init (&surface->base, + &cairo_mime_surface_backend, + NULL, /* device */ + content); + + surface->extents.x = 0; + surface->extents.y = 0; + surface->extents.width = width; + surface->extents.height = height; + + surface->user_data = data; + + return &surface->base; +} + +void +cairo_mime_surface_set_callback_data (cairo_surface_t *surface, + void *data) +{ + cairo_mime_surface_t *mime; + + if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count)) + return; + + if (surface->backend != &cairo_mime_surface_backend) + return; + + mime = (cairo_mime_surface_t *)surface; + mime->user_data = data; +} + +void * +cairo_mime_surface_get_callback_data (cairo_surface_t *surface) +{ + cairo_mime_surface_t *mime; + + if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count)) + return NULL; + + if (surface->backend != &cairo_mime_surface_backend) + return NULL; + + mime = (cairo_mime_surface_t *)surface; + return mime->user_data; +} + +void +cairo_mime_surface_set_acquire (cairo_surface_t *surface, + cairo_mime_surface_acquire_t acquire, + cairo_mime_surface_release_t release) +{ + cairo_mime_surface_t *mime; + + if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count)) + return; + + if (surface->backend != &cairo_mime_surface_backend) + return; + + mime = (cairo_mime_surface_t *)surface; + mime->acquire = acquire; + mime->release = release; +} + +void +cairo_mime_surface_get_acquire (cairo_surface_t *surface, + cairo_mime_surface_acquire_t *acquire, + cairo_mime_surface_release_t *release) +{ + cairo_mime_surface_t *mime; + + if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count)) + return; + + if (surface->backend != &cairo_mime_surface_backend) + return; + + mime = (cairo_mime_surface_t *)surface; + if (acquire) + *acquire = mime->acquire; + if (release) + *release = mime->release; +} + +void +cairo_mime_surface_set_snapshot (cairo_surface_t *surface, + cairo_mime_surface_snapshot_t snapshot) +{ + cairo_mime_surface_t *mime; + + if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count)) + return; + + if (surface->backend != &cairo_mime_surface_backend) + return; + + mime = (cairo_mime_surface_t *)surface; + mime->snapshot = snapshot; +} + +cairo_mime_surface_snapshot_t +cairo_mime_surface_get_snapshot (cairo_surface_t *surface) +{ + cairo_mime_surface_t *mime; + + if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count)) + return NULL; + + if (surface->backend != &cairo_mime_surface_backend) + return NULL; + + mime = (cairo_mime_surface_t *)surface; + return mime->snapshot; +} + +void +cairo_mime_surface_set_destroy (cairo_surface_t *surface, + cairo_mime_surface_destroy_t destroy) +{ + cairo_mime_surface_t *mime; + + if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count)) + return; + + if (surface->backend != &cairo_mime_surface_backend) + return; + + mime = (cairo_mime_surface_t *)surface; + mime->destroy = destroy; +} + +cairo_mime_surface_destroy_t +cairo_mime_surface_get_destroy (cairo_surface_t *surface) +{ + cairo_mime_surface_t *mime; + + if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count)) + return NULL; + + if (surface->backend != &cairo_mime_surface_backend) + return NULL; + + mime = (cairo_mime_surface_t *)surface; + return mime->destroy; +} diff --git a/src/cairo.c b/src/cairo.c index a9f8c6e4..6f6d00e6 100644 --- a/src/cairo.c +++ b/src/cairo.c @@ -212,9 +212,11 @@ _cairo_create_in_error (cairo_status_t status) * with cairo_destroy() when you are done using the #cairo_t. * This function never returns %NULL. If memory cannot be * allocated, a special #cairo_t object will be returned on - * which cairo_status() returns %CAIRO_STATUS_NO_MEMORY. - * You can use this object normally, but no drawing will - * be done. + * which cairo_status() returns %CAIRO_STATUS_NO_MEMORY. If + * you attempt to target a surface which does not support + * writing (such as #cairo_mime_surface_t) then a + * %CAIRO_STATUS_WRITE_ERROR will be raised. You can use this + * object normally, but no drawing will be done. **/ cairo_t * cairo_create (cairo_surface_t *target) @@ -224,6 +226,9 @@ cairo_create (cairo_surface_t *target) if (unlikely (target->status)) return _cairo_create_in_error (target->status); + if (target->backend->create_context == NULL) + return _cairo_create_in_error (_cairo_error (CAIRO_STATUS_WRITE_ERROR)); + return target->backend->create_context (target); } diff --git a/src/cairo.h b/src/cairo.h index bf2e232b..4d0afaf4 100644 --- a/src/cairo.h +++ b/src/cairo.h @@ -433,6 +433,24 @@ typedef cairo_status_t (*cairo_read_func_t) (void *closure, unsigned char *data, unsigned int length); +/** + * cairo_rectangle_int_t: + * @x: X coordinate of the left side of the rectangle + * @y: Y coordinate of the the top side of the rectangle + * @width: width of the rectangle + * @height: height of the rectangle + * + * A data structure for holding a rectangle with integer coordinates. + * + * Since: 1.10 + **/ + +typedef struct _cairo_rectangle_int { + int x, y; + int width, height; +} cairo_rectangle_int_t; + + /* Functions for manipulating state objects */ cairo_public cairo_t * cairo_create (cairo_surface_t *target); @@ -2153,6 +2171,7 @@ cairo_surface_status (cairo_surface_t *surface); * @CAIRO_SURFACE_TYPE_SKIA: The surface is of type Skia, since 1.10 * @CAIRO_SURFACE_TYPE_SUBSURFACE: The surface is a subsurface created with * cairo_surface_create_for_rectangle(), since 1.10 + * @CAIRO_SURFACE_TYPE_MIME: The surface is a callback (mime) surface, since 1.12 * * #cairo_surface_type_t is used to describe the type of a given * surface. The surface types are also known as "backends" or "surface @@ -2202,7 +2221,8 @@ typedef enum _cairo_surface_type { CAIRO_SURFACE_TYPE_TEE, CAIRO_SURFACE_TYPE_XML, CAIRO_SURFACE_TYPE_SKIA, - CAIRO_SURFACE_TYPE_SUBSURFACE + CAIRO_SURFACE_TYPE_SUBSURFACE, + CAIRO_SURFACE_TYPE_MIME } cairo_surface_type_t; cairo_public cairo_surface_type_t @@ -2357,6 +2377,56 @@ cairo_recording_surface_ink_extents (cairo_surface_t *surface, double *width, double *height); +/* Mime-surface (callback) functions */ + +typedef cairo_surface_t *(*cairo_mime_surface_acquire_t) (cairo_surface_t *mime_surface, + void *callback_data, + cairo_surface_t *target, + const cairo_rectangle_int_t *sample_extents, + cairo_rectangle_int_t *surface_extents); + +typedef void (*cairo_mime_surface_release_t) (cairo_surface_t *mime_surface, + void *callback_data, + cairo_surface_t *image_surface); + +typedef cairo_surface_t *(*cairo_mime_surface_snapshot_t) (cairo_surface_t *mime_surface, + void *callback_data); +typedef void (*cairo_mime_surface_destroy_t) (cairo_surface_t *mime_surface, + void *callback_data); + +cairo_public cairo_surface_t * +cairo_mime_surface_create (void *data, cairo_content_t content, int width, int height); + +cairo_public void +cairo_mime_surface_set_callback_data (cairo_surface_t *surface, + void *data); + +cairo_public void * +cairo_mime_surface_get_callback_data (cairo_surface_t *surface); + +cairo_public void +cairo_mime_surface_set_acquire (cairo_surface_t *surface, + cairo_mime_surface_acquire_t acquire, + cairo_mime_surface_release_t release); + +cairo_public void +cairo_mime_surface_get_acquire (cairo_surface_t *surface, + cairo_mime_surface_acquire_t *acquire, + cairo_mime_surface_release_t *release); +cairo_public void +cairo_mime_surface_set_snapshot (cairo_surface_t *surface, + cairo_mime_surface_snapshot_t snapshot); + +cairo_public cairo_mime_surface_snapshot_t +cairo_mime_surface_get_snapshot (cairo_surface_t *surface); + +cairo_public void +cairo_mime_surface_set_destroy (cairo_surface_t *surface, + cairo_mime_surface_destroy_t destroy); + +cairo_public cairo_mime_surface_destroy_t +cairo_mime_surface_get_destroy (cairo_surface_t *surface); + /* Pattern creation functions */ cairo_public cairo_pattern_t * @@ -2684,23 +2754,6 @@ cairo_matrix_transform_point (const cairo_matrix_t *matrix, **/ typedef struct _cairo_region cairo_region_t; -/** - * cairo_rectangle_int_t: - * @x: X coordinate of the left side of the rectangle - * @y: Y coordinate of the the top side of the rectangle - * @width: width of the rectangle - * @height: height of the rectangle - * - * A data structure for holding a rectangle with integer coordinates. - * - * Since: 1.10 - **/ - -typedef struct _cairo_rectangle_int { - int x, y; - int width, height; -} cairo_rectangle_int_t; - typedef enum _cairo_region_overlap { CAIRO_REGION_OVERLAP_IN, /* completely inside region */ CAIRO_REGION_OVERLAP_OUT, /* completely outside region */ diff --git a/test/Makefile.refs b/test/Makefile.refs index c435bf6a..2d291f08 100644 --- a/test/Makefile.refs +++ b/test/Makefile.refs @@ -789,6 +789,7 @@ REFERENCE_IMAGES = \ mime-data.ref.png \ mime-data.script.ref.png \ mime-data.svg.ref.png \ + mime-surface.ref.png \ miter-precision.ps2.ref.png \ miter-precision.ps3.ref.png \ miter-precision.ref.png \ diff --git a/test/Makefile.sources b/test/Makefile.sources index 21e58e8b..a39a201e 100644 --- a/test/Makefile.sources +++ b/test/Makefile.sources @@ -190,6 +190,7 @@ test_sources = \ mesh-pattern-overlap.c \ mesh-pattern-transformed.c \ mime-data.c \ + mime-surface.c \ miter-precision.c \ move-to-show-surface.c \ new-sub-path.c \ diff --git a/test/mime-surface.c b/test/mime-surface.c new file mode 100644 index 00000000..d59112f2 --- /dev/null +++ b/test/mime-surface.c @@ -0,0 +1,174 @@ +/* + * Copyright © 2011 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Author: Chris Wilson <chris@chris-wilson.co.uk> + */ + +#include "cairo-test.h" + +#include <stdio.h> +#include <errno.h> + +/* Basic test to exercise the new mime-surface callback. */ + +#define WIDTH 200 +#define HEIGHT 80 + +/* Lazy way of determining PNG dimensions... */ +static void +png_dimensions (const char *filename, + cairo_content_t *content, int *width, int *height) +{ + cairo_surface_t *surface; + + surface = cairo_image_surface_create_from_png (filename); + *content = cairo_surface_get_content (surface); + *width = cairo_image_surface_get_width (surface); + *height = cairo_image_surface_get_height (surface); + cairo_surface_destroy (surface); +} + +static cairo_surface_t * +png_acquire (cairo_surface_t *mime_surface, void *closure, + cairo_surface_t *target, const cairo_rectangle_int_t *roi, + cairo_rectangle_int_t *extents) +{ + cairo_surface_t *image; + + image = cairo_image_surface_create_from_png (closure); + extents->x = extents->y = 0; + extents->width = cairo_image_surface_get_width (image); + extents->height = cairo_image_surface_get_height (image); + return image; +} + +static cairo_surface_t * +red_acquire (cairo_surface_t *mime_surface, void *closure, + cairo_surface_t *target, const cairo_rectangle_int_t *roi, + cairo_rectangle_int_t *extents) +{ + cairo_surface_t *image; + cairo_t *cr; + + image = cairo_surface_create_similar_image (target, + CAIRO_FORMAT_RGB24, + roi->width, roi->height); + cr = cairo_create (image); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_paint (cr); + cairo_destroy (cr); + + *extents = *roi; + return image; +} + +static void +release (cairo_surface_t *mime_surface, void *closure, cairo_surface_t *image) +{ + cairo_surface_destroy (image); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const char *png_filename = "png.png"; + cairo_surface_t *png, *red; + cairo_content_t content; + int png_width, png_height; + int i, j; + + png_dimensions (png_filename, &content, &png_width, &png_height); + + png = cairo_mime_surface_create ((void*)png_filename, content, png_width, png_height); + cairo_mime_surface_set_acquire (png, png_acquire, release); + + red = cairo_mime_surface_create (NULL, CAIRO_CONTENT_COLOR, WIDTH, HEIGHT); + cairo_mime_surface_set_acquire (red, red_acquire, release); + + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_paint (cr); + + cairo_translate (cr, 0, (HEIGHT-png_height)/2); + for (i = 0; i < 4; i++) { + for (j = 0; j < 4; j++) { + cairo_surface_t *source; + if ((i ^ j) & 1) + source = red; + else + source = png; + cairo_set_source_surface (cr, source, 0, 0); + cairo_rectangle (cr, i * WIDTH/4, j * png_height/4, WIDTH/4, png_height/4); + cairo_fill (cr); + } + } + + cairo_surface_destroy (red); + cairo_surface_destroy (png); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +check_status (const cairo_test_context_t *ctx, + cairo_status_t status, + cairo_status_t expected) +{ + if (status == expected) + return CAIRO_TEST_SUCCESS; + + cairo_test_log (ctx, + "Error: Expected status value %d (%s), received %d (%s)\n", + expected, + cairo_status_to_string (expected), + status, + cairo_status_to_string (status)); + return CAIRO_TEST_FAILURE; +} + +static cairo_test_status_t +preamble (cairo_test_context_t *ctx) +{ + cairo_surface_t *mime; + cairo_status_t status; + cairo_t *cr; + + /* drawing to a mime-surface is verboten */ + + mime = cairo_mime_surface_create (NULL, CAIRO_CONTENT_COLOR, 0, 0); + cr = cairo_create (mime); + cairo_surface_destroy (mime); + status = cairo_status (cr); + cairo_destroy (cr); + status = check_status (ctx, status, CAIRO_STATUS_WRITE_ERROR); + if (status) + return status; + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (mime_surface, + "Check that the mime-surface embedding works", + "api", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + preamble, draw) diff --git a/test/mime-surface.ref.png b/test/mime-surface.ref.png Binary files differnew file mode 100644 index 00000000..ac5e5606 --- /dev/null +++ b/test/mime-surface.ref.png diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c index 614783c6..1b42bed3 100644 --- a/util/cairo-trace/trace.c +++ b/util/cairo-trace/trace.c @@ -3496,6 +3496,55 @@ cairo_image_surface_create_for_data (unsigned char *data, cairo_format_t format, } cairo_surface_t * +cairo_mime_surface_create (void *data, cairo_content_t content, int width, int height) +{ + cairo_surface_t *ret; + + _enter_trace (); + + ret = DLCALL (cairo_mime_surface_create, data, content, width, height); + + _emit_line_info (); + if (_write_lock ()) { + Object *obj = _create_surface (ret); + cairo_format_t format; + cairo_surface_t *image; + cairo_t *cr; + + /* Impossible to accurately record the interaction with a mime-surface + * so just suck all the data into an image upfront */ + switch (content) { + case CAIRO_CONTENT_ALPHA: format = CAIRO_FORMAT_A8; break; + case CAIRO_CONTENT_COLOR: format = CAIRO_FORMAT_RGB24; break; + default: + case CAIRO_CONTENT_COLOR_ALPHA: format = CAIRO_FORMAT_ARGB32; break; + } + + _trace_printf ("%% mime-surface\n"); + + image = DLCALL (cairo_image_surface_create, format, width, height); + cr = DLCALL (cairo_create, image); + DLCALL (cairo_set_source_surface, cr, ret, 0, 0); + DLCALL (cairo_paint, cr); + DLCALL (cairo_destroy, cr); + + _emit_image (image, NULL); + DLCALL (cairo_surface_destroy, image); + _trace_printf (" dup /s%ld exch def\n", + obj->token); + + obj->width = width; + obj->height = height; + obj->defined = TRUE; + _push_object (obj); + _write_unlock (); + } + + _exit_trace (); + return ret; +} + +cairo_surface_t * cairo_surface_create_similar (cairo_surface_t *other, cairo_content_t content, int width, int height) |