summaryrefslogtreecommitdiff
path: root/gs/src/gsclipsr.c
diff options
context:
space:
mode:
Diffstat (limited to 'gs/src/gsclipsr.c')
-rw-r--r--gs/src/gsclipsr.c71
1 files changed, 67 insertions, 4 deletions
diff --git a/gs/src/gsclipsr.c b/gs/src/gsclipsr.c
index d4e3d9742..052c1aa63 100644
--- a/gs/src/gsclipsr.c
+++ b/gs/src/gsclipsr.c
@@ -21,19 +21,82 @@
#include "gx.h"
#include "gserrors.h"
#include "gsclipsr.h"
+#include "gsstruct.h"
+#include "gxclipsr.h"
+#include "gxfixed.h" /* for gxpath.h */
+#include "gxpath.h"
+#include "gzstate.h"
+
+/* Structure descriptors */
+private_st_clip_stack();
+
+/*
+ * When we free a clip stack entry, free the associated clip path,
+ * and iterate down the list. We do this iteratively so that we don't
+ * take a level of recursion for each node on the list.
+ */
+private void
+rc_free_clip_stack(gs_memory_t * mem, void *vstack, client_name_t cname)
+{
+ gx_clip_stack_t *stack = (gx_clip_stack_t *)vstack;
+ gx_clip_stack_t *next;
+
+ do {
+ gx_clip_path *pcpath = stack->clip_path;
+
+ next = stack->next;
+ gs_free_object(stack->rc.memory, stack, cname);
+ gx_cpath_free(pcpath, "rc_free_clip_stack");
+ } while ((stack = next) != 0 && !--(stack->rc.ref_count));
+}
/* clipsave */
int
gs_clipsave(gs_state *pgs)
{
- /****** NYI ******/
- return_error(gs_error_undefined);
+ gs_memory_t *mem = pgs->memory;
+ gx_clip_path *copy =
+ gx_cpath_alloc_shared(pgs->clip_path, mem, "gs_clipsave(clip_path)");
+ gx_clip_stack_t *stack =
+ gs_alloc_struct(mem, gx_clip_stack_t, &st_clip_stack,
+ "gs_clipsave(stack)");
+
+ if (copy == 0 || stack == 0) {
+ gs_free_object(mem, stack, "gs_clipsave(stack)");
+ gs_free_object(mem, copy, "gs_clipsave(clip_path)");
+ return_error(gs_error_VMerror);
+ }
+ rc_init_free(stack, mem, 1, rc_free_clip_stack);
+ stack->clip_path = copy;
+ stack->next = pgs->clip_stack;
+ pgs->clip_stack = stack;
+ return 0;
}
/* cliprestore */
int
gs_cliprestore(gs_state *pgs)
{
- /****** NYI ******/
- return_error(gs_error_undefined);
+ gx_clip_stack_t *stack = pgs->clip_stack;
+
+ if (stack) {
+ gx_clip_stack_t *next = stack->next;
+ gx_clip_path *pcpath = stack->clip_path;
+ int code;
+
+ if (stack->rc.ref_count == 1) {
+ /* Use assign_free rather than assign_preserve. */
+ gs_free_object(stack->rc.memory, stack, "cliprestore");
+ code = gx_cpath_assign_free(pgs->clip_path, pcpath);
+ } else {
+ code = gx_cpath_assign_preserve(pgs->clip_path, pcpath);
+ if (code < 0)
+ return code;
+ --(stack->rc.ref_count);
+ }
+ pgs->clip_stack = next;
+ return code;
+ } else {
+ return gx_cpath_assign_preserve(pgs->clip_path, pgs->saved->clip_path);
+ }
}