From a98430092f5f43cfa6eee555a56d91575d92cd62 Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Fri, 11 Mar 2005 14:29:15 +0000 Subject: [PATCH] Added some documentation, so we get some churn here. New functions: cairo_copy_path_data, cairo_copy_path_data_flat, and cairo_append_path_data. Add new implementation for cairo_copy_path_data and cairo_append_path_data. New test for new path_data functions. --- ChangeLog | 19 ++ doc/public/cairo-sections.txt | 11 ++ doc/public/tmpl/cairo-surface.sgml | 22 +++ doc/public/tmpl/cairo.sgml | 43 +++++ src/Makefile.am | 2 + src/cairo-path-data-private.h | 57 ++++++ src/cairo-path-data.c | 268 +++++++++++++++++++++++++++++ src/cairo.c | 88 +++++++++- src/cairo.h | 100 ++++++++++- src/cairo_path_data.c | 268 +++++++++++++++++++++++++++++ test/.cvsignore | 3 + test/Makefile.am | 3 + test/path-data.c | 167 ++++++++++++++++++ test/path_data.c | 167 ++++++++++++++++++ 14 files changed, 1210 insertions(+), 8 deletions(-) create mode 100644 src/cairo-path-data-private.h create mode 100644 src/cairo-path-data.c create mode 100644 src/cairo_path_data.c create mode 100644 test/path-data.c create mode 100644 test/path_data.c diff --git a/ChangeLog b/ChangeLog index 8ee98f3ca..b66f1f03f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,22 @@ +2005-03-11 Carl Worth + + * doc/public/cairo-sections.txt: + * doc/public/tmpl/cairo-surface.sgml: + * doc/public/tmpl/cairo.sgml: Added some documentation, so we get + some churn here. + + * src/cairo.c: + * src/cairo.h: New functions: cairo_copy_path_data, + cairo_copy_path_data_flat, and cairo_append_path_data. + + * src/Makefile.am: + * src/cairo-path-data-private.h: + * src/cairo_path_data.c: Add new implementation for + cairo_copy_path_data and cairo_append_path_data. + + * test/Makefile.am: + * test/path_data.c: New test for new path_data functions. + 2005-03-10 Kristian Høgsberg * src/cairo_surface.c (_destroy_user_data): Add this function and diff --git a/doc/public/cairo-sections.txt b/doc/public/cairo-sections.txt index 97a83d828..70776cf04 100644 --- a/doc/public/cairo-sections.txt +++ b/doc/public/cairo-sections.txt @@ -86,6 +86,8 @@ cairo_surface_set_matrix cairo_surface_get_matrix cairo_surface_set_filter cairo_surface_get_filter +cairo_surface_set_user_data +cairo_surface_get_user_data
@@ -225,12 +227,17 @@ cairo_get_matrix cairo_get_target_surface cairo_get_path cairo_get_path_flat +cairo_copy_path_data +cairo_copy_path_data_flat +cairo_append_path_data cairo_status_t cairo_status cairo_status_string cairo_filter_t cairo_image_surface_create cairo_image_surface_create_for_data +cairo_destroy_func_t +cairo_user_data_key_t CAIRO_API_SHAKEUP_FLAG_DAY CAIRO_BEGIN_DECLS @@ -247,6 +254,10 @@ cairo_current_line_join cairo_current_miter_limit cairo_current_matrix cairo_current_target_surface +cairo_current_path +cairo_current_path_flat +cairo_current_font +cairo_current_font_extents cairo_get_status cairo_get_status_string
diff --git a/doc/public/tmpl/cairo-surface.sgml b/doc/public/tmpl/cairo-surface.sgml index 7b93a7c5e..a52df4c69 100644 --- a/doc/public/tmpl/cairo-surface.sgml +++ b/doc/public/tmpl/cairo-surface.sgml @@ -113,3 +113,25 @@ cairo_surface_t @Returns: + + + + + +@surface: +@key: +@data: +@destroy: +@Returns: + + + + + + + +@surface: +@key: +@Returns: + + diff --git a/doc/public/tmpl/cairo.sgml b/doc/public/tmpl/cairo.sgml index 88d688162..597f236e5 100644 --- a/doc/public/tmpl/cairo.sgml +++ b/doc/public/tmpl/cairo.sgml @@ -953,6 +953,33 @@ Drawing contexts. @closure: + + + + + +@cr: +@Returns: + + + + + + + +@cr: +@Returns: + + + + + + + +@cr: +@path_data: + + @@ -967,6 +994,7 @@ Drawing contexts. @CAIRO_STATUS_NO_TARGET_SURFACE: @CAIRO_STATUS_NULL_POINTER: @CAIRO_STATUS_INVALID_STRING: +@CAIRO_STATUS_INVALID_PATH_DATA: @@ -1031,3 +1059,18 @@ End: --> + + + + + +@data: + + + + + + + +@unused: + diff --git a/src/Makefile.am b/src/Makefile.am index 3f76d2726..c60025a03 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -91,6 +91,8 @@ libcairo_la_SOURCES = \ cairo_matrix.c \ cairo_path.c \ cairo_path_bounds.c \ + cairo_path_data.c \ + cairo-path-data-private.h \ cairo_path_fill.c \ cairo_path_stroke.c \ cairo_pen.c \ diff --git a/src/cairo-path-data-private.h b/src/cairo-path-data-private.h new file mode 100644 index 000000000..5cce71d2a --- /dev/null +++ b/src/cairo-path-data-private.h @@ -0,0 +1,57 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Carl D. Worth + */ + +#ifndef CAIRO_PATH_DATA_PRIVATE_H +#define CAIRO_PATH_DATA_PRIVATE_H + +#include "cairoint.h" + +extern cairo_path_data_t _cairo_path_data_nil; + +CAIRO_BEGIN_DECLS + +cairo_path_data_t * +_cairo_path_data_create (cairo_gstate_t *gstate); + +cairo_path_data_t * +_cairo_path_data_create_flat (cairo_gstate_t *gstate); + +cairo_status_t +_cairo_path_data_append_to_context (cairo_path_data_t *path_data, + cairo_t *cr); + +CAIRO_END_DECLS + +#endif /* CAIRO_PATH_DATA_PRIVATE_H */ diff --git a/src/cairo-path-data.c b/src/cairo-path-data.c new file mode 100644 index 000000000..62d6ef051 --- /dev/null +++ b/src/cairo-path-data.c @@ -0,0 +1,268 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Carl D. Worth + */ + +#include "cairo-path-data-private.h" + +cairo_path_data_t +_cairo_path_data_nil = { {0} }; + +/* Closure for path interpretation. */ +typedef struct cairo_path_data_count { + int count; +} cpdc_t; + +static void +_cpdc_move_to (void *closure, double x, double y) +{ + cpdc_t *cpdc = closure; + + cpdc->count += 2; +} + +static void +_cpdc_line_to (void *closure, double x, double y) +{ + cpdc_t *cpdc = closure; + + cpdc->count += 2; +} + +static void +_cpdc_curve_to (void *closure, + double x1, double y1, + double x2, double y2, + double x3, double y3) +{ + cpdc_t *cpdc = closure; + + cpdc->count += 4; +} + +static void +_cpdc_close_path (void *closure) +{ + cpdc_t *cpdc = closure; + + cpdc->count += 1; +} + +static int +_cairo_path_data_count (cairo_gstate_t *gstate, cairo_bool_t flatten) +{ + cpdc_t cpdc; + + cpdc.count = 0; + + _cairo_gstate_interpret_path (gstate, + _cpdc_move_to, + _cpdc_line_to, + flatten ? NULL : _cpdc_curve_to, + _cpdc_close_path, + &cpdc); + + /* Add 1 for the final CAIRO_PATH_END */ + cpdc.count++; + + return cpdc.count; +} + +/* Closure for path interpretation. */ +typedef struct cairo_path_data_populate { + cairo_path_data_t *data; +} cpdp_t; + +static void +_cpdp_move_to (void *closure, double x, double y) +{ + cpdp_t *cpdp = closure; + cairo_path_data_t *data = cpdp->data; + + data->header.type = CAIRO_PATH_MOVE_TO; + data->header.length = 2; + + /* We index from 1 to leave room for data->header */ + data[1].point.x = x; + data[1].point.y = y; + + cpdp->data += data->header.length; +} + +static void +_cpdp_line_to (void *closure, double x, double y) +{ + cpdp_t *cpdp = closure; + cairo_path_data_t *data = cpdp->data; + + data->header.type = CAIRO_PATH_LINE_TO; + data->header.length = 2; + + /* We index from 1 to leave room for data->header */ + data[1].point.x = x; + data[1].point.y = y; + + cpdp->data += data->header.length; +} + +static void +_cpdp_curve_to (void *closure, + double x1, double y1, + double x2, double y2, + double x3, double y3) +{ + cpdp_t *cpdp = closure; + cairo_path_data_t *data = cpdp->data; + + data->header.type = CAIRO_PATH_CURVE_TO; + data->header.length = 4; + + /* We index from 1 to leave room for data->header */ + data[1].point.x = x1; + data[1].point.y = y1; + + data[2].point.x = x2; + data[2].point.y = y2; + + data[3].point.x = x3; + data[3].point.y = y3; + + cpdp->data += data->header.length; +} + +static void +_cpdp_close_path (void *closure) +{ + cpdp_t *cpdp = closure; + cairo_path_data_t *data = cpdp->data; + + data->header.type = CAIRO_PATH_CLOSE_PATH; + data->header.length = 1; + + cpdp->data += data->header.length; +} + +static void +_cairo_path_data_populate (cairo_path_data_t *data, + int count, + cairo_gstate_t *gstate, + cairo_bool_t flatten) +{ + cpdp_t cpdp; + + cpdp.data = data; + + _cairo_gstate_interpret_path (gstate, + _cpdp_move_to, + _cpdp_line_to, + flatten ? NULL : _cpdp_curve_to, + _cpdp_close_path, + &cpdp); + + cpdp.data->header.type = CAIRO_PATH_END; + cpdp.data->header.length = 0; + cpdp.data++; + + /* Sanity check the count */ + assert (cpdp.data - data == count); +} + +static cairo_path_data_t * +_cairo_path_data_create_real (cairo_gstate_t *gstate, cairo_bool_t flatten) +{ + int count; + cairo_path_data_t *data; + + count = _cairo_path_data_count (gstate, flatten); + + data = malloc (count * sizeof (cairo_path_data_t)); + if (data == NULL) + return &_cairo_path_data_nil; + + _cairo_path_data_populate (data, count, gstate, flatten); + + return data; +} + +cairo_path_data_t * +_cairo_path_data_create (cairo_gstate_t *gstate) +{ + return _cairo_path_data_create_real (gstate, FALSE); +} + +cairo_path_data_t * +_cairo_path_data_create_flat (cairo_gstate_t *gstate) +{ + return _cairo_path_data_create_real (gstate, TRUE); +} + +cairo_status_t +_cairo_path_data_append_to_context (cairo_path_data_t *path_data, + cairo_t *cr) +{ + cairo_path_data_t *p; + + for (p = path_data; p->header.type != CAIRO_PATH_END; p += p->header.length) { + switch (p->header.type) { + case CAIRO_PATH_MOVE_TO: + cairo_move_to (cr, + p[1].point.x, p[1].point.y); + if (p->header.length != 2) + return CAIRO_STATUS_INVALID_PATH_DATA; + break; + case CAIRO_PATH_LINE_TO: + cairo_line_to (cr, + p[1].point.x, p[1].point.y); + if (p->header.length != 2) + return CAIRO_STATUS_INVALID_PATH_DATA; + break; + case CAIRO_PATH_CURVE_TO: + cairo_curve_to (cr, + p[1].point.x, p[1].point.y, + p[2].point.x, p[2].point.y, + p[3].point.x, p[3].point.y); + if (p->header.length != 4) + return CAIRO_STATUS_INVALID_PATH_DATA; + break; + case CAIRO_PATH_CLOSE_PATH: + cairo_close_path (cr); + if (p->header.length != 1) + return CAIRO_STATUS_INVALID_PATH_DATA; + break; + default: + return CAIRO_STATUS_INVALID_PATH_DATA; + } + } + + return CAIRO_STATUS_SUCCESS; +} diff --git a/src/cairo.c b/src/cairo.c index f408c2c92..b793c6e6a 100644 --- a/src/cairo.c +++ b/src/cairo.c @@ -34,8 +34,8 @@ * Carl D. Worth */ - #include "cairoint.h" +#include "cairo-path-data-private.h" #define CAIRO_TOLERANCE_MINIMUM 0.0002 /* We're limited by 16 bits of sub-pixel precision */ @@ -56,6 +56,8 @@ cairo_sane_state (cairo_t *cr) case CAIRO_STATUS_INVALID_MATRIX: case CAIRO_STATUS_NO_TARGET_SURFACE: case CAIRO_STATUS_NULL_POINTER: + case CAIRO_STATUS_INVALID_STRING: + case CAIRO_STATUS_INVALID_PATH_DATA: break; default: return 0; @@ -1705,6 +1707,88 @@ cairo_get_path_flat (cairo_t *cr, } DEPRECATE (cairo_current_path_flat, cairo_get_path_flat); +/** + * cairo_copy_path_data: + * @cr: a cairo context + * + * Creates a copy of the current path and returns it to the user as an + * array of #cairo_path_data_t. See #cairo_path_data_t for hints on + * how to iterate over the returned data structure. + * + * Return value: the copy of the current path. The caller is + * responsible for the returned memory and should free() it when + * finished. + **/ +cairo_path_data_t * +cairo_copy_path_data (cairo_t *cr) +{ + CAIRO_CHECK_SANITY (cr); + if (cr->status) + return &_cairo_path_data_nil; + + return _cairo_path_data_create (cr->gstate); +} + +/** + * cairo_copy_path_data_flat: + * @cr: a cairo context + * + * Gets a flattened copy of the current path and returns it to the + * user an an array of #cairo_path_data_t. See #cairo_path_data_t for hints on + * how to iterate over the returned data structure. + * + * This function is like cairo_copy_path_data() except that any curves + * in the path will be approximated with piecewise-linear + * approximations, (accurate to within the current tolerance + * value). That is, the result is guaranteed to not have any elements + * of type CAIRO_PATH_CURVE_TO which will instead be replaced by a + * series of CAIRO_PATH_LINE_TO elements. + * + * Return value: the copy of the current path. The caller is + * responsible for the returned memory and should free() it when + * finished. + **/ +cairo_path_data_t * +cairo_copy_path_data_flat (cairo_t *cr) +{ + CAIRO_CHECK_SANITY (cr); + if (cr->status) + return &_cairo_path_data_nil; + + return _cairo_path_data_create_flat (cr->gstate); +} + +/** + * cairo_append_path_data: + * @cr: a cairo context + * @path_data: path data to be appended + * + * Append the @path_data onto the current path. See #cairo_path_data_t + * for details on how the path data array must be initialized. + **/ +void +cairo_append_path_data (cairo_t *cr, + cairo_path_data_t *path_data) +{ + CAIRO_CHECK_SANITY (cr); + if (cr->status) + return; + + if (!path_data) { + cr->status = CAIRO_STATUS_NULL_POINTER; + return; + } + + if (path_data == &_cairo_path_data_nil) { + cr->status = CAIRO_STATUS_NO_MEMORY; + return; + } + + cr->status = _cairo_path_data_append_to_context (path_data, cr); + + CAIRO_CHECK_SANITY (cr); +} + cairo_status_t cairo_status (cairo_t *cr) { @@ -1735,6 +1819,8 @@ cairo_status_string (cairo_t *cr) return "NULL pointer"; case CAIRO_STATUS_INVALID_STRING: return "input string not valid UTF-8"; + case CAIRO_STATUS_INVALID_PATH_DATA: + return "input path data not valid"; } return ""; diff --git a/src/cairo.h b/src/cairo.h index d2743b65d..0fdf49529 100644 --- a/src/cairo.h +++ b/src/cairo.h @@ -55,7 +55,7 @@ CAIRO_BEGIN_DECLS * * #cairo_bool_t is used for boolean values. Returns of type * #cairo_bool_t will always be either 0 or 1, but testing against - * these values explicitely is not encouraged; just use the + * these values explicitly is not encouraged; just use the * value as a boolean condition. * * @@ -106,7 +106,8 @@ typedef enum cairo_status { CAIRO_STATUS_INVALID_MATRIX, CAIRO_STATUS_NO_TARGET_SURFACE, CAIRO_STATUS_NULL_POINTER, - CAIRO_STATUS_INVALID_STRING + CAIRO_STATUS_INVALID_STRING, + CAIRO_STATUS_INVALID_PATH_DATA } cairo_status_t; /* Functions for manipulating state objects */ @@ -145,7 +146,7 @@ cairo_set_target_surface (cairo_t *cr, cairo_surface_t *surface); * cairo_format_t * @CAIRO_FORMAT_ARGB32: each pixel is a 32-bit quantity, with * alpha in the upper 8 bits, then red, then green, then blue. - * The 32-bit quanties are stored native-endian. Pre-multiplied + * The 32-bit quantities are stored native-endian. Pre-multiplied * alpha is used. (That is, 50% transparent red is 0x80800000, * not 0x80ff0000.) * @CAIRO_FORMAT_RGB24: each pixel is a 32-bit quantity, with @@ -664,7 +665,7 @@ cairo_get_miter_limit (cairo_t *cr); void cairo_get_matrix (cairo_t *cr, cairo_matrix_t *matrix); -/* XXX: Need to decide the memory mangement semantics of this +/* XXX: Need to decide the memory management semantics of this function. Should it reference the surface again? */ cairo_surface_t * cairo_get_target_surface (cairo_t *cr); @@ -682,7 +683,7 @@ typedef void (cairo_curve_to_func_t) (void *closure, typedef void (cairo_close_path_func_t) (void *closure); -extern void +void cairo_get_path (cairo_t *cr, cairo_move_to_func_t *move_to, cairo_line_to_func_t *line_to, @@ -690,13 +691,98 @@ cairo_get_path (cairo_t *cr, cairo_close_path_func_t *close_path, void *closure); -extern void +void cairo_get_path_flat (cairo_t *cr, cairo_move_to_func_t *move_to, cairo_line_to_func_t *line_to, cairo_close_path_func_t *close_path, void *closure); +/** + * cairo_path_data_t: + * + * A data structure for holding path data. This data structure is used + * as the return value for cairo_copy_path_data() and + * cairo_copy_path_data_flat() as well the input value for + * cairo_append_path_data(). + * + * The data structure is designed to try to balance the demands of + * efficiency and ease-of-use. A path is represented as an array of + * cairo_path_data_t which is a union of headers and points. The array + * must be terminated by a header element of type CAIRO_PATH_END_PATH. + * + * Each portion of the path is represented by one or more elements in + * the array, (one header followed by 0 or more points). The length + * value of the header is the number of array elements for the current + * portion including the header, (ie. length == 1 + # of points), and + * where the number of points for each element type must be as + * follows: + * + * CAIRO_PATH_MOVE_TO: 1 point + * CAIRO_PATH_LINE_TO: 1 point + * CAIRO_PATH_CURVE_TO: 3 points + * CAIRO_PATH_CLOSE_PATH: 0 points + * + * The semantics and ordering of the coordinate values are consistent + * with cairo_move_to(), cairo_line_to(), cairo_curve_to(), and + * cairo_close_path(). + * + * Here is sample code for iterating through a cairo_path_data_t + * array: + * + * + * cairo_path_data_t *path, *p; + * + * path = cairo_copy_path_data (cr); + * + * for (p = path; p->header.type != CAIRO_PATH_END; p += p->header.length) { + * switch (p->header.type) { + * case CAIRO_PATH_MOVE_TO: + * do_move_to_things (p[1].point.x, p[1].point.y); + * break; + * case CAIRO_PATH_LINE_TO: + * do_line_to_things (p[1].point.x, p[1].point.y); + * break; + * case CAIRO_PATH_CURVE_TO: + * do_curve_to_things (p[1].point.x, p[1].point.y, + * p[2].point.x, p[2].point.y, + * p[3].point.x, p[3].point.y); + * break; + * case CAIRO_PATH_CLOSE_PATH: + * do_close_path_things (); + * break; + * } + * } + * + * free (path); + * + */ +typedef union { + struct { + enum { + CAIRO_PATH_MOVE_TO, + CAIRO_PATH_LINE_TO, + CAIRO_PATH_CURVE_TO, + CAIRO_PATH_CLOSE_PATH, + CAIRO_PATH_END + } type; + int length; + } header; + struct { + double x, y; + } point; +} cairo_path_data_t; + +cairo_path_data_t * +cairo_copy_path_data (cairo_t *cr); + +cairo_path_data_t * +cairo_copy_path_data_flat (cairo_t *cr); + +void +cairo_append_path_data (cairo_t *cr, + cairo_path_data_t *path_data); + /* Error status queries */ cairo_status_t @@ -921,7 +1007,7 @@ cairo_matrix_transform_point (cairo_matrix_t *matrix, double *x, double *y); #define cairo_current_rgb_color cairo_current_rgb_color_DEPRECATED_BY_cairo_get_rgb_color #define cairo_current_alpha cairo_current_alpha_DEPRECATED_BY_cairo_get_alpha #define cairo_current_tolerance cairo_current_tolerance_DEPRECATED_BY_cairo_get_tolerance -#define cairo_current_point cairo_current_point_DEPRECTATED_BY_cairo_get_current_point +#define cairo_current_point cairo_current_point_DEPRECATED_BY_cairo_get_current_point #define cairo_current_fill_rule cairo_current_fill_rule_DEPRECATED_BY_cairo_get_fill_rule #define cairo_current_line_width cairo_current_line_width_DEPRECATED_BY_cairo_get_line_width #define cairo_current_line_cap cairo_current_line_cap_DEPRECATED_BY_cairo_get_line_cap diff --git a/src/cairo_path_data.c b/src/cairo_path_data.c new file mode 100644 index 000000000..62d6ef051 --- /dev/null +++ b/src/cairo_path_data.c @@ -0,0 +1,268 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Carl D. Worth + */ + +#include "cairo-path-data-private.h" + +cairo_path_data_t +_cairo_path_data_nil = { {0} }; + +/* Closure for path interpretation. */ +typedef struct cairo_path_data_count { + int count; +} cpdc_t; + +static void +_cpdc_move_to (void *closure, double x, double y) +{ + cpdc_t *cpdc = closure; + + cpdc->count += 2; +} + +static void +_cpdc_line_to (void *closure, double x, double y) +{ + cpdc_t *cpdc = closure; + + cpdc->count += 2; +} + +static void +_cpdc_curve_to (void *closure, + double x1, double y1, + double x2, double y2, + double x3, double y3) +{ + cpdc_t *cpdc = closure; + + cpdc->count += 4; +} + +static void +_cpdc_close_path (void *closure) +{ + cpdc_t *cpdc = closure; + + cpdc->count += 1; +} + +static int +_cairo_path_data_count (cairo_gstate_t *gstate, cairo_bool_t flatten) +{ + cpdc_t cpdc; + + cpdc.count = 0; + + _cairo_gstate_interpret_path (gstate, + _cpdc_move_to, + _cpdc_line_to, + flatten ? NULL : _cpdc_curve_to, + _cpdc_close_path, + &cpdc); + + /* Add 1 for the final CAIRO_PATH_END */ + cpdc.count++; + + return cpdc.count; +} + +/* Closure for path interpretation. */ +typedef struct cairo_path_data_populate { + cairo_path_data_t *data; +} cpdp_t; + +static void +_cpdp_move_to (void *closure, double x, double y) +{ + cpdp_t *cpdp = closure; + cairo_path_data_t *data = cpdp->data; + + data->header.type = CAIRO_PATH_MOVE_TO; + data->header.length = 2; + + /* We index from 1 to leave room for data->header */ + data[1].point.x = x; + data[1].point.y = y; + + cpdp->data += data->header.length; +} + +static void +_cpdp_line_to (void *closure, double x, double y) +{ + cpdp_t *cpdp = closure; + cairo_path_data_t *data = cpdp->data; + + data->header.type = CAIRO_PATH_LINE_TO; + data->header.length = 2; + + /* We index from 1 to leave room for data->header */ + data[1].point.x = x; + data[1].point.y = y; + + cpdp->data += data->header.length; +} + +static void +_cpdp_curve_to (void *closure, + double x1, double y1, + double x2, double y2, + double x3, double y3) +{ + cpdp_t *cpdp = closure; + cairo_path_data_t *data = cpdp->data; + + data->header.type = CAIRO_PATH_CURVE_TO; + data->header.length = 4; + + /* We index from 1 to leave room for data->header */ + data[1].point.x = x1; + data[1].point.y = y1; + + data[2].point.x = x2; + data[2].point.y = y2; + + data[3].point.x = x3; + data[3].point.y = y3; + + cpdp->data += data->header.length; +} + +static void +_cpdp_close_path (void *closure) +{ + cpdp_t *cpdp = closure; + cairo_path_data_t *data = cpdp->data; + + data->header.type = CAIRO_PATH_CLOSE_PATH; + data->header.length = 1; + + cpdp->data += data->header.length; +} + +static void +_cairo_path_data_populate (cairo_path_data_t *data, + int count, + cairo_gstate_t *gstate, + cairo_bool_t flatten) +{ + cpdp_t cpdp; + + cpdp.data = data; + + _cairo_gstate_interpret_path (gstate, + _cpdp_move_to, + _cpdp_line_to, + flatten ? NULL : _cpdp_curve_to, + _cpdp_close_path, + &cpdp); + + cpdp.data->header.type = CAIRO_PATH_END; + cpdp.data->header.length = 0; + cpdp.data++; + + /* Sanity check the count */ + assert (cpdp.data - data == count); +} + +static cairo_path_data_t * +_cairo_path_data_create_real (cairo_gstate_t *gstate, cairo_bool_t flatten) +{ + int count; + cairo_path_data_t *data; + + count = _cairo_path_data_count (gstate, flatten); + + data = malloc (count * sizeof (cairo_path_data_t)); + if (data == NULL) + return &_cairo_path_data_nil; + + _cairo_path_data_populate (data, count, gstate, flatten); + + return data; +} + +cairo_path_data_t * +_cairo_path_data_create (cairo_gstate_t *gstate) +{ + return _cairo_path_data_create_real (gstate, FALSE); +} + +cairo_path_data_t * +_cairo_path_data_create_flat (cairo_gstate_t *gstate) +{ + return _cairo_path_data_create_real (gstate, TRUE); +} + +cairo_status_t +_cairo_path_data_append_to_context (cairo_path_data_t *path_data, + cairo_t *cr) +{ + cairo_path_data_t *p; + + for (p = path_data; p->header.type != CAIRO_PATH_END; p += p->header.length) { + switch (p->header.type) { + case CAIRO_PATH_MOVE_TO: + cairo_move_to (cr, + p[1].point.x, p[1].point.y); + if (p->header.length != 2) + return CAIRO_STATUS_INVALID_PATH_DATA; + break; + case CAIRO_PATH_LINE_TO: + cairo_line_to (cr, + p[1].point.x, p[1].point.y); + if (p->header.length != 2) + return CAIRO_STATUS_INVALID_PATH_DATA; + break; + case CAIRO_PATH_CURVE_TO: + cairo_curve_to (cr, + p[1].point.x, p[1].point.y, + p[2].point.x, p[2].point.y, + p[3].point.x, p[3].point.y); + if (p->header.length != 4) + return CAIRO_STATUS_INVALID_PATH_DATA; + break; + case CAIRO_PATH_CLOSE_PATH: + cairo_close_path (cr); + if (p->header.length != 1) + return CAIRO_STATUS_INVALID_PATH_DATA; + break; + default: + return CAIRO_STATUS_INVALID_PATH_DATA; + } + } + + return CAIRO_STATUS_SUCCESS; +} diff --git a/test/.cvsignore b/test/.cvsignore index 5aa262f12..5eb114223 100644 --- a/test/.cvsignore +++ b/test/.cvsignore @@ -5,10 +5,13 @@ Makefile.in clip_twice coverage fill_rule +get_and_set imagediff leaky_polygon line_width +linear_gradient move_to_show_surface +path_data pixman_rotate text_cache_crash text_rotate diff --git a/test/Makefile.am b/test/Makefile.am index e2a2d3489..d0d49e6b5 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -8,6 +8,7 @@ leaky_polygon \ line_width \ linear_gradient \ move_to_show_surface \ +path_data \ pixman_rotate \ text_cache_crash \ text_rotate \ @@ -24,6 +25,7 @@ linear_gradient-ref.png \ move_to_show_surface-ref.png \ coverage-ref.png \ clip_twice-ref.png \ +path_data-ref.png \ pixman_rotate-ref.png \ romedalen.png @@ -76,6 +78,7 @@ leaky_polygon_SOURCES = leaky_polygon.c $(cairo_test_lib) line_width_SOURCES = line_width.c $(cairo_test_lib) linear_gradient_SOURCES = linear_gradient.c $(cairo_test_lib) move_to_show_surface_SOURCES = move_to_show_surface.c $(cairo_test_lib) +path_data_SOURCES = path_data.c $(cairo_test_lib) pixman_rotate_SOURCES = pixman_rotate.c $(cairo_test_lib) text_cache_crash_SOURCES = text_cache_crash.c $(cairo_test_lib) text_rotate_SOURCES = text_rotate.c $(cairo_test_lib) diff --git a/test/path-data.c b/test/path-data.c new file mode 100644 index 000000000..5c2d68f08 --- /dev/null +++ b/test/path-data.c @@ -0,0 +1,167 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include +#include "cairo_test.h" + +cairo_test_t test = { + "path_data", + "Tests calls to path_data functions: cairo_copy_path_data, cairo_copy_path_data_flat, and cairo_append_path_data", + 45, 53 +}; + +static void +scale_by_two (double *x, double *y) +{ + *x = *x * 2.0; + *y = *y * 2.0; +} + +typedef void (*munge_func_t) (double *x, double *y); + +static void +munge_and_set_path (cairo_t *cr, + cairo_path_data_t *path, + munge_func_t munge) +{ + cairo_path_data_t *p; + double x1, y1, x2, y2, x3, y3; + + p = path; + while (1) { + switch (p->header.type) { + case CAIRO_PATH_MOVE_TO: + x1 = p[1].point.x; y1 = p[1].point.y; + (munge) (&x1, &y1); + cairo_move_to (cr, x1, y1); + break; + case CAIRO_PATH_LINE_TO: + x1 = p[1].point.x; y1 = p[1].point.y; + (munge) (&x1, &y1); + cairo_line_to (cr, x1, y1); + break; + case CAIRO_PATH_CURVE_TO: + x1 = p[1].point.x; y1 = p[1].point.y; + x2 = p[2].point.x; y2 = p[2].point.y; + x3 = p[3].point.x; y3 = p[3].point.y; + (munge) (&x1, &y1); + (munge) (&x2, &y2); + (munge) (&x3, &y3); + cairo_curve_to (cr, + x1, y1, + x2, y2, + x3, y3); + break; + case CAIRO_PATH_CLOSE_PATH: + cairo_close_path (cr); + break; + case CAIRO_PATH_END: + return; + } + p += p->header.length; + } +} + +static void +make_path (cairo_t *cr) +{ + cairo_rectangle (cr, 0, 0, 5, 5); + cairo_move_to (cr, 15, 2.5); + cairo_arc (cr, 12.5, 2.5, 2.5, 0, 2 * M_PI); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_path_data_t *path; + + /* copy path, munge, and fill */ + cairo_translate (cr, 5, 5); + make_path (cr); + path = cairo_copy_path_data (cr); + + cairo_new_path (cr); + munge_and_set_path (cr, path, scale_by_two); + free (path); + cairo_fill (cr); + + /* copy flattened path, munge, and fill */ + cairo_translate (cr, 0, 15); + make_path (cr); + path = cairo_copy_path_data_flat (cr); + + cairo_new_path (cr); + munge_and_set_path (cr, path, scale_by_two); + free (path); + cairo_fill (cr); + + /* append two copies of path, and fill */ + cairo_translate (cr, 0, 15); + cairo_scale (cr, 2.0, 2.0); + make_path (cr); + path = cairo_copy_path_data (cr); + + cairo_new_path (cr); + cairo_append_path_data (cr, path); + cairo_translate (cr, 2.5, 2.5); + cairo_append_path_data (cr, path); + + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +int +main (void) +{ + cairo_t *cr; + cairo_path_data_t bogus_path_data; + + /* Test a couple error conditions for cairo_append_path_data */ + cr = cairo_create (); + cairo_append_path_data (cr, NULL); + if (cairo_status (cr) != CAIRO_STATUS_NULL_POINTER) + return 1; + cairo_destroy (cr); + + cr = cairo_create (); + bogus_path_data.header.type = CAIRO_PATH_MOVE_TO; + bogus_path_data.header.length = 1; + cairo_append_path_data (cr, &bogus_path_data); + if (cairo_status (cr) != CAIRO_STATUS_INVALID_PATH_DATA) + return 1; + cairo_destroy (cr); + + /* And test the degnerate case */ + cr = cairo_create (); + bogus_path_data.header.type = CAIRO_PATH_END; + cairo_append_path_data (cr, &bogus_path_data); + if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) + return 1; + cairo_destroy (cr); + + return cairo_test (&test, draw); +} diff --git a/test/path_data.c b/test/path_data.c new file mode 100644 index 000000000..5c2d68f08 --- /dev/null +++ b/test/path_data.c @@ -0,0 +1,167 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include +#include "cairo_test.h" + +cairo_test_t test = { + "path_data", + "Tests calls to path_data functions: cairo_copy_path_data, cairo_copy_path_data_flat, and cairo_append_path_data", + 45, 53 +}; + +static void +scale_by_two (double *x, double *y) +{ + *x = *x * 2.0; + *y = *y * 2.0; +} + +typedef void (*munge_func_t) (double *x, double *y); + +static void +munge_and_set_path (cairo_t *cr, + cairo_path_data_t *path, + munge_func_t munge) +{ + cairo_path_data_t *p; + double x1, y1, x2, y2, x3, y3; + + p = path; + while (1) { + switch (p->header.type) { + case CAIRO_PATH_MOVE_TO: + x1 = p[1].point.x; y1 = p[1].point.y; + (munge) (&x1, &y1); + cairo_move_to (cr, x1, y1); + break; + case CAIRO_PATH_LINE_TO: + x1 = p[1].point.x; y1 = p[1].point.y; + (munge) (&x1, &y1); + cairo_line_to (cr, x1, y1); + break; + case CAIRO_PATH_CURVE_TO: + x1 = p[1].point.x; y1 = p[1].point.y; + x2 = p[2].point.x; y2 = p[2].point.y; + x3 = p[3].point.x; y3 = p[3].point.y; + (munge) (&x1, &y1); + (munge) (&x2, &y2); + (munge) (&x3, &y3); + cairo_curve_to (cr, + x1, y1, + x2, y2, + x3, y3); + break; + case CAIRO_PATH_CLOSE_PATH: + cairo_close_path (cr); + break; + case CAIRO_PATH_END: + return; + } + p += p->header.length; + } +} + +static void +make_path (cairo_t *cr) +{ + cairo_rectangle (cr, 0, 0, 5, 5); + cairo_move_to (cr, 15, 2.5); + cairo_arc (cr, 12.5, 2.5, 2.5, 0, 2 * M_PI); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_path_data_t *path; + + /* copy path, munge, and fill */ + cairo_translate (cr, 5, 5); + make_path (cr); + path = cairo_copy_path_data (cr); + + cairo_new_path (cr); + munge_and_set_path (cr, path, scale_by_two); + free (path); + cairo_fill (cr); + + /* copy flattened path, munge, and fill */ + cairo_translate (cr, 0, 15); + make_path (cr); + path = cairo_copy_path_data_flat (cr); + + cairo_new_path (cr); + munge_and_set_path (cr, path, scale_by_two); + free (path); + cairo_fill (cr); + + /* append two copies of path, and fill */ + cairo_translate (cr, 0, 15); + cairo_scale (cr, 2.0, 2.0); + make_path (cr); + path = cairo_copy_path_data (cr); + + cairo_new_path (cr); + cairo_append_path_data (cr, path); + cairo_translate (cr, 2.5, 2.5); + cairo_append_path_data (cr, path); + + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +int +main (void) +{ + cairo_t *cr; + cairo_path_data_t bogus_path_data; + + /* Test a couple error conditions for cairo_append_path_data */ + cr = cairo_create (); + cairo_append_path_data (cr, NULL); + if (cairo_status (cr) != CAIRO_STATUS_NULL_POINTER) + return 1; + cairo_destroy (cr); + + cr = cairo_create (); + bogus_path_data.header.type = CAIRO_PATH_MOVE_TO; + bogus_path_data.header.length = 1; + cairo_append_path_data (cr, &bogus_path_data); + if (cairo_status (cr) != CAIRO_STATUS_INVALID_PATH_DATA) + return 1; + cairo_destroy (cr); + + /* And test the degnerate case */ + cr = cairo_create (); + bogus_path_data.header.type = CAIRO_PATH_END; + cairo_append_path_data (cr, &bogus_path_data); + if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) + return 1; + cairo_destroy (cr); + + return cairo_test (&test, draw); +}