1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007-2015 Nicola Fontana <ntd at entidi.it>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
25 static cairo_path_data_t data
[] = {
26 /* Useless heading CPML_MOVE */
27 { .header
= { CPML_MOVE
, 2 }},
30 /* First segment: a couple of lines of length 2 */
31 { .header
= { CPML_MOVE
, 2 }},
33 { .header
= { CPML_LINE
, 2 }},
35 { .header
= { CPML_LINE
, 2 }},
38 /* Another useless CPML_MOVE with useless embedded data */
39 { .header
= { CPML_MOVE
, 3 }},
43 /* Second segment: a Bézier curve with a trailing CPML_CLOSE */
44 { .header
= { CPML_MOVE
, 2 }},
45 { .point
= { 10, 13 }},
46 { .header
= { CPML_CURVE
, 4 }},
48 { .point
= { 10, 11 }},
49 { .point
= { 12, 13 }},
50 { .header
= { CPML_CLOSE
, 1 }},
52 /* A valid cairo segment considered invalid by CPML
53 * because does not have a leading CPML_MOVE */
54 { .header
= { CPML_LINE
, 2 }},
55 { .point
= { 10, 0 }},
56 { .header
= { CPML_CLOSE
, 1 }},
58 /* Another valid cairo segment invalid in CPML */
59 { .header
= { CPML_CLOSE
, 1 }},
61 /* Third segment: a couple of arcs */
62 { .header
= { CPML_MOVE
, 2 }},
63 { .point
= { 14, 15 }},
64 { .header
= { CPML_ARC
, 3 }},
65 { .point
= { 16, 17 }},
66 { .point
= { 18, 19 }},
67 { .header
= { CPML_ARC
, 3 }},
68 { .point
= { 20, 21 }},
69 { .point
= { 22, 23 }},
71 /* Forth segment: a floating CPML_CLOSE */
72 { .header
= { CPML_MOVE
, 2 }},
73 { .point
= { 24, 25 }},
74 { .header
= { CPML_CLOSE
, 1 }}
77 static cairo_path_data_t noop_data
[] = {
78 /* Useless heading CPML_MOVE */
79 { .header
= { CPML_MOVE
, 2 }},
81 { .header
= { CPML_MOVE
, 4 }},
85 { .header
= { CPML_MOVE
, 2 }},
89 static cairo_path_data_t y1_data
[] = {
90 { .header
= { CPML_MOVE
, 2 }},
92 { .header
= { CPML_LINE
, 2 }},
102 cairo_path_t noop_path
= {
103 CAIRO_STATUS_SUCCESS
,
105 G_N_ELEMENTS(noop_data
)
108 cairo_path_t y1_path
= {
109 CAIRO_STATUS_SUCCESS
,
111 G_N_ELEMENTS(y1_data
)
116 _cpml_test_browsing(void)
119 cpml_segment_from_cairo(&segment
, &path
);
122 g_assert_cmpint(segment
.data
[0].header
.type
, ==, CPML_MOVE
);
123 g_assert_cmpint(segment
.data
[2].header
.type
, ==, CPML_LINE
);
125 cpml_segment_reset(&segment
);
126 g_assert_cmpint(segment
.data
[0].header
.type
, ==, CPML_MOVE
);
127 g_assert_cmpint(segment
.data
[2].header
.type
, ==, CPML_LINE
);
130 g_assert_cmpint(cpml_segment_next(&segment
), ==, 1);
131 g_assert_cmpint(segment
.data
[0].header
.type
, ==, CPML_MOVE
);
132 g_assert_cmpint(segment
.data
[2].header
.type
, ==, CPML_CURVE
);
135 g_assert_cmpint(cpml_segment_next(&segment
), ==, 1);
136 g_assert_cmpint(segment
.data
[0].header
.type
, ==, CPML_MOVE
);
137 g_assert_cmpint(segment
.data
[2].header
.type
, ==, CPML_ARC
);
140 g_assert_cmpint(cpml_segment_next(&segment
), ==, 1);
141 g_assert_cmpint(segment
.data
[0].header
.type
, ==, CPML_MOVE
);
142 g_assert_cmpint(segment
.data
[2].header
.type
, ==, CPML_CLOSE
);
144 g_assert_cmpint(cpml_segment_next(&segment
), ==, 0);
146 cpml_segment_reset(&segment
);
147 g_assert_cmpint(segment
.data
[0].header
.type
, ==, CPML_MOVE
);
148 g_assert_cmpint(segment
.data
[2].header
.type
, ==, CPML_LINE
);
152 _cpml_test_sanity_from_cairo(gint i
)
158 cpml_segment_from_cairo(NULL
, &path
);
161 cpml_segment_from_cairo(&segment
, NULL
);
164 g_test_trap_assert_failed();
170 _cpml_test_sanity_get_length(gint i
)
174 cpml_segment_get_length(NULL
);
177 g_test_trap_assert_failed();
183 _cpml_test_sanity_put_intersections(gint i
)
190 cpml_segment_put_intersections(NULL
, &segment
, 2, &pair
);
193 cpml_segment_put_intersections(&segment
, NULL
, 2, &pair
);
196 cpml_segment_put_intersections(&segment
, &segment
, 2, NULL
);
199 g_test_trap_assert_failed();
205 _cpml_test_sanity_offset(gint i
)
209 cpml_segment_offset(NULL
, 1);
212 g_test_trap_assert_failed();
218 _cpml_test_sanity_transform(gint i
)
221 cairo_matrix_t matrix
;
225 cpml_segment_transform(NULL
, &matrix
);
228 cpml_segment_transform(&segment
, NULL
);
231 g_test_trap_assert_failed();
237 _cpml_test_sanity_reverse(gint i
)
241 cpml_segment_reverse(NULL
);
244 g_test_trap_assert_failed();
250 _cpml_test_sanity_to_cairo(gint i
)
256 cpml_segment_to_cairo(NULL
, adg_test_cairo_context());
259 cpml_segment_to_cairo(&segment
, NULL
);
261 g_test_trap_assert_failed();
267 _cpml_test_sanity_dump(gint i
)
271 cpml_segment_dump(NULL
);
274 g_test_trap_assert_failed();
280 _cpml_test_from_cairo(void)
283 g_assert_cmpint(cpml_segment_from_cairo(&segment
, &noop_path
), ==, 0);
284 g_assert_cmpint(cpml_segment_from_cairo(&segment
, &path
), ==, 1);
288 _cpml_test_get_length(void)
291 cpml_segment_from_cairo(&segment
, &path
);
295 g_assert_cmpfloat(cpml_segment_get_length(&segment
), ==, 4);
296 g_assert_cmpfloat(cpml_segment_get_length(&segment
), ==, 4);
299 cpml_segment_next(&segment
);
300 /* TODO: Bézier curve length not yet implemented
301 * g_assert_cmpfloat(cpml_segment_get_length(&segment), ==, ???); */
304 cpml_segment_next(&segment
);
305 g_assert_cmpfloat(cpml_segment_get_length(&segment
), ==, 0);
308 cpml_segment_next(&segment
);
309 g_assert_cmpfloat(cpml_segment_get_length(&segment
), ==, 0);
313 _cpml_test_put_intersections(void)
315 CpmlSegment segment1
, segment2
;
318 cpml_segment_from_cairo(&segment1
, &path
);
319 cpml_segment_from_cairo(&segment2
, &y1_path
);
321 g_assert_cmpuint(cpml_segment_put_intersections(&segment1
, &segment2
, 0, pair
), ==, 0);
323 /* The first segment of path intersects y1_path in (2, 1) */
324 g_assert_cmpuint(cpml_segment_put_intersections(&segment1
, &segment2
, 2, pair
), ==, 1);
325 g_assert_cmpfloat(pair
[0].x
, ==, 2);
326 g_assert_cmpfloat(pair
[0].y
, ==, 1);
328 /* The third segment of path does not intersect y1_path */
329 cpml_segment_next(&segment1
);
330 cpml_segment_next(&segment1
);
331 g_assert_cmpuint(cpml_segment_put_intersections(&segment1
, &segment2
, 2, pair
), ==, 0);
335 _cpml_test_offset(void)
337 CpmlSegment original
, *segment
;
339 cpml_segment_from_cairo(&original
, &path
);
341 /* Working on a duplicate of the first segment to avoid modifying path */
342 segment
= cpml_segment_deep_dup(&original
);
343 cpml_segment_offset(segment
, 1);
345 g_assert_cmpint(segment
->data
[0].header
.type
, ==, CPML_MOVE
);
346 g_assert_cmpfloat(segment
->data
[1].point
.x
, ==, 0);
347 g_assert_cmpfloat(segment
->data
[1].point
.y
, ==, 1);
349 g_assert_cmpint(segment
->data
[2].header
.type
, ==, CPML_LINE
);
350 g_assert_cmpfloat(segment
->data
[3].point
.x
, ==, 1);
351 g_assert_cmpfloat(segment
->data
[3].point
.y
, ==, 1);
353 g_assert_cmpint(segment
->data
[4].header
.type
, ==, CPML_LINE
);
354 g_assert_cmpfloat(segment
->data
[5].point
.x
, ==, 1);
355 g_assert_cmpfloat(segment
->data
[5].point
.y
, ==, 2);
357 /* TODO: provide tests for arcs and curves */
363 _cpml_test_transform(void)
365 CpmlSegment original
, *segment
;
366 cairo_matrix_t matrix
;
368 cpml_segment_from_cairo(&original
, &path
);
370 /* Working on a duplicate of the first segment to avoid modifying path */
371 segment
= cpml_segment_deep_dup(&original
);
373 cairo_matrix_init_translate(&matrix
, 1, 2);
374 cpml_segment_transform(segment
, &matrix
);
376 g_assert_cmpint(segment
->data
[0].header
.type
, ==, CPML_MOVE
);
377 g_assert_cmpfloat(segment
->data
[1].point
.x
, ==, 1);
378 g_assert_cmpfloat(segment
->data
[1].point
.y
, ==, 2);
380 g_assert_cmpint(segment
->data
[2].header
.type
, ==, CPML_LINE
);
381 g_assert_cmpfloat(segment
->data
[3].point
.x
, ==, 3);
382 g_assert_cmpfloat(segment
->data
[3].point
.y
, ==, 2);
384 g_assert_cmpint(segment
->data
[4].header
.type
, ==, CPML_LINE
);
385 g_assert_cmpfloat(segment
->data
[5].point
.x
, ==, 3);
386 g_assert_cmpfloat(segment
->data
[5].point
.y
, ==, 4);
392 _cpml_test_reverse(void)
394 CpmlSegment original
, *segment
;
396 cpml_segment_from_cairo(&original
, &path
);
398 /* First segment: work on a duplicate to avoid modifying path */
399 segment
= cpml_segment_deep_dup(&original
);
400 cpml_segment_reverse(segment
);
402 g_assert_cmpint(segment
->num_data
, ==, 6);
404 g_assert_cmpint(segment
->data
[0].header
.type
, ==, CPML_MOVE
);
405 g_assert_cmpfloat(segment
->data
[1].point
.x
, ==, 2);
406 g_assert_cmpfloat(segment
->data
[1].point
.y
, ==, 2);
408 g_assert_cmpint(segment
->data
[2].header
.type
, ==, CPML_LINE
);
409 g_assert_cmpfloat(segment
->data
[3].point
.x
, ==, 2);
410 g_assert_cmpfloat(segment
->data
[3].point
.y
, ==, 0);
412 g_assert_cmpint(segment
->data
[4].header
.type
, ==, CPML_LINE
);
413 g_assert_cmpfloat(segment
->data
[5].point
.x
, ==, 0);
414 g_assert_cmpfloat(segment
->data
[5].point
.y
, ==, 0);
418 /* TODO: the second segment is an invalid CPML segment because
419 * it is followed by a segment without a leading move_to.
420 * Find a decent reverse algorithm and document it.
421 * I'm just skipping that segment for now.
423 cpml_segment_next(&original
);
426 cpml_segment_next(&original
);
427 segment
= cpml_segment_deep_dup(&original
);
428 cpml_segment_reverse(segment
);
430 g_assert_cmpint(segment
->num_data
, ==, 8);
432 g_assert_cmpint(segment
->data
[0].header
.type
, ==, CPML_MOVE
);
433 g_assert_cmpfloat(segment
->data
[1].point
.x
, ==, 22);
434 g_assert_cmpfloat(segment
->data
[1].point
.y
, ==, 23);
436 g_assert_cmpint(segment
->data
[2].header
.type
, ==, CPML_ARC
);
437 g_assert_cmpfloat(segment
->data
[3].point
.x
, ==, 20);
438 g_assert_cmpfloat(segment
->data
[3].point
.y
, ==, 21);
439 g_assert_cmpfloat(segment
->data
[4].point
.x
, ==, 18);
440 g_assert_cmpfloat(segment
->data
[4].point
.y
, ==, 19);
442 g_assert_cmpint(segment
->data
[5].header
.type
, ==, CPML_ARC
);
443 g_assert_cmpfloat(segment
->data
[6].point
.x
, ==, 16);
444 g_assert_cmpfloat(segment
->data
[6].point
.y
, ==, 17);
445 g_assert_cmpfloat(segment
->data
[7].point
.x
, ==, 14);
446 g_assert_cmpfloat(segment
->data
[7].point
.y
, ==, 15);
451 cpml_segment_next(&original
);
452 segment
= cpml_segment_deep_dup(&original
);
453 cpml_segment_reverse(segment
);
455 g_assert_cmpint(segment
->num_data
, ==, 3);
457 g_assert_cmpint(segment
->data
[0].header
.type
, ==, CPML_MOVE
);
458 g_assert_cmpfloat(segment
->data
[1].point
.x
, ==, 24);
459 g_assert_cmpfloat(segment
->data
[1].point
.y
, ==, 25);
461 g_assert_cmpint(segment
->data
[2].header
.type
, ==, CPML_CLOSE
);
467 _cpml_test_to_cairo(void)
471 int length
, last_length
;
473 cr
= adg_test_cairo_context();
474 cpml_segment_from_cairo(&segment
, &path
);
476 g_assert_cmpint(adg_test_cairo_num_data(cr
), ==, 0);
480 last_length
= length
;
481 cpml_segment_to_cairo(&segment
, cr
);
482 length
= adg_test_cairo_num_data(cr
);
483 g_assert_cmpint(length
, >, last_length
);
484 } while (cpml_segment_next(&segment
));
490 _cpml_test_dump(gint i
)
496 cpml_segment_from_cairo(&segment
, &path
);
497 cpml_segment_dump(&segment
);
498 cpml_segment_next(&segment
);
499 cpml_segment_dump(&segment
);
502 g_test_trap_assert_passed();
503 g_test_trap_assert_stderr_unmatched("?");
504 g_test_trap_assert_stdout("*move*");
505 g_test_trap_assert_stdout("*line*");
506 g_test_trap_assert_stdout("*curve*");
507 g_test_trap_assert_stdout_unmatched("*arc*");
514 main(int argc
, char *argv
[])
516 adg_test_init(&argc
, &argv
);
518 g_test_add_func("/cpml/segment/behavior/browsing", _cpml_test_browsing
);
520 adg_test_add_traps("/cpml/segment/sanity/from-cairo", _cpml_test_sanity_from_cairo
, 2);
521 adg_test_add_traps("/cpml/segment/sanity/get-length", _cpml_test_sanity_get_length
, 1);
522 adg_test_add_traps("/cpml/segment/sanity/put-intersections", _cpml_test_sanity_put_intersections
, 3);
523 adg_test_add_traps("/cpml/segment/sanity/offset", _cpml_test_sanity_offset
, 1);
524 adg_test_add_traps("/cpml/segment/sanity/transform", _cpml_test_sanity_transform
, 2);
525 adg_test_add_traps("/cpml/segment/sanity/reverse", _cpml_test_sanity_reverse
, 1);
526 adg_test_add_traps("/cpml/segment/sanity/to-cairo", _cpml_test_sanity_to_cairo
, 2);
527 adg_test_add_traps("/cpml/segment/sanity/dump", _cpml_test_sanity_dump
, 1);
529 g_test_add_func("/cpml/segment/method/from-cairo", _cpml_test_from_cairo
);
530 g_test_add_func("/cpml/segment/method/get-length", _cpml_test_get_length
);
531 g_test_add_func("/cpml/segment/method/put-intersections", _cpml_test_put_intersections
);
532 g_test_add_func("/cpml/segment/method/offset", _cpml_test_offset
);
533 g_test_add_func("/cpml/segment/method/transform", _cpml_test_transform
);
534 g_test_add_func("/cpml/segment/method/reverse", _cpml_test_reverse
);
535 g_test_add_func("/cpml/segment/method/to-cairo", _cpml_test_to_cairo
);
536 adg_test_add_traps("/cpml/segment/method/dump", _cpml_test_dump
, 1);