/libgnomeprint-2.18.8/libgnomeprint/gp-path.c

# · C · 961 lines · 726 code · 196 blank · 39 comment · 145 complexity · 2cddc529c880b1c963ab108c7ead417f MD5 · raw file

  1. /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
  2. /*
  3. * gp-path.c:
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU Library General Public License
  7. * as published by the Free Software Foundation; either version 2 of
  8. * the License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Library General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Library General Public
  16. * License along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18. *
  19. * Authors:
  20. * Lauris Kaplinski <lauris@ariman.ee>
  21. *
  22. * Copyrithg (C) 1999-2000 authors
  23. */
  24. #include <config.h>
  25. #include <string.h>
  26. #include <libart_lgpl/art_misc.h>
  27. #include <libgnomeprint/gp-path.h>
  28. #define GP_PATH_LENSTEP 32
  29. struct _GPPath {
  30. gint refcount;
  31. ArtBpath * bpath;
  32. gint end; /* ART_END position */
  33. gint length; /* Num allocated Bpaths */
  34. gint substart; /* subpath start */
  35. gdouble x, y; /* previous moveto position */
  36. guint sbpath : 1; /* Bpath is static */
  37. guint hascpt : 1; /* Currentpoint is defined */
  38. guint posset : 1; /* Previous was moveto */
  39. guint moving : 1; /* Bpath end is moving */
  40. guint allclosed : 1; /* All subpaths are closed */
  41. guint allopen : 1; /* All subpaths are open */
  42. };
  43. static gboolean sp_bpath_good (const ArtBpath * bpath);
  44. static const ArtBpath * sp_bpath_check_subpath (const ArtBpath * bpath);
  45. static gint sp_bpath_length (const ArtBpath * bpath);
  46. static gboolean sp_bpath_all_closed (const ArtBpath * bpath);
  47. static gboolean sp_bpath_all_open (const ArtBpath * bpath);
  48. /* Constructors */
  49. GPPath *
  50. gp_path_new (void)
  51. {
  52. GPPath * path;
  53. path = gp_path_new_sized (GP_PATH_LENSTEP);
  54. return path;
  55. }
  56. GPPath *
  57. gp_path_new_sized (gint length)
  58. {
  59. GPPath * path;
  60. g_return_val_if_fail (length > 0, NULL);
  61. path = g_new (GPPath, 1);
  62. path->refcount = 1;
  63. path->bpath = art_new (ArtBpath, length);
  64. path->end = 0;
  65. path->bpath[path->end].code = ART_END;
  66. path->length = length;
  67. path->sbpath = FALSE;
  68. path->hascpt = FALSE;
  69. path->posset = FALSE;
  70. path->moving = FALSE;
  71. path->allclosed = TRUE;
  72. path->allopen = TRUE;
  73. return path;
  74. }
  75. GPPath *
  76. gp_path_new_from_bpath (ArtBpath * bpath)
  77. {
  78. GPPath * path;
  79. g_return_val_if_fail (sp_bpath_good (bpath), NULL);
  80. path = g_new (GPPath, 1);
  81. path->refcount = 1;
  82. path->bpath = bpath;
  83. path->length = sp_bpath_length (bpath);
  84. path->end = path->length - 1;
  85. path->sbpath = FALSE;
  86. path->hascpt = FALSE;
  87. path->posset = FALSE;
  88. path->moving = FALSE;
  89. path->allclosed = sp_bpath_all_closed (bpath);
  90. path->allopen = sp_bpath_all_open (bpath);
  91. return path;
  92. }
  93. GPPath *
  94. gp_path_new_from_static_bpath (ArtBpath * bpath)
  95. {
  96. GPPath * path;
  97. g_return_val_if_fail (sp_bpath_good (bpath), NULL);
  98. path = g_new (GPPath, 1);
  99. path->refcount = 1;
  100. path->bpath = bpath;
  101. path->length = sp_bpath_length (bpath);
  102. path->end = path->length - 1;
  103. path->sbpath = TRUE;
  104. path->hascpt = FALSE;
  105. path->posset = FALSE;
  106. path->moving = FALSE;
  107. path->allclosed = sp_bpath_all_closed (bpath);
  108. path->allopen = sp_bpath_all_open (bpath);
  109. return path;
  110. }
  111. GPPath *
  112. gp_path_new_from_foreign_bpath (const ArtBpath * bpath)
  113. {
  114. GPPath * path;
  115. gint length;
  116. g_return_val_if_fail (sp_bpath_good (bpath), NULL);
  117. length = sp_bpath_length (bpath);
  118. path = gp_path_new_sized (length);
  119. memcpy (path->bpath, bpath, sizeof (ArtBpath) * length);
  120. path->end = length - 1;
  121. path->allclosed = sp_bpath_all_closed (bpath);
  122. path->allopen = sp_bpath_all_open (bpath);
  123. return path;
  124. }
  125. void
  126. gp_path_ref (GPPath * path)
  127. {
  128. g_return_if_fail (path != NULL);
  129. path->refcount++;
  130. }
  131. void
  132. gp_path_finish (GPPath * path)
  133. {
  134. g_return_if_fail (path != NULL);
  135. g_return_if_fail (path->sbpath);
  136. if ((path->end + 1) < path->length) {
  137. path->bpath = art_renew (path->bpath, ArtBpath, path->end + 1);
  138. path->length = path->end + 1;
  139. }
  140. path->hascpt = FALSE;
  141. path->posset = FALSE;
  142. path->moving = FALSE;
  143. }
  144. void
  145. gp_path_ensure_space (GPPath * path, gint space)
  146. {
  147. g_return_if_fail (path != NULL);
  148. g_return_if_fail (space > 0);
  149. if (path->end + space < path->length) return;
  150. if (space < GP_PATH_LENSTEP) space = GP_PATH_LENSTEP;
  151. path->bpath = art_renew (path->bpath, ArtBpath, path->length + space);
  152. path->length += space;
  153. }
  154. GPPath *
  155. gp_path_copy (GPPath * dst, const GPPath * src)
  156. {
  157. g_return_val_if_fail (dst != NULL, NULL);
  158. g_return_val_if_fail (src != NULL, NULL);
  159. g_free (dst->bpath);
  160. memcpy (dst, src, sizeof (GPPath));
  161. dst->bpath = g_new (ArtBpath, src->end + 1);
  162. memcpy (dst->bpath, src->bpath, (src->end + 1) * sizeof (ArtBpath));
  163. dst->sbpath = FALSE;
  164. return dst;
  165. }
  166. GPPath *
  167. gp_path_duplicate (const GPPath * path)
  168. {
  169. GPPath * new;
  170. g_return_val_if_fail (path != NULL, NULL);
  171. new = gp_path_new_from_foreign_bpath (path->bpath);
  172. g_return_val_if_fail (new != NULL, NULL);
  173. new->x = path->x;
  174. new->y = path->y;
  175. new->hascpt = path->hascpt;
  176. new->posset = path->posset;
  177. new->moving = path->moving;
  178. new->allclosed = path->allclosed;
  179. new->allopen = path->allopen;
  180. return new;
  181. }
  182. GPPath *
  183. gp_path_concat (const GSList * list)
  184. {
  185. GPPath * c, * new;
  186. ArtBpath * bp;
  187. const GSList * l;
  188. gint length;
  189. g_return_val_if_fail (list != NULL, NULL);
  190. length = 1;
  191. for (l = list; l != NULL; l = l->next) {
  192. c = (GPPath *) l->data;
  193. length += c->end;
  194. }
  195. new = gp_path_new_sized (length);
  196. bp = new->bpath;
  197. for (l = list; l != NULL; l = l->next) {
  198. c = (GPPath *) l->data;
  199. memcpy (bp, c->bpath, c->end);
  200. bp += c->end;
  201. }
  202. bp->code = ART_END;
  203. new->end = length - 1;
  204. new->allclosed = sp_bpath_all_closed (new->bpath);
  205. new->allopen = sp_bpath_all_open (new->bpath);
  206. return new;
  207. }
  208. GSList *
  209. gp_path_split (const GPPath * path)
  210. {
  211. GPPath * new;
  212. GSList * l;
  213. gint p, i;
  214. g_return_val_if_fail (path != NULL, NULL);
  215. p = 0;
  216. l = NULL;
  217. while (p < path->end) {
  218. i = 1;
  219. while ((path->bpath[p + i].code == ART_LINETO) || (path->bpath[p + i].code == ART_CURVETO)) i++;
  220. new = gp_path_new_sized (i + 1);
  221. memcpy (new->bpath, path->bpath + p, i * sizeof (ArtBpath));
  222. new->end = i;
  223. new->bpath[i].code = ART_END;
  224. new->allclosed = (new->bpath->code == ART_MOVETO);
  225. new->allopen = (new->bpath->code == ART_MOVETO_OPEN);
  226. l = g_slist_append (l, new);
  227. p += i;
  228. }
  229. return l;
  230. }
  231. GPPath *
  232. gp_path_open_parts (const GPPath * path)
  233. {
  234. GPPath * new;
  235. ArtBpath * p, * d;
  236. gint len;
  237. gboolean closed;
  238. g_return_val_if_fail (path != NULL, NULL);
  239. closed = TRUE;
  240. len = 0;
  241. for (p = path->bpath; p->code != ART_END; p++) {
  242. switch (p->code) {
  243. case ART_MOVETO_OPEN:
  244. closed = FALSE;
  245. len++;
  246. break;
  247. case ART_MOVETO:
  248. closed = TRUE;
  249. break;
  250. case ART_LINETO:
  251. case ART_CURVETO:
  252. if (!closed) len++;
  253. break;
  254. default:
  255. g_assert_not_reached ();
  256. }
  257. }
  258. new = gp_path_new_sized (len + 1);
  259. closed = TRUE;
  260. d = new->bpath;
  261. for (p = path->bpath; p->code != ART_END; p++) {
  262. switch (p->code) {
  263. case ART_MOVETO_OPEN:
  264. closed = FALSE;
  265. *d++ = *p;
  266. break;
  267. case ART_MOVETO:
  268. closed = TRUE;
  269. break;
  270. case ART_LINETO:
  271. case ART_CURVETO:
  272. if (!closed) *d++ = *p;
  273. break;
  274. default:
  275. g_assert_not_reached ();
  276. }
  277. }
  278. d->code = ART_END;
  279. new->end = len;
  280. new->allclosed = FALSE;
  281. new->allopen = TRUE;
  282. return new;
  283. }
  284. GPPath *
  285. gp_path_closed_parts (const GPPath * path)
  286. {
  287. GPPath * new;
  288. ArtBpath * p, * d;
  289. gint len;
  290. gboolean closed;
  291. g_return_val_if_fail (path != NULL, NULL);
  292. closed = FALSE;
  293. len = 0;
  294. for (p = path->bpath; p->code != ART_END; p++) {
  295. switch (p->code) {
  296. case ART_MOVETO_OPEN:
  297. closed = FALSE;
  298. break;
  299. case ART_MOVETO:
  300. closed = TRUE;
  301. len++;
  302. break;
  303. case ART_LINETO:
  304. case ART_CURVETO:
  305. if (closed) len++;
  306. break;
  307. default:
  308. g_assert_not_reached ();
  309. }
  310. }
  311. new = gp_path_new_sized (len + 1);
  312. closed = FALSE;
  313. d = new->bpath;
  314. for (p = path->bpath; p->code != ART_END; p++) {
  315. switch (p->code) {
  316. case ART_MOVETO_OPEN:
  317. closed = FALSE;
  318. break;
  319. case ART_MOVETO:
  320. closed = TRUE;
  321. *d++ = *p;
  322. break;
  323. case ART_LINETO:
  324. case ART_CURVETO:
  325. if (closed) *d++ = *p;
  326. break;
  327. default:
  328. g_assert_not_reached ();
  329. }
  330. }
  331. d->code = ART_END;
  332. new->end = len;
  333. new->allclosed = TRUE;
  334. new->allopen = FALSE;
  335. return new;
  336. }
  337. GPPath *
  338. gp_path_close_all (const GPPath * path)
  339. {
  340. GPPath * new;
  341. ArtBpath * p, * d, * start;
  342. gint len;
  343. gboolean closed;
  344. g_return_val_if_fail (path != NULL, NULL);
  345. if (path->allclosed) {
  346. new = gp_path_duplicate (path);
  347. return new;
  348. }
  349. len = 1;
  350. /* Count MOVETO_OPEN */
  351. for (p = path->bpath; p->code != ART_END; p++) {
  352. len += 1;
  353. if (p->code == ART_MOVETO_OPEN) len += 2;
  354. }
  355. new = gp_path_new_sized (len);
  356. d = start = new->bpath;
  357. closed = TRUE;
  358. for (p = path->bpath; p->code != ART_END; p++) {
  359. switch (p->code) {
  360. case ART_MOVETO_OPEN:
  361. case ART_MOVETO:
  362. if ((!closed) && ((start->x3 != p->x3) || (start->y3 != p->y3))) {
  363. d->code = ART_LINETO;
  364. d->x3 = start->x3;
  365. d->y3 = start->y3;
  366. d++;
  367. }
  368. closed = (p->code == ART_MOVETO);
  369. d->code = ART_MOVETO;
  370. d->x3 = p->x3;
  371. d->y3 = p->y3;
  372. d++;
  373. start = p;
  374. break;
  375. case ART_LINETO:
  376. case ART_CURVETO:
  377. *d++ = *p;
  378. break;
  379. default:
  380. g_assert_not_reached ();
  381. }
  382. }
  383. if (!closed && (p->code == ART_END ||
  384. start->x3 != p->x3 || (start->y3 != p->y3))) {
  385. d->code = ART_LINETO;
  386. d->x3 = start->x3;
  387. d->y3 = start->y3;
  388. d++;
  389. }
  390. d->code = ART_END;
  391. new->end = d - new->bpath;
  392. new->allclosed = TRUE;
  393. new->allopen = FALSE;
  394. return new;
  395. }
  396. /* Destructor */
  397. void
  398. gp_path_unref (GPPath * path)
  399. {
  400. g_return_if_fail (path != NULL);
  401. if (--path->refcount < 1) {
  402. if ((!path->sbpath) && (path->bpath)) art_free (path->bpath);
  403. g_free (path);
  404. }
  405. }
  406. /* Methods */
  407. void
  408. gp_path_reset (GPPath * path)
  409. {
  410. g_return_if_fail (path != NULL);
  411. g_return_if_fail (!path->sbpath);
  412. path->bpath->code = ART_END;
  413. path->end = 0;
  414. path->hascpt = FALSE;
  415. path->posset = FALSE;
  416. path->moving = FALSE;
  417. path->allclosed = TRUE;
  418. path->allopen = TRUE;
  419. }
  420. /* Several consequtive movetos are ALLOWED */
  421. void
  422. gp_path_moveto (GPPath * path, gdouble x, gdouble y)
  423. {
  424. g_return_if_fail (path != NULL);
  425. g_return_if_fail (!path->sbpath);
  426. g_return_if_fail (!path->moving);
  427. path->substart = path->end;
  428. path->hascpt = TRUE;
  429. path->posset = TRUE;
  430. path->x = x;
  431. path->y = y;
  432. path->allclosed = FALSE;
  433. }
  434. void
  435. gp_path_lineto (GPPath * path, gdouble x, gdouble y)
  436. {
  437. ArtBpath * bp;
  438. g_return_if_fail (path != NULL);
  439. g_return_if_fail (!path->sbpath);
  440. g_return_if_fail (path->hascpt);
  441. if (path->moving) {
  442. /* simply fix endpoint */
  443. g_return_if_fail (!path->posset);
  444. g_return_if_fail (path->end > 1);
  445. bp = path->bpath + path->end - 1;
  446. g_return_if_fail (bp->code == ART_LINETO);
  447. bp->x3 = x;
  448. bp->y3 = y;
  449. path->moving = FALSE;
  450. return;
  451. }
  452. if (path->posset) {
  453. /* start a new segment */
  454. gp_path_ensure_space (path, 2);
  455. bp = path->bpath + path->end;
  456. bp->code = ART_MOVETO_OPEN;
  457. bp->x3 = path->x;
  458. bp->y3 = path->y;
  459. bp++;
  460. bp->code = ART_LINETO;
  461. bp->x3 = x;
  462. bp->y3 = y;
  463. bp++;
  464. bp->code = ART_END;
  465. path->end += 2;
  466. path->posset = FALSE;
  467. path->allclosed = FALSE;
  468. return;
  469. }
  470. /* Simply add line */
  471. g_return_if_fail (path->end > 1);
  472. gp_path_ensure_space (path, 1);
  473. bp = path->bpath + path->end;
  474. bp->code = ART_LINETO;
  475. bp->x3 = x;
  476. bp->y3 = y;
  477. bp++;
  478. bp->code = ART_END;
  479. path->end++;
  480. }
  481. void
  482. gp_path_lineto_moving (GPPath * path, gdouble x, gdouble y)
  483. {
  484. ArtBpath * bp;
  485. g_return_if_fail (path != NULL);
  486. g_return_if_fail (!path->sbpath);
  487. g_return_if_fail (path->hascpt);
  488. if (path->moving) {
  489. /* simply change endpoint */
  490. g_return_if_fail (!path->posset);
  491. g_return_if_fail (path->end > 1);
  492. bp = path->bpath + path->end - 1;
  493. g_return_if_fail (bp->code == ART_LINETO);
  494. bp->x3 = x;
  495. bp->y3 = y;
  496. return;
  497. }
  498. if (path->posset) {
  499. /* start a new segment */
  500. gp_path_ensure_space (path, 2);
  501. bp = path->bpath + path->end;
  502. bp->code = ART_MOVETO_OPEN;
  503. bp->x3 = path->x;
  504. bp->y3 = path->y;
  505. bp++;
  506. bp->code = ART_LINETO;
  507. bp->x3 = x;
  508. bp->y3 = y;
  509. bp++;
  510. bp->code = ART_END;
  511. path->end += 2;
  512. path->posset = FALSE;
  513. path->moving = TRUE;
  514. path->allclosed = FALSE;
  515. return;
  516. }
  517. /* Simply add line */
  518. g_return_if_fail (path->end > 1);
  519. gp_path_ensure_space (path, 1);
  520. bp = path->bpath + path->end;
  521. bp->code = ART_LINETO;
  522. bp->x3 = x;
  523. bp->y3 = y;
  524. bp++;
  525. bp->code = ART_END;
  526. path->end++;
  527. path->moving = TRUE;
  528. }
  529. void
  530. gp_path_curveto (GPPath * path, gdouble x0, gdouble y0, gdouble x1, gdouble y1, gdouble x2, gdouble y2)
  531. {
  532. ArtBpath * bp;
  533. g_return_if_fail (path != NULL);
  534. g_return_if_fail (!path->sbpath);
  535. g_return_if_fail (path->hascpt);
  536. g_return_if_fail (!path->moving);
  537. if (path->posset) {
  538. /* start a new segment */
  539. gp_path_ensure_space (path, 2);
  540. bp = path->bpath + path->end;
  541. bp->code = ART_MOVETO_OPEN;
  542. bp->x3 = path->x;
  543. bp->y3 = path->y;
  544. bp++;
  545. bp->code = ART_CURVETO;
  546. bp->x1 = x0;
  547. bp->y1 = y0;
  548. bp->x2 = x1;
  549. bp->y2 = y1;
  550. bp->x3 = x2;
  551. bp->y3 = y2;
  552. bp++;
  553. bp->code = ART_END;
  554. path->end += 2;
  555. path->posset = FALSE;
  556. path->allclosed = FALSE;
  557. return;
  558. }
  559. /* Simply add path */
  560. g_return_if_fail (path->end > 1);
  561. gp_path_ensure_space (path, 1);
  562. bp = path->bpath + path->end;
  563. bp->code = ART_CURVETO;
  564. bp->x1 = x0;
  565. bp->y1 = y0;
  566. bp->x2 = x1;
  567. bp->y2 = y1;
  568. bp->x3 = x2;
  569. bp->y3 = y2;
  570. bp++;
  571. bp->code = ART_END;
  572. path->end++;
  573. }
  574. void
  575. gp_path_closepath (GPPath * path)
  576. {
  577. ArtBpath * bs, * be;
  578. g_return_if_fail (path != NULL);
  579. g_return_if_fail (!path->sbpath);
  580. g_return_if_fail (path->hascpt);
  581. g_return_if_fail (!path->posset);
  582. g_return_if_fail (!path->moving);
  583. g_return_if_fail (!path->allclosed);
  584. /* We need at last M + L + L + E */
  585. g_return_if_fail (path->end - path->substart > 2);
  586. bs = path->bpath + path->substart;
  587. be = path->bpath + path->end - 1;
  588. if ((bs->x3 != be->x3) || (bs->y3 != be->y3)) {
  589. gp_path_lineto (path, bs->x3, bs->y3);
  590. }
  591. bs = path->bpath + path->substart; /* NB. def_lineto can realloc bpath */
  592. bs->code = ART_MOVETO;
  593. path->allclosed = sp_bpath_all_closed (path->bpath);
  594. path->allopen = sp_bpath_all_open (path->bpath);
  595. path->hascpt = FALSE;
  596. }
  597. void
  598. gp_path_closepath_current (GPPath * path)
  599. {
  600. ArtBpath * bs, * be;
  601. g_return_if_fail (path != NULL);
  602. g_return_if_fail (!path->sbpath);
  603. g_return_if_fail (path->hascpt);
  604. g_return_if_fail (!path->posset);
  605. g_return_if_fail (!path->allclosed);
  606. /* We need at last M + L + L + E */
  607. g_return_if_fail (path->end - path->substart > 2);
  608. bs = path->bpath + path->substart;
  609. be = path->bpath + path->end - 1;
  610. be->x3 = bs->x3;
  611. be->y3 = bs->y3;
  612. bs->code = ART_MOVETO;
  613. path->allclosed = sp_bpath_all_closed (path->bpath);
  614. path->allopen = sp_bpath_all_open (path->bpath);
  615. path->hascpt = FALSE;
  616. path->moving = FALSE;
  617. }
  618. ArtBpath * gp_path_bpath (const GPPath * path)
  619. {
  620. g_return_val_if_fail (path != NULL, NULL);
  621. return path->bpath;
  622. }
  623. gint gp_path_length (const GPPath * path)
  624. {
  625. g_return_val_if_fail (path != NULL, -1);
  626. return path->end + 1;
  627. }
  628. gboolean
  629. gp_path_is_empty (const GPPath * path)
  630. {
  631. g_return_val_if_fail (path != NULL, TRUE);
  632. return (path->bpath->code == ART_END);
  633. }
  634. gboolean
  635. gp_path_has_currentpoint (const GPPath * path)
  636. {
  637. g_return_val_if_fail (path != NULL, FALSE);
  638. return (path->hascpt);
  639. }
  640. ArtPoint *
  641. gp_path_currentpoint (const GPPath * path, ArtPoint * p)
  642. {
  643. g_return_val_if_fail (path != NULL, NULL);
  644. g_return_val_if_fail (p != NULL, NULL);
  645. g_return_val_if_fail (path->hascpt, NULL);
  646. if (path->posset) {
  647. p->x = path->x;
  648. p->y = path->y;
  649. } else {
  650. p->x = (path->bpath + path->end - 1)->x3;
  651. p->y = (path->bpath + path->end - 1)->y3;
  652. }
  653. return p;
  654. }
  655. ArtBpath *
  656. gp_path_last_bpath (const GPPath * path)
  657. {
  658. g_return_val_if_fail (path != NULL, NULL);
  659. if (path->end == 0) return NULL;
  660. return path->bpath + path->end - 1;
  661. }
  662. ArtBpath *
  663. gp_path_first_bpath (const GPPath * path)
  664. {
  665. g_return_val_if_fail (path != NULL, NULL);
  666. if (path->end == 0) return NULL;
  667. return path->bpath;
  668. }
  669. gboolean
  670. gp_path_any_open (const GPPath * path)
  671. {
  672. g_return_val_if_fail (path != NULL, FALSE);
  673. return (!path->allclosed);
  674. }
  675. gboolean
  676. gp_path_all_open (const GPPath * path)
  677. {
  678. g_return_val_if_fail (path != NULL, FALSE);
  679. return (path->allopen);
  680. }
  681. gboolean
  682. gp_path_any_closed (const GPPath * path)
  683. {
  684. g_return_val_if_fail (path != NULL, FALSE);
  685. return (!path->allopen);
  686. }
  687. gboolean
  688. gp_path_all_closed (const GPPath * path)
  689. {
  690. g_return_val_if_fail (path != NULL, FALSE);
  691. return (path->allclosed);
  692. }
  693. /* Private methods */
  694. static
  695. gboolean sp_bpath_good (const ArtBpath * bpath)
  696. {
  697. const ArtBpath * bp;
  698. g_return_val_if_fail (bpath != NULL, FALSE);
  699. if (bpath->code == ART_END) return TRUE;
  700. bp = bpath;
  701. while (bp->code != ART_END) {
  702. bp = sp_bpath_check_subpath (bp);
  703. if (bp == NULL) return FALSE;
  704. }
  705. return TRUE;
  706. }
  707. static const ArtBpath *
  708. sp_bpath_check_subpath (const ArtBpath * bpath)
  709. {
  710. gint i, len;
  711. gboolean closed;
  712. g_return_val_if_fail (bpath != NULL, NULL);
  713. if (bpath->code == ART_MOVETO) {
  714. closed = TRUE;
  715. } else if (bpath->code == ART_MOVETO_OPEN) {
  716. closed = FALSE;
  717. } else {
  718. return NULL;
  719. }
  720. len = 0;
  721. for (i = 1; (bpath[i].code != ART_END) && (bpath[i].code != ART_MOVETO) && (bpath[i].code != ART_MOVETO_OPEN); i++) {
  722. switch (bpath[i].code) {
  723. case ART_LINETO:
  724. case ART_CURVETO:
  725. len++;
  726. break;
  727. default:
  728. return NULL;
  729. }
  730. }
  731. if (closed) {
  732. if (len < 2) return NULL;
  733. if ((bpath->x3 != bpath[i-1].x3) || (bpath->y3 != bpath[i-1].y3)) return NULL;
  734. } else {
  735. if (len < 1) return NULL;
  736. }
  737. return bpath + i;
  738. }
  739. static gint
  740. sp_bpath_length (const ArtBpath * bpath)
  741. {
  742. gint l;
  743. g_return_val_if_fail (bpath != NULL, FALSE);
  744. for (l = 0; bpath[l].code != ART_END; l++) ;
  745. l++;
  746. return l;
  747. }
  748. static gboolean
  749. sp_bpath_all_closed (const ArtBpath * bpath)
  750. {
  751. const ArtBpath * bp;
  752. g_return_val_if_fail (bpath != NULL, FALSE);
  753. for (bp = bpath; bp->code != ART_END; bp++)
  754. if (bp->code == ART_MOVETO_OPEN) return FALSE;
  755. return TRUE;
  756. }
  757. static gboolean
  758. sp_bpath_all_open (const ArtBpath * bpath)
  759. {
  760. const ArtBpath * bp;
  761. g_return_val_if_fail (bpath != NULL, FALSE);
  762. for (bp = bpath; bp->code != ART_END; bp++)
  763. if (bp->code == ART_MOVETO) return FALSE;
  764. return TRUE;
  765. }