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;
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.