diff options
author | Kristian Høgsberg <krh@redhat.com> | 2005-03-16 12:08:41 +0000 |
---|---|---|
committer | Kristian Høgsberg <krh@redhat.com> | 2005-03-16 12:08:41 +0000 |
commit | 6993c086ebaa9a98b1794f2c483013ec51cc41ec (patch) | |
tree | fcfc4cff8c0fb6197198587b453e92ebba5fa35e | |
parent | 5fecf69e2c41ed1957fdde8b0208e7a4aa031466 (diff) |
Add cairo_output_stream.c
Add new errors, CAIRO_STATUS_WRITE_ERROR and CAIRO_STATUS_SURFACE_FINISHED, add cairo_surface_finish() prototype, add cairo_write_func_t.
Add strings for new errors, documentation fix.
Rename surface destroy functions to finish and change them to not free the surface.
Change PDF surface constructors to take a write function in the general case and add stdio convenience constructors. Change destroy function to finish for cairo_pdf_surface. Change implementation to use cairo_output_stream_t functions for output.
Use _cairo_surface_show_glyphs instead of calling function pointer directly.
Add prototypes for cairo output stream functions, rename destroy to finish in cairo_surface_backend_t and add finished flag to cairo_surface_t.
Add cairo_surface_finish() and call it from cairo_surface_destroy(). Check the finished flag in cairo_surface_t in functions that change the surface.
-rw-r--r-- | ChangeLog | 38 | ||||
-rw-r--r-- | src/Makefile.am | 1 | ||||
-rw-r--r-- | src/cairo-font.c | 19 | ||||
-rw-r--r-- | src/cairo-glitz-surface.c | 11 | ||||
-rw-r--r-- | src/cairo-image-surface.c | 8 | ||||
-rw-r--r-- | src/cairo-pdf-surface.c | 849 | ||||
-rw-r--r-- | src/cairo-pdf.h | 40 | ||||
-rw-r--r-- | src/cairo-ps-surface.c | 8 | ||||
-rw-r--r-- | src/cairo-surface.c | 116 | ||||
-rw-r--r-- | src/cairo-win32-surface.c | 6 | ||||
-rw-r--r-- | src/cairo-xcb-surface.c | 6 | ||||
-rw-r--r-- | src/cairo-xlib-surface.c | 8 | ||||
-rw-r--r-- | src/cairo.c | 6 | ||||
-rw-r--r-- | src/cairo.h | 22 | ||||
-rw-r--r-- | src/cairo_font.c | 19 | ||||
-rw-r--r-- | src/cairo_glitz_surface.c | 11 | ||||
-rw-r--r-- | src/cairo_image_surface.c | 8 | ||||
-rw-r--r-- | src/cairo_pdf_surface.c | 849 | ||||
-rw-r--r-- | src/cairo_png_surface.c | 8 | ||||
-rw-r--r-- | src/cairo_ps_surface.c | 8 | ||||
-rw-r--r-- | src/cairo_surface.c | 116 | ||||
-rw-r--r-- | src/cairo_win32_surface.c | 6 | ||||
-rw-r--r-- | src/cairo_xcb_surface.c | 6 | ||||
-rw-r--r-- | src/cairo_xlib_surface.c | 8 | ||||
-rw-r--r-- | src/cairoint.h | 49 |
25 files changed, 1415 insertions, 811 deletions
@@ -1,3 +1,41 @@ +2005-03-16 Kristian Høgsberg <set EMAIL_ADDRESS environment variable> + + * src/Makefile.am: Add cairo_output_stream.c + + * src/cairo.h: Add new errors, CAIRO_STATUS_WRITE_ERROR and + CAIRO_STATUS_SURFACE_FINISHED, add cairo_surface_finish() + prototype, add cairo_write_func_t. + + * src/cairo.c: Add strings for new errors, documentation fix. + + * src/cairo_win32_surface.c: + * src/cairo_xcb_surface.c: + * src/cairo_xlib_surface.c: + * src/cairo_glitz_surface.c: + * src/cairo_image_surface.c: + * src/cairo_png_surface.c: + * src/cairo_ps_surface.c: Rename surface destroy functions to + finish and change them to not free the surface. + + * src/cairo-pdf.h: + * src/cairo_pdf_surface.c: Change PDF surface constructors to take + a write function in the general case and add stdio convenience + constructors. Change destroy function to finish for + cairo_pdf_surface. Change implementation to use + cairo_output_stream_t functions for output. + + * src/cairo_font.c: (_cairo_font_show_glyphs): Use + _cairo_surface_show_glyphs instead of calling function pointer + directly. + + * src/cairoint.h: Add prototypes for cairo output stream + functions, rename destroy to finish in cairo_surface_backend_t and + add finished flag to cairo_surface_t. + + * src/cairo_surface.c: Add cairo_surface_finish() and call it from + cairo_surface_destroy(). Check the finished flag in + cairo_surface_t in functions that change the surface. + 2005-03-15 Owen Taylor <otaylor@redhat.com> * src/cairo-xlib.h src/cairo_xlib_surface.c: Rework set diff --git a/src/Makefile.am b/src/Makefile.am index c60025a0..2bdf2d36 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -103,6 +103,7 @@ libcairo_la_SOURCES = \ cairo_traps.c \ cairo_pattern.c \ cairo_unicode.c \ + cairo_output_stream.c \ cairo_wideint.c \ cairo-wideint.h \ $(libcairo_atsui_sources)\ diff --git a/src/cairo-font.c b/src/cairo-font.c index 529c1c7c..f168e6f2 100644 --- a/src/cairo-font.c +++ b/src/cairo-font.c @@ -114,16 +114,15 @@ _cairo_font_show_glyphs (cairo_font_t *font, int num_glyphs) { cairo_status_t status; - if (surface->backend->show_glyphs != NULL) { - status = surface->backend->show_glyphs (font, operator, pattern, - surface, - source_x, source_y, - dest_x, dest_y, - width, height, - glyphs, num_glyphs); - if (status == CAIRO_STATUS_SUCCESS) - return status; - } + + status = _cairo_surface_show_glyphs (font, operator, pattern, + surface, + source_x, source_y, + dest_x, dest_y, + width, height, + glyphs, num_glyphs); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; /* Surface display routine either does not exist or failed. */ return font->backend->show_glyphs (font, operator, pattern, diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c index ee664e1c..acdee9a0 100644 --- a/src/cairo-glitz-surface.c +++ b/src/cairo-glitz-surface.c @@ -54,8 +54,8 @@ typedef struct _cairo_glitz_surface { pixman_region16_t *clip; } cairo_glitz_surface_t; -static void -_cairo_glitz_surface_destroy (void *abstract_surface) +static cairo_status_t +_cairo_glitz_surface_finish (void *abstract_surface) { cairo_glitz_surface_t *surface = abstract_surface; @@ -66,7 +66,8 @@ _cairo_glitz_surface_destroy (void *abstract_surface) } glitz_surface_destroy (surface->surface); - free (surface); + + return CAIRO_STATUS_SUCCESS; } static glitz_format_name_t @@ -733,7 +734,7 @@ _cairo_glitz_pattern_release_surface (cairo_glitz_surface_t *dst, _cairo_pattern_release_surface (&dst->base, &surface->base, &attr->base); else - _cairo_glitz_surface_destroy (surface); + cairo_surface_destroy (&surface->base); } static cairo_int_status_t @@ -1277,7 +1278,7 @@ _cairo_glitz_surface_set_clip_region (void *abstract_surface, static const cairo_surface_backend_t cairo_glitz_surface_backend = { _cairo_glitz_surface_create_similar, - _cairo_glitz_surface_destroy, + _cairo_glitz_surface_finish, _cairo_glitz_surface_pixels_per_inch, _cairo_glitz_surface_acquire_source_image, _cairo_glitz_surface_release_source_image, diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c index 9745b315..106fcf0e 100644 --- a/src/cairo-image-surface.c +++ b/src/cairo-image-surface.c @@ -234,8 +234,8 @@ _cairo_image_surface_create_similar (void *abstract_src, return cairo_image_surface_create (format, width, height); } -static void -_cairo_image_abstract_surface_destroy (void *abstract_surface) +static cairo_status_t +_cairo_image_abstract_surface_finish (void *abstract_surface) { cairo_image_surface_t *surface = abstract_surface; @@ -247,7 +247,7 @@ _cairo_image_abstract_surface_destroy (void *abstract_surface) surface->data = NULL; } - free (surface); + return CAIRO_STATUS_SUCCESS; } void @@ -658,7 +658,7 @@ _cairo_surface_is_image (cairo_surface_t *surface) static const cairo_surface_backend_t cairo_image_surface_backend = { _cairo_image_surface_create_similar, - _cairo_image_abstract_surface_destroy, + _cairo_image_abstract_surface_finish, _cairo_image_surface_pixels_per_inch, _cairo_image_surface_acquire_source_image, _cairo_image_surface_release_source_image, diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c index fee91835..5a73e7e8 100644 --- a/src/cairo-pdf-surface.c +++ b/src/cairo-pdf-surface.c @@ -153,8 +153,10 @@ struct cairo_pdf_stream { }; struct cairo_pdf_document { - FILE *file; + cairo_output_stream_t *output_stream; unsigned long refcount; + cairo_surface_t *owner; + cairo_bool_t finished; double width_inches; double height_inches; @@ -190,15 +192,18 @@ struct cairo_pdf_surface { static cairo_pdf_document_t * -_cairo_pdf_document_create (FILE *file, - double width_inches, - double height_inches, - double x_pixels_per_inch, - double y_pixels_per_inch); +_cairo_pdf_document_create (cairo_output_stream_t *stream, + double width_inches, + double height_inches, + double x_pixels_per_inch, + double y_pixels_per_inch); static void _cairo_pdf_document_destroy (cairo_pdf_document_t *document); +static cairo_status_t +_cairo_pdf_document_finish (cairo_pdf_document_t *document); + static void _cairo_pdf_document_reference (cairo_pdf_document_t *document); @@ -814,7 +819,7 @@ _cairo_pdf_document_new_object (cairo_pdf_document_t *document) { cairo_pdf_object_t object; - object.offset = ftell (document->file); + object.offset = _cairo_output_stream_get_position (document->output_stream); if (_cairo_array_append (&document->objects, &object, 1) == NULL) return 0; @@ -828,7 +833,7 @@ _cairo_pdf_document_update_object (cairo_pdf_document_t *document, cairo_pdf_object_t *object; object = _cairo_array_index (&document->objects, id - 1); - object->offset = ftell (document->file); + object->offset = _cairo_output_stream_get_position (document->output_stream); } static void @@ -899,17 +904,17 @@ _cairo_pdf_surface_add_font (cairo_pdf_surface_t *surface, unsigned int id) _cairo_array_append (&surface->fonts, &resource, 1); } -cairo_surface_t * -cairo_pdf_surface_create (FILE *file, - double width_inches, - double height_inches, - double x_pixels_per_inch, - double y_pixels_per_inch) +static cairo_surface_t * +_cairo_pdf_surface_create_for_stream (cairo_output_stream_t *stream, + double width_inches, + double height_inches, + double x_pixels_per_inch, + double y_pixels_per_inch) { cairo_pdf_document_t *document; cairo_surface_t *surface; - document = _cairo_pdf_document_create (file, + document = _cairo_pdf_document_create (stream, width_inches, height_inches, x_pixels_per_inch, @@ -921,11 +926,54 @@ cairo_pdf_surface_create (FILE *file, width_inches, height_inches); + document->owner = surface; _cairo_pdf_document_destroy (document); return surface; } +cairo_surface_t * +cairo_pdf_surface_create (cairo_write_func_t write, + cairo_destroy_func_t destroy_closure, + void *closure, + double width_inches, + double height_inches, + double x_pixels_per_inch, + double y_pixels_per_inch) +{ + cairo_output_stream_t *stream; + + stream = _cairo_output_stream_create (write, destroy_closure, closure); + if (stream == NULL) + return NULL; + + return _cairo_pdf_surface_create_for_stream (stream, + width_inches, + height_inches, + x_pixels_per_inch, + y_pixels_per_inch); +} + +cairo_surface_t * +cairo_pdf_surface_create_for_file (FILE *fp, + double width_inches, + double height_inches, + double x_pixels_per_inch, + double y_pixels_per_inch) +{ + cairo_output_stream_t *stream; + + stream = _cairo_output_stream_create_for_file (fp); + if (stream == NULL) + return NULL; + + return _cairo_pdf_surface_create_for_stream (stream, + width_inches, + height_inches, + x_pixels_per_inch, + y_pixels_per_inch); +} + static cairo_surface_t * _cairo_pdf_surface_create_for_document (cairo_pdf_document_t *document, double width_inches, @@ -989,7 +1037,7 @@ static cairo_pdf_stream_t * _cairo_pdf_document_open_stream (cairo_pdf_document_t *document, const char *extra_entries) { - FILE *file = document->file; + cairo_output_stream_t *output_stream = document->output_stream; cairo_pdf_stream_t *stream; stream = malloc (sizeof (cairo_pdf_stream_t)); @@ -1000,17 +1048,17 @@ _cairo_pdf_document_open_stream (cairo_pdf_document_t *document, stream->id = _cairo_pdf_document_new_object (document); stream->length_id = _cairo_pdf_document_new_object (document); - fprintf (file, - "%d 0 obj\r\n" - "<< /Length %d 0 R\r\n" - "%s" - ">>\r\n" - "stream\r\n", - stream->id, - stream->length_id, - extra_entries); + _cairo_output_stream_printf (output_stream, + "%d 0 obj\r\n" + "<< /Length %d 0 R\r\n" + "%s" + ">>\r\n" + "stream\r\n", + stream->id, + stream->length_id, + extra_entries); - stream->start_offset = ftell (file); + stream->start_offset = _cairo_output_stream_get_position (output_stream); document->current_stream = stream; @@ -1020,7 +1068,7 @@ _cairo_pdf_document_open_stream (cairo_pdf_document_t *document, static void _cairo_pdf_document_close_stream (cairo_pdf_document_t *document) { - FILE *file = document->file; + cairo_output_stream_t *output_stream = document->output_stream; long length; cairo_pdf_stream_t *stream; @@ -1028,35 +1076,42 @@ _cairo_pdf_document_close_stream (cairo_pdf_document_t *document) if (stream == NULL) return; - length = ftell(file) - stream->start_offset; - fprintf (file, - "\r\n" - "endstream\r\n" - "endobj\r\n"); + length = _cairo_output_stream_get_position (output_stream) - + stream->start_offset; + _cairo_output_stream_printf (output_stream, + "\r\n" + "endstream\r\n" + "endobj\r\n"); _cairo_pdf_document_update_object (document, stream->length_id); - fprintf (file, - "%d 0 obj\r\n" - " %ld\r\n" - "endobj\r\n", - stream->length_id, - length); + _cairo_output_stream_printf (output_stream, + "%d 0 obj\r\n" + " %ld\r\n" + "endobj\r\n", + stream->length_id, + length); document->current_stream = NULL; } -static void -_cairo_pdf_surface_destroy (void *abstract_surface) +static cairo_status_t +_cairo_pdf_surface_finish (void *abstract_surface) { + cairo_status_t status; cairo_pdf_surface_t *surface = abstract_surface; cairo_pdf_document_t *document = surface->document; if (surface->current_stream == document->current_stream) _cairo_pdf_document_close_stream (document); + if (document->owner == &surface->base) + status = _cairo_pdf_document_finish (document); + else + status = CAIRO_STATUS_SUCCESS; + _cairo_pdf_document_destroy (document); - free (surface); + return status; } /* XXX: We should re-work this interface to return both X/Y ppi values. */ @@ -1073,7 +1128,7 @@ _cairo_pdf_surface_ensure_stream (cairo_pdf_surface_t *surface) { cairo_pdf_document_t *document = surface->document; cairo_pdf_stream_t *stream; - FILE *file = document->file; + cairo_output_stream_t *output = document->output_stream; char extra[200]; if (document->current_stream == NULL || @@ -1091,8 +1146,9 @@ _cairo_pdf_surface_ensure_stream (cairo_pdf_surface_t *surface) /* If this is the first stream we open for this surface, * output the cairo to PDF transformation matrix. */ if (_cairo_array_num_elements (&surface->streams) == 1) - fprintf (file, "1 0 0 -1 0 %f cm\r\n", - document->height_inches * document->y_ppi); + _cairo_output_stream_printf (output, + "1 0 0 -1 0 %f cm\r\n", + document->height_inches * document->y_ppi); } } @@ -1159,7 +1215,7 @@ static unsigned int emit_image_data (cairo_pdf_document_t *document, cairo_image_surface_t *image) { - FILE *file = document->file; + cairo_output_stream_t *output = document->output_stream; cairo_pdf_stream_t *stream; char entries[200]; char *rgb, *compressed; @@ -1202,7 +1258,7 @@ emit_image_data (cairo_pdf_document_t *document, image->width, image->height); stream = _cairo_pdf_document_open_stream (document, entries); - fwrite (compressed, 1, compressed_size, file); + _cairo_output_stream_write (output, compressed, compressed_size); _cairo_pdf_document_close_stream (document); free (rgb); @@ -1216,7 +1272,7 @@ _cairo_pdf_surface_composite_image (cairo_pdf_surface_t *dst, cairo_surface_pattern_t *pattern) { cairo_pdf_document_t *document = dst->document; - FILE *file = document->file; + cairo_output_stream_t *output = document->output_stream; unsigned id; cairo_matrix_t i2u; cairo_status_t status; @@ -1244,12 +1300,12 @@ _cairo_pdf_surface_composite_image (cairo_pdf_surface_t *dst, cairo_matrix_translate (&i2u, 0, image->height); cairo_matrix_scale (&i2u, image->width, -image->height); - fprintf (file, - "q %f %f %f %f %f %f cm /res%d Do Q\r\n", - i2u.m[0][0], i2u.m[0][1], - i2u.m[1][0], i2u.m[1][1], - i2u.m[2][0], i2u.m[2][1], - id); + _cairo_output_stream_printf (output, + "q %f %f %f %f %f %f cm /res%d Do Q\r\n", + i2u.m[0][0], i2u.m[0][1], + i2u.m[1][0], i2u.m[1][1], + i2u.m[2][0], i2u.m[2][1], + id); bail: _cairo_surface_release_source_image (src, image, image_extra); @@ -1272,7 +1328,7 @@ _cairo_pdf_surface_composite_pdf (cairo_pdf_surface_t *dst, cairo_surface_pattern_t *pattern) { cairo_pdf_document_t *document = dst->document; - FILE *file = document->file; + cairo_output_stream_t *output = document->output_stream; cairo_matrix_t i2u; cairo_pdf_stream_t *stream; int num_streams, i; @@ -1288,24 +1344,24 @@ _cairo_pdf_surface_composite_pdf (cairo_pdf_surface_t *dst, 1.0 / (src->width_inches * document->x_ppi), 1.0 / (src->height_inches * document->y_ppi)); - fprintf (file, - "q %f %f %f %f %f %f cm", - i2u.m[0][0], i2u.m[0][1], - i2u.m[1][0], i2u.m[1][1], - i2u.m[2][0], i2u.m[2][1]); + _cairo_output_stream_printf (output, + "q %f %f %f %f %f %f cm", + i2u.m[0][0], i2u.m[0][1], + i2u.m[1][0], i2u.m[1][1], + i2u.m[2][0], i2u.m[2][1]); num_streams = _cairo_array_num_elements (&src->streams); for (i = 0; i < num_streams; i++) { _cairo_array_copy_element (&src->streams, i, &stream); - fprintf (file, - " /res%d Do", - stream->id); + _cairo_output_stream_printf (output, + " /res%d Do", + stream->id); _cairo_pdf_surface_add_xobject (dst, stream->id); } - fprintf (file, " Q\r\n"); + _cairo_output_stream_printf (output, " Q\r\n"); return CAIRO_STATUS_SUCCESS; } @@ -1348,20 +1404,20 @@ _cairo_pdf_surface_fill_rectangles (void *abstract_surface, { cairo_pdf_surface_t *surface = abstract_surface; cairo_pdf_document_t *document = surface->document; - FILE *file = document->file; + cairo_output_stream_t *output = document->output_stream; int i; _cairo_pdf_surface_ensure_stream (surface); - fprintf (file, - "%f %f %f rg\r\n", - color->red, color->green, color->blue); + _cairo_output_stream_printf (output, + "%f %f %f rg\r\n", + color->red, color->green, color->blue); for (i = 0; i < num_rects; i++) { - fprintf (file, - "%d %d %d %d re f\r\n", - rects[i].x, rects[i].y, - rects[i].width, rects[i].height); + _cairo_output_stream_printf (output, + "%d %d %d %d re f\r\n", + rects[i].x, rects[i].y, + rects[i].width, rects[i].height); } return CAIRO_STATUS_SUCCESS; @@ -1372,17 +1428,17 @@ emit_solid_pattern (cairo_pdf_surface_t *surface, cairo_solid_pattern_t *pattern) { cairo_pdf_document_t *document = surface->document; - FILE *file = document->file; + cairo_output_stream_t *output = document->output_stream; unsigned int alpha; alpha = _cairo_pdf_surface_add_alpha (surface, pattern->base.alpha); _cairo_pdf_surface_ensure_stream (surface); - fprintf (file, - "%f %f %f rg /a%d gs\r\n", - pattern->red, - pattern->green, - pattern->blue, - alpha); + _cairo_output_stream_printf (output, + "%f %f %f rg /a%d gs\r\n", + pattern->red, + pattern->green, + pattern->blue, + alpha); } static void @@ -1390,7 +1446,7 @@ emit_surface_pattern (cairo_pdf_surface_t *dst, cairo_surface_pattern_t *pattern) { cairo_pdf_document_t *document = dst->document; - FILE *file = document->file; + cairo_output_stream_t *output = document->output_stream; cairo_pdf_stream_t *stream; cairo_image_surface_t *image; void *image_extra; @@ -1441,9 +1497,9 @@ emit_surface_pattern (cairo_pdf_surface_t *dst, _cairo_pdf_surface_ensure_stream (dst); alpha = _cairo_pdf_surface_add_alpha (dst, 1.0); - fprintf (file, - "/Pattern cs /res%d scn /a%d gs\r\n", - stream->id, alpha); + _cairo_output_stream_printf (output, + "/Pattern cs /res%d scn /a%d gs\r\n", + stream->id, alpha); _cairo_surface_release_source_image (pattern->surface, image, image_extra); } @@ -1452,33 +1508,37 @@ static unsigned int emit_pattern_stops (cairo_pdf_surface_t *surface, cairo_gradient_pattern_t *pattern) { cairo_pdf_document_t *document = surface->document; - FILE *file = document->file; + cairo_output_stream_t *output = document->output_stream; unsigned int function_id; + char stops[2][3]; function_id = _cairo_pdf_document_new_object (document); - fprintf (file, - "%d 0 obj\r\n" - "<< /FunctionType 0\r\n" - " /Domain [ 0.0 1.0 ]\r\n" - " /Size [ 2 ]\r\n" - " /BitsPerSample 8\r\n" - " /Range [ 0.0 1.0 0.0 1.0 0.0 1.0 ]\r\n" - " /Length 6\r\n" - ">>\r\n" - "stream\r\n", - function_id); - - fputc (pattern->stops[0].color.red * 0xff, file); - fputc (pattern->stops[0].color.green * 0xff, file); - fputc (pattern->stops[0].color.blue * 0xff, file); - fputc (pattern->stops[1].color.red * 0xff, file); - fputc (pattern->stops[1].color.green * 0xff, file); - fputc (pattern->stops[1].color.blue * 0xff, file); - - fprintf (file, - "\r\n" - "endstream\r\n" - "endobj\r\n"); + + _cairo_output_stream_printf (output, + "%d 0 obj\r\n" + "<< /FunctionType 0\r\n" + " /Domain [ 0.0 1.0 ]\r\n" + " /Size [ 2 ]\r\n" + " /BitsPerSample 8\r\n" + " /Range [ 0.0 1.0 0.0 1.0 0.0 1.0 ]\r\n" + " /Length 6\r\n" + ">>\r\n" + "stream\r\n", + function_id); + + stops[0][0] = pattern->stops[0].color.red * 0xff + 0.5; + stops[0][1] = pattern->stops[0].color.green * 0xff + 0.5; + stops[0][2] = pattern->stops[0].color.blue * 0xff + 0.5; + stops[1][0] = pattern->stops[1].color.red * 0xff + 0.5; + stops[1][1] = pattern->stops[1].color.green * 0xff + 0.5; + stops[1][2] = pattern->stops[1].color.blue * 0xff + 0.5; + + _cairo_output_stream_write (output, stops, sizeof (stops)); + + _cairo_output_stream_printf (output, + "\r\n" + "endstream\r\n" + "endobj\r\n"); return function_id; } @@ -1487,7 +1547,7 @@ static void emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_linear_pattern_t *pattern) { cairo_pdf_document_t *document = surface->document; - FILE *file = document->file; + cairo_output_stream_t *output = document->output_stream; unsigned int function_id, pattern_id, alpha; double x0, y0, x1, y1; cairo_matrix_t p2u; @@ -1507,24 +1567,24 @@ emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_linear_pattern_t *patte cairo_matrix_transform_point (&p2u, &x1, &y1); pattern_id = _cairo_pdf_document_new_object (document); - fprintf (file, - "%d 0 obj\r\n" - "<< /Type /Pattern\r\n" - " /PatternType 2\r\n" - " /Matrix [ 1 0 0 -1 0 %f ]\r\n" - " /Shading\r\n" - " << /ShadingType 2\r\n" - " /ColorSpace /DeviceRGB\r\n" - " /Coords [ %f %f %f %f ]\r\n" - " /Function %d 0 R\r\n" - " /Extend [ true true ]\r\n" - " >>\r\n" - ">>\r\n" - "endobj\r\n", - pattern_id, - document->height_inches * document->y_ppi, - x0, y0, x1, y1, - function_id); + _cairo_output_stream_printf (output, + "%d 0 obj\r\n" + "<< /Type /Pattern\r\n" + " /PatternType 2\r\n" + " /Matrix [ 1 0 0 -1 0 %f ]\r\n" + " /Shading\r\n" + " << /ShadingType 2\r\n" + " /ColorSpace /DeviceRGB\r\n" + " /Coords [ %f %f %f %f ]\r\n" + " /Function %d 0 R\r\n" + " /Extend [ true true ]\r\n" + " >>\r\n" + ">>\r\n" + "endobj\r\n", + pattern_id, + document->height_inches * document->y_ppi, + x0, y0, x1, y1, + function_id); _cairo_pdf_surface_add_pattern (surface, pattern_id); @@ -1532,16 +1592,16 @@ emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_linear_pattern_t *patte alpha = _cairo_pdf_surface_add_alpha (surface, 1.0); /* Use pattern */ - fprintf (file, - "/Pattern cs /res%d scn /a%d gs\r\n", - pattern_id, alpha); + _cairo_output_stream_printf (output, + "/Pattern cs /res%d scn /a%d gs\r\n", + pattern_id, alpha); } static void emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_radial_pattern_t *pattern) { cairo_pdf_document_t *document = surface->document; - FILE *file = document->file; + cairo_output_stream_t *output = document->output_stream; unsigned int function_id, pattern_id, alpha; double x0, y0, x1, y1, r0, r1; cairo_matrix_t p2u; @@ -1574,24 +1634,24 @@ emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_radial_pattern_t *patte * behavoir, not yet sure how to implement the cairo mirror and * repeat behaviour. */ pattern_id = _cairo_pdf_document_new_object (document); - fprintf (file, - "%d 0 obj\r\n" - "<< /Type /Pattern\r\n" - " /PatternType 2\r\n" - " /Matrix [ 1 0 0 -1 0 %f ]\r\n" - " /Shading\r\n" - " << /ShadingType 3\r\n" - " /ColorSpace /DeviceRGB\r\n" - " /Coords [ %f %f %f %f %f %f ]\r\n" - " /Function %d 0 R\r\n" - " /Extend [ true true ]\r\n" - " >>\r\n" - ">>\r\n" - "endobj\r\n", - pattern_id, - document->height_inches * document->y_ppi, - x0, y0, r0, x1, y1, r1, - function_id); + _cairo_output_stream_printf (output, + "%d 0 obj\r\n" + "<< /Type /Pattern\r\n" + " /PatternType 2\r\n" + " /Matrix [ 1 0 0 -1 0 %f ]\r\n" + " /Shading\r\n" + " << /ShadingType 3\r\n" + " /ColorSpace /DeviceRGB\r\n" + " /Coords [ %f %f %f %f %f %f ]\r\n" + " /Function %d 0 R\r\n" + " /Extend [ true true ]\r\n" + " >>\r\n" + ">>\r\n" + "endobj\r\n", + pattern_id, + document->height_inches * document->y_ppi, + x0, y0, r0, x1, y1, r1, + function_id); _cairo_pdf_surface_add_pattern (surface, pattern_id); @@ -1599,9 +1659,9 @@ emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_radial_pattern_t *patte alpha = _cairo_pdf_surface_add_alpha (surface, 1.0); /* Use pattern */ - fprintf (file, - "/Pattern cs /res%d scn /a%d gs\r\n", - pattern_id, alpha); + _cairo_output_stream_printf (output, + "/Pattern cs /res%d scn /a%d gs\r\n", + pattern_id, alpha); } static void @@ -1650,7 +1710,7 @@ _cairo_pdf_surface_composite_trapezoids (cairo_operator_t operator, { cairo_pdf_surface_t *surface = abstract_dst; cairo_pdf_document_t *document = surface->document; - FILE *file = document->file; + cairo_output_stream_t *output = document->output_stream; int i; emit_pattern (surface, pattern); @@ -1668,16 +1728,16 @@ _cairo_pdf_surface_composite_trapezoids (cairo_operator_t operator, right_x1 = intersect (&traps[i].right, traps[i].top); right_x2 = intersect (&traps[i].right, traps[i].bottom); - fprintf (file, - "%f %f m %f %f l %f %f l %f %f l h\r\n", - left_x1, _cairo_fixed_to_double (traps[i].top), - left_x2, _cairo_fixed_to_double (traps[i].bottom), - right_x2, _cairo_fixed_to_double (traps[i].bottom), - right_x1, _cairo_fixed_to_double (traps[i].top)); + _cairo_output_stream_printf (output, + "%f %f m %f %f l %f %f l %f %f l h\r\n", + left_x1, _cairo_fixed_to_double (traps[i].top), + left_x2, _cairo_fixed_to_double (traps[i].bottom), + right_x2, _cairo_fixed_to_double (traps[i].bottom), + right_x1, _cairo_fixed_to_double (traps[i].top)); } - fprintf (file, - "f\r\n"); + _cairo_output_stream_printf (output, + "f\r\n"); return CAIRO_STATUS_SUCCESS; } @@ -1759,7 +1819,7 @@ _cairo_pdf_surface_show_glyphs (cairo_font_t *font, { cairo_pdf_surface_t *surface = abstract_surface; cairo_pdf_document_t *document = surface->document; - FILE *file = document->file; + cairo_output_stream_t *output = document->output_stream; cairo_pdf_font_t *pdf_font; int i, index; @@ -1769,22 +1829,24 @@ _cairo_pdf_surface_show_glyphs (cairo_font_t *font, emit_pattern (surface, pattern); - fprintf (file, "BT /res%u 1 Tf", pdf_font->font_id); + _cairo_output_stream_printf (output, + "BT /res%u 1 Tf", pdf_font->font_id); for (i = 0; i < num_glyphs; i++) { index = cairo_pdf_font_use_glyph (pdf_font, glyphs[i].index); - fprintf (file, - " %f %f %f %f %f %f Tm (\\%o) Tj", - font->scale.matrix[0][0], - font->scale.matrix[0][1], - font->scale.matrix[1][0], - -font->scale.matrix[1][1], - glyphs[i].x, - glyphs[i].y, - index); + _cairo_output_stream_printf (output, + " %f %f %f %f %f %f Tm (\\%o) Tj", + font->scale.matrix[0][0], + font->scale.matrix[0][1], + font->scale.matrix[1][0], + -font->scale.matrix[1][1], + glyphs[i].x, + glyphs[i].y, + index); } - fprintf (file, " ET\r\n"); + _cairo_output_stream_printf (output, + " ET\r\n"); _cairo_pdf_surface_add_font (surface, pdf_font->font_id); @@ -1793,7 +1855,7 @@ _cairo_pdf_surface_show_glyphs (cairo_font_t *font, static const cairo_surface_backend_t cairo_pdf_surface_backend = { _cairo_pdf_surface_create_similar, - _cairo_pdf_surface_destroy, + _cairo_pdf_surface_finish, _cairo_pdf_surface_pixels_per_inch, _cairo_pdf_surface_acquire_source_image, _cairo_pdf_surface_release_source_image, @@ -1810,11 +1872,11 @@ static const cairo_surface_backend_t cairo_pdf_surface_backend = { }; static cairo_pdf_document_t * -_cairo_pdf_document_create (FILE *file, - double width_inches, - double height_inches, - double x_pixels_per_inch, - double y_pixels_per_inch) +_cairo_pdf_document_create (cairo_output_stream_t *output_stream, + double width_inches, + double height_inches, + double x_pixels_per_inch, + double y_pixels_per_inch) { cairo_pdf_document_t *document; @@ -1822,8 +1884,10 @@ _cairo_pdf_document_create (FILE *file, if (document == NULL) return NULL; - document->file = file; + document->output_stream = output_stream; document->refcount = 1; + document->owner = NULL; + document->finished = FALSE; document->width_inches = width_inches; document->height_inches = height_inches; document->x_ppi = x_pixels_per_inch; @@ -1840,7 +1904,8 @@ _cairo_pdf_document_create (FILE *file, _cairo_array_init (&document->fonts, sizeof (cairo_pdf_font_t *)); /* Document header */ - fprintf (file, "%%PDF-1.4\r\n"); + _cairo_output_stream_printf (output_stream, + "%%PDF-1.4\r\n"); return document; } @@ -1848,17 +1913,17 @@ _cairo_pdf_document_create (FILE *file, static unsigned int _cairo_pdf_document_write_info (cairo_pdf_document_t *document) { - FILE *file = document->file; + cairo_output_stream_t *output = document->output_stream; unsigned int id; id = _cairo_pdf_document_new_object (document); - fprintf (file, - "%d 0 obj\r\n" - "<< /Creator (cairographics.org)\r\n" - " /Producer (cairographics.org)\r\n" - ">>\r\n" - "endobj\r\n", - id); + _cairo_output_stream_printf (output, + "%d 0 obj\r\n" + "<< /Creator (cairographics.org)\r\n" + " /Producer (cairographics.org)\r\n" + ">>\r\n" + "endobj\r\n", + id); return id; } @@ -1866,40 +1931,40 @@ _cairo_pdf_document_write_info (cairo_pdf_document_t *document) static void _cairo_pdf_document_write_pages (cairo_pdf_document_t *document) { - FILE *file = document->file; + cairo_output_stream_t *stream = document->output_stream; unsigned int page_id; int num_pages, i; _cairo_pdf_document_update_object (document, document->pages_id); - fprintf (file, - "%d 0 obj\r\n" - "<< /Type /Pages\r\n" - " /Kids [ ", - document->pages_id); + _cairo_output_stream_printf (stream, + "%d 0 obj\r\n" + "<< /Type /Pages\r\n" + " /Kids [ ", + document->pages_id); num_pages = _cairo_array_num_elements (&document->pages); for (i = 0; i < num_pages; i++) { _cairo_array_copy_element (&document->pages, i, &page_id); - fprintf (file, "%d 0 R ", page_id); + _cairo_output_stream_printf (stream, "%d 0 R ", page_id); } - fprintf (file, "]\r\n"); - fprintf (file, " /Count %d\r\n", num_pages); + _cairo_output_stream_printf (stream, "]\r\n"); + _cairo_output_stream_printf (stream, " /Count %d\r\n", num_pages); /* TODO: Figure out wich other defaults to be inherited by /Page * objects. */ - fprintf (file, - " /MediaBox [ 0 0 %f %f ]\r\n" - ">>\r\n" - "endobj\r\n", - document->width_inches * document->x_ppi, - document->height_inches * document->y_ppi); + _cairo_output_stream_printf (stream, + " /MediaBox [ 0 0 %f %f ]\r\n" + ">>\r\n" + "endobj\r\n", + document->width_inches * document->x_ppi, + document->height_inches * document->y_ppi); } static cairo_status_t _cairo_pdf_document_write_fonts (cairo_pdf_document_t *document) { - FILE *file = document->file; + cairo_output_stream_t *output = document->output_stream; cairo_pdf_font_t *font; int num_fonts, i, j; const char *data; @@ -1923,76 +1988,76 @@ _cairo_pdf_document_write_fonts (cairo_pdf_document_t *document) } stream_id = _cairo_pdf_document_new_object (document); - fprintf (file, - "%d 0 obj\r\n" - "<< /Filter /FlateDecode\r\n" - " /Length %lu\r\n" - " /Length1 %lu\r\n" - ">>\r\n" - "stream\r\n", - stream_id, - compressed_size, - data_size); - fwrite (compressed, 1, compressed_size, file); - fprintf (file, - "\r\n" - "endstream\r\n" - "endobj\r\n"); + _cairo_output_stream_printf (output, + "%d 0 obj\r\n" + "<< /Filter /FlateDecode\r\n" + " /Length %lu\r\n" + " /Length1 %lu\r\n" + ">>\r\n" + "stream\r\n", + stream_id, + compressed_size, + data_size); + _cairo_output_stream_write (output, compressed, compressed_size); + _cairo_output_stream_printf (output, + "\r\n" + "endstream\r\n" + "endobj\r\n"); free (compressed); descriptor_id = _cairo_pdf_document_new_object (document); - fprintf (file, - "%d 0 obj\r\n" - "<< /Type /FontDescriptor\r\n" - " /FontName /7%s\r\n" - " /Flags 4\r\n" - " /FontBBox [ %ld %ld %ld %ld ]\r\n" - " /ItalicAngle 0\r\n" - " /Ascent %ld\r\n" - " /Descent %ld\r\n" - " /CapHeight 500\r\n" - " /StemV 80\r\n" - " /StemH 80\r\n" - " /FontFile2 %u 0 R\r\n" - ">>\r\n" - "endobj\r\n", - descriptor_id, - font->base_font, - font->x_min, - font->y_min, - font->x_max, - font->y_max, - font->ascent, - font->descent, - stream_id); + _cairo_output_stream_printf (output, + "%d 0 obj\r\n" + "<< /Type /FontDescriptor\r\n" + " /FontName /7%s\r\n" + " /Flags 4\r\n" + " /FontBBox [ %ld %ld %ld %ld ]\r\n" + " /ItalicAngle 0\r\n" + " /Ascent %ld\r\n" + " /Descent %ld\r\n" + " /CapHeight 500\r\n" + " /StemV 80\r\n" + " /StemH 80\r\n" + " /FontFile2 %u 0 R\r\n" + ">>\r\n" + "endobj\r\n", + descriptor_id, + font->base_font, + font->x_min, + font->y_min, + font->x_max, + font->y_max, + font->ascent, + font->descent, + stream_id); _cairo_pdf_document_update_object (document, font->font_id); - fprintf (file, - "%d 0 obj\r\n" - "<< /Type /Font\r\n" - " /Subtype /TrueType\r\n" - " /BaseFont /%s\r\n" - " /FirstChar 0\r\n" - " /LastChar %d\r\n" - " /FontDescriptor %d 0 R\r\n" - " /Widths ", - font->font_id, - font->base_font, - font->num_glyphs, - descriptor_id); - - fprintf (file, - "["); + _cairo_output_stream_printf (output, + "%d 0 obj\r\n" + "<< /Type /Font\r\n" + " /Subtype /TrueType\r\n" + " /BaseFont /%s\r\n" + " /FirstChar 0\r\n" + " /LastChar %d\r\n" + " /FontDescriptor %d 0 R\r\n" + " /Widths ", + font->font_id, + font->base_font, + font->num_glyphs, + descriptor_id); + + _cairo_output_stream_printf (output, + "["); for (j = 0; j < font->num_glyphs; j++) - fprintf (file, - " %d", - font->widths[j]); + _cairo_output_stream_printf (output, + " %d", + font->widths[j]); - fprintf (file, - " ]\r\n" - ">>\r\n" - "endobj\r\n"); + _cairo_output_stream_printf (output, + " ]\r\n" + ">>\r\n" + "endobj\r\n"); fail: cairo_pdf_ft_font_destroy (font); @@ -2004,17 +2069,17 @@ _cairo_pdf_document_write_fonts (cairo_pdf_document_t *document) static unsigned int _cairo_pdf_document_write_catalog (cairo_pdf_document_t *document) { - FILE *file = document->file; + cairo_output_stream_t *output = document->output_stream; unsigned int id; id = _cairo_pdf_document_new_object (document); - fprintf (file, - "%d 0 obj\r\n" - "<< /Type /Catalog\r\n" - " /Pages %d 0 R\r\n" - ">>\r\n" - "endobj\r\n", - id, document->pages_id); + _cairo_output_stream_printf (output, + "%d 0 obj\r\n" + "<< /Type /Catalog\r\n" + " /Pages %d 0 R\r\n" + ">>\r\n" + "endobj\r\n", + id, document->pages_id); return id; } @@ -2022,23 +2087,25 @@ _cairo_pdf_document_write_catalog (cairo_pdf_document_t *document) static long _cairo_pdf_document_write_xref (cairo_pdf_document_t *document) { - FILE *file = document->file; + cairo_output_stream_t *output = document->output_stream; cairo_pdf_object_t *object; int num_objects, i; long offset; num_objects = _cairo_array_num_elements (&document->objects); - offset = ftell(file); - fprintf (document->file, - "xref\r\n" - "%d %d\r\n", - 0, num_objects + 1); + offset = _cairo_output_stream_get_position (output); + _cairo_output_stream_printf (output, + "xref\r\n" + "%d %d\r\n", + 0, num_objects + 1); - fprintf (file, "0000000000 65535 f\r\n"); + _cairo_output_stream_printf (output, + "0000000000 65535 f\r\n"); for (i = 0; i < num_objects; i++) { object = _cairo_array_index (&document->objects, i); - fprintf (file, "%010ld 00000 n\r\n", object->offset); + _cairo_output_stream_printf (output, + "%010ld 00000 n\r\n", object->offset); } return offset; @@ -2053,14 +2120,25 @@ _cairo_pdf_document_reference (cairo_pdf_document_t *document) static void _cairo_pdf_document_destroy (cairo_pdf_document_t *document) { - FILE *file = document->file; - long offset; - unsigned int info_id, catalog_id; - document->refcount--; if (document->refcount > 0) return; + _cairo_pdf_document_finish (document); + + free (document); +} + +static cairo_status_t +_cairo_pdf_document_finish (cairo_pdf_document_t *document) +{ + cairo_output_stream_t *output = document->output_stream; + long offset; + unsigned int info_id, catalog_id; + + if (document->finished) + return CAIRO_STATUS_SUCCESS; + _cairo_pdf_document_close_stream (document); _cairo_pdf_document_write_pages (document); _cairo_pdf_document_write_fonts (document); @@ -2068,23 +2146,26 @@ _cairo_pdf_document_destroy (cairo_pdf_document_t *document) catalog_id = _cairo_pdf_document_write_catalog (document); offset = _cairo_pdf_document_write_xref (document); - fprintf (file, - "trailer\r\n" - "<< /Size %d\r\n" - " /Root %d 0 R\r\n" - " /Info %d 0 R\r\n" - ">>\r\n", - document->next_available_id, - catalog_id, - info_id); - - fprintf (file, - "startxref\r\n" - "%ld\r\n" - "%%%%EOF\r\n", - offset); + _cairo_output_stream_printf (output, + "trailer\r\n" + "<< /Size %d\r\n" + " /Root %d 0 R\r\n" + " /Info %d 0 R\r\n" + ">>\r\n", + document->next_available_id, + catalog_id, + info_id); - free (document); + _cairo_output_stream_printf (output, + "startxref\r\n" + "%ld\r\n" + "%%%%EOF\r\n", + offset); + + _cairo_output_stream_destroy (output); + document->finished = TRUE; + + return _cairo_output_stream_get_status (output); } static cairo_status_t @@ -2093,122 +2174,124 @@ _cairo_pdf_document_add_page (cairo_pdf_document_t *document, { cairo_pdf_stream_t *stream; cairo_pdf_resource_t *res; - FILE *file = document->file; + cairo_output_stream_t *output = document->output_stream; unsigned int page_id; double alpha; int num_streams, num_alphas, num_resources, i; + assert (!document->finished); + _cairo_pdf_document_close_stream (document); page_id = _cairo_pdf_document_new_object (document); - fprintf (file, - "%d 0 obj\r\n" - "<< /Type /Page\r\n" - " /Parent %d 0 R\r\n" - " /Contents [", - page_id, - document->pages_id); + _cairo_output_stream_printf (output, + "%d 0 obj\r\n" + "<< /Type /Page\r\n" + " /Parent %d 0 R\r\n" + " /Contents [", + page_id, + document->pages_id); num_streams = _cairo_array_num_elements (&surface->streams); for (i = 0; i < num_streams; i++) { _cairo_array_copy_element (&surface->streams, i, &stream); - fprintf (file, - " %d 0 R", - stream->id); + _cairo_output_stream_printf (output, + " %d 0 R", + stream->id); } - fprintf (file, - " ]\r\n" - " /Resources <<\r\n"); + _cairo_output_stream_printf (output, + " ]\r\n" + " /Resources <<\r\n"); num_resources = _cairo_array_num_elements (&surface->fonts); if (num_resources > 0) { - fprintf (file, - " /Font <<"); + _cairo_output_stream_printf (output, + " /Font <<"); for (i = 0; i < num_resources; i++) { res = _cairo_array_index (&surface->fonts, i); - fprintf (file, - " /res%d %d 0 R", - res->id, res->id); + _cairo_output_stream_printf (output, + " /res%d %d 0 R", + res->id, res->id); } - fprintf (file, - " >>\r\n"); + _cairo_output_stream_printf (output, + " >>\r\n"); } num_alphas = _cairo_array_num_elements (&surface->alphas); if (num_alphas > 0) { - fprintf (file, - " /ExtGState <<\r\n"); + _cairo_output_stream_printf (output, + " /ExtGState <<\r\n"); for (i = 0; i < num_alphas; i++) { _cairo_array_copy_element (&surface->alphas, i, &alpha); - fprintf (file, - " /a%d << /ca %f >>\r\n", - i, alpha); + _cairo_output_stream_printf (output, + " /a%d << /ca %f >>\r\n", + i, alpha); } - fprintf (file, - " >>\r\n"); + _cairo_output_stream_printf (output, + " >>\r\n"); } num_resources = _cairo_array_num_elements (&surface->patterns); if (num_resources > 0) { - fprintf (file, - " /Pattern <<"); + _cairo_output_stream_printf (output, + " /Pattern <<"); for (i = 0; i < num_resources; i++) { res = _cairo_array_index (&surface->patterns, i); - fprintf (file, - " /res%d %d 0 R", - res->id, res->id); + _cairo_output_stream_printf (output, + " /res%d %d 0 R", + res->id, res->id); } - fprintf (file, - " >>\r\n"); + _cairo_output_stream_printf (output, + " >>\r\n"); } num_resources = _cairo_array_num_elements (&surface->xobjects); if (num_resources > 0) { - fprintf (file, - " /XObject <<"); + _cairo_output_stream_printf (output, + " /XObject <<"); for (i = 0; i < num_resources; i++) { res = _cairo_array_index (&surface->xobjects, i); - fprintf (file, - " /res%d %d 0 R", - res->id, res->id); + _cairo_output_stream_printf (output, + " /res%d %d 0 R", + res->id, res->id); } - fprintf (file, - " >>\r\n"); + _cairo_output_stream_printf (output, + " >>\r\n"); } - fprintf (file, - " >>\r\n" - ">>\r\n" - "endobj\r\n"); + _cairo_output_stream_printf (output, + " >>\r\n" + ">>\r\n" + "endobj\r\n"); _cairo_array_append (&document->pages, &page_id, 1); return CAIRO_STATUS_SUCCESS; } -void -cairo_set_target_pdf (cairo_t *cr, - FILE *file, - double width_inches, - double height_inches, - double x_pixels_per_inch, - double y_pixels_per_inch) +static void +_cairo_set_target_pdf_as_stream (cairo_t *cr, + cairo_output_stream_t *stream, + double width_inches, + double height_inches, + double x_pixels_per_inch, + double y_pixels_per_inch) { cairo_surface_t *surface; - surface = cairo_pdf_surface_create (file, - width_inches, - height_inches, - x_pixels_per_inch, - y_pixels_per_inch); + surface = _cairo_pdf_surface_create_for_stream (stream, + width_inches, + height_inches, + x_pixels_per_inch, + y_pixels_per_inch); if (surface == NULL) { cr->status = CAIRO_STATUS_NO_MEMORY; @@ -2220,3 +2303,51 @@ cairo_set_target_pdf (cairo_t *cr, /* cairo_set_target_surface takes a reference, so we must destroy ours */ cairo_surface_destroy (surface); } + +void +cairo_set_target_pdf (cairo_t *cr, + cairo_write_func_t write, + cairo_destroy_func_t destroy_closure, + void *closure, + double width_inches, + double height_inches, + double x_pixels_per_inch, + double y_pixels_per_inch) +{ + cairo_output_stream_t *stream; + + stream = _cairo_output_stream_create (write, destroy_closure, closure); + if (stream == NULL) { + cr->status = CAIRO_STATUS_NO_MEMORY; + return; + } + + return _cairo_set_target_pdf_as_stream (cr, stream, + width_inches, + height_inches, + x_pixels_per_inch, + y_pixels_per_inch); +} + +void +cairo_set_target_pdf_as_file (cairo_t *cr, + FILE *fp, + double width_inches, + double height_inches, + double x_pixels_per_inch, + double y_pixels_per_inch) +{ + cairo_output_stream_t *stream; + + stream = _cairo_output_stream_create_for_file (fp); + if (stream == NULL) { + cr->status = CAIRO_STATUS_NO_MEMORY; + return; + } + + return _cairo_set_target_pdf_as_stream (cr, stream, + width_inches, + height_inches, + x_pixels_per_inch, + y_pixels_per_inch); +} diff --git a/src/cairo-pdf.h b/src/cairo-pdf.h index 701a7b4a..99d53a8c 100644 --- a/src/cairo-pdf.h +++ b/src/cairo-pdf.h @@ -46,20 +46,38 @@ CAIRO_BEGIN_DECLS void -cairo_set_target_pdf (cairo_t *cr, - FILE *file, - double width_inches, - double height_inches, - double x_pixels_per_inch, - double y_pixels_per_inch); +cairo_set_target_pdf (cairo_t *cr, + cairo_write_func_t write_func, + cairo_destroy_func_t destroy_closure_func, + void *closure, + double width_inches, + double height_inches, + double x_pixels_per_inch, + double y_pixels_per_inch); +void +cairo_set_target_pdf_as_file (cairo_t *cr, + FILE *fp, + double width_inches, + double height_inches, + double x_pixels_per_inch, + double y_pixels_per_inch); + +cairo_surface_t * +cairo_pdf_surface_create (cairo_write_func_t write_func, + cairo_destroy_func_t destroy_closure_func, + void *closure, + double width_inches, + double height_inches, + double x_pixels_per_inch, + double y_pixels_per_inch); cairo_surface_t * -cairo_pdf_surface_create (FILE *file, - double width_inches, - double height_inches, - double x_pixels_per_inch, - double y_pixels_per_inch); +cairo_pdf_surface_create_for_file (FILE *fp, + double width_inches, + double height_inches, + double x_pixels_per_inch, + double y_pixels_per_inch); CAIRO_END_DECLS diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c index 4a45fc67..a0a92dc2 100644 --- a/src/cairo-ps-surface.c +++ b/src/cairo-ps-surface.c @@ -170,8 +170,8 @@ _cairo_ps_surface_create_similar (void *abstract_src, return NULL; } -static void -_cairo_ps_surface_destroy (void *abstract_surface) +static cairo_status_t +_cairo_ps_surface_finish (void *abstract_surface) { cairo_ps_surface_t *surface = abstract_surface; @@ -180,7 +180,7 @@ _cairo_ps_surface_destroy (void *abstract_surface) cairo_surface_destroy (&surface->image->base); - free (surface); + return CAIRO_STATUS_SUCCESS; } static void @@ -426,7 +426,7 @@ _cairo_ps_surface_set_clip_region (void *abstract_surface, static const cairo_surface_backend_t cairo_ps_surface_backend = { _cairo_ps_surface_create_similar, - _cairo_ps_surface_destroy, + _cairo_ps_surface_finish, _cairo_ps_surface_pixels_per_inch, _cairo_ps_surface_acquire_source_image, _cairo_ps_surface_release_source_image, diff --git a/src/cairo-surface.c b/src/cairo-surface.c index 2afedc2c..18b4eb07 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -51,6 +51,8 @@ _cairo_surface_init (cairo_surface_t *surface, surface->backend = backend; surface->ref_count = 1; + surface->finished = FALSE; + _cairo_array_init (&surface->user_data_slots, sizeof (cairo_user_data_slot_t)); @@ -164,14 +166,49 @@ cairo_surface_destroy (cairo_surface_t *surface) if (surface->ref_count) return; - if (surface->backend->destroy) - surface->backend->destroy (surface); + cairo_surface_finish (surface); _destroy_user_data (surface); + + free (surface); } slim_hidden_def(cairo_surface_destroy); /** + * cairo_surface_finish: + * @surface: the #cairo_surface_t to finish + * + * This function finishes the surface and drops all references to + * external resources. For example, for the Xlib backend it means + * that cairo will no longer access the drawable, which can be freed. + * After calling cairo_surface_finish() the only valid operations on a + * surface are getting and setting user data and referencing and + * destroying it. Further drawing the the surface will not affect the + * surface but set the surface status to + * CAIRO_STATUS_SURFACE_FINISHED. + * + * When the last call to cairo_surface_destroy() decreases the + * reference count to zero, cairo will call cairo_surface_finish() if + * it hasn't been called already, before freeing the resources + * associated with the surface. + * + * Return value: CAIRO_STATUS_SUCCESS if the surface was finished + * successfully, otherwise CAIRO_STATUS_NO_MEMORY or + * CAIRO_STATUS_WRITE_ERROR. + **/ +cairo_status_t +cairo_surface_finish (cairo_surface_t *surface) +{ + if (surface->finished) + return CAIRO_STATUS_SURFACE_FINISHED; + + if (surface->backend->finish) + return surface->backend->finish (surface); + + return CAIRO_STATUS_SUCCESS; +} + +/** * cairo_surface_get_user_data: * @surface: a #cairo_surface_t * @key: the address of the #cairo_user_data_key_t the user data was @@ -281,6 +318,8 @@ _cairo_surface_acquire_source_image (cairo_surface_t *surface, cairo_image_surface_t **image_out, void **image_extra) { + assert (!surface->finished); + return surface->backend->acquire_source_image (surface, image_out, image_extra); } @@ -296,6 +335,8 @@ _cairo_surface_release_source_image (cairo_surface_t *surface, cairo_image_surface_t *image, void *image_extra) { + assert (!surface->finished); + surface->backend->release_source_image (surface, image, image_extra); } @@ -334,6 +375,8 @@ _cairo_surface_acquire_dest_image (cairo_surface_t *surface, cairo_rectangle_t *image_rect, void **image_extra) { + assert (!surface->finished); + return surface->backend->acquire_dest_image (surface, interest_rect, image_out, image_rect, image_extra); } @@ -357,6 +400,8 @@ _cairo_surface_release_dest_image (cairo_surface_t *surface, cairo_rectangle_t *image_rect, void *image_extra) { + assert (!surface->finished); + surface->backend->release_dest_image (surface, interest_rect, image, image_rect, image_extra); } @@ -386,6 +431,9 @@ _cairo_surface_clone_similar (cairo_surface_t *surface, cairo_image_surface_t *image; void *image_extra; + if (surface->finished) + return CAIRO_STATUS_SURFACE_FINISHED; + status = surface->backend->clone_similar (surface, src, clone_out); if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; @@ -409,6 +457,9 @@ _cairo_surface_clone_similar (cairo_surface_t *surface, cairo_status_t cairo_surface_set_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix) { + if (surface->finished) + return CAIRO_STATUS_SURFACE_FINISHED; + if (surface == NULL) return CAIRO_STATUS_NULL_POINTER; @@ -419,6 +470,9 @@ slim_hidden_def(cairo_surface_set_matrix); cairo_status_t cairo_surface_get_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix) { + if (surface->finished) + return CAIRO_STATUS_SURFACE_FINISHED; + if (surface == NULL) return CAIRO_STATUS_NULL_POINTER; @@ -429,6 +483,9 @@ slim_hidden_def(cairo_surface_get_matrix); cairo_status_t cairo_surface_set_filter (cairo_surface_t *surface, cairo_filter_t filter) { + if (surface->finished) + return CAIRO_STATUS_SURFACE_FINISHED; + if (surface == NULL) return CAIRO_STATUS_NULL_POINTER; @@ -460,6 +517,9 @@ cairo_surface_clip_restore (cairo_surface_t *surface); cairo_status_t cairo_surface_set_repeat (cairo_surface_t *surface, int repeat) { + if (surface->finished) + return CAIRO_STATUS_SURFACE_FINISHED; + if (surface == NULL) return CAIRO_STATUS_NULL_POINTER; @@ -552,6 +612,9 @@ _cairo_surface_composite (cairo_operator_t operator, { cairo_int_status_t status; + if (dst->finished) + return CAIRO_STATUS_SURFACE_FINISHED; + status = dst->backend->composite (operator, src, mask, dst, src_x, src_y, @@ -580,6 +643,9 @@ _cairo_surface_fill_rectangle (cairo_surface_t *surface, { cairo_rectangle_t rect; + if (surface->finished) + return CAIRO_STATUS_SURFACE_FINISHED; + rect.x = x; rect.y = y; rect.width = width; @@ -668,6 +734,9 @@ _cairo_surface_fill_rectangles (cairo_surface_t *surface, { cairo_int_status_t status; + if (surface->finished) + return CAIRO_STATUS_SURFACE_FINISHED; + if (num_rects == 0) return CAIRO_STATUS_SUCCESS; @@ -763,6 +832,9 @@ _cairo_surface_composite_trapezoids (cairo_operator_t operator, { cairo_int_status_t status; + if (dst->finished) + return CAIRO_STATUS_SURFACE_FINISHED; + status = dst->backend->composite_trapezoids (operator, pattern, dst, src_x, src_y, @@ -784,6 +856,9 @@ _cairo_surface_copy_page (cairo_surface_t *surface) { cairo_int_status_t status; + if (surface->finished) + return CAIRO_STATUS_SURFACE_FINISHED; + status = surface->backend->copy_page (surface); /* It's fine if some backends just don't support this. */ if (status == CAIRO_INT_STATUS_UNSUPPORTED) @@ -799,6 +874,9 @@ _cairo_surface_show_page (cairo_surface_t *surface) { cairo_int_status_t status; + if (surface->finished) + return CAIRO_STATUS_SURFACE_FINISHED; + status = surface->backend->show_page (surface); /* It's fine if some backends just don't support this. */ if (status == CAIRO_INT_STATUS_UNSUPPORTED) @@ -812,5 +890,39 @@ _cairo_surface_show_page (cairo_surface_t *surface) cairo_status_t _cairo_surface_set_clip_region (cairo_surface_t *surface, pixman_region16_t *region) { + if (surface->finished) + return CAIRO_STATUS_SURFACE_FINISHED; + return surface->backend->set_clip_region (surface, region); } + +cairo_status_t +_cairo_surface_show_glyphs (cairo_font_t *font, + cairo_operator_t operator, + cairo_pattern_t *pattern, + cairo_surface_t *dst, + int source_x, + int source_y, + int dest_x, + int dest_y, + unsigned int width, + unsigned int height, + const cairo_glyph_t *glyphs, + int num_glyphs) +{ + cairo_status_t status; + + if (dst->finished) + return CAIRO_STATUS_SURFACE_FINISHED; + + if (dst->backend->show_glyphs != NULL) + status = dst->backend->show_glyphs (font, operator, pattern, dst, + source_x, source_y, + dest_x, dest_y, + width, height, + glyphs, num_glyphs); + else + status = CAIRO_INT_STATUS_UNSUPPORTED; + + return status; +} diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c index dcfe6d04..e5a27b0e 100644 --- a/src/cairo-win32-surface.c +++ b/src/cairo-win32-surface.c @@ -346,7 +346,7 @@ _cairo_win32_surface_create_dib (cairo_format_t format, } static void -_cairo_win32_surface_destroy (void *abstract_surface) +_cairo_win32_surface_finish (void *abstract_surface) { cairo_win32_surface_t *surface = abstract_surface; @@ -362,8 +362,6 @@ _cairo_win32_surface_destroy (void *abstract_surface) DeleteObject (surface->bitmap); DeleteDC (surface->dc); } - - free (surface); } static double @@ -914,7 +912,7 @@ _cairo_surface_is_win32 (cairo_surface_t *surface) static const cairo_surface_backend_t cairo_win32_surface_backend = { _cairo_win32_surface_create_similar, - _cairo_win32_surface_destroy, + _cairo_win32_surface_finish, _cairo_win32_surface_pixels_per_inch, _cairo_win32_surface_acquire_source_image, _cairo_win32_surface_release_source_image, diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c index 0694b77a..aef8368f 100644 --- a/src/cairo-xcb-surface.c +++ b/src/cairo-xcb-surface.c @@ -278,7 +278,7 @@ _cairo_xcb_surface_create_similar (void *abstract_src, } static void -_cairo_xcb_surface_destroy (void *abstract_surface) +_cairo_xcb_surface_finish (void *abstract_surface) { cairo_xcb_surface_t *surface = abstract_surface; if (surface->picture.xid) @@ -291,8 +291,6 @@ _cairo_xcb_surface_destroy (void *abstract_surface) XCBFreeGC (surface->dpy, surface->gc); surface->dpy = 0; - - free (surface); } static double @@ -901,7 +899,7 @@ _cairo_xcb_surface_set_clip_region (void *abstract_surface, static const cairo_surface_backend_t cairo_xcb_surface_backend = { _cairo_xcb_surface_create_similar, - _cairo_xcb_surface_destroy, + _cairo_xcb_surface_finish, _cairo_xcb_surface_pixels_per_inch, _cairo_xcb_surface_acquire_source_image, _cairo_xcb_surface_release_source_image, diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c index 8e05a320..3aaa94d6 100644 --- a/src/cairo-xlib-surface.c +++ b/src/cairo-xlib-surface.c @@ -185,8 +185,8 @@ _cairo_xlib_surface_create_similar (void *abstract_src, return &surface->base; } -static void -_cairo_xlib_surface_destroy (void *abstract_surface) +static cairo_status_t +_cairo_xlib_surface_finish (void *abstract_surface) { cairo_xlib_surface_t *surface = abstract_surface; if (surface->picture) @@ -200,7 +200,7 @@ _cairo_xlib_surface_destroy (void *abstract_surface) surface->dpy = NULL; - free (surface); + return CAIRO_STATUS_SUCCESS; } static double @@ -959,7 +959,7 @@ _cairo_xlib_surface_show_glyphs (cairo_font_t *font, static const cairo_surface_backend_t cairo_xlib_surface_backend = { _cairo_xlib_surface_create_similar, - _cairo_xlib_surface_destroy, + _cairo_xlib_surface_finish, _cairo_xlib_surface_pixels_per_inch, _cairo_xlib_surface_acquire_source_image, _cairo_xlib_surface_release_source_image, diff --git a/src/cairo.c b/src/cairo.c index 622c88a3..9f9d1b4b 100644 --- a/src/cairo.c +++ b/src/cairo.c @@ -127,7 +127,7 @@ cairo_reference (cairo_t *cr) * * Decreases the reference count on @cr by one. If the result * is zero, then @cr and all associated resources are freed. - * See cairo_destroy(). + * See cairo_reference(). **/ void cairo_destroy (cairo_t *cr) @@ -1821,6 +1821,10 @@ cairo_status_string (cairo_t *cr) return "input string not valid UTF-8"; case CAIRO_STATUS_INVALID_PATH_DATA: return "input path data not valid"; + case CAIRO_STATUS_WRITE_ERROR: + return "error while writing to output stream"; + case CAIRO_STATUS_SURFACE_FINISHED: + return "the target surface has been finished"; } return "<unknown error status>"; diff --git a/src/cairo.h b/src/cairo.h index bac76bbd..e6c27ca8 100644 --- a/src/cairo.h +++ b/src/cairo.h @@ -107,7 +107,9 @@ typedef enum cairo_status { CAIRO_STATUS_NO_TARGET_SURFACE, CAIRO_STATUS_NULL_POINTER, CAIRO_STATUS_INVALID_STRING, - CAIRO_STATUS_INVALID_PATH_DATA + CAIRO_STATUS_INVALID_PATH_DATA, + CAIRO_STATUS_WRITE_ERROR, + CAIRO_STATUS_SURFACE_FINISHED } cairo_status_t; /* Functions for manipulating state objects */ @@ -824,6 +826,9 @@ cairo_surface_reference (cairo_surface_t *surface); void cairo_surface_destroy (cairo_surface_t *surface); +cairo_status_t +cairo_surface_finish (cairo_surface_t *surface); + /* XXX: Note: The current Render/Ic implementations don't do the right thing with repeat when the surface has a non-identity matrix. */ /* XXX: Rework this as a cairo function with an enum: cairo_set_pattern_extend */ @@ -989,6 +994,21 @@ cairo_matrix_transform_distance (cairo_matrix_t *matrix, double *dx, double *dy) cairo_status_t cairo_matrix_transform_point (cairo_matrix_t *matrix, double *x, double *y); +/** + * cairo_write_func_t + * + * #cairo_write_func_t is the type of function which is called when a + * backend needs to write data to an output stream. It is passed the + * closure which was specified by the user at the time the write + * function was registered, the data to write and the length of the + * data in bytes. The write function should return + * CAIRO_STATUS_SUCCESS if all the data was successfully written, + * CAIRO_STATUS_WRITE_ERROR otherwise. + */ +typedef cairo_status_t (*cairo_write_func_t) (void *closure, + const char *data, + unsigned int length); + #define CAIRO_API_SHAKEUP_FLAG_DAY 0 #ifndef _CAIROINT_H_ diff --git a/src/cairo_font.c b/src/cairo_font.c index 529c1c7c..f168e6f2 100644 --- a/src/cairo_font.c +++ b/src/cairo_font.c @@ -114,16 +114,15 @@ _cairo_font_show_glyphs (cairo_font_t *font, int num_glyphs) { cairo_status_t status; - if (surface->backend->show_glyphs != NULL) { - status = surface->backend->show_glyphs (font, operator, pattern, - surface, - source_x, source_y, - dest_x, dest_y, - width, height, - glyphs, num_glyphs); - if (status == CAIRO_STATUS_SUCCESS) - return status; - } + + status = _cairo_surface_show_glyphs (font, operator, pattern, + surface, + source_x, source_y, + dest_x, dest_y, + width, height, + glyphs, num_glyphs); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; /* Surface display routine either does not exist or failed. */ return font->backend->show_glyphs (font, operator, pattern, diff --git a/src/cairo_glitz_surface.c b/src/cairo_glitz_surface.c index ee664e1c..acdee9a0 100644 --- a/src/cairo_glitz_surface.c +++ b/src/cairo_glitz_surface.c @@ -54,8 +54,8 @@ typedef struct _cairo_glitz_surface { pixman_region16_t *clip; } cairo_glitz_surface_t; -static void -_cairo_glitz_surface_destroy (void *abstract_surface) +static cairo_status_t +_cairo_glitz_surface_finish (void *abstract_surface) { cairo_glitz_surface_t *surface = abstract_surface; @@ -66,7 +66,8 @@ _cairo_glitz_surface_destroy (void *abstract_surface) } glitz_surface_destroy (surface->surface); - free (surface); + + return CAIRO_STATUS_SUCCESS; } static glitz_format_name_t @@ -733,7 +734,7 @@ _cairo_glitz_pattern_release_surface (cairo_glitz_surface_t *dst, _cairo_pattern_release_surface (&dst->base, &surface->base, &attr->base); else - _cairo_glitz_surface_destroy (surface); + cairo_surface_destroy (&surface->base); } static cairo_int_status_t @@ -1277,7 +1278,7 @@ _cairo_glitz_surface_set_clip_region (void *abstract_surface, static const cairo_surface_backend_t cairo_glitz_surface_backend = { _cairo_glitz_surface_create_similar, - _cairo_glitz_surface_destroy, + _cairo_glitz_surface_finish, _cairo_glitz_surface_pixels_per_inch, _cairo_glitz_surface_acquire_source_image, _cairo_glitz_surface_release_source_image, diff --git a/src/cairo_image_surface.c b/src/cairo_image_surface.c index 9745b315..106fcf0e 100644 --- a/src/cairo_image_surface.c +++ b/src/cairo_image_surface.c @@ -234,8 +234,8 @@ _cairo_image_surface_create_similar (void *abstract_src, return cairo_image_surface_create (format, width, height); } -static void -_cairo_image_abstract_surface_destroy (void *abstract_surface) +static cairo_status_t +_cairo_image_abstract_surface_finish (void *abstract_surface) { cairo_image_surface_t *surface = abstract_surface; @@ -247,7 +247,7 @@ _cairo_image_abstract_surface_destroy (void *abstract_surface) surface->data = NULL; } - free (surface); + return CAIRO_STATUS_SUCCESS; } void @@ -658,7 +658,7 @@ _cairo_surface_is_image (cairo_surface_t *surface) static const cairo_surface_backend_t cairo_image_surface_backend = { _cairo_image_surface_create_similar, - _cairo_image_abstract_surface_destroy, + _cairo_image_abstract_surface_finish, _cairo_image_surface_pixels_per_inch, _cairo_image_surface_acquire_source_image, _cairo_image_surface_release_source_image, diff --git a/src/cairo_pdf_surface.c b/src/cairo_pdf_surface.c index fee91835..5a73e7e8 100644 --- a/src/cairo_pdf_surface.c +++ b/src/cairo_pdf_surface.c @@ -153,8 +153,10 @@ struct cairo_pdf_stream { }; struct cairo_pdf_document { - FILE *file; + cairo_output_stream_t *output_stream; unsigned long refcount; + cairo_surface_t *owner; + cairo_bool_t finished; double width_inches; double height_inches; @@ -190,15 +192,18 @@ struct cairo_pdf_surface { static cairo_pdf_document_t * -_cairo_pdf_document_create (FILE *file, - double width_inches, - double height_inches, - double x_pixels_per_inch, - double y_pixels_per_inch); +_cairo_pdf_document_create (cairo_output_stream_t *stream, + double width_inches, + double height_inches, + double x_pixels_per_inch, + double y_pixels_per_inch); static void _cairo_pdf_document_destroy (cairo_pdf_document_t *document); +static cairo_status_t +_cairo_pdf_document_finish (cairo_pdf_document_t *document); + static void _cairo_pdf_document_reference (cairo_pdf_document_t *document); @@ -814,7 +819,7 @@ _cairo_pdf_document_new_object (cairo_pdf_document_t *document) { cairo_pdf_object_t object; - object.offset = ftell (document->file); + object.offset = _cairo_output_stream_get_position (document->output_stream); if (_cairo_array_append (&document->objects, &object, 1) == NULL) return 0; @@ -828,7 +833,7 @@ _cairo_pdf_document_update_object (cairo_pdf_document_t *document, cairo_pdf_object_t *object; object = _cairo_array_index (&document->objects, id - 1); - object->offset = ftell (document->file); + object->offset = _cairo_output_stream_get_position (document->output_stream); } static void @@ -899,17 +904,17 @@ _cairo_pdf_surface_add_font (cairo_pdf_surface_t *surface, unsigned int id) _cairo_array_append (&surface->fonts, &resource, 1); } -cairo_surface_t * -cairo_pdf_surface_create (FILE *file, - double width_inches, - double height_inches, - double x_pixels_per_inch, - double y_pixels_per_inch) +static cairo_surface_t * +_cairo_pdf_surface_create_for_stream (cairo_output_stream_t *stream, + double width_inches, + double height_inches, + double x_pixels_per_inch, + double y_pixels_per_inch) { cairo_pdf_document_t *document; cairo_surface_t *surface; - document = _cairo_pdf_document_create (file, + document = _cairo_pdf_document_create (stream, width_inches, height_inches, x_pixels_per_inch, @@ -921,11 +926,54 @@ cairo_pdf_surface_create (FILE *file, width_inches, height_inches); + document->owner = surface; _cairo_pdf_document_destroy (document); return surface; } +cairo_surface_t * +cairo_pdf_surface_create (cairo_write_func_t write, + cairo_destroy_func_t destroy_closure, + void *closure, + double width_inches, + double height_inches, + double x_pixels_per_inch, + double y_pixels_per_inch) +{ + cairo_output_stream_t *stream; + + stream = _cairo_output_stream_create (write, destroy_closure, closure); + if (stream == NULL) + return NULL; + + return _cairo_pdf_surface_create_for_stream (stream, + width_inches, + height_inches, + x_pixels_per_inch, + y_pixels_per_inch); +} + +cairo_surface_t * +cairo_pdf_surface_create_for_file (FILE *fp, + double width_inches, + double height_inches, + double x_pixels_per_inch, + double y_pixels_per_inch) +{ + cairo_output_stream_t *stream; + + stream = _cairo_output_stream_create_for_file (fp); + if (stream == NULL) + return NULL; + + return _cairo_pdf_surface_create_for_stream (stream, + width_inches, + height_inches, + x_pixels_per_inch, + y_pixels_per_inch); +} + static cairo_surface_t * _cairo_pdf_surface_create_for_document (cairo_pdf_document_t *document, double width_inches, @@ -989,7 +1037,7 @@ static cairo_pdf_stream_t * _cairo_pdf_document_open_stream (cairo_pdf_document_t *document, const char *extra_entries) { - FILE *file = document->file; + cairo_output_stream_t *output_stream = document->output_stream; cairo_pdf_stream_t *stream; stream = malloc (sizeof (cairo_pdf_stream_t)); @@ -1000,17 +1048,17 @@ _cairo_pdf_document_open_stream (cairo_pdf_document_t *document, stream->id = _cairo_pdf_document_new_object (document); stream->length_id = _cairo_pdf_document_new_object (document); - fprintf (file, - "%d 0 obj\r\n" - "<< /Length %d 0 R\r\n" - "%s" - ">>\r\n" - "stream\r\n", - stream->id, - stream->length_id, - extra_entries); + _cairo_output_stream_printf (output_stream, + "%d 0 obj\r\n" + "<< /Length %d 0 R\r\n" + "%s" + ">>\r\n" + "stream\r\n", + stream->id, + stream->length_id, + extra_entries); - stream->start_offset = ftell (file); + stream->start_offset = _cairo_output_stream_get_position (output_stream); document->current_stream = stream; @@ -1020,7 +1068,7 @@ _cairo_pdf_document_open_stream (cairo_pdf_document_t *document, static void _cairo_pdf_document_close_stream (cairo_pdf_document_t *document) { - FILE *file = document->file; + cairo_output_stream_t *output_stream = document->output_stream; long length; cairo_pdf_stream_t *stream; @@ -1028,35 +1076,42 @@ _cairo_pdf_document_close_stream (cairo_pdf_document_t *document) if (stream == NULL) return; - length = ftell(file) - stream->start_offset; - fprintf (file, - "\r\n" - "endstream\r\n" - "endobj\r\n"); + length = _cairo_output_stream_get_position (output_stream) - + stream->start_offset; + _cairo_output_stream_printf (output_stream, + "\r\n" + "endstream\r\n" + "endobj\r\n"); _cairo_pdf_document_update_object (document, stream->length_id); - fprintf (file, - "%d 0 obj\r\n" - " %ld\r\n" - "endobj\r\n", - stream->length_id, - length); + _cairo_output_stream_printf (output_stream, + "%d 0 obj\r\n" + " %ld\r\n" + "endobj\r\n", + stream->length_id, + length); document->current_stream = NULL; } -static void -_cairo_pdf_surface_destroy (void *abstract_surface) +static cairo_status_t +_cairo_pdf_surface_finish (void *abstract_surface) { + cairo_status_t status; cairo_pdf_surface_t *surface = abstract_surface; cairo_pdf_document_t *document = surface->document; if (surface->current_stream == document->current_stream) _cairo_pdf_document_close_stream (document); + if (document->owner == &surface->base) + status = _cairo_pdf_document_finish (document); + else + status = CAIRO_STATUS_SUCCESS; + _cairo_pdf_document_destroy (document); - free (surface); + return status; } /* XXX: We should re-work this interface to return both X/Y ppi values. */ @@ -1073,7 +1128,7 @@ _cairo_pdf_surface_ensure_stream (cairo_pdf_surface_t *surface) { cairo_pdf_document_t *document = surface->document; cairo_pdf_stream_t *stream; - FILE *file = document->file; + cairo_output_stream_t *output = document->output_stream; char extra[200]; if (document->current_stream == NULL || @@ -1091,8 +1146,9 @@ _cairo_pdf_surface_ensure_stream (cairo_pdf_surface_t *surface) /* If this is the first stream we open for this surface, * output the cairo to PDF transformation matrix. */ if (_cairo_array_num_elements (&surface->streams) == 1) - fprintf (file, "1 0 0 -1 0 %f cm\r\n", - document->height_inches * document->y_ppi); + _cairo_output_stream_printf (output, + "1 0 0 -1 0 %f cm\r\n", + document->height_inches * document->y_ppi); } } @@ -1159,7 +1215,7 @@ static unsigned int emit_image_data (cairo_pdf_document_t *document, cairo_image_surface_t *image) { - FILE *file = document->file; + cairo_output_stream_t *output = document->output_stream; cairo_pdf_stream_t *stream; char entries[200]; char *rgb, *compressed; @@ -1202,7 +1258,7 @@ emit_image_data (cairo_pdf_document_t *document, image->width, image->height); stream = _cairo_pdf_document_open_stream (document, entries); - fwrite (compressed, 1, compressed_size, file); + _cairo_output_stream_write (output, compressed, compressed_size); _cairo_pdf_document_close_stream (document); free (rgb); @@ -1216,7 +1272,7 @@ _cairo_pdf_surface_composite_image (cairo_pdf_surface_t *dst, cairo_surface_pattern_t *pattern) { cairo_pdf_document_t *document = dst->document; - FILE *file = document->file; + cairo_output_stream_t *output = document->output_stream; unsigned id; cairo_matrix_t i2u; cairo_status_t status; @@ -1244,12 +1300,12 @@ _cairo_pdf_surface_composite_image (cairo_pdf_surface_t *dst, cairo_matrix_translate (&i2u, 0, image->height); cairo_matrix_scale (&i2u, image->width, -image->height); - fprintf (file, - "q %f %f %f %f %f %f cm /res%d Do Q\r\n", - i2u.m[0][0], i2u.m[0][1], - i2u.m[1][0], i2u.m[1][1], - i2u.m[2][0], i2u.m[2][1], - id); + _cairo_output_stream_printf (output, + "q %f %f %f %f %f %f cm /res%d Do Q\r\n", + i2u.m[0][0], i2u.m[0][1], + i2u.m[1][0], i2u.m[1][1], + i2u.m[2][0], i2u.m[2][1], + id); bail: _cairo_surface_release_source_image (src, image, image_extra); @@ -1272,7 +1328,7 @@ _cairo_pdf_surface_composite_pdf (cairo_pdf_surface_t *dst, cairo_surface_pattern_t *pattern) { cairo_pdf_document_t *document = dst->document; - FILE *file = document->file; + cairo_output_stream_t *output = document->output_stream; cairo_matrix_t i2u; cairo_pdf_stream_t *stream; int num_streams, i; @@ -1288,24 +1344,24 @@ _cairo_pdf_surface_composite_pdf (cairo_pdf_surface_t *dst, 1.0 / (src->width_inches * document->x_ppi), 1.0 / (src->height_inches * document->y_ppi)); - fprintf (file, - "q %f %f %f %f %f %f cm", - i2u.m[0][0], i2u.m[0][1], - i2u.m[1][0], i2u.m[1][1], - i2u.m[2][0], i2u.m[2][1]); + _cairo_output_stream_printf (output, + "q %f %f %f %f %f %f cm", + i2u.m[0][0], i2u.m[0][1], + i2u.m[1][0], i2u.m[1][1], + i2u.m[2][0], i2u.m[2][1]); num_streams = _cairo_array_num_elements (&src->streams); for (i = 0; i < num_streams; i++) { _cairo_array_copy_element (&src->streams, i, &stream); - fprintf (file, - " /res%d Do", - stream->id); + _cairo_output_stream_printf (output, + " /res%d Do", + stream->id); _cairo_pdf_surface_add_xobject (dst, stream->id); } - fprintf (file, " Q\r\n"); + _cairo_output_stream_printf (output, " Q\r\n"); return CAIRO_STATUS_SUCCESS; } @@ -1348,20 +1404,20 @@ _cairo_pdf_surface_fill_rectangles (void *abstract_surface, { cairo_pdf_surface_t *surface = abstract_surface; cairo_pdf_document_t *document = surface->document; - FILE *file = document->file; + cairo_output_stream_t *output = document->output_stream; int i; _cairo_pdf_surface_ensure_stream (surface); - fprintf (file, - "%f %f %f rg\r\n", - color->red, color->green, color->blue); + _cairo_output_stream_printf (output, + "%f %f %f rg\r\n", + color->red, color->green, color->blue); for (i = 0; i < num_rects; i++) { - fprintf (file, - "%d %d %d %d re f\r\n", - rects[i].x, rects[i].y, - rects[i].width, rects[i].height); + _cairo_output_stream_printf (output, + "%d %d %d %d re f\r\n", + rects[i].x, rects[i].y, + rects[i].width, rects[i].height); } return CAIRO_STATUS_SUCCESS; @@ -1372,17 +1428,17 @@ emit_solid_pattern (cairo_pdf_surface_t *surface, cairo_solid_pattern_t *pattern) { cairo_pdf_document_t *document = surface->document; - FILE *file = document->file; + cairo_output_stream_t *output = document->output_stream; unsigned int alpha; alpha = _cairo_pdf_surface_add_alpha (surface, pattern->base.alpha); _cairo_pdf_surface_ensure_stream (surface); - fprintf (file, - "%f %f %f rg /a%d gs\r\n", - pattern->red, - pattern->green, - pattern->blue, - alpha); + _cairo_output_stream_printf (output, + "%f %f %f rg /a%d gs\r\n", + pattern->red, + pattern->green, + pattern->blue, + alpha); } static void @@ -1390,7 +1446,7 @@ emit_surface_pattern (cairo_pdf_surface_t *dst, cairo_surface_pattern_t *pattern) { cairo_pdf_document_t *document = dst->document; - FILE *file = document->file; + cairo_output_stream_t *output = document->output_stream; cairo_pdf_stream_t *stream; cairo_image_surface_t *image; void *image_extra; @@ -1441,9 +1497,9 @@ emit_surface_pattern (cairo_pdf_surface_t *dst, _cairo_pdf_surface_ensure_stream (dst); alpha = _cairo_pdf_surface_add_alpha (dst, 1.0); - fprintf (file, - "/Pattern cs /res%d scn /a%d gs\r\n", - stream->id, alpha); + _cairo_output_stream_printf (output, + "/Pattern cs /res%d scn /a%d gs\r\n", + stream->id, alpha); _cairo_surface_release_source_image (pattern->surface, image, image_extra); } @@ -1452,33 +1508,37 @@ static unsigned int emit_pattern_stops (cairo_pdf_surface_t *surface, cairo_gradient_pattern_t *pattern) { cairo_pdf_document_t *document = surface->document; - FILE *file = document->file; + cairo_output_stream_t *output = document->output_stream; unsigned int function_id; + char stops[2][3]; function_id = _cairo_pdf_document_new_object (document); - fprintf (file, - "%d 0 obj\r\n" - "<< /FunctionType 0\r\n" - " /Domain [ 0.0 1.0 ]\r\n" - " /Size [ 2 ]\r\n" - " /BitsPerSample 8\r\n" - " /Range [ 0.0 1.0 0.0 1.0 0.0 1.0 ]\r\n" - " /Length 6\r\n" - ">>\r\n" - "stream\r\n", - function_id); - - fputc (pattern->stops[0].color.red * 0xff, file); - fputc (pattern->stops[0].color.green * 0xff, file); - fputc (pattern->stops[0].color.blue * 0xff, file); - fputc (pattern->stops[1].color.red * 0xff, file); - fputc (pattern->stops[1].color.green * 0xff, file); - fputc (pattern->stops[1].color.blue * 0xff, file); - - fprintf (file, - "\r\n" - "endstream\r\n" - "endobj\r\n"); + + _cairo_output_stream_printf (output, + "%d 0 obj\r\n" + "<< /FunctionType 0\r\n" + " /Domain [ 0.0 1.0 ]\r\n" + " /Size [ 2 ]\r\n" + " /BitsPerSample 8\r\n" + " /Range [ 0.0 1.0 0.0 1.0 0.0 1.0 ]\r\n" + " /Length 6\r\n" + ">>\r\n" + "stream\r\n", + function_id); + + stops[0][0] = pattern->stops[0].color.red * 0xff + 0.5; + stops[0][1] = pattern->stops[0].color.green * 0xff + 0.5; + stops[0][2] = pattern->stops[0].color.blue * 0xff + 0.5; + stops[1][0] = pattern->stops[1].color.red * 0xff + 0.5; + stops[1][1] = pattern->stops[1].color.green * 0xff + 0.5; + stops[1][2] = pattern->stops[1].color.blue * 0xff + 0.5; + + _cairo_output_stream_write (output, stops, sizeof (stops)); + + _cairo_output_stream_printf (output, + "\r\n" + "endstream\r\n" + "endobj\r\n"); return function_id; } @@ -1487,7 +1547,7 @@ static void emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_linear_pattern_t *pattern) { cairo_pdf_document_t *document = surface->document; - FILE *file = document->file; + cairo_output_stream_t *output = document->output_stream; unsigned int function_id, pattern_id, alpha; double x0, y0, x1, y1; cairo_matrix_t p2u; @@ -1507,24 +1567,24 @@ emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_linear_pattern_t *patte cairo_matrix_transform_point (&p2u, &x1, &y1); pattern_id = _cairo_pdf_document_new_object (document); - fprintf (file, - "%d 0 obj\r\n" - "<< /Type /Pattern\r\n" - " /PatternType 2\r\n" - " /Matrix [ 1 0 0 -1 0 %f ]\r\n" - " /Shading\r\n" - " << /ShadingType 2\r\n" - " /ColorSpace /DeviceRGB\r\n" - " /Coords [ %f %f %f %f ]\r\n" - " /Function %d 0 R\r\n" - " /Extend [ true true ]\r\n" - " >>\r\n" - ">>\r\n" - "endobj\r\n", - pattern_id, - document->height_inches * document->y_ppi, - x0, y0, x1, y1, - function_id); + _cairo_output_stream_printf (output, + "%d 0 obj\r\n" + "<< /Type /Pattern\r\n" + " /PatternType 2\r\n" + " /Matrix [ 1 0 0 -1 0 %f ]\r\n" + " /Shading\r\n" + " << /ShadingType 2\r\n" + " /ColorSpace /DeviceRGB\r\n" + " /Coords [ %f %f %f %f ]\r\n" + " /Function %d 0 R\r\n" + " /Extend [ true true ]\r\n" + " >>\r\n" + ">>\r\n" + "endobj\r\n", + pattern_id, + document->height_inches * document->y_ppi, + x0, y0, x1, y1, + function_id); _cairo_pdf_surface_add_pattern (surface, pattern_id); @@ -1532,16 +1592,16 @@ emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_linear_pattern_t *patte alpha = _cairo_pdf_surface_add_alpha (surface, 1.0); /* Use pattern */ - fprintf (file, - "/Pattern cs /res%d scn /a%d gs\r\n", - pattern_id, alpha); + _cairo_output_stream_printf (output, + "/Pattern cs /res%d scn /a%d gs\r\n", + pattern_id, alpha); } static void emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_radial_pattern_t *pattern) { cairo_pdf_document_t *document = surface->document; - FILE *file = document->file; + cairo_output_stream_t *output = document->output_stream; unsigned int function_id, pattern_id, alpha; double x0, y0, x1, y1, r0, r1; cairo_matrix_t p2u; @@ -1574,24 +1634,24 @@ emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_radial_pattern_t *patte * behavoir, not yet sure how to implement the cairo mirror and * repeat behaviour. */ pattern_id = _cairo_pdf_document_new_object (document); - fprintf (file, - "%d 0 obj\r\n" - "<< /Type /Pattern\r\n" - " /PatternType 2\r\n" - " /Matrix [ 1 0 0 -1 0 %f ]\r\n" - " /Shading\r\n" - " << /ShadingType 3\r\n" - " /ColorSpace /DeviceRGB\r\n" - " /Coords [ %f %f %f %f %f %f ]\r\n" - " /Function %d 0 R\r\n" - " /Extend [ true true ]\r\n" - " >>\r\n" - ">>\r\n" - "endobj\r\n", - pattern_id, - document->height_inches * document->y_ppi, - x0, y0, r0, x1, y1, r1, - function_id); + _cairo_output_stream_printf (output, + "%d 0 obj\r\n" + "<< /Type /Pattern\r\n" + " /PatternType 2\r\n" + " /Matrix [ 1 0 0 -1 0 %f ]\r\n" + " /Shading\r\n" + " << /ShadingType 3\r\n" + " /ColorSpace /DeviceRGB\r\n" + " /Coords [ %f %f %f %f %f %f ]\r\n" + " /Function %d 0 R\r\n" + " /Extend [ true true ]\r\n" + " >>\r\n" + ">>\r\n" + "endobj\r\n", + pattern_id, + document->height_inches * document->y_ppi, + x0, y0, r0, x1, y1, r1, + function_id); _cairo_pdf_surface_add_pattern (surface, pattern_id); @@ -1599,9 +1659,9 @@ emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_radial_pattern_t *patte alpha = _cairo_pdf_surface_add_alpha (surface, 1.0); /* Use pattern */ - fprintf (file, - "/Pattern cs /res%d scn /a%d gs\r\n", - pattern_id, alpha); + _cairo_output_stream_printf (output, + "/Pattern cs /res%d scn /a%d gs\r\n", + pattern_id, alpha); } static void @@ -1650,7 +1710,7 @@ _cairo_pdf_surface_composite_trapezoids (cairo_operator_t operator, { cairo_pdf_surface_t *surface = abstract_dst; cairo_pdf_document_t *document = surface->document; - FILE *file = document->file; + cairo_output_stream_t *output = document->output_stream; int i; emit_pattern (surface, pattern); @@ -1668,16 +1728,16 @@ _cairo_pdf_surface_composite_trapezoids (cairo_operator_t operator, right_x1 = intersect (&traps[i].right, traps[i].top); right_x2 = intersect (&traps[i].right, traps[i].bottom); - fprintf (file, - "%f %f m %f %f l %f %f l %f %f l h\r\n", - left_x1, _cairo_fixed_to_double (traps[i].top), - left_x2, _cairo_fixed_to_double (traps[i].bottom), - right_x2, _cairo_fixed_to_double (traps[i].bottom), - right_x1, _cairo_fixed_to_double (traps[i].top)); + _cairo_output_stream_printf (output, + "%f %f m %f %f l %f %f l %f %f l h\r\n", + left_x1, _cairo_fixed_to_double (traps[i].top), + left_x2, _cairo_fixed_to_double (traps[i].bottom), + right_x2, _cairo_fixed_to_double (traps[i].bottom), + right_x1, _cairo_fixed_to_double (traps[i].top)); } - fprintf (file, - "f\r\n"); + _cairo_output_stream_printf (output, + "f\r\n"); return CAIRO_STATUS_SUCCESS; } @@ -1759,7 +1819,7 @@ _cairo_pdf_surface_show_glyphs (cairo_font_t *font, { cairo_pdf_surface_t *surface = abstract_surface; cairo_pdf_document_t *document = surface->document; - FILE *file = document->file; + cairo_output_stream_t *output = document->output_stream; cairo_pdf_font_t *pdf_font; int i, index; @@ -1769,22 +1829,24 @@ _cairo_pdf_surface_show_glyphs (cairo_font_t *font, emit_pattern (surface, pattern); - fprintf (file, "BT /res%u 1 Tf", pdf_font->font_id); + _cairo_output_stream_printf (output, + "BT /res%u 1 Tf", pdf_font->font_id); for (i = 0; i < num_glyphs; i++) { index = cairo_pdf_font_use_glyph (pdf_font, glyphs[i].index); - fprintf (file, - " %f %f %f %f %f %f Tm (\\%o) Tj", - font->scale.matrix[0][0], - font->scale.matrix[0][1], - font->scale.matrix[1][0], - -font->scale.matrix[1][1], - glyphs[i].x, - glyphs[i].y, - index); + _cairo_output_stream_printf (output, + " %f %f %f %f %f %f Tm (\\%o) Tj", + font->scale.matrix[0][0], + font->scale.matrix[0][1], + font->scale.matrix[1][0], + -font->scale.matrix[1][1], + glyphs[i].x, + glyphs[i].y, + index); } - fprintf (file, " ET\r\n"); + _cairo_output_stream_printf (output, + " ET\r\n"); _cairo_pdf_surface_add_font (surface, pdf_font->font_id); @@ -1793,7 +1855,7 @@ _cairo_pdf_surface_show_glyphs (cairo_font_t *font, static const cairo_surface_backend_t cairo_pdf_surface_backend = { _cairo_pdf_surface_create_similar, - _cairo_pdf_surface_destroy, + _cairo_pdf_surface_finish, _cairo_pdf_surface_pixels_per_inch, _cairo_pdf_surface_acquire_source_image, _cairo_pdf_surface_release_source_image, @@ -1810,11 +1872,11 @@ static const cairo_surface_backend_t cairo_pdf_surface_backend = { }; static cairo_pdf_document_t * -_cairo_pdf_document_create (FILE *file, - double width_inches, - double height_inches, - double x_pixels_per_inch, - double y_pixels_per_inch) +_cairo_pdf_document_create (cairo_output_stream_t *output_stream, + double width_inches, + double height_inches, + double x_pixels_per_inch, + double y_pixels_per_inch) { cairo_pdf_document_t *document; @@ -1822,8 +1884,10 @@ _cairo_pdf_document_create (FILE *file, if (document == NULL) return NULL; - document->file = file; + document->output_stream = output_stream; document->refcount = 1; + document->owner = NULL; + document->finished = FALSE; document->width_inches = width_inches; document->height_inches = height_inches; document->x_ppi = x_pixels_per_inch; @@ -1840,7 +1904,8 @@ _cairo_pdf_document_create (FILE *file, _cairo_array_init (&document->fonts, sizeof (cairo_pdf_font_t *)); /* Document header */ - fprintf (file, "%%PDF-1.4\r\n"); + _cairo_output_stream_printf (output_stream, + "%%PDF-1.4\r\n"); return document; } @@ -1848,17 +1913,17 @@ _cairo_pdf_document_create (FILE *file, static unsigned int _cairo_pdf_document_write_info (cairo_pdf_document_t *document) { - FILE *file = document->file; + cairo_output_stream_t *output = document->output_stream; unsigned int id; id = _cairo_pdf_document_new_object (document); - fprintf (file, - "%d 0 obj\r\n" - "<< /Creator (cairographics.org)\r\n" - " /Producer (cairographics.org)\r\n" - ">>\r\n" - "endobj\r\n", - id); + _cairo_output_stream_printf (output, + "%d 0 obj\r\n" + "<< /Creator (cairographics.org)\r\n" + " /Producer (cairographics.org)\r\n" + ">>\r\n" + "endobj\r\n", + id); return id; } @@ -1866,40 +1931,40 @@ _cairo_pdf_document_write_info (cairo_pdf_document_t *document) static void _cairo_pdf_document_write_pages (cairo_pdf_document_t *document) { - FILE *file = document->file; + cairo_output_stream_t *stream = document->output_stream; unsigned int page_id; int num_pages, i; _cairo_pdf_document_update_object (document, document->pages_id); - fprintf (file, - "%d 0 obj\r\n" - "<< /Type /Pages\r\n" - " /Kids [ ", - document->pages_id); + _cairo_output_stream_printf (stream, + "%d 0 obj\r\n" + "<< /Type /Pages\r\n" + " /Kids [ ", + document->pages_id); num_pages = _cairo_array_num_elements (&document->pages); for (i = 0; i < num_pages; i++) { _cairo_array_copy_element (&document->pages, i, &page_id); - fprintf (file, "%d 0 R ", page_id); + _cairo_output_stream_printf (stream, "%d 0 R ", page_id); } - fprintf (file, "]\r\n"); - fprintf (file, " /Count %d\r\n", num_pages); + _cairo_output_stream_printf (stream, "]\r\n"); + _cairo_output_stream_printf (stream, " /Count %d\r\n", num_pages); /* TODO: Figure out wich other defaults to be inherited by /Page * objects. */ - fprintf (file, - " /MediaBox [ 0 0 %f %f ]\r\n" - ">>\r\n" - "endobj\r\n", - document->width_inches * document->x_ppi, - document->height_inches * document->y_ppi); + _cairo_output_stream_printf (stream, + " /MediaBox [ 0 0 %f %f ]\r\n" + ">>\r\n" + "endobj\r\n", + document->width_inches * document->x_ppi, + document->height_inches * document->y_ppi); } static cairo_status_t _cairo_pdf_document_write_fonts (cairo_pdf_document_t *document) { - FILE *file = document->file; + cairo_output_stream_t *output = document->output_stream; cairo_pdf_font_t *font; int num_fonts, i, j; const char *data; @@ -1923,76 +1988,76 @@ _cairo_pdf_document_write_fonts (cairo_pdf_document_t *document) } stream_id = _cairo_pdf_document_new_object (document); - fprintf (file, - "%d 0 obj\r\n" - "<< /Filter /FlateDecode\r\n" - " /Length %lu\r\n" - " /Length1 %lu\r\n" - ">>\r\n" - "stream\r\n", - stream_id, - compressed_size, - data_size); - fwrite (compressed, 1, compressed_size, file); - fprintf (file, - "\r\n" - "endstream\r\n" - "endobj\r\n"); + _cairo_output_stream_printf (output, + "%d 0 obj\r\n" + "<< /Filter /FlateDecode\r\n" + " /Length %lu\r\n" + " /Length1 %lu\r\n" + ">>\r\n" + "stream\r\n", + stream_id, + compressed_size, + data_size); + _cairo_output_stream_write (output, compressed, compressed_size); + _cairo_output_stream_printf (output, + "\r\n" + "endstream\r\n" + "endobj\r\n"); free (compressed); descriptor_id = _cairo_pdf_document_new_object (document); - fprintf (file, - "%d 0 obj\r\n" - "<< /Type /FontDescriptor\r\n" - " /FontName /7%s\r\n" - " /Flags 4\r\n" - " /FontBBox [ %ld %ld %ld %ld ]\r\n" - " /ItalicAngle 0\r\n" - " /Ascent %ld\r\n" - " /Descent %ld\r\n" - " /CapHeight 500\r\n" - " /StemV 80\r\n" - " /StemH 80\r\n" - " /FontFile2 %u 0 R\r\n" - ">>\r\n" - "endobj\r\n", - descriptor_id, - font->base_font, - font->x_min, - font->y_min, - font->x_max, - font->y_max, - font->ascent, - font->descent, - stream_id); + _cairo_output_stream_printf (output, + "%d 0 obj\r\n" + "<< /Type /FontDescriptor\r\n" + " /FontName /7%s\r\n" + " /Flags 4\r\n" + " /FontBBox [ %ld %ld %ld %ld ]\r\n" + " /ItalicAngle 0\r\n" + " /Ascent %ld\r\n" + " /Descent %ld\r\n" + " /CapHeight 500\r\n" + " /StemV 80\r\n" + " /StemH 80\r\n" + " /FontFile2 %u 0 R\r\n" + ">>\r\n" + "endobj\r\n", + descriptor_id, + font->base_font, + font->x_min, + font->y_min, + font->x_max, + font->y_max, + font->ascent, + font->descent, + stream_id); _cairo_pdf_document_update_object (document, font->font_id); - fprintf (file, - "%d 0 obj\r\n" - "<< /Type /Font\r\n" - " /Subtype /TrueType\r\n" - " /BaseFont /%s\r\n" - " /FirstChar 0\r\n" - " /LastChar %d\r\n" - " /FontDescriptor %d 0 R\r\n" - " /Widths ", - font->font_id, - font->base_font, - font->num_glyphs, - descriptor_id); - - fprintf (file, - "["); + _cairo_output_stream_printf (output, + "%d 0 obj\r\n" + "<< /Type /Font\r\n" + " /Subtype /TrueType\r\n" + " /BaseFont /%s\r\n" + " /FirstChar 0\r\n" + " /LastChar %d\r\n" + " /FontDescriptor %d 0 R\r\n" + " /Widths ", + font->font_id, + font->base_font, + font->num_glyphs, + descriptor_id); + + _cairo_output_stream_printf (output, + "["); for (j = 0; j < font->num_glyphs; j++) - fprintf (file, - " %d", - font->widths[j]); + _cairo_output_stream_printf (output, + " %d", + font->widths[j]); - fprintf (file, - " ]\r\n" - ">>\r\n" - "endobj\r\n"); + _cairo_output_stream_printf (output, + " ]\r\n" + ">>\r\n" + "endobj\r\n"); fail: cairo_pdf_ft_font_destroy (font); @@ -2004,17 +2069,17 @@ _cairo_pdf_document_write_fonts (cairo_pdf_document_t *document) static unsigned int _cairo_pdf_document_write_catalog (cairo_pdf_document_t *document) { - FILE *file = document->file; + cairo_output_stream_t *output = document->output_stream; unsigned int id; id = _cairo_pdf_document_new_object (document); - fprintf (file, - "%d 0 obj\r\n" - "<< /Type /Catalog\r\n" - " /Pages %d 0 R\r\n" - ">>\r\n" - "endobj\r\n", - id, document->pages_id); + _cairo_output_stream_printf (output, + "%d 0 obj\r\n" + "<< /Type /Catalog\r\n" + " /Pages %d 0 R\r\n" + ">>\r\n" + "endobj\r\n", + id, document->pages_id); return id; } @@ -2022,23 +2087,25 @@ _cairo_pdf_document_write_catalog (cairo_pdf_document_t *document) static long _cairo_pdf_document_write_xref (cairo_pdf_document_t *document) { - FILE *file = document->file; + cairo_output_stream_t *output = document->output_stream; cairo_pdf_object_t *object; int num_objects, i; long offset; num_objects = _cairo_array_num_elements (&document->objects); - offset = ftell(file); - fprintf (document->file, - "xref\r\n" - "%d %d\r\n", - 0, num_objects + 1); + offset = _cairo_output_stream_get_position (output); + _cairo_output_stream_printf (output, + "xref\r\n" + "%d %d\r\n", + 0, num_objects + 1); - fprintf (file, "0000000000 65535 f\r\n"); + _cairo_output_stream_printf (output, + "0000000000 65535 f\r\n"); for (i = 0; i < num_objects; i++) { object = _cairo_array_index (&document->objects, i); - fprintf (file, "%010ld 00000 n\r\n", object->offset); + _cairo_output_stream_printf (output, + "%010ld 00000 n\r\n", object->offset); } return offset; @@ -2053,14 +2120,25 @@ _cairo_pdf_document_reference (cairo_pdf_document_t *document) static void _cairo_pdf_document_destroy (cairo_pdf_document_t *document) { - FILE *file = document->file; - long offset; - unsigned int info_id, catalog_id; - document->refcount--; if (document->refcount > 0) return; + _cairo_pdf_document_finish (document); + + free (document); +} + +static cairo_status_t +_cairo_pdf_document_finish (cairo_pdf_document_t *document) +{ + cairo_output_stream_t *output = document->output_stream; + long offset; + unsigned int info_id, catalog_id; + + if (document->finished) + return CAIRO_STATUS_SUCCESS; + _cairo_pdf_document_close_stream (document); _cairo_pdf_document_write_pages (document); _cairo_pdf_document_write_fonts (document); @@ -2068,23 +2146,26 @@ _cairo_pdf_document_destroy (cairo_pdf_document_t *document) catalog_id = _cairo_pdf_document_write_catalog (document); offset = _cairo_pdf_document_write_xref (document); - fprintf (file, - "trailer\r\n" - "<< /Size %d\r\n" - " /Root %d 0 R\r\n" - " /Info %d 0 R\r\n" - ">>\r\n", - document->next_available_id, - catalog_id, - info_id); - - fprintf (file, - "startxref\r\n" - "%ld\r\n" - "%%%%EOF\r\n", - offset); + _cairo_output_stream_printf (output, + "trailer\r\n" + "<< /Size %d\r\n" + " /Root %d 0 R\r\n" + " /Info %d 0 R\r\n" + ">>\r\n", + document->next_available_id, + catalog_id, + info_id); - free (document); + _cairo_output_stream_printf (output, + "startxref\r\n" + "%ld\r\n" + "%%%%EOF\r\n", + offset); + + _cairo_output_stream_destroy (output); + document->finished = TRUE; + + return _cairo_output_stream_get_status (output); } static cairo_status_t @@ -2093,122 +2174,124 @@ _cairo_pdf_document_add_page (cairo_pdf_document_t *document, { cairo_pdf_stream_t *stream; cairo_pdf_resource_t *res; - FILE *file = document->file; + cairo_output_stream_t *output = document->output_stream; unsigned int page_id; double alpha; int num_streams, num_alphas, num_resources, i; + assert (!document->finished); + _cairo_pdf_document_close_stream (document); page_id = _cairo_pdf_document_new_object (document); - fprintf (file, - "%d 0 obj\r\n" - "<< /Type /Page\r\n" - " /Parent %d 0 R\r\n" - " /Contents [", - page_id, - document->pages_id); + _cairo_output_stream_printf (output, + "%d 0 obj\r\n" + "<< /Type /Page\r\n" + " /Parent %d 0 R\r\n" + " /Contents [", + page_id, + document->pages_id); num_streams = _cairo_array_num_elements (&surface->streams); for (i = 0; i < num_streams; i++) { _cairo_array_copy_element (&surface->streams, i, &stream); - fprintf (file, - " %d 0 R", - stream->id); + _cairo_output_stream_printf (output, + " %d 0 R", + stream->id); } - fprintf (file, - " ]\r\n" - " /Resources <<\r\n"); + _cairo_output_stream_printf (output, + " ]\r\n" + " /Resources <<\r\n"); num_resources = _cairo_array_num_elements (&surface->fonts); if (num_resources > 0) { - fprintf (file, - " /Font <<"); + _cairo_output_stream_printf (output, + " /Font <<"); for (i = 0; i < num_resources; i++) { res = _cairo_array_index (&surface->fonts, i); - fprintf (file, - " /res%d %d 0 R", - res->id, res->id); + _cairo_output_stream_printf (output, + " /res%d %d 0 R", + res->id, res->id); } - fprintf (file, - " >>\r\n"); + _cairo_output_stream_printf (output, + " >>\r\n"); } num_alphas = _cairo_array_num_elements (&surface->alphas); if (num_alphas > 0) { - fprintf (file, - " /ExtGState <<\r\n"); + _cairo_output_stream_printf (output, + " /ExtGState <<\r\n"); for (i = 0; i < num_alphas; i++) { _cairo_array_copy_element (&surface->alphas, i, &alpha); - fprintf (file, - " /a%d << /ca %f >>\r\n", - i, alpha); + _cairo_output_stream_printf (output, + " /a%d << /ca %f >>\r\n", + i, alpha); } - fprintf (file, - " >>\r\n"); + _cairo_output_stream_printf (output, + " >>\r\n"); } num_resources = _cairo_array_num_elements (&surface->patterns); if (num_resources > 0) { - fprintf (file, - " /Pattern <<"); + _cairo_output_stream_printf (output, + " /Pattern <<"); for (i = 0; i < num_resources; i++) { res = _cairo_array_index (&surface->patterns, i); - fprintf (file, - " /res%d %d 0 R", - res->id, res->id); + _cairo_output_stream_printf (output, + " /res%d %d 0 R", + res->id, res->id); } - fprintf (file, - " >>\r\n"); + _cairo_output_stream_printf (output, + " >>\r\n"); } num_resources = _cairo_array_num_elements (&surface->xobjects); if (num_resources > 0) { - fprintf (file, - " /XObject <<"); + _cairo_output_stream_printf (output, + " /XObject <<"); for (i = 0; i < num_resources; i++) { res = _cairo_array_index (&surface->xobjects, i); - fprintf (file, - " /res%d %d 0 R", - res->id, res->id); + _cairo_output_stream_printf (output, + " /res%d %d 0 R", + res->id, res->id); } - fprintf (file, - " >>\r\n"); + _cairo_output_stream_printf (output, + " >>\r\n"); } - fprintf (file, - " >>\r\n" - ">>\r\n" - "endobj\r\n"); + _cairo_output_stream_printf (output, + " >>\r\n" + ">>\r\n" + "endobj\r\n"); _cairo_array_append (&document->pages, &page_id, 1); return CAIRO_STATUS_SUCCESS; } -void -cairo_set_target_pdf (cairo_t *cr, - FILE *file, - double width_inches, - double height_inches, - double x_pixels_per_inch, - double y_pixels_per_inch) +static void +_cairo_set_target_pdf_as_stream (cairo_t *cr, + cairo_output_stream_t *stream, + double width_inches, + double height_inches, + double x_pixels_per_inch, + double y_pixels_per_inch) { cairo_surface_t *surface; - surface = cairo_pdf_surface_create (file, - width_inches, - height_inches, - x_pixels_per_inch, - y_pixels_per_inch); + surface = _cairo_pdf_surface_create_for_stream (stream, + width_inches, + height_inches, + x_pixels_per_inch, + y_pixels_per_inch); if (surface == NULL) { cr->status = CAIRO_STATUS_NO_MEMORY; @@ -2220,3 +2303,51 @@ cairo_set_target_pdf (cairo_t *cr, /* cairo_set_target_surface takes a reference, so we must destroy ours */ cairo_surface_destroy (surface); } + +void +cairo_set_target_pdf (cairo_t *cr, + cairo_write_func_t write, + cairo_destroy_func_t destroy_closure, + void *closure, + double width_inches, + double height_inches, + double x_pixels_per_inch, + double y_pixels_per_inch) +{ + cairo_output_stream_t *stream; + + stream = _cairo_output_stream_create (write, destroy_closure, closure); + if (stream == NULL) { + cr->status = CAIRO_STATUS_NO_MEMORY; + return; + } + + return _cairo_set_target_pdf_as_stream (cr, stream, + width_inches, + height_inches, + x_pixels_per_inch, + y_pixels_per_inch); +} + +void +cairo_set_target_pdf_as_file (cairo_t *cr, + FILE *fp, + double width_inches, + double height_inches, + double x_pixels_per_inch, + double y_pixels_per_inch) +{ + cairo_output_stream_t *stream; + + stream = _cairo_output_stream_create_for_file (fp); + if (stream == NULL) { + cr->status = CAIRO_STATUS_NO_MEMORY; + return; + } + + return _cairo_set_target_pdf_as_stream (cr, stream, + width_inches, + height_inches, + x_pixels_per_inch, + y_pixels_per_inch); +} diff --git a/src/cairo_png_surface.c b/src/cairo_png_surface.c index 1ae745cb..b016cea4 100644 --- a/src/cairo_png_surface.c +++ b/src/cairo_png_surface.c @@ -150,8 +150,8 @@ unpremultiply_data (png_structp png, png_row_infop row_info, png_bytep data) } } -static void -_cairo_png_surface_destroy (void *abstract_surface) +static cairo_status_t +_cairo_png_surface_finish (void *abstract_surface) { cairo_png_surface_t *surface = abstract_surface; @@ -160,7 +160,7 @@ _cairo_png_surface_destroy (void *abstract_surface) cairo_surface_destroy (&surface->image->base); - free (surface); + return CAIRO_STATUS_SUCCESS; } static void @@ -408,7 +408,7 @@ _cairo_png_surface_set_clip_region (void *abstract_surface, static const cairo_surface_backend_t cairo_png_surface_backend = { _cairo_png_surface_create_similar, - _cairo_png_surface_destroy, + _cairo_png_surface_finish, _cairo_png_surface_pixels_per_inch, _cairo_png_surface_acquire_source_image, _cairo_png_surface_release_source_image, diff --git a/src/cairo_ps_surface.c b/src/cairo_ps_surface.c index 4a45fc67..a0a92dc2 100644 --- a/src/cairo_ps_surface.c +++ b/src/cairo_ps_surface.c @@ -170,8 +170,8 @@ _cairo_ps_surface_create_similar (void *abstract_src, return NULL; } -static void -_cairo_ps_surface_destroy (void *abstract_surface) +static cairo_status_t +_cairo_ps_surface_finish (void *abstract_surface) { cairo_ps_surface_t *surface = abstract_surface; @@ -180,7 +180,7 @@ _cairo_ps_surface_destroy (void *abstract_surface) cairo_surface_destroy (&surface->image->base); - free (surface); + return CAIRO_STATUS_SUCCESS; } static void @@ -426,7 +426,7 @@ _cairo_ps_surface_set_clip_region (void *abstract_surface, static const cairo_surface_backend_t cairo_ps_surface_backend = { _cairo_ps_surface_create_similar, - _cairo_ps_surface_destroy, + _cairo_ps_surface_finish, _cairo_ps_surface_pixels_per_inch, _cairo_ps_surface_acquire_source_image, _cairo_ps_surface_release_source_image, diff --git a/src/cairo_surface.c b/src/cairo_surface.c index 2afedc2c..18b4eb07 100644 --- a/src/cairo_surface.c +++ b/src/cairo_surface.c @@ -51,6 +51,8 @@ _cairo_surface_init (cairo_surface_t *surface, surface->backend = backend; surface->ref_count = 1; + surface->finished = FALSE; + _cairo_array_init (&surface->user_data_slots, sizeof (cairo_user_data_slot_t)); @@ -164,14 +166,49 @@ cairo_surface_destroy (cairo_surface_t *surface) if (surface->ref_count) return; - if (surface->backend->destroy) - surface->backend->destroy (surface); + cairo_surface_finish (surface); _destroy_user_data (surface); + + free (surface); } slim_hidden_def(cairo_surface_destroy); /** + * cairo_surface_finish: + * @surface: the #cairo_surface_t to finish + * + * This function finishes the surface and drops all references to + * external resources. For example, for the Xlib backend it means + * that cairo will no longer access the drawable, which can be freed. + * After calling cairo_surface_finish() the only valid operations on a + * surface are getting and setting user data and referencing and + * destroying it. Further drawing the the surface will not affect the + * surface but set the surface status to + * CAIRO_STATUS_SURFACE_FINISHED. + * + * When the last call to cairo_surface_destroy() decreases the + * reference count to zero, cairo will call cairo_surface_finish() if + * it hasn't been called already, before freeing the resources + * associated with the surface. + * + * Return value: CAIRO_STATUS_SUCCESS if the surface was finished + * successfully, otherwise CAIRO_STATUS_NO_MEMORY or + * CAIRO_STATUS_WRITE_ERROR. + **/ +cairo_status_t +cairo_surface_finish (cairo_surface_t *surface) +{ + if (surface->finished) + return CAIRO_STATUS_SURFACE_FINISHED; + + if (surface->backend->finish) + return surface->backend->finish (surface); + + return CAIRO_STATUS_SUCCESS; +} + +/** * cairo_surface_get_user_data: * @surface: a #cairo_surface_t * @key: the address of the #cairo_user_data_key_t the user data was @@ -281,6 +318,8 @@ _cairo_surface_acquire_source_image (cairo_surface_t *surface, cairo_image_surface_t **image_out, void **image_extra) { + assert (!surface->finished); + return surface->backend->acquire_source_image (surface, image_out, image_extra); } @@ -296,6 +335,8 @@ _cairo_surface_release_source_image (cairo_surface_t *surface, cairo_image_surface_t *image, void *image_extra) { + assert (!surface->finished); + surface->backend->release_source_image (surface, image, image_extra); } @@ -334,6 +375,8 @@ _cairo_surface_acquire_dest_image (cairo_surface_t *surface, cairo_rectangle_t *image_rect, void **image_extra) { + assert (!surface->finished); + return surface->backend->acquire_dest_image (surface, interest_rect, image_out, image_rect, image_extra); } @@ -357,6 +400,8 @@ _cairo_surface_release_dest_image (cairo_surface_t *surface, cairo_rectangle_t *image_rect, void *image_extra) { + assert (!surface->finished); + surface->backend->release_dest_image (surface, interest_rect, image, image_rect, image_extra); } @@ -386,6 +431,9 @@ _cairo_surface_clone_similar (cairo_surface_t *surface, cairo_image_surface_t *image; void *image_extra; + if (surface->finished) + return CAIRO_STATUS_SURFACE_FINISHED; + status = surface->backend->clone_similar (surface, src, clone_out); if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; @@ -409,6 +457,9 @@ _cairo_surface_clone_similar (cairo_surface_t *surface, cairo_status_t cairo_surface_set_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix) { + if (surface->finished) + return CAIRO_STATUS_SURFACE_FINISHED; + if (surface == NULL) return CAIRO_STATUS_NULL_POINTER; @@ -419,6 +470,9 @@ slim_hidden_def(cairo_surface_set_matrix); cairo_status_t cairo_surface_get_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix) { + if (surface->finished) + return CAIRO_STATUS_SURFACE_FINISHED; + if (surface == NULL) return CAIRO_STATUS_NULL_POINTER; @@ -429,6 +483,9 @@ slim_hidden_def(cairo_surface_get_matrix); cairo_status_t cairo_surface_set_filter (cairo_surface_t *surface, cairo_filter_t filter) { + if (surface->finished) + return CAIRO_STATUS_SURFACE_FINISHED; + if (surface == NULL) return CAIRO_STATUS_NULL_POINTER; @@ -460,6 +517,9 @@ cairo_surface_clip_restore (cairo_surface_t *surface); cairo_status_t cairo_surface_set_repeat (cairo_surface_t *surface, int repeat) { + if (surface->finished) + return CAIRO_STATUS_SURFACE_FINISHED; + if (surface == NULL) return CAIRO_STATUS_NULL_POINTER; @@ -552,6 +612,9 @@ _cairo_surface_composite (cairo_operator_t operator, { cairo_int_status_t status; + if (dst->finished) + return CAIRO_STATUS_SURFACE_FINISHED; + status = dst->backend->composite (operator, src, mask, dst, src_x, src_y, @@ -580,6 +643,9 @@ _cairo_surface_fill_rectangle (cairo_surface_t *surface, { cairo_rectangle_t rect; + if (surface->finished) + return CAIRO_STATUS_SURFACE_FINISHED; + rect.x = x; rect.y = y; rect.width = width; @@ -668,6 +734,9 @@ _cairo_surface_fill_rectangles (cairo_surface_t *surface, { cairo_int_status_t status; + if (surface->finished) + return CAIRO_STATUS_SURFACE_FINISHED; + if (num_rects == 0) return CAIRO_STATUS_SUCCESS; @@ -763,6 +832,9 @@ _cairo_surface_composite_trapezoids (cairo_operator_t operator, { cairo_int_status_t status; + if (dst->finished) + return CAIRO_STATUS_SURFACE_FINISHED; + status = dst->backend->composite_trapezoids (operator, pattern, dst, src_x, src_y, @@ -784,6 +856,9 @@ _cairo_surface_copy_page (cairo_surface_t *surface) { cairo_int_status_t status; + if (surface->finished) + return CAIRO_STATUS_SURFACE_FINISHED; + status = surface->backend->copy_page (surface); /* It's fine if some backends just don't support this. */ if (status == CAIRO_INT_STATUS_UNSUPPORTED) @@ -799,6 +874,9 @@ _cairo_surface_show_page (cairo_surface_t *surface) { cairo_int_status_t status; + if (surface->finished) + return CAIRO_STATUS_SURFACE_FINISHED; + status = surface->backend->show_page (surface); /* It's fine if some backends just don't support this. */ if (status == CAIRO_INT_STATUS_UNSUPPORTED) @@ -812,5 +890,39 @@ _cairo_surface_show_page (cairo_surface_t *surface) cairo_status_t _cairo_surface_set_clip_region (cairo_surface_t *surface, pixman_region16_t *region) { + if (surface->finished) + return CAIRO_STATUS_SURFACE_FINISHED; + return surface->backend->set_clip_region (surface, region); } + +cairo_status_t +_cairo_surface_show_glyphs (cairo_font_t *font, + cairo_operator_t operator, + cairo_pattern_t *pattern, + cairo_surface_t *dst, + int source_x, + int source_y, + int dest_x, + int dest_y, + unsigned int width, + unsigned int height, + const cairo_glyph_t *glyphs, + int num_glyphs) +{ + cairo_status_t status; + + if (dst->finished) + return CAIRO_STATUS_SURFACE_FINISHED; + + if (dst->backend->show_glyphs != NULL) + status = dst->backend->show_glyphs (font, operator, pattern, dst, + source_x, source_y, + dest_x, dest_y, + width, height, + glyphs, num_glyphs); + else + status = CAIRO_INT_STATUS_UNSUPPORTED; + + return status; +} diff --git a/src/cairo_win32_surface.c b/src/cairo_win32_surface.c index dcfe6d04..e5a27b0e 100644 --- a/src/cairo_win32_surface.c +++ b/src/cairo_win32_surface.c @@ -346,7 +346,7 @@ _cairo_win32_surface_create_dib (cairo_format_t format, } static void -_cairo_win32_surface_destroy (void *abstract_surface) +_cairo_win32_surface_finish (void *abstract_surface) { cairo_win32_surface_t *surface = abstract_surface; @@ -362,8 +362,6 @@ _cairo_win32_surface_destroy (void *abstract_surface) DeleteObject (surface->bitmap); DeleteDC (surface->dc); } - - free (surface); } static double @@ -914,7 +912,7 @@ _cairo_surface_is_win32 (cairo_surface_t *surface) static const cairo_surface_backend_t cairo_win32_surface_backend = { _cairo_win32_surface_create_similar, - _cairo_win32_surface_destroy, + _cairo_win32_surface_finish, _cairo_win32_surface_pixels_per_inch, _cairo_win32_surface_acquire_source_image, _cairo_win32_surface_release_source_image, diff --git a/src/cairo_xcb_surface.c b/src/cairo_xcb_surface.c index 0694b77a..aef8368f 100644 --- a/src/cairo_xcb_surface.c +++ b/src/cairo_xcb_surface.c @@ -278,7 +278,7 @@ _cairo_xcb_surface_create_similar (void *abstract_src, } static void -_cairo_xcb_surface_destroy (void *abstract_surface) +_cairo_xcb_surface_finish (void *abstract_surface) { cairo_xcb_surface_t *surface = abstract_surface; if (surface->picture.xid) @@ -291,8 +291,6 @@ _cairo_xcb_surface_destroy (void *abstract_surface) XCBFreeGC (surface->dpy, surface->gc); surface->dpy = 0; - - free (surface); } static double @@ -901,7 +899,7 @@ _cairo_xcb_surface_set_clip_region (void *abstract_surface, static const cairo_surface_backend_t cairo_xcb_surface_backend = { _cairo_xcb_surface_create_similar, - _cairo_xcb_surface_destroy, + _cairo_xcb_surface_finish, _cairo_xcb_surface_pixels_per_inch, _cairo_xcb_surface_acquire_source_image, _cairo_xcb_surface_release_source_image, diff --git a/src/cairo_xlib_surface.c b/src/cairo_xlib_surface.c index 8e05a320..3aaa94d6 100644 --- a/src/cairo_xlib_surface.c +++ b/src/cairo_xlib_surface.c @@ -185,8 +185,8 @@ _cairo_xlib_surface_create_similar (void *abstract_src, return &surface->base; } -static void -_cairo_xlib_surface_destroy (void *abstract_surface) +static cairo_status_t +_cairo_xlib_surface_finish (void *abstract_surface) { cairo_xlib_surface_t *surface = abstract_surface; if (surface->picture) @@ -200,7 +200,7 @@ _cairo_xlib_surface_destroy (void *abstract_surface) surface->dpy = NULL; - free (surface); + return CAIRO_STATUS_SUCCESS; } static double @@ -959,7 +959,7 @@ _cairo_xlib_surface_show_glyphs (cairo_font_t *font, static const cairo_surface_backend_t cairo_xlib_surface_backend = { _cairo_xlib_surface_create_similar, - _cairo_xlib_surface_destroy, + _cairo_xlib_surface_finish, _cairo_xlib_surface_pixels_per_inch, _cairo_xlib_surface_acquire_source_image, _cairo_xlib_surface_release_source_image, diff --git a/src/cairoint.h b/src/cairoint.h index 6afaece0..1c3ad6e6 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -55,6 +55,7 @@ #include <math.h> #include <limits.h> #include <stdint.h> +#include <stdio.h> #include "cairo.h" @@ -550,8 +551,8 @@ typedef struct _cairo_surface_backend { int width, int height); - void - (*destroy) (void *surface); + cairo_status_t + (*finish) (void *surface); double (*pixels_per_inch) (void *surface); @@ -666,6 +667,7 @@ struct _cairo_surface { const cairo_surface_backend_t *backend; unsigned int ref_count; + cairo_bool_t finished; cairo_array_t user_data_slots; cairo_matrix_t matrix; @@ -1501,6 +1503,20 @@ _cairo_surface_clone_similar (cairo_surface_t *surface, cairo_private cairo_status_t _cairo_surface_set_clip_region (cairo_surface_t *surface, pixman_region16_t *region); +cairo_private cairo_status_t +_cairo_surface_show_glyphs (cairo_font_t *font, + cairo_operator_t operator, + cairo_pattern_t *pattern, + cairo_surface_t *surface, + int source_x, + int source_y, + int dest_x, + int dest_y, + unsigned int width, + unsigned int height, + const cairo_glyph_t *glyphs, + int num_glyphs); + /* cairo_image_surface.c */ cairo_private cairo_image_surface_t * @@ -1764,6 +1780,35 @@ _cairo_utf8_to_utf16 (const char *str, uint16_t **result, int *items_written); +/* cairo_output_stream.c */ + +typedef struct _cairo_output_stream cairo_output_stream_t; + +cairo_private cairo_output_stream_t * +_cairo_output_stream_create (cairo_write_func_t write_func, + cairo_destroy_func_t destroy_closure_func, + void *closure); + +cairo_private void +_cairo_output_stream_destroy (cairo_output_stream_t *stream); + +cairo_private cairo_status_t +_cairo_output_stream_write (cairo_output_stream_t *stream, + const void *data, size_t length); + +cairo_private cairo_status_t +_cairo_output_stream_printf (cairo_output_stream_t *stream, + const char *fmt, ...); + +cairo_private long +_cairo_output_stream_get_position (cairo_output_stream_t *status); + +cairo_private cairo_status_t +_cairo_output_stream_get_status (cairo_output_stream_t *stream); + +cairo_output_stream_t * +_cairo_output_stream_create_for_file (FILE *fp); + /* Avoid unnecessary PLT entries. */ slim_hidden_proto(cairo_close_path) |