diff options
author | sanine <sanine.not@pm.me> | 2022-10-12 12:03:23 -0500 |
---|---|---|
committer | sanine <sanine.not@pm.me> | 2022-10-12 12:03:23 -0500 |
commit | 530ffd0b7d3c39757b20f00716e486b5caf89aff (patch) | |
tree | 76b35fdf57317038acf6b828871f6ae25fce2ebe /libs/cairo-1.16.0/test/mime-unique-id.c | |
parent | 3dbe9332e47c143a237db12440f134caebd1cfbe (diff) |
add cairo
Diffstat (limited to 'libs/cairo-1.16.0/test/mime-unique-id.c')
-rwxr-xr-x | libs/cairo-1.16.0/test/mime-unique-id.c | 511 |
1 files changed, 511 insertions, 0 deletions
diff --git a/libs/cairo-1.16.0/test/mime-unique-id.c b/libs/cairo-1.16.0/test/mime-unique-id.c new file mode 100755 index 0000000..bdd0561 --- /dev/null +++ b/libs/cairo-1.16.0/test/mime-unique-id.c @@ -0,0 +1,511 @@ +/* + * Copyright © 2017 Adrian Johnson + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Author: Adrian Johnson <ajohnson@redneon.com> + */ + + +/* Check that source surfaces with same CAIRO_MIME_TYPE_UNIQUE_ID are + * embedded only once in PDF/PS. + * + * To exercise all the surface embedding code in PS/PDF, four types of + * source surfaces are painted on each page, each with its own UNIQUE_ID: + * - an image surface + * - a recording surface with a jpeg mime attached + * - a bounded recording surface + * - an unbounded recording surface. + * + * Four pages are generated. Each source is clipped starting with the + * smallest area on the first page increasing to the unclipped size on + * the last page. This is to ensure the output does not embed the + * source clipped to a smaller size than used on subsequent pages. + * + * The test verifies the use of UNIQUE_ID by comparing the file size + * with the expected size. + */ + +#include "cairo-test.h" + +#include <math.h> +#include <stdio.h> + +#include <cairo.h> + +#if CAIRO_HAS_PS_SURFACE +#include <cairo-ps.h> +#endif + +#if CAIRO_HAS_PDF_SURFACE +#include <cairo-pdf.h> +#endif + +#define NUM_PAGES 4 + +#define WIDTH 275 +#define HEIGHT 275 + +#define BASENAME "mime-unique-id" + + +/* Expected file size to check that surfaces are embedded only once. + * SIZE_TOLERANCE should be large enough to allow some variation in + * file size due to changes to the PS/PDF surfaces while being small + * enough to catch any attempt to embed the surface more than + * once. The compressed size of each surface embedded in PDF is: + * - image: 108,774 + * - jpeg: 11,400 + * - recording: 17,518 + * + * If the size check fails, manually check the output and if the + * surfaces are still embedded only once, update the expected sizes. + */ +#define PS2_EXPECTED_SIZE 417510 +#define PS3_EXPECTED_SIZE 381554 +#define PDF_EXPECTED_SIZE 347182 +#define SIZE_TOLERANCE 5000 + +static const char *png_filename = "romedalen.png"; +static const char *jpeg_filename = "romedalen.jpg"; + +static cairo_test_status_t +create_image_surface (cairo_test_context_t *ctx, cairo_surface_t **surface) +{ + cairo_status_t status; + const char *unique_id = "image"; + + *surface = cairo_test_create_surface_from_png (ctx, png_filename); + status = cairo_surface_set_mime_data (*surface, CAIRO_MIME_TYPE_UNIQUE_ID, + (unsigned char *)unique_id, + strlen (unique_id), + NULL, NULL); + if (status) { + cairo_surface_destroy (*surface); + return cairo_test_status_from_status (ctx, status); + } + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +create_recording_surface_with_mime_jpg (cairo_test_context_t *ctx, cairo_surface_t **surface) +{ + cairo_status_t status; + FILE *f; + unsigned char *data; + long len; + const char *unique_id = "jpeg"; + cairo_rectangle_t extents = { 0, 0, 1, 1 }; + + *surface = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, &extents); + f = fopen (jpeg_filename, "rb"); + if (f == NULL) { + cairo_test_log (ctx, "Unable to open file %s\n", jpeg_filename); + return CAIRO_TEST_FAILURE; + } + + fseek (f, 0, SEEK_END); + len = ftell(f); + fseek (f, 0, SEEK_SET); + data = malloc (len); + if (fread(data, len, 1, f) != 1) { + cairo_test_log (ctx, "Unable to read file %s\n", jpeg_filename); + return CAIRO_TEST_FAILURE; + } + + fclose(f); + status = cairo_surface_set_mime_data (*surface, + CAIRO_MIME_TYPE_JPEG, + data, len, + free, data); + if (status) { + cairo_surface_destroy (*surface); + return cairo_test_status_from_status (ctx, status); + } + + status = cairo_surface_set_mime_data (*surface, CAIRO_MIME_TYPE_UNIQUE_ID, + (unsigned char *)unique_id, + strlen (unique_id), + NULL, NULL); + if (status) { + cairo_surface_destroy (*surface); + return cairo_test_status_from_status (ctx, status); + } + + return CAIRO_TEST_SUCCESS; +} + +static void +draw_tile (cairo_t *cr) +{ + cairo_move_to (cr, 10 + 5, 10); + cairo_arc (cr, 10, 10, 5, 0, 2*M_PI); + cairo_close_path (cr); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_fill (cr); + + cairo_move_to (cr, 30, 10-10*0.43); + cairo_line_to (cr, 25, 10+10*0.43); + cairo_line_to (cr, 35, 10+10*0.43); + cairo_close_path (cr); + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_fill (cr); + + cairo_rectangle (cr, 5, 25, 10, 10); + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_fill (cr); + + cairo_save (cr); + cairo_translate (cr, 30, 30); + cairo_rotate (cr, M_PI/4.0); + cairo_rectangle (cr, -5, -5, 10, 10); + cairo_set_source_rgb (cr, 1, 0, 1); + cairo_fill (cr); + cairo_restore (cr); +} + +#define RECORDING_SIZE 800 +#define TILE_SIZE 40 + +static cairo_test_status_t +create_recording_surface (cairo_test_context_t *ctx, cairo_surface_t **surface, cairo_bool_t bounded) +{ + cairo_status_t status; + int x, y; + cairo_t *cr; + cairo_matrix_t ctm; + int start, size; + const char *bounded_id = "recording bounded"; + const char *unbounded_id = "recording unbounded"; + cairo_rectangle_t extents = { 0, 0, RECORDING_SIZE, RECORDING_SIZE }; + + if (bounded) { + *surface = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, &extents); + start = 0; + size = RECORDING_SIZE; + } else { + *surface = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, NULL); + start = RECORDING_SIZE / 2; + size = RECORDING_SIZE * 2; + } + + /* Draw each tile instead of creating a cairo pattern to make size + * of the emitted recording as large as possible. + */ + cr = cairo_create (*surface); + cairo_set_source_rgb (cr, 1, 1, 0); + cairo_paint (cr); + cairo_get_matrix (cr, &ctm); + for (y = start; y < size; y += TILE_SIZE) { + for (x = start; x < size; x += TILE_SIZE) { + draw_tile (cr); + cairo_translate (cr, TILE_SIZE, 0); + } + cairo_matrix_translate (&ctm, 0, TILE_SIZE); + cairo_set_matrix (cr, &ctm); + } + cairo_destroy (cr); + + status = cairo_surface_set_mime_data (*surface, CAIRO_MIME_TYPE_UNIQUE_ID, + (unsigned char *)(bounded ? bounded_id : unbounded_id), + strlen (bounded ? bounded_id : unbounded_id), + NULL, NULL); + if (status) { + cairo_surface_destroy (*surface); + return cairo_test_status_from_status (ctx, status); + } + + return CAIRO_TEST_SUCCESS; +} + +/* Draw @source scaled to fit @rect and clipped to a rectangle + * @clip_margin units smaller on each side. @rect will be stroked + * with a solid line and the clip rect stroked with a dashed line. + */ +static void +draw_surface (cairo_t *cr, cairo_surface_t *source, cairo_rectangle_int_t *rect, int clip_margin) +{ + cairo_surface_type_t type; + int width, height; + cairo_rectangle_t extents; + const double dashes[2] = { 2, 2 }; + + type = cairo_surface_get_type (source); + if (type == CAIRO_SURFACE_TYPE_IMAGE) { + width = cairo_image_surface_get_width (source); + height = cairo_image_surface_get_height (source); + } else { + if (cairo_recording_surface_get_extents (source, &extents)) { + width = extents.width; + height = extents.height; + } else { + width = RECORDING_SIZE; + height = RECORDING_SIZE; + } + } + + cairo_save (cr); + cairo_rectangle (cr, rect->x, rect->y, rect->width, rect->height); + cairo_stroke (cr); + cairo_rectangle (cr, + rect->x + clip_margin, + rect->y + clip_margin, + rect->width - clip_margin*2, + rect->height - clip_margin*2); + cairo_set_dash (cr, dashes, 2, 0); + cairo_stroke_preserve (cr); + cairo_clip (cr); + + cairo_translate (cr, rect->x, rect->y); + cairo_scale (cr, (double)rect->width/width, (double)rect->height/height); + cairo_set_source_surface (cr, source, 0, 0); + cairo_paint (cr); + + cairo_restore (cr); +} + +static cairo_test_status_t +draw_pages (cairo_test_context_t *ctx, cairo_surface_t *surface) +{ + cairo_t *cr; + int i; + cairo_rectangle_int_t img_rect; + cairo_rectangle_int_t jpg_rect; + cairo_rectangle_int_t bounded_rect; + cairo_rectangle_int_t unbounded_rect; + int clip_margin; + cairo_surface_t *source; + cairo_test_status_t status; + + cr = cairo_create (surface); + + /* target area to fill with the image source */ + img_rect.x = 25; + img_rect.y = 25; + img_rect.width = 100; + img_rect.height = 100; + + /* target area to fill with the recording with jpeg mime source */ + jpg_rect.x = 150; + jpg_rect.y = 25; + jpg_rect.width = 100; + jpg_rect.height = 100; + + /* target area to fill with the bounded recording source */ + bounded_rect.x = 25; + bounded_rect.y = 150; + bounded_rect.width = 100; + bounded_rect.height = 100; + + /* target area to fill with the unbounded recording source */ + unbounded_rect.x = 150; + unbounded_rect.y = 150; + unbounded_rect.width = 100; + unbounded_rect.height = 100; + + /* Draw the image and recording surface on each page. The sources + * are clipped starting with a small clip area on the first page + * and increasing to the source size on last page to ensure the + * embedded source is not clipped to the area used on the first + * page. + * + * The sources are created each time they are used to ensure + * CAIRO_MIME_TYPE_UNIQUE_ID is tested. + */ + for (i = 0; i < NUM_PAGES; i++) { + clip_margin = (NUM_PAGES - i - 1) * 5; + + status = create_image_surface (ctx, &source); + if (status) + return status; + draw_surface (cr, source, &img_rect, clip_margin); + cairo_surface_destroy (source); + + status = create_recording_surface_with_mime_jpg (ctx, &source); + if (status) + return status; + draw_surface (cr, source, &jpg_rect, clip_margin); + cairo_surface_destroy (source); + + status = create_recording_surface (ctx, &source, TRUE); + if (status) + return status; + draw_surface (cr, source, &bounded_rect, clip_margin); + cairo_surface_destroy (source); + + status = create_recording_surface (ctx, &source, FALSE); + if (status) + return status; + draw_surface (cr, source, &unbounded_rect, clip_margin); + cairo_surface_destroy (source); + + cairo_show_page (cr); + } + + cairo_destroy (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +check_file_size (cairo_test_context_t *ctx, const char *filename, long expected_size) +{ + FILE *f; + long size; + + f = fopen (filename, "rb"); + if (f == NULL) { + cairo_test_log (ctx, "Unable to open file %s\n", filename); + return CAIRO_TEST_FAILURE; + } + + fseek (f, 0, SEEK_END); + size = ftell (f); + fclose(f); + + if (labs(size - expected_size) > SIZE_TOLERANCE) { + cairo_test_log (ctx, + "mime-unique-id: File %s has size %ld. Expected size %ld +/- %ld." + " Check if surfaces are embedded once.\n", + filename, size, expected_size, (long)SIZE_TOLERANCE); + return CAIRO_TEST_FAILURE; + } + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +preamble (cairo_test_context_t *ctx) +{ + cairo_surface_t *surface; + cairo_status_t status; + char *filename; + cairo_test_status_t result = CAIRO_TEST_UNTESTED; + cairo_test_status_t test_status; + const char *path = cairo_test_mkdir (CAIRO_TEST_OUTPUT_DIR) ? CAIRO_TEST_OUTPUT_DIR : "."; + +#if CAIRO_HAS_PS_SURFACE + if (cairo_test_is_target_enabled (ctx, "ps2")) + { + xasprintf (&filename, "%s/%s.ps2.out.ps", path, BASENAME); + surface = cairo_ps_surface_create (filename, WIDTH, HEIGHT); + status = cairo_surface_status (surface); + if (status) { + cairo_test_log (ctx, "Failed to create ps surface for file %s: %s\n", + filename, cairo_status_to_string (status)); + test_status = CAIRO_TEST_FAILURE; + goto ps2_finish; + } + + cairo_ps_surface_restrict_to_level (surface, CAIRO_PS_LEVEL_2); + + test_status = draw_pages (ctx, surface); + cairo_surface_destroy (surface); + + if (test_status == CAIRO_TEST_SUCCESS) + test_status = check_file_size (ctx, filename, PS2_EXPECTED_SIZE); + + ps2_finish: + cairo_test_log (ctx, "TEST: %s TARGET: %s RESULT: %s\n", + ctx->test->name, + "ps2", + test_status ? "FAIL" : "PASS"); + + if (result == CAIRO_TEST_UNTESTED || test_status == CAIRO_TEST_FAILURE) + result = test_status; + + free (filename); + } + + if (cairo_test_is_target_enabled (ctx, "ps3")) + { + xasprintf (&filename, "%s/%s.ps3.out.ps", path, BASENAME); + surface = cairo_ps_surface_create (filename, WIDTH, HEIGHT); + status = cairo_surface_status (surface); + if (status) { + cairo_test_log (ctx, "Failed to create ps surface for file %s: %s\n", + filename, cairo_status_to_string (status)); + test_status = CAIRO_TEST_FAILURE; + goto ps3_finish; + } + + test_status = draw_pages (ctx, surface); + cairo_surface_destroy (surface); + + if (test_status == CAIRO_TEST_SUCCESS) + test_status = check_file_size (ctx, filename, PS3_EXPECTED_SIZE); + + ps3_finish: + cairo_test_log (ctx, "TEST: %s TARGET: %s RESULT: %s\n", + ctx->test->name, + "ps3", + test_status ? "FAIL" : "PASS"); + + if (result == CAIRO_TEST_UNTESTED || test_status == CAIRO_TEST_FAILURE) + result = test_status; + + free (filename); + } +#endif + +#if CAIRO_HAS_PDF_SURFACE + if (cairo_test_is_target_enabled (ctx, "pdf")) + { + xasprintf (&filename, "%s/%s.pdf.out.pdf", path, BASENAME); + surface = cairo_pdf_surface_create (filename, WIDTH, HEIGHT); + status = cairo_surface_status (surface); + if (status) { + cairo_test_log (ctx, "Failed to create pdf surface for file %s: %s\n", + filename, cairo_status_to_string (status)); + test_status = CAIRO_TEST_FAILURE; + goto pdf_finish; + } + + test_status = draw_pages (ctx, surface); + cairo_surface_destroy (surface); + + if (test_status == CAIRO_TEST_SUCCESS) + test_status = check_file_size (ctx, filename, PDF_EXPECTED_SIZE); + + + pdf_finish: + cairo_test_log (ctx, "TEST: %s TARGET: %s RESULT: %s\n", + ctx->test->name, + "pdf", + test_status ? "FAIL" : "PASS"); + + if (result == CAIRO_TEST_UNTESTED || test_status == CAIRO_TEST_FAILURE) + result = test_status; + + free (filename); + } +#endif + + return result; +} + +CAIRO_TEST (mime_unique_id, + "Check that paginated surfaces embed only one copy of surfaces with the same CAIRO_MIME_TYPE_UNIQUE_ID.", + "paginated", /* keywords */ + "target=vector", /* requirements */ + 0, 0, + preamble, NULL) |