Re: Preliminary patch for preserving clip path lists - bug 686885
Raph Levien <[email protected]>
| Newsgroups | gmane.comp.printing.ghostscript.patches |
|---|---|
| Message-ID | <[email protected]> |
On Sat, Nov 01, 2003 at 06:50:59PM +0300, Igor V. Melichev wrote:
> Raph,
>
> Attaching a patch for writing high level paths to PDF.
> It has 2 problems :
>
> 1. pdfwrite with 012-05.ps pdf_put_clip_path_list_elem recieves a path with
> no segments. This causes a regression with this and many other files.
Yes. The problem is that the call to gx_cpath_intersect_path_slow()
destructively modified the path field of the cpath. I've fixed this by
copying the path into the path_list node _before_ doing the
rectlist-based intersection.
> An additional question :
> Is the recursive pdf_put_clip_path_list_elem fine, or it should convert to
> an iteration with a local modification of pointers ? I know that streams do
> so, but I don't like. It should be const. Do you think to add
>
> struct gx_cpath_path_list_s {
> ...
> gx_cpath_path_list *prev;
> };
>
> ? Not sure that 'prev' is fine with local/global.
I'm perfectly happy with it being recursive; this isn't code that is
likely to be called from inside very small-footprint devices.
Raph
_______________________________________________
gs-code-review mailing list
[email protected]
http://www.ghostscript.com/mailman/listinfo/gs-code-review
cpath-patch-2
(text/plain, 8.4 KB)
Index: src/gdevpdfd.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevpdfd.c,v
retrieving revision 1.34
diff -C2 -r1.34 gdevpdfd.c
*** src/gdevpdfd.c 14 Oct 2003 12:43:18 -0000 1.34
--- src/gdevpdfd.c 12 Nov 2003 08:30:40 -0000
***************
*** 260,263 ****
--- 260,286 ----
}
+ /* Put a single element of a clipping path list. */
+ int
+ pdf_put_clip_path_list_elem(gx_device_pdf * pdev, gx_cpath_path_list *e,
+ gs_path_enum *cenum, gdev_vector_dopath_state_t *state,
+ gs_fixed_point vs[3])
+ { /* This recursive function provides a reverse order of the list elements. */
+ int pe_op;
+
+ if (e->next != NULL) {
+ int code = pdf_put_clip_path_list_elem(pdev, e->next, cenum, state, vs);
+
+ if (code != 0)
+ return code;
+ }
+ gx_path_enum_init(cenum, &e->path);
+ while ((pe_op = gx_path_enum_next(cenum, vs)) > 0)
+ gdev_vector_dopath_segment(state, pe_op, vs);
+ pprints1(pdev->strm, "%s n\n", (e->rule <= 0 ? "W" : "W*"));
+ if (pe_op < 0)
+ return pe_op;
+ return 0;
+ }
+
/* Put a clipping path on the output file. */
int
***************
*** 308,312 ****
if (new_id != pdev->no_clip_path_id) {
gdev_vector_dopath_state_t state;
- gs_cpath_enum cenum;
gs_fixed_point vs[3];
int pe_op;
--- 331,334 ----
***************
*** 318,321 ****
--- 340,346 ----
gdev_vector_dopath_init(&state, (gx_device_vector *)pdev,
gx_path_type_fill, NULL);
+ if (pcpath->path_list == NULL) {
+ gs_cpath_enum cenum;
+
/*
* We have to break 'const' here because the clip path
***************
*** 330,333 ****
--- 355,365 ----
if (pe_op < 0)
return pe_op;
+ } else {
+ gs_path_enum cenum;
+
+ code = pdf_put_clip_path_list_elem(pdev, pcpath->path_list, &cenum, &state, vs);
+ if (code < 0)
+ return code;
+ }
}
pdev->clip_path_id = new_id;
Index: src/gxcpath.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gxcpath.c,v
retrieving revision 1.8
diff -C2 -r1.8 gxcpath.c
*** src/gxcpath.c 8 Sep 2003 12:06:56 -0000 1.8
--- src/gxcpath.c 12 Nov 2003 08:30:40 -0000
***************
*** 40,51 ****
public_st_device_clip();
private_st_cpath_enum();
/* GC procedures for gx_clip_path */
private
! ENUM_PTRS_WITH(clip_path_enum_ptrs, gx_clip_path *cptr) return ENUM_USING(st_path, &cptr->path, sizeof(cptr->path), index - 1);
case 0:
! ENUM_RETURN((cptr->rect_list == &cptr->local_list ? 0 :
cptr->rect_list));
ENUM_PTRS_END
private
--- 40,54 ----
public_st_device_clip();
private_st_cpath_enum();
+ private_st_cpath_path_list();
/* GC procedures for gx_clip_path */
private
! ENUM_PTRS_WITH(clip_path_enum_ptrs, gx_clip_path *cptr) return ENUM_USING(st_path, &cptr->path, sizeof(cptr->path), index - 2);
case 0:
! return ENUM_OBJ((cptr->rect_list == &cptr->local_list ? 0 :
cptr->rect_list));
+ case 1:
+ return ENUM_OBJ(cptr->path_list);
ENUM_PTRS_END
private
***************
*** 54,57 ****
--- 57,61 ----
if (cptr->rect_list != &cptr->local_list)
RELOC_VAR(cptr->rect_list);
+ RELOC_VAR(cptr->path_list);
RELOC_USING(st_path, &cptr->path, sizeof(gx_path));
}
***************
*** 95,98 ****
--- 99,103 ----
private rc_free_proc(rc_free_cpath_list);
private rc_free_proc(rc_free_cpath_list_local);
+ private rc_free_proc(rc_free_cpath_path_list);
/*
***************
*** 117,120 ****
--- 122,126 ----
null_rect.p.x = null_rect.p.y = null_rect.q.x = null_rect.q.y = 0;
cpath_init_rectangle(pcpath, &null_rect);
+ pcpath->path_list = NULL;
}
private void
***************
*** 152,155 ****
--- 158,162 ----
rc_increment(pcpath->path.segments);
rc_increment(pcpath->rect_list);
+ rc_increment(pcpath->path_list);
} else {
int code = cpath_alloc_list(&pcpath->rect_list, mem, cname);
***************
*** 206,209 ****
--- 213,218 ----
pcpath->rect_list = shared->rect_list;
rc_increment(pcpath->rect_list);
+ pcpath->path_list = shared->path_list;
+ rc_increment(pcpath->path_list);
cpath_share_own_contents(pcpath, shared);
} else {
***************
*** 243,248 ****
--- 252,259 ----
{
rc_decrement(pcpath->rect_list, cname);
+ rc_decrement(pcpath->path_list, cname);
/* Clean up pointers for GC. */
pcpath->rect_list = 0;
+ pcpath->path_list = 0;
{
gx_path_allocation_t alloc = pcpath->path.allocation;
***************
*** 323,326 ****
--- 334,367 ----
}
+ private void
+ rc_free_cpath_path_list(gs_memory_t * mem, void *vplist, client_name_t cname)
+ {
+ gx_cpath_path_list *plist = (gx_cpath_path_list *)vplist;
+ rc_decrement(plist->next, cname);
+ gx_path_free(&plist->path, cname);
+ gs_free_object(plist->path.memory, plist, cname);
+ }
+
+ /* Allocate a new clip path list node. The created node has a ref count
+ of 1, and "steals" the reference to next (i.e. does not increment
+ its reference count). */
+ private gx_cpath_path_list *
+ gx_cpath_path_list_new(gs_memory_t *mem, int rule, gx_path *ppfrom,
+ gx_cpath_path_list *next)
+ {
+ int code;
+ client_name_t cname = "gx_cpath_path_list_new";
+ gx_cpath_path_list *pcplist = gs_alloc_struct(mem, gx_cpath_path_list,
+ &st_cpath_path_list,
+ cname);
+
+ if (pcplist == 0)
+ return 0;
+ rc_init_free(pcplist, mem, 1, rc_free_cpath_path_list);
+ code = gx_path_init_contained_shared(&pcplist->path, ppfrom, mem, cname);
+ pcplist->next = next;
+ return pcplist;
+ }
+
/* ------ Clipping path accessing ------ */
***************
*** 500,504 ****
ppath = &fpath;
}
! /**************** SHOULD CHANGE THIS TO KEEP PATH ****************/
if (gx_cpath_inner_box(pcpath, &old_box) &&
((code = gx_path_is_rectangle(ppath, &new_box)) ||
--- 541,545 ----
ppath = &fpath;
}
!
if (gx_cpath_inner_box(pcpath, &old_box) &&
((code = gx_path_is_rectangle(ppath, &new_box)) ||
***************
*** 535,538 ****
--- 576,580 ----
}
/* Release the existing path. */
+ rc_decrement(pcpath->path_list, pcpath->path.memory);
gx_path_new(&pcpath->path);
ppath->bbox = new_box;
***************
*** 544,548 ****
}
} else {
! /* Existing clip path is not a rectangle. Intersect the slow way. */
bool path_valid =
gx_cpath_inner_box(pcpath, &old_box) &&
--- 586,591 ----
}
} else {
! /* New clip path is nontrivial. Intersect the slow way. */
! gx_cpath_path_list *next = pcpath->path_list;
bool path_valid =
gx_cpath_inner_box(pcpath, &old_box) &&
***************
*** 552,559 ****
--- 595,611 ----
new_box.q.x, new_box.q.y);
+ if (!path_valid && next == NULL) {
+ gs_memory_t *mem = pcpath->path.memory;
+ next = gx_cpath_path_list_new(mem, pcpath->rule,
+ &pcpath->path, NULL);
+ }
code = gx_cpath_intersect_path_slow(pcpath, ppath, rule, pis);
if (code >= 0 && path_valid) {
gx_path_assign_preserve(&pcpath->path, ppath_orig);
pcpath->path_valid = true;
+ } else {
+ gs_memory_t *mem = pcpath->path.memory;
+ pcpath->path_list = gx_cpath_path_list_new(mem, rule, ppath_orig,
+ next);
}
}
Index: src/gzcpath.h
===================================================================
RCS file: /cvs/ghostscript/gs/src/gzcpath.h,v
retrieving revision 1.4
diff -C2 -r1.4 gzcpath.h
*** src/gzcpath.h 21 Feb 2002 22:24:53 -0000 1.4
--- src/gzcpath.h 12 Nov 2003 08:30:40 -0000
***************
*** 41,44 ****
--- 41,64 ----
st_clip_list, list)
+ /*
+ * When the clip path consists of the intersection of two or more
+ * source paths, we maintain the complete list paths, so that it
+ * can be accurately output for high-level devices.
+ */
+
+ typedef struct gx_cpath_path_list_s gx_cpath_path_list;
+
+ struct gx_cpath_path_list_s {
+ gx_path path;
+ rc_header rc;
+ int rule;
+ gx_cpath_path_list *next;
+ };
+
+ #define private_st_cpath_path_list() /* in gxcpath.c */\
+ gs_private_st_suffix_add1(st_cpath_path_list, gx_cpath_path_list,\
+ "gs_cpath_list", cpath_path_list_enum_ptrs, cpath_path_list_reloc_ptrs,\
+ st_path, next)
+
/* gx_clip_path is a 'subclass' of gx_path. */
struct gx_clip_path_s {
***************
*** 55,58 ****
--- 75,79 ----
gx_clip_rect_list *rect_list;
bool path_valid; /* path representation is valid */
+ gx_cpath_path_list *path_list;
/* The id changes whenever the clipping region changes. */
gs_id id;