gspath.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. /* Copyright (C) 1989, 1995, 1996, 1997, 1998, 1999 Aladdin Enterprises. All rights reserved.
  2. This software is provided AS-IS with no warranty, either express or
  3. implied.
  4. This software is distributed under license and may not be copied,
  5. modified or distributed except as expressly authorized under the terms
  6. of the license contained in the file LICENSE in this distribution.
  7. For more information about licensing, please refer to
  8. http://www.ghostscript.com/licensing/. For information on
  9. commercial licensing, go to http://www.artifex.com/licensing/ or
  10. contact Artifex Software, Inc., 101 Lucas Valley Road #110,
  11. San Rafael, CA 94903, U.S.A., +1(415)492-9861.
  12. */
  13. /* $Id: gspath.c,v 1.10 2004/08/31 13:23:16 igor Exp $ */
  14. /* Basic path routines for Ghostscript library */
  15. #include "gx.h"
  16. #include "math_.h"
  17. #include "gserrors.h"
  18. #include "gxfixed.h"
  19. #include "gxmatrix.h"
  20. #include "gscoord.h" /* requires gsmatrix.h */
  21. #include "gspath.h" /* for checking prototypes */
  22. #include "gzstate.h"
  23. #include "gzpath.h"
  24. #include "gxdevice.h" /* for gxcpath.h */
  25. #include "gxdevmem.h" /* for gs_device_is_memory */
  26. #include "gzcpath.h"
  27. /* ------ Miscellaneous ------ */
  28. int
  29. gs_newpath(gs_state * pgs)
  30. {
  31. pgs->current_point_valid = false;
  32. return gx_path_new(pgs->path);
  33. }
  34. int
  35. gs_closepath(gs_state * pgs)
  36. {
  37. gx_path *ppath = pgs->path;
  38. int code = gx_path_close_subpath(ppath);
  39. if (code < 0)
  40. return code;
  41. pgs->current_point = pgs->subpath_start;
  42. return code;
  43. }
  44. int
  45. gs_upmergepath(gs_state * pgs)
  46. {
  47. return gx_path_add_path(pgs->saved->path, pgs->path);
  48. }
  49. /* Get the current path (for internal use only). */
  50. gx_path *
  51. gx_current_path(const gs_state * pgs)
  52. {
  53. return pgs->path;
  54. }
  55. /* ------ Points and lines ------ */
  56. /*
  57. * Define clamped values for out-of-range coordinates.
  58. * Currently the path drawing routines can't handle values
  59. * close to the edge of the representable space.
  60. */
  61. #define max_coord_fixed (max_fixed - int2fixed(1000)) /* arbitrary */
  62. #define min_coord_fixed (-max_coord_fixed)
  63. private inline void
  64. clamp_point(gs_fixed_point * ppt, floatp x, floatp y)
  65. {
  66. #define clamp_coord(xy)\
  67. ppt->xy = (xy > fixed2float(max_coord_fixed) ? max_coord_fixed :\
  68. xy < fixed2float(min_coord_fixed) ? min_coord_fixed :\
  69. float2fixed(xy))
  70. clamp_coord(x);
  71. clamp_coord(y);
  72. #undef clamp_coord
  73. }
  74. int
  75. gs_currentpoint(gs_state * pgs, gs_point * ppt)
  76. {
  77. if (!pgs->current_point_valid)
  78. return_error(gs_error_nocurrentpoint);
  79. return gs_itransform(pgs, pgs->current_point.x,
  80. pgs->current_point.y, ppt);
  81. }
  82. private inline int
  83. gs_point_transform_compat(floatp x, floatp y, const gs_matrix_fixed *m, gs_point *pt)
  84. {
  85. #if !PRECISE_CURRENTPOINT
  86. gs_fixed_point p;
  87. int code = gs_point_transform2fixed(m, x, y, &p);
  88. if (code < 0)
  89. return code;
  90. pt->x = fixed2float(p.x);
  91. pt->y = fixed2float(p.y);
  92. return 0;
  93. #else
  94. return gs_point_transform(x, y, (const gs_matrix *)m, pt);
  95. #endif
  96. }
  97. private inline int
  98. gs_distance_transform_compat(floatp x, floatp y, const gs_matrix_fixed *m, gs_point *pt)
  99. {
  100. #if !PRECISE_CURRENTPOINT
  101. gs_fixed_point p;
  102. int code = gs_distance_transform2fixed(m, x, y, &p);
  103. if (code < 0)
  104. return code;
  105. pt->x = fixed2float(p.x);
  106. pt->y = fixed2float(p.y);
  107. return 0;
  108. #else
  109. return gs_distance_transform(x, y, (const gs_matrix *)m, pt);
  110. #endif
  111. }
  112. private inline int
  113. clamp_point_aux(bool clamp_coordinates, gs_fixed_point *ppt, floatp x, floatp y)
  114. {
  115. if (!f_fits_in_bits(x, fixed_int_bits) || !f_fits_in_bits(y, fixed_int_bits)) {
  116. if (!clamp_coordinates)
  117. return_error(gs_error_limitcheck);
  118. clamp_point(ppt, x, y);
  119. } else {
  120. /* 181-01.ps" fails with no rounding in
  121. "Verify as last element of a userpath and effect on setbbox." */
  122. ppt->x = float2fixed_rounded(x);
  123. ppt->y = float2fixed_rounded(y);
  124. }
  125. return 0;
  126. }
  127. int
  128. gs_moveto_aux(gs_imager_state *pis, gx_path *ppath, floatp x, floatp y)
  129. {
  130. gs_fixed_point pt;
  131. int code;
  132. code = clamp_point_aux(pis->clamp_coordinates, &pt, x, y);
  133. if (code < 0)
  134. return code;
  135. code = gx_path_add_point(ppath, pt.x, pt.y);
  136. if (code < 0)
  137. return code;
  138. ppath->start_flags = ppath->state_flags;
  139. gx_setcurrentpoint(pis, x, y);
  140. pis->subpath_start = pis->current_point;
  141. pis->current_point_valid = true;
  142. return 0;
  143. }
  144. int
  145. gs_moveto(gs_state * pgs, floatp x, floatp y)
  146. {
  147. gs_point pt;
  148. int code = gs_point_transform_compat(x, y, &pgs->ctm, &pt);
  149. if (code < 0)
  150. return code;
  151. return gs_moveto_aux((gs_imager_state *)pgs, pgs->path, pt.x, pt.y);
  152. }
  153. int
  154. gs_rmoveto(gs_state * pgs, floatp x, floatp y)
  155. {
  156. gs_point dd;
  157. int code;
  158. if (!pgs->current_point_valid)
  159. return_error(gs_error_nocurrentpoint);
  160. code = gs_distance_transform_compat(x, y, &pgs->ctm, &dd);
  161. if (code < 0)
  162. return code;
  163. /* fixme : check in range. */
  164. return gs_moveto_aux((gs_imager_state *)pgs, pgs->path,
  165. dd.x + pgs->current_point.x, dd.y + pgs->current_point.y);
  166. }
  167. private inline int
  168. gs_lineto_aux(gs_state * pgs, floatp x, floatp y)
  169. {
  170. gx_path *ppath = pgs->path;
  171. gs_fixed_point pt;
  172. int code;
  173. code = clamp_point_aux(pgs->clamp_coordinates, &pt, x, y);
  174. if (code < 0)
  175. return code;
  176. code = gx_path_add_line(ppath, pt.x, pt.y);
  177. if (code < 0)
  178. return code;
  179. gx_setcurrentpoint(pgs, x, y);
  180. return 0;
  181. }
  182. int
  183. gs_lineto(gs_state * pgs, floatp x, floatp y)
  184. {
  185. gs_point pt;
  186. int code = gs_point_transform_compat(x, y, &pgs->ctm, &pt);
  187. if (code < 0)
  188. return code;
  189. return gs_lineto_aux(pgs, pt.x, pt.y);
  190. }
  191. int
  192. gs_rlineto(gs_state * pgs, floatp x, floatp y)
  193. {
  194. gs_point dd;
  195. int code;
  196. if (!pgs->current_point_valid)
  197. return_error(gs_error_nocurrentpoint);
  198. code = gs_distance_transform_compat(x, y, &pgs->ctm, &dd);
  199. if (code < 0)
  200. return code;
  201. /* fixme : check in range. */
  202. return gs_lineto_aux(pgs, dd.x + pgs->current_point.x,
  203. dd.y + pgs->current_point.y);
  204. }
  205. /* ------ Curves ------ */
  206. private inline int
  207. gs_curveto_aux(gs_state * pgs,
  208. floatp x1, floatp y1, floatp x2, floatp y2, floatp x3, floatp y3)
  209. {
  210. gs_fixed_point p1, p2, p3;
  211. int code;
  212. gx_path *ppath = pgs->path;
  213. code = clamp_point_aux(pgs->clamp_coordinates, &p1, x1, y1);
  214. if (code < 0)
  215. return code;
  216. code = clamp_point_aux(pgs->clamp_coordinates, &p2, x2, y2);
  217. if (code < 0)
  218. return code;
  219. code = clamp_point_aux(pgs->clamp_coordinates, &p3, x3, y3);
  220. if (code < 0)
  221. return code;
  222. code = gx_path_add_curve(ppath, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y);
  223. if (code < 0)
  224. return code;
  225. gx_setcurrentpoint(pgs, x3, y3);
  226. return 0;
  227. }
  228. int
  229. gs_curveto(gs_state * pgs,
  230. floatp x1, floatp y1, floatp x2, floatp y2, floatp x3, floatp y3)
  231. {
  232. gs_point pt1, pt2, pt3;
  233. int code;
  234. code = gs_point_transform_compat(x1, y1, &pgs->ctm, &pt1);
  235. if (code < 0)
  236. return code;
  237. code = gs_point_transform_compat(x2, y2, &pgs->ctm, &pt2);
  238. if (code < 0)
  239. return code;
  240. code = gs_point_transform_compat(x3, y3, &pgs->ctm, &pt3);
  241. if (code < 0)
  242. return code;
  243. return gs_curveto_aux(pgs, pt1.x, pt1.y, pt2.x, pt2.y, pt3.x, pt3.y);
  244. }
  245. int
  246. gs_rcurveto(gs_state * pgs,
  247. floatp dx1, floatp dy1, floatp dx2, floatp dy2, floatp dx3, floatp dy3)
  248. {
  249. gs_point dd1, dd2, dd3;
  250. int code;
  251. if (!pgs->current_point_valid)
  252. return_error(gs_error_nocurrentpoint);
  253. code = gs_distance_transform_compat(dx1, dy1, &pgs->ctm, &dd1);
  254. if (code < 0)
  255. return code;
  256. code = gs_distance_transform_compat(dx2, dy2, &pgs->ctm, &dd2);
  257. if (code < 0)
  258. return code;
  259. code = gs_distance_transform_compat(dx3, dy3, &pgs->ctm, &dd3);
  260. if (code < 0)
  261. return code;
  262. /* fixme : check in range. */
  263. return gs_curveto_aux(pgs, dd1.x + pgs->current_point.x, dd1.y + pgs->current_point.y,
  264. dd2.x + pgs->current_point.x, dd2.y + pgs->current_point.y,
  265. dd3.x + pgs->current_point.x, dd3.y + pgs->current_point.y);
  266. }
  267. /* ------ Clipping ------ */
  268. /* Forward references */
  269. private int common_clip(gs_state *, int);
  270. /*
  271. * Return the effective clipping path of a graphics state. Sometimes this
  272. * is the intersection of the clip path and the view clip path; sometimes it
  273. * is just the clip path. We aren't sure what the correct algorithm is for
  274. * this: for now, we use view clipping unless the current device is a memory
  275. * device. This takes care of the most important case, where the current
  276. * device is a cache device.
  277. */
  278. int
  279. gx_effective_clip_path(gs_state * pgs, gx_clip_path ** ppcpath)
  280. {
  281. gs_id view_clip_id =
  282. (pgs->view_clip == 0 || pgs->view_clip->rule == 0 ? gs_no_id :
  283. pgs->view_clip->id);
  284. if (gs_device_is_memory(pgs->device)) {
  285. *ppcpath = pgs->clip_path;
  286. return 0;
  287. }
  288. if (pgs->effective_clip_id == pgs->clip_path->id &&
  289. pgs->effective_view_clip_id == view_clip_id
  290. ) {
  291. *ppcpath = pgs->effective_clip_path;
  292. return 0;
  293. }
  294. /* Update the cache. */
  295. if (view_clip_id == gs_no_id) {
  296. if (!pgs->effective_clip_shared)
  297. gx_cpath_free(pgs->effective_clip_path, "gx_effective_clip_path");
  298. pgs->effective_clip_path = pgs->clip_path;
  299. pgs->effective_clip_shared = true;
  300. } else {
  301. gs_fixed_rect cbox, vcbox;
  302. gx_cpath_inner_box(pgs->clip_path, &cbox);
  303. gx_cpath_outer_box(pgs->view_clip, &vcbox);
  304. if (rect_within(vcbox, cbox)) {
  305. if (!pgs->effective_clip_shared)
  306. gx_cpath_free(pgs->effective_clip_path,
  307. "gx_effective_clip_path");
  308. pgs->effective_clip_path = pgs->view_clip;
  309. pgs->effective_clip_shared = true;
  310. } else {
  311. /* Construct the intersection of the two clip paths. */
  312. int code;
  313. gx_clip_path ipath;
  314. gx_path vpath;
  315. gx_clip_path *npath = pgs->effective_clip_path;
  316. if (pgs->effective_clip_shared) {
  317. npath = gx_cpath_alloc(pgs->memory, "gx_effective_clip_path");
  318. if (npath == 0)
  319. return_error(gs_error_VMerror);
  320. }
  321. gx_cpath_init_local(&ipath, pgs->memory);
  322. code = gx_cpath_assign_preserve(&ipath, pgs->clip_path);
  323. if (code < 0)
  324. return code;
  325. gx_path_init_local(&vpath, pgs->memory);
  326. code = gx_cpath_to_path(pgs->view_clip, &vpath);
  327. if (code < 0 ||
  328. (code = gx_cpath_clip(pgs, &ipath, &vpath,
  329. gx_rule_winding_number)) < 0 ||
  330. (code = gx_cpath_assign_free(npath, &ipath)) < 0
  331. )
  332. DO_NOTHING;
  333. gx_path_free(&vpath, "gx_effective_clip_path");
  334. gx_cpath_free(&ipath, "gx_effective_clip_path");
  335. if (code < 0)
  336. return code;
  337. pgs->effective_clip_path = npath;
  338. pgs->effective_clip_shared = false;
  339. }
  340. }
  341. pgs->effective_clip_id = pgs->effective_clip_path->id;
  342. pgs->effective_view_clip_id = view_clip_id;
  343. *ppcpath = pgs->effective_clip_path;
  344. return 0;
  345. }
  346. #ifdef DEBUG
  347. /* Note that we just set the clipping path (internal). */
  348. private void
  349. note_set_clip_path(const gs_state * pgs)
  350. {
  351. if (gs_debug_c('P')) {
  352. dlprintf("[P]Clipping path:\n");
  353. gx_cpath_print(pgs->clip_path);
  354. }
  355. }
  356. #else
  357. # define note_set_clip_path(pgs) DO_NOTHING
  358. #endif
  359. int
  360. gs_clippath(gs_state * pgs)
  361. {
  362. gx_path cpath;
  363. int code;
  364. gx_path_init_local(&cpath, pgs->path->memory);
  365. code = gx_cpath_to_path(pgs->clip_path, &cpath);
  366. if (code >= 0)
  367. code = gx_path_assign_free(pgs->path, &cpath);
  368. if (code < 0)
  369. gx_path_free(&cpath, "gs_clippath");
  370. return code;
  371. }
  372. int
  373. gs_initclip(gs_state * pgs)
  374. {
  375. gs_fixed_rect box;
  376. int code = gx_default_clip_box(pgs, &box);
  377. if (code < 0)
  378. return code;
  379. return gx_clip_to_rectangle(pgs, &box);
  380. }
  381. int
  382. gs_clip(gs_state * pgs)
  383. {
  384. return common_clip(pgs, gx_rule_winding_number);
  385. }
  386. int
  387. gs_eoclip(gs_state * pgs)
  388. {
  389. return common_clip(pgs, gx_rule_even_odd);
  390. }
  391. private int
  392. common_clip(gs_state * pgs, int rule)
  393. {
  394. int code = gx_cpath_clip(pgs, pgs->clip_path, pgs->path, rule);
  395. if (code < 0)
  396. return code;
  397. pgs->clip_path->rule = rule;
  398. note_set_clip_path(pgs);
  399. return 0;
  400. }
  401. /* Establish a rectangle as the clipping path. */
  402. /* Used by initclip and by the character and Pattern cache logic. */
  403. int
  404. gx_clip_to_rectangle(gs_state * pgs, gs_fixed_rect * pbox)
  405. {
  406. int code = gx_cpath_from_rectangle(pgs->clip_path, pbox);
  407. if (code < 0)
  408. return code;
  409. pgs->clip_path->rule = gx_rule_winding_number;
  410. note_set_clip_path(pgs);
  411. return 0;
  412. }
  413. /* Set the clipping path to the current path, without intersecting. */
  414. /* This is very inefficient right now. */
  415. int
  416. gx_clip_to_path(gs_state * pgs)
  417. {
  418. gs_fixed_rect bbox;
  419. int code;
  420. if ((code = gx_path_bbox(pgs->path, &bbox)) < 0 ||
  421. (code = gx_clip_to_rectangle(pgs, &bbox)) < 0 ||
  422. (code = gs_clip(pgs)) < 0
  423. )
  424. return code;
  425. note_set_clip_path(pgs);
  426. return 0;
  427. }
  428. /* Get the default clipping box. */
  429. int
  430. gx_default_clip_box(const gs_state * pgs, gs_fixed_rect * pbox)
  431. {
  432. register gx_device *dev = gs_currentdevice(pgs);
  433. gs_rect bbox;
  434. gs_matrix imat;
  435. int code;
  436. if (dev->ImagingBBox_set) { /* Use the ImagingBBox, relative to default user space. */
  437. gs_defaultmatrix(pgs, &imat);
  438. bbox.p.x = dev->ImagingBBox[0];
  439. bbox.p.y = dev->ImagingBBox[1];
  440. bbox.q.x = dev->ImagingBBox[2];
  441. bbox.q.y = dev->ImagingBBox[3];
  442. } else { /* Use the MediaSize indented by the HWMargins, */
  443. /* relative to unrotated user space adjusted by */
  444. /* the Margins. (We suspect this isn't quite right, */
  445. /* but the whole issue of "margins" is such a mess that */
  446. /* we don't think we can do any better.) */
  447. (*dev_proc(dev, get_initial_matrix)) (dev, &imat);
  448. /* Adjust for the Margins. */
  449. imat.tx += dev->Margins[0] * dev->HWResolution[0] /
  450. dev->MarginsHWResolution[0];
  451. imat.ty += dev->Margins[1] * dev->HWResolution[1] /
  452. dev->MarginsHWResolution[1];
  453. bbox.p.x = dev->HWMargins[0];
  454. bbox.p.y = dev->HWMargins[1];
  455. bbox.q.x = dev->MediaSize[0] - dev->HWMargins[2];
  456. bbox.q.y = dev->MediaSize[1] - dev->HWMargins[3];
  457. }
  458. code = gs_bbox_transform(&bbox, &imat, &bbox);
  459. if (code < 0)
  460. return code;
  461. /* Round the clipping box so that it doesn't get ceilinged. */
  462. pbox->p.x = fixed_rounded(float2fixed(bbox.p.x));
  463. pbox->p.y = fixed_rounded(float2fixed(bbox.p.y));
  464. pbox->q.x = fixed_rounded(float2fixed(bbox.q.x));
  465. pbox->q.y = fixed_rounded(float2fixed(bbox.q.y));
  466. return 0;
  467. }