copy-path.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. /*
  2. * Copyright © 2005 Red Hat, Inc.
  3. *
  4. * Permission to use, copy, modify, distribute, and sell this software
  5. * and its documentation for any purpose is hereby granted without
  6. * fee, provided that the above copyright notice appear in all copies
  7. * and that both that copyright notice and this permission notice
  8. * appear in supporting documentation, and that the name of
  9. * Red Hat, Inc. not be used in advertising or publicity pertaining to
  10. * distribution of the software without specific, written prior
  11. * permission. Red Hat, Inc. makes no representations about the
  12. * suitability of this software for any purpose. It is provided "as
  13. * is" without express or implied warranty.
  14. *
  15. * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
  16. * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  17. * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
  18. * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
  19. * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  20. * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
  21. * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  22. *
  23. * Author: Carl D. Worth <cworth@cworth.org>
  24. */
  25. #include "cairo-test.h"
  26. #include <stdlib.h>
  27. static void
  28. scale_by_two (double *x, double *y)
  29. {
  30. *x = *x * 2.0;
  31. *y = *y * 2.0;
  32. }
  33. typedef void (*munge_func_t) (double *x, double *y);
  34. static void
  35. munge_and_set_path (cairo_t *cr,
  36. cairo_path_t *path,
  37. munge_func_t munge)
  38. {
  39. int i;
  40. cairo_path_data_t *p;
  41. double x1, y1, x2, y2, x3, y3;
  42. if (path->status) {
  43. cairo_append_path (cr, path);
  44. return;
  45. }
  46. for (i=0; i < path->num_data; i += path->data[i].header.length) {
  47. p = &path->data[i];
  48. switch (p->header.type) {
  49. case CAIRO_PATH_MOVE_TO:
  50. x1 = p[1].point.x; y1 = p[1].point.y;
  51. (munge) (&x1, &y1);
  52. cairo_move_to (cr, x1, y1);
  53. break;
  54. case CAIRO_PATH_LINE_TO:
  55. x1 = p[1].point.x; y1 = p[1].point.y;
  56. (munge) (&x1, &y1);
  57. cairo_line_to (cr, x1, y1);
  58. break;
  59. case CAIRO_PATH_CURVE_TO:
  60. x1 = p[1].point.x; y1 = p[1].point.y;
  61. x2 = p[2].point.x; y2 = p[2].point.y;
  62. x3 = p[3].point.x; y3 = p[3].point.y;
  63. (munge) (&x1, &y1);
  64. (munge) (&x2, &y2);
  65. (munge) (&x3, &y3);
  66. cairo_curve_to (cr,
  67. x1, y1,
  68. x2, y2,
  69. x3, y3);
  70. break;
  71. case CAIRO_PATH_CLOSE_PATH:
  72. cairo_close_path (cr);
  73. break;
  74. }
  75. }
  76. }
  77. static void
  78. make_path (cairo_t *cr)
  79. {
  80. cairo_rectangle (cr, 0, 0, 5, 5);
  81. cairo_move_to (cr, 15, 2.5);
  82. cairo_arc (cr, 12.5, 2.5, 2.5, 0, 2 * M_PI);
  83. }
  84. static cairo_test_status_t
  85. draw (cairo_t *cr, int width, int height)
  86. {
  87. const cairo_test_context_t *ctx = cairo_test_get_context (cr);
  88. cairo_path_t *path;
  89. cairo_t *cr_error;
  90. /* Ensure that calling cairo_copy_path on an in-error cairo_t will
  91. * propagate the error. */
  92. cr_error = cairo_create (NULL);
  93. path = cairo_copy_path (cr_error);
  94. if (path->status != CAIRO_STATUS_NULL_POINTER) {
  95. cairo_test_log (ctx,
  96. "Error: cairo_copy_path returned status of %s rather than propagating %s\n",
  97. cairo_status_to_string (path->status),
  98. cairo_status_to_string (CAIRO_STATUS_NULL_POINTER));
  99. cairo_path_destroy (path);
  100. cairo_destroy (cr_error);
  101. return CAIRO_TEST_FAILURE;
  102. }
  103. cairo_path_destroy (path);
  104. path = cairo_copy_path_flat (cr_error);
  105. if (path->status != CAIRO_STATUS_NULL_POINTER) {
  106. cairo_test_log (ctx,
  107. "Error: cairo_copy_path_flat returned status of %s rather than propagating %s\n",
  108. cairo_status_to_string (path->status),
  109. cairo_status_to_string (CAIRO_STATUS_NULL_POINTER));
  110. cairo_path_destroy (path);
  111. cairo_destroy (cr_error);
  112. return CAIRO_TEST_FAILURE;
  113. }
  114. cairo_path_destroy (path);
  115. cairo_destroy (cr_error);
  116. /* first check that we can copy an empty path */
  117. cairo_new_path (cr);
  118. path = cairo_copy_path (cr);
  119. if (path->status != CAIRO_STATUS_SUCCESS) {
  120. cairo_status_t status = path->status;
  121. cairo_test_log (ctx,
  122. "Error: cairo_copy_path returned status of %s\n",
  123. cairo_status_to_string (status));
  124. cairo_path_destroy (path);
  125. return cairo_test_status_from_status (ctx, status);
  126. }
  127. if (path->num_data != 0) {
  128. cairo_test_log (ctx,
  129. "Error: cairo_copy_path did not copy an empty path, returned path contains %d elements\n",
  130. path->num_data);
  131. cairo_path_destroy (path);
  132. return CAIRO_TEST_FAILURE;
  133. }
  134. cairo_append_path (cr, path);
  135. cairo_path_destroy (path);
  136. if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) {
  137. cairo_test_log (ctx,
  138. "Error: cairo_append_path failed with a copy of an empty path, returned status of %s\n",
  139. cairo_status_to_string (cairo_status (cr)));
  140. return cairo_test_status_from_status (ctx, cairo_status (cr));
  141. }
  142. /* We draw in the default black, so paint white first. */
  143. cairo_save (cr);
  144. cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */
  145. cairo_paint (cr);
  146. cairo_restore (cr);
  147. /* copy path, munge, and fill */
  148. cairo_translate (cr, 5, 5);
  149. make_path (cr);
  150. path = cairo_copy_path (cr);
  151. cairo_new_path (cr);
  152. munge_and_set_path (cr, path, scale_by_two);
  153. cairo_path_destroy (path);
  154. cairo_fill (cr);
  155. /* copy flattened path, munge, and fill */
  156. cairo_translate (cr, 0, 15);
  157. make_path (cr);
  158. path = cairo_copy_path_flat (cr);
  159. cairo_new_path (cr);
  160. munge_and_set_path (cr, path, scale_by_two);
  161. cairo_path_destroy (path);
  162. cairo_fill (cr);
  163. /* append two copies of path, and fill */
  164. cairo_translate (cr, 0, 15);
  165. cairo_scale (cr, 2.0, 2.0);
  166. make_path (cr);
  167. path = cairo_copy_path (cr);
  168. cairo_new_path (cr);
  169. cairo_append_path (cr, path);
  170. cairo_translate (cr, 2.5, 2.5);
  171. cairo_append_path (cr, path);
  172. cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
  173. cairo_fill (cr);
  174. cairo_path_destroy (path);
  175. return CAIRO_TEST_SUCCESS;
  176. }
  177. static cairo_test_status_t
  178. preamble (cairo_test_context_t *ctx)
  179. {
  180. cairo_t *cr;
  181. cairo_path_data_t data;
  182. cairo_path_t path;
  183. cairo_surface_t *surface;
  184. cairo_status_t status;
  185. surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
  186. status = cairo_surface_status (surface);
  187. if (status) {
  188. cairo_surface_destroy (surface);
  189. return cairo_test_status_from_status (ctx, status);
  190. }
  191. /* Test a few error cases for cairo_append_path_data */
  192. #define CAIRO_CREATE() do {\
  193. cr = cairo_create (surface); \
  194. status = cairo_status (cr); \
  195. if (status) { \
  196. cairo_destroy (cr); \
  197. cairo_surface_destroy (surface); \
  198. return cairo_test_status_from_status (ctx, status); \
  199. } \
  200. } while (0)
  201. CAIRO_CREATE ();
  202. cairo_append_path (cr, NULL);
  203. status = cairo_status (cr);
  204. cairo_destroy (cr);
  205. if (status != CAIRO_STATUS_NULL_POINTER) {
  206. cairo_surface_destroy (surface);
  207. return cairo_test_status_from_status (ctx, status);
  208. }
  209. CAIRO_CREATE ();
  210. path.status = -1;
  211. cairo_append_path (cr, &path);
  212. status = cairo_status (cr);
  213. cairo_destroy (cr);
  214. if (status != CAIRO_STATUS_INVALID_STATUS) {
  215. cairo_surface_destroy (surface);
  216. return cairo_test_status_from_status (ctx, status);
  217. }
  218. CAIRO_CREATE ();
  219. path.status = CAIRO_STATUS_NO_MEMORY;
  220. cairo_append_path (cr, &path);
  221. status = cairo_status (cr);
  222. cairo_destroy (cr);
  223. if (status != CAIRO_STATUS_NO_MEMORY) {
  224. cairo_surface_destroy (surface);
  225. return cairo_test_status_from_status (ctx, status);
  226. }
  227. CAIRO_CREATE ();
  228. path.data = NULL;
  229. path.num_data = 0;
  230. path.status = CAIRO_STATUS_SUCCESS;
  231. cairo_append_path (cr, &path);
  232. status = cairo_status (cr);
  233. cairo_destroy (cr);
  234. if (status != CAIRO_STATUS_SUCCESS) {
  235. cairo_surface_destroy (surface);
  236. return cairo_test_status_from_status (ctx, status);
  237. }
  238. CAIRO_CREATE ();
  239. path.data = NULL;
  240. path.num_data = 1;
  241. path.status = CAIRO_STATUS_SUCCESS;
  242. cairo_append_path (cr, &path);
  243. status = cairo_status (cr);
  244. cairo_destroy (cr);
  245. if (status != CAIRO_STATUS_NULL_POINTER) {
  246. cairo_surface_destroy (surface);
  247. return cairo_test_status_from_status (ctx, status);
  248. }
  249. CAIRO_CREATE ();
  250. /* Intentionally insert bogus header.length value (otherwise would be 2) */
  251. data.header.type = CAIRO_PATH_MOVE_TO;
  252. data.header.length = 1;
  253. path.data = &data;
  254. path.num_data = 1;
  255. cairo_append_path (cr, &path);
  256. status = cairo_status (cr);
  257. cairo_destroy (cr);
  258. if (status != CAIRO_STATUS_INVALID_PATH_DATA) {
  259. cairo_surface_destroy (surface);
  260. return cairo_test_status_from_status (ctx, status);
  261. }
  262. /* And test the degnerate case */
  263. CAIRO_CREATE ();
  264. path.num_data = 0;
  265. cairo_append_path (cr, &path);
  266. status = cairo_status (cr);
  267. cairo_destroy (cr);
  268. if (status != CAIRO_STATUS_SUCCESS) {
  269. cairo_surface_destroy (surface);
  270. return cairo_test_status_from_status (ctx, status);
  271. }
  272. cairo_surface_destroy (surface);
  273. return CAIRO_TEST_SUCCESS;
  274. }
  275. CAIRO_TEST (copy_path,
  276. "Tests calls to path_data functions: cairo_copy_path, cairo_copy_path_flat, and cairo_append_path",
  277. "path", /* keywords */
  278. NULL, /* requirements */
  279. 45, 53,
  280. preamble, draw)