1 #define GNOME_CANVAS_PATH_DEF_C
2 
3 /*
4  * GnomeCanvasPathDef
5  *
6  * (C) 1999-2000 Lauris Kaplinski <lauris@ximian.com>
7  * Released under LGPL
8  *
9  * Authors: Lauris Kaplinski <lauris@ximian.com>
10  *          Rusty Conover <rconover@bangtail.net>
11  *
12  * Copyright 1999-2001 Ximian Inc. and authors.
13  */
14 
15 #include <string.h>
16 #include <libart_lgpl/art_misc.h>
17 #include "gnome-canvas-path-def.h"
18 
19 /* The number of points to allocate at once */
20 #define GNOME_CANVAS_PATH_DEF_LENSTEP 32
21 
22 struct _GnomeCanvasPathDef {
23 	gint refcount;
24 	ArtBpath * bpath;
25 	gint end;		/* ART_END position */
26 	gint length;		/* Num allocated Bpaths */
27 	gint substart;		/* subpath start */
28 	gdouble x, y;		/* previous moveto position */
29 	guint sbpath : 1;	/* Bpath is static */
30 	guint hascpt : 1;	/* Currentpoint is defined */
31 	guint posset : 1;	/* Previous was moveto */
32 	guint moving : 1;	/* Bpath end is moving */
33 	guint allclosed : 1;	/* All subpaths are closed */
34 	guint allopen : 1;	/* All subpaths are open */
35 };
36 
37 static gboolean sp_bpath_good (ArtBpath * bpath);
38 static ArtBpath * sp_bpath_check_subpath (ArtBpath * bpath);
39 static gint sp_bpath_length (const ArtBpath * bpath);
40 static gboolean sp_bpath_all_closed (const ArtBpath * bpath);
41 static gboolean sp_bpath_all_open (const ArtBpath * bpath);
42 
43 /* Boxed Type Support */
44 
45 static GnomeCanvasPathDef *
path_def_boxed_copy(GnomeCanvasPathDef * path_def)46 path_def_boxed_copy (GnomeCanvasPathDef * path_def)
47 {
48 	if (path_def)
49 		gnome_canvas_path_def_ref (path_def);
50 	return path_def;
51 }
52 
53 GType
gnome_canvas_path_def_get_type(void)54 gnome_canvas_path_def_get_type (void)
55 {
56 	static GType t = 0;
57 	if (t == 0)
58 		t = g_boxed_type_register_static
59 				("GnomeCanvasPathDef",
60 				 (GBoxedCopyFunc)path_def_boxed_copy,
61 				 (GBoxedFreeFunc)gnome_canvas_path_def_unref);
62 	return t;
63 }
64 
65 /* Constructors */
66 
67 /**
68  * gnome_canvas_path_def_new:
69  *
70  * This function creates a new empty #gnome_canvas_path_def.
71  *
72  * Returns: the new canvas path definition.
73  */
74 GnomeCanvasPathDef *
gnome_canvas_path_def_new(void)75 gnome_canvas_path_def_new (void)
76 {
77 	GnomeCanvasPathDef * path;
78 
79 	path = gnome_canvas_path_def_new_sized (GNOME_CANVAS_PATH_DEF_LENSTEP);
80 
81 	return path;
82 }
83 
84 /**
85  * gnome_canvas_path_def_new_sized:
86  * @length: number of points to allocate for the path
87  *
88  * This function creates a new #gnome_canvas_path_def with @length
89  * number of points allocated. It is useful, if you know the exact
90  * number of points in path, so you can avoid automatic point
91  * array reallocation.
92  *
93  * Returns: the new canvas path definition
94  */
95 GnomeCanvasPathDef *
gnome_canvas_path_def_new_sized(gint length)96 gnome_canvas_path_def_new_sized (gint length)
97 {
98 	GnomeCanvasPathDef * path;
99 
100 	g_return_val_if_fail (length > 0, NULL);
101 
102 	path = g_new (GnomeCanvasPathDef, 1);
103 
104 	path->refcount = 1;
105 	path->bpath = art_new (ArtBpath, length);
106 	path->end = 0;
107 	path->bpath[path->end].code = ART_END;
108 	path->length = length;
109 	path->sbpath = FALSE;
110 	path->hascpt = FALSE;
111 	path->posset = FALSE;
112 	path->moving = FALSE;
113 	path->allclosed = TRUE;
114 	path->allopen = TRUE;
115 
116 	return path;
117 }
118 
119 /**
120  * gnome_canvas_path_def_new_from_bpath:
121  * @bpath: libart bezier path
122  *
123  * This function constructs a new #gnome_canvas_path_def and uses the
124  * passed @bpath as the contents.  The passed bpath should not be
125  * static as the path definition is editable when constructed with
126  * this function. Also, passed bpath will be freed with art_free, if
127  * path is destroyed, so use it with caution.
128  * For constructing a #gnome_canvas_path_def
129  * from (non-modifiable) bpath use
130  * #gnome_canvas_path_def_new_from_static_bpath.
131  *
132  * Returns: the new canvas path definition that is populated with the
133  * passed bezier path, if the @bpath is bad NULL is returned.
134  */
135 GnomeCanvasPathDef *
gnome_canvas_path_def_new_from_bpath(ArtBpath * bpath)136 gnome_canvas_path_def_new_from_bpath (ArtBpath * bpath)
137 {
138 	GnomeCanvasPathDef * path;
139 
140 	g_return_val_if_fail (sp_bpath_good (bpath), NULL);
141 
142 	path = g_new (GnomeCanvasPathDef, 1);
143 
144 	path->refcount = 1;
145 	path->bpath = bpath;
146 	path->length = sp_bpath_length (bpath);
147 	path->end = path->length - 1;
148 	path->sbpath = FALSE;
149 	path->hascpt = FALSE;
150 	path->posset = FALSE;
151 	path->moving = FALSE;
152 	path->allclosed = sp_bpath_all_closed (bpath);
153 	path->allopen = sp_bpath_all_open (bpath);
154 
155 	return path;
156 }
157 
158 /**
159  * gnome_canvas_path_def_new_from_static_bpath:
160  * @bpath: libart bezier path
161  *
162  * This function constructs a new #gnome_canvas_path_def and
163  * references the passed @bpath as its contents.  The
164  * #gnome_canvas_path_def returned from this function is to be
165  * considered static and non-editable (meaning you cannot change the
166  * path from what you passed in @bpath). The bpath will not be freed,
167  * if path will be destroyed, so use it with caution.
168  *
169  * Returns: the new canvas path definition that references the passed
170  * @bpath, or if the path is bad NULL is returned.
171  */
172 GnomeCanvasPathDef *
gnome_canvas_path_def_new_from_static_bpath(ArtBpath * bpath)173 gnome_canvas_path_def_new_from_static_bpath (ArtBpath * bpath)
174 {
175 	GnomeCanvasPathDef * path;
176 
177 	g_return_val_if_fail (sp_bpath_good (bpath), NULL);
178 
179 	path = g_new (GnomeCanvasPathDef, 1);
180 
181 	path->refcount = 1;
182 	path->bpath = bpath;
183 	path->length = sp_bpath_length (bpath);
184 	path->end = path->length - 1;
185 	path->sbpath = TRUE;
186 	path->hascpt = FALSE;
187 	path->posset = FALSE;
188 	path->moving = FALSE;
189 	path->allclosed = sp_bpath_all_closed (bpath);
190 	path->allopen = sp_bpath_all_open (bpath);
191 
192 	return path;
193 }
194 
195 /**
196  * gnome_canvas_path_def_new_from_foreign_bpath:
197  * @bpath: libart bezier path
198  *
199  * This function constructs a new #gnome_canvas_path_def and
200  * duplicates the contents of the passed @bpath in the definition.
201  *
202  * Returns: the newly created #gnome_canvas_path_def or NULL if the
203  * path is invalid.
204  */
205 GnomeCanvasPathDef *
gnome_canvas_path_def_new_from_foreign_bpath(ArtBpath * bpath)206 gnome_canvas_path_def_new_from_foreign_bpath (ArtBpath * bpath)
207 {
208 	GnomeCanvasPathDef * path;
209 	gint length;
210 
211 	g_return_val_if_fail (sp_bpath_good (bpath), NULL);
212 
213 	length = sp_bpath_length (bpath);
214 
215 	path = gnome_canvas_path_def_new_sized (length);
216 	memcpy (path->bpath, bpath, sizeof (ArtBpath) * length);
217 	path->end = length - 1;
218 	path->allclosed = sp_bpath_all_closed (bpath);
219 	path->allopen = sp_bpath_all_open (bpath);
220 
221 	return path;
222 }
223 
224 /**
225  * gnome_canvas_path_def_ref:
226  * @path: a GnomeCanvasPathDef
227  *
228  * Increment the reference count of the GnomeCanvasPathDef.
229  */
230 void
gnome_canvas_path_def_ref(GnomeCanvasPathDef * path)231 gnome_canvas_path_def_ref (GnomeCanvasPathDef * path)
232 {
233 	g_return_if_fail (path != NULL);
234 
235 	path->refcount++;
236 }
237 
238 /**
239  * gnome_canvas_path_def_finish:
240  * @path: a GnomeCanvasPathDef
241  *
242  * Trims dynamic point array to exact length of path.
243  */
244 void
gnome_canvas_path_def_finish(GnomeCanvasPathDef * path)245 gnome_canvas_path_def_finish (GnomeCanvasPathDef * path)
246 {
247 	g_return_if_fail (path != NULL);
248 	g_return_if_fail (path->sbpath);
249 
250 	if ((path->end + 1) < path->length) {
251 		path->bpath = art_renew (path->bpath, ArtBpath, path->end + 1);
252 		path->length = path->end + 1;
253 	}
254 
255 	path->hascpt = FALSE;
256 	path->posset = FALSE;
257 	path->moving = FALSE;
258 }
259 /**
260  * gnome_canvas_path_def_ensure_space:
261  * @path: a GnomeCanvasPathDef
262  * @space: number of points to guarantee are allocated at the end of
263  * the path.
264  *
265  * This function ensures that enough space for @space points is
266  * allocated at the end of the path.
267  */
268 void
gnome_canvas_path_def_ensure_space(GnomeCanvasPathDef * path,gint space)269 gnome_canvas_path_def_ensure_space (GnomeCanvasPathDef * path, gint space)
270 {
271 	g_return_if_fail (path != NULL);
272 	g_return_if_fail (space > 0);
273 
274 	if (path->end + space < path->length) return;
275 
276 	if (space < GNOME_CANVAS_PATH_DEF_LENSTEP) space = GNOME_CANVAS_PATH_DEF_LENSTEP;
277 
278 	path->bpath = art_renew (path->bpath, ArtBpath, path->length + space);
279 
280 	path->length += space;
281 }
282 
283 /**
284  * gnome_canvas_path_def_copy:
285  * @dst: a GnomeCanvasPathDef where the contents of @src will be stored.
286  * @src: a GnomeCanvasPathDef whose contents will be copied it @src.
287  *
288  * This function copies the contents @src to @dest. The old @dest path
289  * array is freed and @dest is marked as non-static (editable),
290  * regardless of the status of @src.
291  */
292 void
gnome_canvas_path_def_copy(GnomeCanvasPathDef * dst,const GnomeCanvasPathDef * src)293 gnome_canvas_path_def_copy (GnomeCanvasPathDef * dst, const GnomeCanvasPathDef * src)
294 {
295 	g_return_if_fail (dst != NULL);
296 	g_return_if_fail (src != NULL);
297 
298 	if (!dst->sbpath) g_free (dst->bpath);
299 
300 	memcpy (dst, src, sizeof (GnomeCanvasPathDef));
301 
302 	dst->bpath = g_new (ArtBpath, src->end + 1);
303 	memcpy (dst->bpath, src->bpath, (src->end + 1) * sizeof (ArtBpath));
304 
305 	dst->sbpath = FALSE;
306 }
307 
308 
309 /**
310  * gnome_canvas_path_def_duplicate:
311  * @path: a GnomeCanvasPathDef to duplicate
312  *
313  * This function duplicates the passed @path. The new path is
314  * marked as non-static regardless of the state of original.
315  *
316  * Returns: a GnomeCanvasPathDef which is a duplicate of @path.
317  */
318 GnomeCanvasPathDef *
gnome_canvas_path_def_duplicate(const GnomeCanvasPathDef * path)319 gnome_canvas_path_def_duplicate (const GnomeCanvasPathDef * path)
320 {
321 	GnomeCanvasPathDef * new;
322 
323 	g_return_val_if_fail (path != NULL, NULL);
324 
325 	new = gnome_canvas_path_def_new_from_foreign_bpath (path->bpath);
326 	new->x = path->x;
327 	new->y = path->y;
328 	new->hascpt = path->hascpt;
329 	new->posset = path->posset;
330 	new->moving = path->moving;
331 	new->allclosed = path->allclosed;
332 	new->allopen = path->allopen;
333 
334 	return new;
335 }
336 
337 /**
338  * gnome_canvas_path_def_concat:
339  * @list: a GSList of GnomeCanvasPathDefs to concatenate into one new
340  * path.
341  *
342  * This function concatenates a list of GnomeCanvasPathDefs into one
343  * newly created GnomeCanvasPathDef.
344  *
345  * Returns: a new GnomeCanvasPathDef
346  */
347 GnomeCanvasPathDef *
gnome_canvas_path_def_concat(const GSList * list)348 gnome_canvas_path_def_concat (const GSList * list)
349 {
350 	GnomeCanvasPathDef * c, * new;
351 	ArtBpath * bp;
352 	const GSList * l;
353 	gint length;
354 
355 	g_return_val_if_fail (list != NULL, NULL);
356 
357 	length = 1;
358 
359 	for (l = list; l != NULL; l = l->next) {
360 		c = (GnomeCanvasPathDef *) l->data;
361 		length += c->end;
362 	}
363 
364 	new = gnome_canvas_path_def_new_sized (length);
365 
366 	bp = new->bpath;
367 
368 	for (l = list; l != NULL; l = l->next) {
369 		c = (GnomeCanvasPathDef *) l->data;
370 		memcpy (bp, c->bpath, c->end * sizeof (ArtBpath));
371 		bp += c->end;
372 	}
373 
374 	bp->code = ART_END;
375 
376 	new->end = length - 1;
377 
378 	new->allclosed = sp_bpath_all_closed (new->bpath);
379 	new->allopen = sp_bpath_all_open (new->bpath);
380 
381 	return new;
382 }
383 
384 /**
385  * gnome_canvas_path_def_split:
386  * @path: a GnomeCanvasPathDef
387  *
388  * This function splits the passed @path into a list of
389  * GnomeCanvasPathDefs which represent each segment of the origional
390  * path.  The path is split when ever an ART_MOVETO or ART_MOVETO_OPEN
391  * is encountered. The closedness of resulting paths is set accordingly
392  * to closedness of corresponding segment.
393  *
394  * Returns: a list of GnomeCanvasPathDef(s).
395  */
396 GSList *
gnome_canvas_path_def_split(const GnomeCanvasPathDef * path)397 gnome_canvas_path_def_split (const GnomeCanvasPathDef * path)
398 {
399 	GnomeCanvasPathDef * new;
400 	GSList * l;
401 	gint p, i;
402 
403 	g_return_val_if_fail (path != NULL, NULL);
404 
405 	p = 0;
406 	l = NULL;
407 
408 	while (p < path->end) {
409 		i = 1;
410 		while ((path->bpath[p + i].code == ART_LINETO) || (path->bpath[p + i].code == ART_CURVETO)) i++;
411 		new = gnome_canvas_path_def_new_sized (i + 1);
412 		memcpy (new->bpath, path->bpath + p, i * sizeof (ArtBpath));
413 		new->end = i;
414 		new->bpath[i].code = ART_END;
415 		new->allclosed = (new->bpath->code == ART_MOVETO);
416 		new->allopen = (new->bpath->code == ART_MOVETO_OPEN);
417 		l = g_slist_append (l, new);
418 		p += i;
419 	}
420 
421 	return l;
422 }
423 
424 /**
425  * gnome_canvas_path_def_open_parts:
426  * @path: a GnomeCanvasPathDef
427  *
428  * This function creates a new GnomeCanvasPathDef that contains all of
429  * the open segments on the passed @path.
430  *
431  * Returns: a new GnomeCanvasPathDef that contains all of the open segemtns in @path.
432  */
433 GnomeCanvasPathDef *
gnome_canvas_path_def_open_parts(const GnomeCanvasPathDef * path)434 gnome_canvas_path_def_open_parts (const GnomeCanvasPathDef * path)
435 {
436 	GnomeCanvasPathDef * new;
437 	ArtBpath * p, * d;
438 	gint len;
439 	gboolean closed;
440 
441 	g_return_val_if_fail (path != NULL, NULL);
442 
443 	closed = TRUE;
444 	len = 0;
445 
446 	for (p = path->bpath; p->code != ART_END; p++) {
447 		switch (p->code) {
448 		case ART_MOVETO_OPEN:
449 			closed = FALSE;
450 			len++;
451 			break;
452 		case ART_MOVETO:
453 			closed = TRUE;
454 			break;
455 		case ART_LINETO:
456 		case ART_CURVETO:
457 			if (!closed) len++;
458 			break;
459 		default:
460 			g_assert_not_reached ();
461 		}
462 	}
463 
464 	new = gnome_canvas_path_def_new_sized (len + 1);
465 
466 	closed = TRUE;
467 	d = new->bpath;
468 
469 	for (p = path->bpath; p->code != ART_END; p++) {
470 		switch (p->code) {
471 		case ART_MOVETO_OPEN:
472 			closed = FALSE;
473 			*d++ = *p;
474 			break;
475 		case ART_MOVETO:
476 			closed = TRUE;
477 			break;
478 		case ART_LINETO:
479 		case ART_CURVETO:
480 			if (!closed) *d++ = *p;
481 			break;
482 		default:
483 			g_assert_not_reached ();
484 		}
485 	}
486 
487 	d->code = ART_END;
488 
489 	new->end = len;
490 	new->allclosed = FALSE;
491 	new->allopen = TRUE;
492 
493 	return new;
494 }
495 
496 /**
497  * gnome_canvas_path_def_closed_parts:
498  * @path: a GnomeCanvasPathDef
499  *
500  * This function returns a new GnomeCanvasPathDef that contains the
501  * all of close parts of passed @path.
502  *
503  * Returns: a new GnomeCanvasPathDef that contains all of the closed
504  * parts of passed @path.
505  */
506 GnomeCanvasPathDef *
gnome_canvas_path_def_closed_parts(const GnomeCanvasPathDef * path)507 gnome_canvas_path_def_closed_parts (const GnomeCanvasPathDef * path)
508 {
509 	GnomeCanvasPathDef * new;
510 	ArtBpath * p, * d;
511 	gint len;
512 	gboolean closed;
513 
514 	g_return_val_if_fail (path != NULL, NULL);
515 
516 	closed = FALSE;
517 	len = 0;
518 
519 	for (p = path->bpath; p->code != ART_END; p++) {
520 		switch (p->code) {
521 		case ART_MOVETO_OPEN:
522 			closed = FALSE;
523 			break;
524 		case ART_MOVETO:
525 			closed = TRUE;
526 			len++;
527 			break;
528 		case ART_LINETO:
529 		case ART_CURVETO:
530 			if (closed) len++;
531 			break;
532 		default:
533 			g_assert_not_reached ();
534 		}
535 	}
536 
537 	new = gnome_canvas_path_def_new_sized (len + 1);
538 
539 	closed = FALSE;
540 	d = new->bpath;
541 
542 	for (p = path->bpath; p->code != ART_END; p++) {
543 		switch (p->code) {
544 		case ART_MOVETO_OPEN:
545 			closed = FALSE;
546 			break;
547 		case ART_MOVETO:
548 			closed = TRUE;
549 			*d++ = *p;
550 			break;
551 		case ART_LINETO:
552 		case ART_CURVETO:
553 			if (closed) *d++ = *p;
554 			break;
555 		default:
556 			g_assert_not_reached ();
557 		}
558 	}
559 
560 	d->code = ART_END;
561 
562 	new->end = len;
563 	new->allclosed = TRUE;
564 	new->allopen = FALSE;
565 
566 	return new;
567 }
568 
569 /**
570  * gnome_canvas_path_def_close_all:
571  * @path: a GnomeCanvasPathDef
572  *
573  * This function closes all of the open segments in the passed path
574  * and returns a new GnomeCanvasPathDef.
575  *
576  * Returns: a GnomeCanvasPathDef that contains the contents of @path
577  * but has modified the path is fully closed
578  */
579 GnomeCanvasPathDef *
gnome_canvas_path_def_close_all(const GnomeCanvasPathDef * path)580 gnome_canvas_path_def_close_all (const GnomeCanvasPathDef * path)
581 {
582 	GnomeCanvasPathDef * new;
583 	ArtBpath * p, * d, * start;
584 	gint len;
585 	gboolean closed;
586 
587 	g_return_val_if_fail (path != NULL, NULL);
588 
589 	if (path->allclosed) {
590 		new = gnome_canvas_path_def_duplicate (path);
591 		return new;
592 	}
593 
594 	len = 1;
595 
596 	/* Count MOVETO_OPEN */
597 
598 	for (p = path->bpath; p->code != ART_END; p++) {
599 		len += 1;
600 		if (p->code == ART_MOVETO_OPEN) len += 2;
601 	}
602 
603 	new = gnome_canvas_path_def_new_sized (len);
604 
605 	d = start = new->bpath;
606 	closed = TRUE;
607 
608 	for (p = path->bpath; p->code != ART_END; p++) {
609 		switch (p->code) {
610 		case ART_MOVETO_OPEN:
611 			start = p;
612 			closed = FALSE;
613 		case ART_MOVETO:
614 			if ((!closed) && ((start->x3 != p->x3) || (start->y3 != p->y3))) {
615 				d->code = ART_LINETO;
616 				d->x3 = start->x3;
617 				d->y3 = start->y3;
618 				d++;
619 			}
620 			if (p->code == ART_MOVETO) closed = TRUE;
621 			d->code = ART_MOVETO;
622 			d->x3 = p->x3;
623 			d->y3 = p->y3;
624 			d++;
625 			break;
626 		case ART_LINETO:
627 		case ART_CURVETO:
628 			*d++ = *p;
629 			break;
630 		default:
631 			g_assert_not_reached ();
632 		}
633 	}
634 
635 	if ((!closed) && ((start->x3 != p->x3) || (start->y3 != p->y3))) {
636 		d->code = ART_LINETO;
637 		d->x3 = start->x3;
638 		d->y3 = start->y3;
639 		d++;
640 	}
641 
642 	d->code = ART_END;
643 
644 	new->end = d - new->bpath;
645 	new->allclosed = TRUE;
646 	new->allopen = FALSE;
647 
648 	return new;
649 }
650 
651 /* Destructor */
652 
653 /**
654  * gnome_canvas_path_def_unref:
655  * @path: a GnomeCanvasPathDef
656  *
657  * Decrease the reference count of the passed @path.  If the reference
658  * count is < 1 the path is deallocated.
659  */
660 void
gnome_canvas_path_def_unref(GnomeCanvasPathDef * path)661 gnome_canvas_path_def_unref (GnomeCanvasPathDef * path)
662 {
663 	g_return_if_fail (path != NULL);
664 
665 	if (--path->refcount < 1) {
666 		if ((!path->sbpath) && (path->bpath)) art_free (path->bpath);
667 		g_free (path);
668 	}
669 }
670 
671 
672 /* Methods */
673 /**
674  * gnome_canvas_path_def_reset:
675  * @path: a GnomeCanvasPathDef
676  *
677  * This function clears the contents of the passed @path.
678  */
679 void
gnome_canvas_path_def_reset(GnomeCanvasPathDef * path)680 gnome_canvas_path_def_reset (GnomeCanvasPathDef * path)
681 {
682 	g_return_if_fail (path != NULL);
683 	g_return_if_fail (!path->sbpath);
684 
685 	path->bpath->code = ART_END;
686 	path->end = 0;
687 	path->hascpt = FALSE;
688 	path->posset = FALSE;
689 	path->moving = FALSE;
690 	path->allclosed = TRUE;
691 	path->allopen = TRUE;
692 }
693 
694 /* Several consequtive movetos are ALLOWED */
695 
696 /**
697  * gnome_canvas_path_def_moveto:
698  * @path: a GnomeCanvasPathDef
699  * @x: x coordinate
700  * @y: y coordinate
701  *
702  * This function adds starts new subpath on @path, and sets its
703  * starting point to @x and @y. If current subpath is empty, it
704  * simply changes its starting coordinates to new values.
705  */
706 void
gnome_canvas_path_def_moveto(GnomeCanvasPathDef * path,gdouble x,gdouble y)707 gnome_canvas_path_def_moveto (GnomeCanvasPathDef * path, gdouble x, gdouble y)
708 {
709 	g_return_if_fail (path != NULL);
710 	g_return_if_fail (!path->sbpath);
711 	g_return_if_fail (!path->moving);
712 
713 	path->substart = path->end;
714 	path->hascpt = TRUE;
715 	path->posset = TRUE;
716 	path->x = x;
717 	path->y = y;
718 
719 	path->allclosed = FALSE;
720 }
721 
722 /**
723  * gnome_canvas_path_def_lineto:
724  * @path: a GnomeCanvasPathDef
725  * @x: x coordinate
726  * @y: y coordinate
727  *
728  * This function add a line segment to the passed @path with the
729  * specified @x and @y coordinates.
730  */
731 void
gnome_canvas_path_def_lineto(GnomeCanvasPathDef * path,gdouble x,gdouble y)732 gnome_canvas_path_def_lineto (GnomeCanvasPathDef * path, gdouble x, gdouble y)
733 {
734 	ArtBpath * bp;
735 
736 	g_return_if_fail (path != NULL);
737 	g_return_if_fail (!path->sbpath);
738 	g_return_if_fail (path->hascpt);
739 
740 	if (path->moving) {
741 		/* simply fix endpoint */
742 		g_return_if_fail (!path->posset);
743 		g_return_if_fail (path->end > 1);
744 		bp = path->bpath + path->end - 1;
745 		g_return_if_fail (bp->code == ART_LINETO);
746 		bp->x3 = x;
747 		bp->y3 = y;
748 		path->moving = FALSE;
749 		return;
750 	}
751 
752 	if (path->posset) {
753 		/* start a new segment */
754 		gnome_canvas_path_def_ensure_space (path, 2);
755 		bp = path->bpath + path->end;
756 		bp->code = ART_MOVETO_OPEN;
757 		bp->x3 = path->x;
758 		bp->y3 = path->y;
759 		bp++;
760 		bp->code = ART_LINETO;
761 		bp->x3 = x;
762 		bp->y3 = y;
763 		bp++;
764 		bp->code = ART_END;
765 		path->end += 2;
766 		path->posset = FALSE;
767 		path->allclosed = FALSE;
768 		return;
769 	}
770 
771 	/* Simply add line */
772 
773 	g_return_if_fail (path->end > 1);
774 	gnome_canvas_path_def_ensure_space (path, 1);
775 	bp = path->bpath + path->end;
776 	bp->code = ART_LINETO;
777 	bp->x3 = x;
778 	bp->y3 = y;
779 	bp++;
780 	bp->code = ART_END;
781 	path->end++;
782 }
783 
784 
785 /**
786  * gnome_canvas_path_def_lineto_moving:
787  * @path: a GnomeCanvasPathDef
788  * @x: x coordinate
789  * @y: y coordinate
790  *
791  * This functions adds a new line segment with loose endpoint to the path, or
792  * if endpoint is already loose, changes its coordinates to @x, @y. You
793  * can change the coordinates of loose endpoint as many times as you want,
794  * the last ones set will be fixed, if you continue line. This is useful
795  * for handling drawing with mouse.
796  */
797 void
gnome_canvas_path_def_lineto_moving(GnomeCanvasPathDef * path,gdouble x,gdouble y)798 gnome_canvas_path_def_lineto_moving (GnomeCanvasPathDef * path, gdouble x, gdouble y)
799 {
800 	ArtBpath * bp;
801 
802 	g_return_if_fail (path != NULL);
803 	g_return_if_fail (!path->sbpath);
804 	g_return_if_fail (path->hascpt);
805 
806 	if (path->moving) {
807 		/* simply change endpoint */
808 		g_return_if_fail (!path->posset);
809 		g_return_if_fail (path->end > 1);
810 		bp = path->bpath + path->end - 1;
811 		g_return_if_fail (bp->code == ART_LINETO);
812 		bp->x3 = x;
813 		bp->y3 = y;
814 		return;
815 	}
816 
817 	if (path->posset) {
818 		/* start a new segment */
819 		gnome_canvas_path_def_ensure_space (path, 2);
820 		bp = path->bpath + path->end;
821 		bp->code = ART_MOVETO_OPEN;
822 		bp->x3 = path->x;
823 		bp->y3 = path->y;
824 		bp++;
825 		bp->code = ART_LINETO;
826 		bp->x3 = x;
827 		bp->y3 = y;
828 		bp++;
829 		bp->code = ART_END;
830 		path->end += 2;
831 		path->posset = FALSE;
832 		path->moving = TRUE;
833 		path->allclosed = FALSE;
834 		return;
835 	}
836 
837 	/* Simply add line */
838 
839 	g_return_if_fail (path->end > 1);
840 	gnome_canvas_path_def_ensure_space (path, 1);
841 	bp = path->bpath + path->end;
842 	bp->code = ART_LINETO;
843 	bp->x3 = x;
844 	bp->y3 = y;
845 	bp++;
846 	bp->code = ART_END;
847 	path->end++;
848 	path->moving = TRUE;
849 }
850 
851 /**
852  * gnome_canvas_path_def_curveto:
853  * @path: a GnomeCanvasPathDef
854  * @x0: first control point x coordinate
855  * @y0: first control point y coordinate
856  * @x1: second control point x coordinate
857  * @y1: second control point y coordinate
858  * @x2: end of curve x coordinate
859  * @y2: end of curve y coordinate
860  *
861  * This function adds a bezier curve segment to the path definition.
862  */
863 
864 void
gnome_canvas_path_def_curveto(GnomeCanvasPathDef * path,gdouble x0,gdouble y0,gdouble x1,gdouble y1,gdouble x2,gdouble y2)865 gnome_canvas_path_def_curveto (GnomeCanvasPathDef * path, gdouble x0, gdouble y0, gdouble x1, gdouble y1, gdouble x2, gdouble y2)
866 {
867 	ArtBpath * bp;
868 
869 	g_return_if_fail (path != NULL);
870 	g_return_if_fail (!path->sbpath);
871 	g_return_if_fail (path->hascpt);
872 	g_return_if_fail (!path->moving);
873 
874 	if (path->posset) {
875 		/* start a new segment */
876 		gnome_canvas_path_def_ensure_space (path, 2);
877 		bp = path->bpath + path->end;
878 		bp->code = ART_MOVETO_OPEN;
879 		bp->x3 = path->x;
880 		bp->y3 = path->y;
881 		bp++;
882 		bp->code = ART_CURVETO;
883 		bp->x1 = x0;
884 		bp->y1 = y0;
885 		bp->x2 = x1;
886 		bp->y2 = y1;
887 		bp->x3 = x2;
888 		bp->y3 = y2;
889 		bp++;
890 		bp->code = ART_END;
891 		path->end += 2;
892 		path->posset = FALSE;
893 		path->allclosed = FALSE;
894 		return;
895 	}
896 
897 	/* Simply add path */
898 
899 	g_return_if_fail (path->end > 1);
900 	gnome_canvas_path_def_ensure_space (path, 1);
901 	bp = path->bpath + path->end;
902 	bp->code = ART_CURVETO;
903 	bp->x1 = x0;
904 	bp->y1 = y0;
905 	bp->x2 = x1;
906 	bp->y2 = y1;
907 	bp->x3 = x2;
908 	bp->y3 = y2;
909 	bp++;
910 	bp->code = ART_END;
911 	path->end++;
912 }
913 
914 /**
915  * gnome_canvas_path_def_closepath:
916  * @path: a GnomeCanvasPathDef
917  *
918  * This function closes the last subpath of @path, adding a ART_LINETO to
919  * subpath starting point, if needed and changing starting pathcode to
920  * ART_MOVETO
921  */
922 void
gnome_canvas_path_def_closepath(GnomeCanvasPathDef * path)923 gnome_canvas_path_def_closepath (GnomeCanvasPathDef * path)
924 {
925 	ArtBpath * bs, * be;
926 
927 	g_return_if_fail (path != NULL);
928 	g_return_if_fail (!path->sbpath);
929 	g_return_if_fail (path->hascpt);
930 	g_return_if_fail (!path->posset);
931 	g_return_if_fail (!path->moving);
932 	g_return_if_fail (!path->allclosed);
933 	/* We need at last M + L + L + E */
934 	g_return_if_fail (path->end - path->substart > 2);
935 
936 	bs = path->bpath + path->substart;
937 	be = path->bpath + path->end - 1;
938 
939 	if ((bs->x3 != be->x3) || (bs->y3 != be->y3)) {
940 		gnome_canvas_path_def_lineto (path, bs->x3, bs->y3);
941 	}
942 
943 	bs = path->bpath + path->substart; /* NB. def_lineto can
944 					      realloc bpath */
945 	bs->code = ART_MOVETO;
946 
947 	path->allclosed = sp_bpath_all_closed (path->bpath);
948 	path->allopen = sp_bpath_all_open (path->bpath);
949 
950 	path->hascpt = FALSE;
951 }
952 
953 /**
954  * gnome_canvas_path_def_closepath_current:
955  * @path: a GnomeCanvasPathDef
956  *
957  * This function closes the last subpath by setting the coordinates of
958  * the endpoint of the last segment (line or curve) to starting point.
959  */
960 void
gnome_canvas_path_def_closepath_current(GnomeCanvasPathDef * path)961 gnome_canvas_path_def_closepath_current (GnomeCanvasPathDef * path)
962 {
963 	ArtBpath * bs, * be;
964 
965 	g_return_if_fail (path != NULL);
966 	g_return_if_fail (!path->sbpath);
967 	g_return_if_fail (path->hascpt);
968 	g_return_if_fail (!path->posset);
969 	g_return_if_fail (!path->allclosed);
970 	/* We need at last M + L + L + E */
971 	g_return_if_fail (path->end - path->substart > 2);
972 
973 	bs = path->bpath + path->substart;
974 	be = path->bpath + path->end - 1;
975 
976 	be->x3 = bs->x3;
977 	be->y3 = bs->y3;
978 
979 	bs->code = ART_MOVETO;
980 
981 	path->allclosed = sp_bpath_all_closed (path->bpath);
982 	path->allopen = sp_bpath_all_open (path->bpath);
983 
984 	path->hascpt = FALSE;
985 	path->moving = FALSE;
986 }
987 
988 /**
989  * gnome_canvas_path_def_bpath:
990  * @path: a GnomeCanvasPathDef
991  *
992  * This function returns a ArtBpath that consists of the path
993  * definition.
994  *
995  * Returns: ArtBpath
996  */
gnome_canvas_path_def_bpath(const GnomeCanvasPathDef * path)997 ArtBpath * gnome_canvas_path_def_bpath (const GnomeCanvasPathDef * path)
998 {
999 	g_return_val_if_fail (path != NULL, NULL);
1000 
1001 	return path->bpath;
1002 }
1003 
1004 /**
1005  * gnome_canvas_path_def_length:
1006  * @path: a GnomeCanvasPathDef
1007  *
1008  * This function returns the length of the path definition.  Not
1009  * Euclidian length of the path but rather the number of points on the
1010  * path.
1011  *
1012  * Returns: integer, number of points on the path.
1013  */
gnome_canvas_path_def_length(const GnomeCanvasPathDef * path)1014 gint gnome_canvas_path_def_length (const GnomeCanvasPathDef * path)
1015 {
1016 	g_return_val_if_fail (path != NULL, -1);
1017 
1018 	return path->end + 1;
1019 }
1020 
1021 /**
1022  * gnome_canvas_path_def_is_empty:
1023  * @path: a GnomeCanvasPathDef
1024  *
1025  * This function is a boolean test to see if the path is empty,
1026  * meaning containing no line segments.
1027  *
1028  * Returns: boolean, indicating if the path is empty.
1029  */
1030 gboolean
gnome_canvas_path_def_is_empty(const GnomeCanvasPathDef * path)1031 gnome_canvas_path_def_is_empty (const GnomeCanvasPathDef * path)
1032 {
1033 	g_return_val_if_fail (path != NULL, TRUE);
1034 
1035 	return (path->bpath->code == ART_END);
1036 }
1037 
1038 /**
1039  * gnome_canvas_path_def_has_currentpoint:
1040  * @path: a GnomeCanvasPathdef
1041  *
1042  * This function is a boolean test checking to see if the path has a
1043  * current point defined. Current point will be set by line operators,
1044  * and cleared by closing subpath.
1045  *
1046  * Returns: boolean, indicating if the path has a current point defined.
1047  */
1048 gboolean
gnome_canvas_path_def_has_currentpoint(const GnomeCanvasPathDef * path)1049 gnome_canvas_path_def_has_currentpoint (const GnomeCanvasPathDef * path)
1050 {
1051 	g_return_val_if_fail (path != NULL, FALSE);
1052 
1053 	return (path->hascpt);
1054 }
1055 
1056 /**
1057  * gnome_canvas_path_def_currentpoint:
1058  * @path: a GnomeCanvasPathDef
1059  * @p: a ArtPoint where to store the current point
1060  *
1061  * Stores the current point of the path definition in the passed ArtPoint @p.
1062  */
1063 void
gnome_canvas_path_def_currentpoint(const GnomeCanvasPathDef * path,ArtPoint * p)1064 gnome_canvas_path_def_currentpoint (const GnomeCanvasPathDef * path, ArtPoint * p)
1065 {
1066 	g_return_if_fail (path != NULL);
1067 	g_return_if_fail (p != NULL);
1068 	g_return_if_fail (path->hascpt);
1069 
1070 	if (path->posset) {
1071 		p->x = path->x;
1072 		p->y = path->y;
1073 	} else {
1074 		p->x = (path->bpath + path->end - 1)->x3;
1075 		p->y = (path->bpath + path->end - 1)->y3;
1076 	}
1077 }
1078 
1079 /**
1080  * gnome_canvas_path_def_last_bpath:
1081  * @path: a GnomeCanvasPathDef
1082  *
1083  * This function returns pointer to the last ArtBpath segment in the path
1084  * definition.
1085  *
1086  * Returns: ArtBpath, being the last segment in the path definition or
1087  * null if no line segments have been defined.
1088  */
1089 ArtBpath *
gnome_canvas_path_def_last_bpath(const GnomeCanvasPathDef * path)1090 gnome_canvas_path_def_last_bpath (const GnomeCanvasPathDef * path)
1091 {
1092 	g_return_val_if_fail (path != NULL, NULL);
1093 
1094 	if (path->end == 0) return NULL;
1095 
1096 	return path->bpath + path->end - 1;
1097 }
1098 
1099 /**
1100  * gnome_canvas_path_def_first_bpath:
1101  * @path: a GnomeCanvasPathDef
1102  *
1103  * This function returns the first ArtBpath point in the definition.
1104  *
1105  * Returns: ArtBpath being the first point in the path definition or
1106  * null if no points are defined
1107 */
1108 ArtBpath *
gnome_canvas_path_def_first_bpath(const GnomeCanvasPathDef * path)1109 gnome_canvas_path_def_first_bpath (const GnomeCanvasPathDef * path)
1110 {
1111 	g_return_val_if_fail (path != NULL, NULL);
1112 
1113 	if (path->end == 0) return NULL;
1114 
1115 	return path->bpath;
1116 }
1117 
1118 /**
1119  * gnome_canvas_path_def_any_open:
1120  * @path: a GnomeCanvasPathDef
1121  *
1122  * This function returns a boolean value indicating if the path has
1123  * any open segments.
1124  *
1125  * Returns: boolean, indicating if the path has any open segments.
1126  */
1127 gboolean
gnome_canvas_path_def_any_open(const GnomeCanvasPathDef * path)1128 gnome_canvas_path_def_any_open (const GnomeCanvasPathDef * path)
1129 {
1130 	g_return_val_if_fail (path != NULL, FALSE);
1131 
1132 	return (!path->allclosed);
1133 }
1134 
1135 /**
1136  * gnome_canvas_path_def_all_open:
1137  * @path: a GnomeCanvasPathDef
1138  *
1139  * This function returns a boolean value indicating if the path only
1140  * contains open segments.
1141  *
1142  * Returns: boolean, indicating if the path has all open segments.
1143  */
1144 gboolean
gnome_canvas_path_def_all_open(const GnomeCanvasPathDef * path)1145 gnome_canvas_path_def_all_open (const GnomeCanvasPathDef * path)
1146 {
1147 	g_return_val_if_fail (path != NULL, FALSE);
1148 
1149 	return (path->allopen);
1150 }
1151 
1152 /**
1153  * gnome_canvas_path_def_any_closed:
1154  * @path: a GnomeCanvasPathDef
1155  *
1156  * This function returns a boolean valid indicating if the path has
1157  * any closed segements.
1158  *
1159  * Returns: boolean, indicating if the path has any closed segments.
1160  */
1161 gboolean
gnome_canvas_path_def_any_closed(const GnomeCanvasPathDef * path)1162 gnome_canvas_path_def_any_closed (const GnomeCanvasPathDef * path)
1163 {
1164 	g_return_val_if_fail (path != NULL, FALSE);
1165 
1166 	return (!path->allopen);
1167 }
1168 
1169 /**
1170  * gnome_canvas_path_def_all_closed:
1171  * @path: a GnomeCanvasPathDef
1172  *
1173  * This function returns a boolean value indicating if the path only
1174  * contains closed segments.
1175  *
1176  * Returns: boolean, indicating if the path has all closed segments.
1177  */
1178 gboolean
gnome_canvas_path_def_all_closed(const GnomeCanvasPathDef * path)1179 gnome_canvas_path_def_all_closed (const GnomeCanvasPathDef * path)
1180 {
1181 	g_return_val_if_fail (path != NULL, FALSE);
1182 
1183 	return (path->allclosed);
1184 }
1185 
1186 /* Private methods */
1187 
1188 static
sp_bpath_good(ArtBpath * bpath)1189 gboolean sp_bpath_good (ArtBpath * bpath)
1190 {
1191 	ArtBpath * bp;
1192 
1193 	g_return_val_if_fail (bpath != NULL, FALSE);
1194 
1195 	if (bpath->code == ART_END)
1196                 return TRUE;
1197 
1198 	bp = bpath;
1199 
1200 	while (bp->code != ART_END) {
1201 		bp = sp_bpath_check_subpath (bp);
1202 		if (bp == NULL) return FALSE;
1203 	}
1204 
1205 	return TRUE;
1206 }
1207 
1208 static ArtBpath *
sp_bpath_check_subpath(ArtBpath * bpath)1209 sp_bpath_check_subpath (ArtBpath * bpath)
1210 {
1211 	gint i, len;
1212 	gboolean closed;
1213 
1214 	g_return_val_if_fail (bpath != NULL, NULL);
1215 
1216 	if (bpath->code == ART_MOVETO) {
1217 		closed = TRUE;
1218 	} else if (bpath->code == ART_MOVETO_OPEN) {
1219 		closed = FALSE;
1220 	} else {
1221 		return NULL;
1222 	}
1223 
1224 	len = 0;
1225 
1226 	for (i = 1; (bpath[i].code != ART_END) && (bpath[i].code != ART_MOVETO) && (bpath[i].code != ART_MOVETO_OPEN); i++) {
1227 		switch (bpath[i].code) {
1228 			case ART_LINETO:
1229 			case ART_CURVETO:
1230 				len++;
1231 				break;
1232 			default:
1233 				return NULL;
1234 		}
1235 	}
1236 
1237 	if (closed) {
1238 		if (len < 2) return NULL;
1239 		if ((bpath->x3 != bpath[i-1].x3) || (bpath->y3 != bpath[i-1].y3)) return NULL;
1240 	} else {
1241 		if (len < 1) return NULL;
1242 	}
1243 
1244 	return bpath + i;
1245 }
1246 
1247 static gint
sp_bpath_length(const ArtBpath * bpath)1248 sp_bpath_length (const ArtBpath * bpath)
1249 {
1250 	gint l;
1251 
1252 	g_return_val_if_fail (bpath != NULL, FALSE);
1253 
1254 	for (l = 0; bpath[l].code != ART_END; l++) ;
1255 
1256 	l++;
1257 
1258 	return l;
1259 }
1260 
1261 static gboolean
sp_bpath_all_closed(const ArtBpath * bpath)1262 sp_bpath_all_closed (const ArtBpath * bpath)
1263 {
1264 	const ArtBpath * bp;
1265 
1266 	g_return_val_if_fail (bpath != NULL, FALSE);
1267 
1268 	for (bp = bpath; bp->code != ART_END; bp++)
1269 		if (bp->code == ART_MOVETO_OPEN) return FALSE;
1270 
1271 	return TRUE;
1272 }
1273 
1274 static gboolean
sp_bpath_all_open(const ArtBpath * bpath)1275 sp_bpath_all_open (const ArtBpath * bpath)
1276 {
1277 	const ArtBpath * bp;
1278 
1279 	g_return_val_if_fail (bpath != NULL, FALSE);
1280 
1281 	for (bp = bpath; bp->code != ART_END; bp++)
1282 		if (bp->code == ART_MOVETO) return FALSE;
1283 
1284 	return TRUE;
1285 }
1286 
1287 
1288