summaryrefslogtreecommitdiff
path: root/gs/src
diff options
context:
space:
mode:
authorHenry Stiles <henry.stiles@artifex.com>1998-08-08 06:11:33 +0000
committerHenry Stiles <henry.stiles@artifex.com>1998-08-08 06:11:33 +0000
commit3305477b99710b8ce6223a0bdd5014ced4de6997 (patch)
tree2cd123878deab83af88cbfcbff04624712c5b46c /gs/src
parentb8cb922d73b866149ca3da2288f1edcf959c45c9 (diff)
Initial revision
git-svn-id: http://svn.ghostscript.com/ghostpcl/trunk/ghostpcl@277 06663e23-700e-0410-b217-a244a6096597
Diffstat (limited to 'gs/src')
-rw-r--r--gs/src/gdevpdfo.c675
-rw-r--r--gs/src/gdevpsci.c130
-rw-r--r--gs/src/gdevpsde.c276
-rw-r--r--gs/src/gdevpsdi.c317
-rw-r--r--gs/src/gdevpsdp.c641
-rw-r--r--gs/src/gdevpsds.c451
-rw-r--r--gs/src/gdevpsds.h101
-rw-r--r--gs/src/gdevrops.c196
-rw-r--r--gs/src/gendev.c363
-rw-r--r--gs/src/gp_getnv.c54
-rw-r--r--gs/src/gp_wgetv.c130
-rw-r--r--gs/src/gpgetenv.h44
-rw-r--r--gs/src/gsalpha.c42
-rw-r--r--gs/src/gsalpha.h35
-rw-r--r--gs/src/gsalphac.c830
-rw-r--r--gs/src/gsalphac.h65
-rw-r--r--gs/src/gscdevn.c178
-rw-r--r--gs/src/gscolor3.c67
-rw-r--r--gs/src/gscolor3.h35
-rw-r--r--gs/src/gscompt.h53
-rw-r--r--gs/src/gscparam.c474
-rw-r--r--gs/src/gscpixel.c83
-rw-r--r--gs/src/gscpixel.h28
-rw-r--r--gs/src/gscrdp.c623
-rw-r--r--gs/src/gscrdp.h98
-rw-r--r--gs/src/gsdpnext.h28
-rw-r--r--gs/src/gsfunc3.c355
-rw-r--r--gs/src/gsfunc3.h108
-rw-r--r--gs/src/gsiparm2.h64
-rw-r--r--gs/src/gsmalloc.c389
-rw-r--r--gs/src/gsmalloc.h71
-rw-r--r--gs/src/gsnorop.c113
-rw-r--r--gs/src/gsptype2.h46
-rw-r--r--gs/src/gsrect.h55
-rw-r--r--gs/src/gsropc.c310
-rw-r--r--gs/src/gsropc.h54
-rw-r--r--gs/src/gsshade.c304
-rw-r--r--gs/src/gsshade.h222
-rw-r--r--gs/src/gstext.c336
-rw-r--r--gs/src/gstext.h223
-rw-r--r--gs/src/gstrap.c184
-rw-r--r--gs/src/gstrap.h75
-rw-r--r--gs/src/gxalpha.h68
-rw-r--r--gs/src/gxbitfmt.h189
-rw-r--r--gs/src/gxbitops.h136
-rw-r--r--gs/src/gxclrast.c2232
-rw-r--r--gs/src/gxclutil.c610
-rw-r--r--gs/src/gxcomp.h107
-rw-r--r--gs/src/gxgetbit.h95
-rw-r--r--gs/src/gxi12bit.c294
-rw-r--r--gs/src/gxicolor.c312
-rw-r--r--gs/src/gxidata.c235
-rw-r--r--gs/src/gxifast.c699
-rw-r--r--gs/src/gxiinit.c911
-rw-r--r--gs/src/gximono.c477
-rw-r--r--gs/src/gxiscale.c243
-rw-r--r--gs/src/gxropc.h47
-rw-r--r--gs/src/gxshade.c363
-rw-r--r--gs/src/gxshade.h257
-rw-r--r--gs/src/gxshade1.c511
-rw-r--r--gs/src/gxshade4.c289
-rw-r--r--gs/src/gxshade4.h53
-rw-r--r--gs/src/gxshade6.c552
-rw-r--r--gs/src/gxtext.h115
-rw-r--r--gs/src/icstate.h70
-rw-r--r--gs/src/idictdef.h122
-rw-r--r--gs/src/idstack.c243
-rw-r--r--gs/src/idstack.h119
-rw-r--r--gs/src/iestack.h50
-rw-r--r--gs/src/iimage2.h44
-rw-r--r--gs/src/inames.h108
-rw-r--r--gs/src/inouparm.c28
-rw-r--r--gs/src/iostack.h39
-rw-r--r--gs/src/pcwin.mak100
-rw-r--r--gs/src/pipe_.h36
-rw-r--r--gs/src/scfparam.c93
-rw-r--r--gs/src/sdcparam.c619
-rw-r--r--gs/src/sdcparam.h51
-rw-r--r--gs/src/sddparam.c72
-rw-r--r--gs/src/sdeparam.c317
-rw-r--r--gs/src/unixinst.mak102
-rw-r--r--gs/src/zcfont.c158
-rw-r--r--gs/src/zchar32.c190
-rw-r--r--gs/src/zcsdevn.c113
-rw-r--r--gs/src/zcspixel.c67
-rw-r--r--gs/src/zfont32.c73
-rw-r--r--gs/src/zfreuse.c200
-rw-r--r--gs/src/zfunc3.c130
-rw-r--r--gs/src/zimage3.c119
-rw-r--r--gs/src/zmisc3.c105
-rw-r--r--gs/src/zshade.c593
-rw-r--r--gs/src/ztrap.c66
92 files changed, 21748 insertions, 0 deletions
diff --git a/gs/src/gdevpdfo.c b/gs/src/gdevpdfo.c
new file mode 100644
index 000000000..8b124845c
--- /dev/null
+++ b/gs/src/gdevpdfo.c
@@ -0,0 +1,675 @@
+/* Copyright (C) 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gdevpdfo.c */
+/* Named object pdfmark processing */
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsutil.h" /* for bytes_compare */
+#include "gdevpdfx.h"
+#include "strimpl.h"
+#include "sstring.h"
+
+/* GC procedures */
+
+private_st_pdf_named_element();
+public_st_pdf_named_object();
+
+#define pne ((pdf_named_element *)vptr)
+private
+ENUM_PTRS_BEGIN(pdf_named_elt_enum_ptrs) return 0;
+
+ENUM_PTR(0, pdf_named_element, next);
+ENUM_STRING_PTR(1, pdf_named_element, key);
+/****** WRONG IF data = 0 ******/
+ENUM_STRING_PTR(2, pdf_named_element, value);
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(pdf_named_elt_reloc_ptrs)
+{
+ RELOC_PTR(pdf_named_element, next);
+ if (pne->key.data != 0)
+ RELOC_STRING_PTR(pdf_named_element, key);
+ RELOC_STRING_PTR(pdf_named_element, value);
+}
+RELOC_PTRS_END
+#undef pne
+
+#define pno ((pdf_named_object *)vptr)
+private ENUM_PTRS_BEGIN(pdf_named_obj_enum_ptrs) return 0;
+ENUM_PTR(0, pdf_named_object, next);
+ENUM_STRING_PTR(1, pdf_named_object, key);
+ENUM_PTR(2, pdf_named_object, elements);
+case 3:
+if (pno->type == named_graphics)
+ ENUM_RETURN(pno->graphics.enclosing);
+else
+ return 0;
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(pdf_named_obj_reloc_ptrs)
+{
+ RELOC_PTR(pdf_named_object, next);
+ RELOC_STRING_PTR(pdf_named_object, key);
+ RELOC_PTR(pdf_named_object, elements);
+ if (pno->type == named_graphics)
+ RELOC_PTR(pdf_named_object, graphics.enclosing);
+}
+RELOC_PTRS_END
+#undef pno
+
+/* ---------------- pdfmark processing ---------------- */
+
+/* Define the pdfmark types implemented here. */
+private pdfmark_proc(pdfmark_BP);
+private pdfmark_proc(pdfmark_EP);
+private pdfmark_proc(pdfmark_SP);
+private pdfmark_proc(pdfmark_OBJ);
+private pdfmark_proc(pdfmark_PUT);
+private pdfmark_proc(pdfmark_PUTDICT);
+private pdfmark_proc(pdfmark_PUTINTERVAL);
+private pdfmark_proc(pdfmark_CLOSE);
+const pdfmark_name pdfmark_names_named[] =
+{
+ {"BP", pdfmark_BP, pdfmark_nameable},
+ {"EP", pdfmark_EP, 0},
+ {"SP", pdfmark_SP, pdfmark_odd_ok | pdfmark_keep_name},
+ {"OBJ", pdfmark_OBJ, pdfmark_nameable},
+ {"PUT", pdfmark_PUT, pdfmark_odd_ok | pdfmark_keep_name},
+ {".PUTDICT", pdfmark_PUTDICT, pdfmark_odd_ok | pdfmark_keep_name},
+ {".PUTINTERVAL", pdfmark_PUTINTERVAL, pdfmark_odd_ok | pdfmark_keep_name},
+ {"CLOSE", pdfmark_CLOSE, pdfmark_odd_ok | pdfmark_keep_name},
+ {0, 0}
+};
+
+/*
+ * Predefined objects:
+ * {Catalog}, {DocInfo}
+ * {Page<#>}, {ThisPage}, {PrevPage}, {NextPage}
+ */
+
+/* ---------------- Utilities ---------------- */
+
+private int pdfmark_write_named(P2(gx_device_pdf * pdev,
+ const pdf_named_object * pno));
+private void pdfmark_free_named(P2(gx_device_pdf * pdev,
+ pdf_named_object * pno));
+
+/* ------ Public ------ */
+
+/*
+ * Look up an object name. Return e_rangecheck if the syntax is invalid.
+ * If the object is missing, then:
+ * - If create is false, return gs_error_undefined;
+ * - If create is true, create the object and return 1.
+ * Note that there is code in gdevpdf.c that relies on the fact that
+ * the named_objects list is sorted by decreasing object number.
+ */
+private int
+pdfmark_find_named(gx_device_pdf * pdev, const gs_param_string * pname,
+ pdf_named_object ** ppno, bool create)
+{
+ const byte *data = pname->data;
+ uint size = pname->size;
+ gs_id key_id =
+ (size == 0 ? 0 : data[0] + data[size / 2] + data[size - 1]);
+ pdf_resource **plist =
+ &pdev->resources[resourceNamedObject].
+ chains[gs_id_hash(key_id) % num_resource_chains];
+ pdf_named_object *pno = (pdf_named_object *) * plist;
+
+ if (!pdfmark_objname_is_valid(data, size))
+ return_error(gs_error_rangecheck);
+ for (; pno; pno = pno->next)
+ if (!bytes_compare(data, size, pno->key.data, pno->key.size)) {
+ *ppno = pno;
+ return 0;
+ }
+ if (!create)
+ return_error(gs_error_undefined);
+ {
+ gs_memory_t *mem = pdev->pdf_memory;
+ byte *key = gs_alloc_string(mem, size, "pdf named object key");
+ pdf_resource *pres;
+ int code;
+
+ if (key == 0)
+ return_error(gs_error_VMerror);
+ code = pdf_alloc_resource(pdev, resourceNamedObject, key_id, &pres);
+ if (code < 0) {
+ gs_free_string(mem, key, size, "pdf named object key");
+ return code;
+ }
+ pno = (pdf_named_object *) pres;
+ memcpy(key, data, size);
+ pno->id = pdf_obj_ref(pdev);
+ pno->type = named_unknown; /* caller may change */
+ pno->key.data = key;
+ pno->key.size = size;
+ pno->elements = 0;
+ pno->open = true;
+ /* For now, just link the object onto the private list. */
+ pno->next = pdev->named_objects;
+ pdev->named_objects = pno;
+ *ppno = pno;
+ return 1;
+ }
+}
+
+/* Replace object names with object references in a (parameter) string. */
+private const byte *
+pdfmark_next_object(const byte * scan, const byte * end, const byte ** pname,
+ pdf_named_object ** ppno, gx_device_pdf * pdev)
+{ /*
+ * Starting at scan, find the next object reference, set *pname
+ * to point to it in the string, store the object at *ppno,
+ * and return a pointer to the first character beyond the
+ * reference. If there are no more object references, set
+ * *pname = end and return end.
+ */
+ const byte *left;
+ const byte *lit;
+ const byte *right;
+
+ *ppno = 0;
+ top:left = memchr(scan, '{', end - scan);
+ if (left == 0)
+ return (*pname = end);
+ lit = memchr(scan, '(', left - scan);
+ if (lit) {
+ /* Skip over the string. */
+ byte buf[50]; /* size is arbitrary */
+ stream_cursor_read r;
+ stream_cursor_write w;
+ stream_PSSD_state ss;
+ int status;
+
+ s_PSSD_init_inline(&ss);
+ r.ptr = lit - 1;
+ r.limit = end - 1;
+ w.limit = buf + sizeof(buf) - 1;
+ do {
+ w.ptr = buf - 1;
+ status = (*s_PSSD_template.process)
+ ((stream_state *) & ss, &r, &w, true);
+ }
+ while (status == 1);
+ scan = r.ptr + 1;
+ goto top;
+ }
+ right = memchr(left + 1, '}', end - (left + 1));
+ if (right == 0) /* malformed name */
+ return (*pname = end);
+ *pname = left;
+ ++right;
+ {
+ gs_param_string sname;
+
+ sname.data = left;
+ sname.size = right - left;
+ pdfmark_find_named(pdev, &sname, ppno, false);
+ }
+ return right;
+}
+int
+pdfmark_replace_names(gx_device_pdf * pdev, const gs_param_string * from,
+ gs_param_string * to)
+{
+ const byte *start = from->data;
+ const byte *end = start + from->size;
+ const byte *scan;
+ uint size = 0;
+ pdf_named_object *pno;
+ bool any = false;
+ byte *sto;
+ char ref[1 + 10 + 5 + 1]; /* max obj number is 10 digits */
+
+ /* Do a first pass to compute the length of the result. */
+ for (scan = start; scan < end;) {
+ const byte *sname;
+ const byte *next =
+ pdfmark_next_object(scan, end, &sname, &pno, pdev);
+
+ size += sname - scan;
+ if (pno) {
+ sprintf(ref, " %ld 0 R ", pno->id);
+ size += strlen(ref);
+ }
+ scan = next;
+ any |= next != sname;
+ }
+ to->persistent = true; /* ??? */
+ if (!any) {
+ to->data = start;
+ to->size = size;
+ return 0;
+ }
+ sto = gs_alloc_bytes(pdev->pdf_memory, size,
+ "pdfmark_replace_names");
+ if (sto == 0)
+ return_error(gs_error_VMerror);
+ to->data = sto;
+ to->size = size;
+ /* Do a second pass to do the actual substitutions. */
+ for (scan = start; scan < end;) {
+ const byte *sname;
+ const byte *next =
+ pdfmark_next_object(scan, end, &sname, &pno, pdev);
+ uint copy = sname - scan;
+ int rlen;
+
+ memcpy(sto, scan, copy);
+ sto += copy;
+ if (pno) {
+ sprintf(ref, " %ld 0 R ", pno->id);
+ rlen = strlen(ref);
+ memcpy(sto, ref, rlen);
+ sto += rlen;
+ }
+ scan = next;
+ }
+ return 0;
+}
+
+/* Write and free an entire list of named objects. */
+int
+pdfmark_write_and_free_named(gx_device_pdf * pdev, pdf_named_object ** ppno)
+{
+ pdf_named_object *pno = *ppno;
+ pdf_named_object *next;
+
+ for (; pno; pno = next) {
+ next = pno->next;
+ pdfmark_write_named(pdev, pno);
+ pdfmark_free_named(pdev, pno);
+ }
+ *ppno = 0;
+ return 0;
+}
+
+/* ------ Private ------ */
+
+/* Put an element of an array object. */
+private int
+pdf_named_array_put(gx_device_pdf * pdev, pdf_named_object * pno, int index,
+ const gs_param_string * pvalue)
+{
+ gs_memory_t *mem = pdev->pdf_memory;
+ pdf_named_element **ppne = &pno->elements;
+ pdf_named_element *pne;
+ pdf_named_element *pnext;
+ gs_string value;
+
+ while ((pnext = *ppne) != 0 && pnext->key.size > index)
+ ppne = &pnext->next;
+ value.data = gs_alloc_string(mem, pvalue->size, "named array value");
+ if (value.data == 0)
+ return_error(gs_error_VMerror);
+ value.size = pvalue->size;
+ if (pnext && pnext->key.size == index) {
+ /* We're replacing an existing element. */
+ gs_free_string(mem, pnext->value.data, pnext->value.size,
+ "named array old value");
+ pne = pnext;
+ } else {
+ /* Create a new element. */
+ pne = gs_alloc_struct(mem, pdf_named_element, &st_pdf_named_element,
+ "named array element");
+ if (pne == 0) {
+ gs_free_string(mem, value.data, value.size, "named array value");
+ return_error(gs_error_VMerror);
+ }
+ pne->key.data = 0;
+ pne->key.size = index;
+ pne->next = pnext;
+ *ppne = pne;
+ }
+ memcpy(value.data, pvalue->data, value.size);
+ pne->value = value;
+ return 0;
+}
+
+/* Put an element of a dictionary object. */
+private int
+pdf_named_dict_put(gx_device_pdf * pdev, pdf_named_object * pno,
+ const gs_param_string * pkey, const gs_param_string * pvalue)
+{
+ gs_memory_t *mem = pdev->pdf_memory;
+ pdf_named_element **ppne = &pno->elements;
+ pdf_named_element *pne;
+ pdf_named_element *pnext;
+ gs_string value;
+
+ while ((pnext = *ppne) != 0 &&
+ bytes_compare(pnext->key.data, pnext->key.size,
+ pkey->data, pkey->size)
+ )
+ ppne = &pnext->next;
+ value.data = gs_alloc_string(mem, pvalue->size, "named dict value");
+ if (value.data == 0)
+ return_error(gs_error_VMerror);
+ value.size = pvalue->size;
+ if (pnext) {
+ /* We're replacing an existing element. */
+ gs_free_string(mem, pnext->value.data, pnext->value.size,
+ "named array old value");
+ pne = pnext;
+ } else {
+ /* Create a new element. */
+ gs_string key;
+
+ key.data = gs_alloc_string(mem, pkey->size, "named dict key");
+ key.size = pkey->size;
+ pne = gs_alloc_struct(mem, pdf_named_element, &st_pdf_named_element,
+ "named dict element");
+ if (key.data == 0 || pne == 0) {
+ gs_free_object(mem, pne, "named dict element");
+ if (key.data)
+ gs_free_string(mem, key.data, key.size, "named dict key");
+ gs_free_string(mem, value.data, value.size, "named dict value");
+ return_error(gs_error_VMerror);
+ }
+ pne->key = key;
+ memcpy(key.data, pkey->data, key.size);
+ pne->next = pnext;
+ *ppne = pne;
+ }
+ memcpy(value.data, pvalue->data, value.size);
+ pne->value = value;
+ return 0;
+}
+
+/* Write out the definition of a named object. */
+private pdf_named_element *
+pdf_reverse_elements(pdf_named_element * pne)
+{
+ pdf_named_element *prev = NULL;
+ pdf_named_element *next;
+
+ for (; pne; pne = next)
+ next = pne->next, pne->next = prev, prev = pne;
+ return prev;
+}
+private int
+pdfmark_write_named(gx_device_pdf * pdev, const pdf_named_object * pno)
+{
+ stream *s = pdev->strm;
+ pdf_named_element *pne = pno->elements;
+
+ switch (pno->type) {
+ case named_array:{
+ uint last_index = 0;
+ pdf_named_element *last = pne = pdf_reverse_elements(pne);
+
+ pdf_open_obj(pdev, pno->id);
+ pputs(s, "[");
+ for (; pne; ++last_index, pne = pne->next) {
+ for (; pne->key.size > last_index; ++last_index)
+ pputs(s, "null\n");
+ pdf_put_value(pdev, pne->value.data, pne->value.size);
+ pputc(s, '\n');
+ }
+ pdf_reverse_elements(last);
+ pputs(s, "]");
+ }
+ break;
+ case named_dict:
+ pdf_open_obj(pdev, pno->id);
+ pputs(s, "<<");
+ dict:for (; pne; pne = pne->next) {
+ pdf_put_value(pdev, pne->key.data, pne->key.size);
+ pputc(s, ' ');
+ pdf_put_value(pdev, pne->value.data, pne->value.size);
+ pputc(s, '\n');
+ }
+ pputs(s, ">>");
+ break;
+ case named_stream:{
+ pdf_named_element *last = pne = pdf_reverse_elements(pne);
+
+/****** NYI ******/
+#if 0
+ pdf_open_stream(pdev, pno->id);
+/****** DOESN'T EXIST ******/
+ for (; pne; pne = pne->next)
+ pwrite(s, pne->value.data, pne->value.size);
+ pdf_close_stream(pdev);
+/****** DITTO ******/
+#endif
+ pdf_reverse_elements(last);
+ }
+ break;
+/****** WHAT TO DO WITH GRAPHICS/UNDEFINED? ******/
+ default:
+ return 0;
+ }
+ pdf_end_obj(pdev);
+ return 0;
+}
+
+/* Free the definition of a named object. */
+private void
+pdfmark_free_named(gx_device_pdf * pdev, pdf_named_object * pno)
+{
+ pdf_named_element *pne = pno->elements;
+ pdf_named_element *next;
+
+ for (; pne; pne = next) {
+ next = pne->next;
+ gs_free_string(pdev->pdf_memory, pne->value.data, pne->value.size,
+ "named object element value");
+ if (pne->key.data)
+ gs_free_string(pdev->pdf_memory, pne->key.data, pne->key.size,
+ "named object element key");
+ }
+ gs_free_string(pdev->pdf_memory, pno->key.data, pno->key.size,
+ "named object key");
+ gs_free_object(pdev->pdf_memory, pno, "named object");
+}
+
+/* ---------------- Individual pdfmarks ---------------- */
+
+/* [ /BBox [llx lly urx ury] /_objdef {obj} /BP pdfmark */
+private int
+pdfmark_BP(gx_device_pdf * pdev, gs_param_string * pairs, uint count,
+ const gs_matrix * pctm, const gs_param_string * objname)
+{
+ gs_rect bbox;
+ pdf_named_object *pno;
+ int code;
+
+ if (objname == 0 || count != 2 || !pdf_key_eq(&pairs[0], "BBox"))
+ return_error(gs_error_rangecheck);
+ if (sscanf((const char *)pairs[1].data, "[%lg %lg %lg %lg]",
+ &bbox.p.x, &bbox.p.y, &bbox.q.x, &bbox.q.y) != 4
+ )
+ return_error(gs_error_rangecheck);
+ code = pdfmark_find_named(pdev, objname, &pno, true);
+ if (code < 0)
+ return code;
+ if (pno->type != named_unknown)
+ return_error(gs_error_rangecheck);
+ code = pdf_named_dict_put(pdev, pno, &pairs[0], &pairs[1]);
+ if (code < 0)
+ return code;
+ pno->type = named_graphics;
+ pno->graphics.enclosing = pdev->open_graphics;
+ pdev->open_graphics = pno;
+/****** NYI ******/
+ return 0;
+}
+
+/* [ /EP pdfmark */
+private int
+pdfmark_EP(gx_device_pdf * pdev, gs_param_string * pairs, uint count,
+ const gs_matrix * pctm, const gs_param_string * no_objname)
+{
+ pdf_named_object *pno = pdev->open_graphics;
+
+ if (count != 0 || pno == 0 || pno->type != named_graphics ||
+ !pno->open
+ )
+ return_error(gs_error_rangecheck);
+ pno->open = false;
+ pdev->open_graphics = pno->graphics.enclosing;
+/****** NYI ******/
+ return 0;
+}
+
+/* [ {obj} /SP pdfmark */
+private int
+pdfmark_SP(gx_device_pdf * pdev, gs_param_string * pairs, uint count,
+ const gs_matrix * pctm, const gs_param_string * no_objname)
+{
+ pdf_named_object *pno;
+ int code;
+
+ if (count != 1)
+ return_error(gs_error_rangecheck);
+ if ((code = pdfmark_find_named(pdev, &pairs[0], &pno, false)) < 0)
+ return code;
+ if (pno->type != named_graphics || pno->open)
+ return_error(gs_error_rangecheck);
+ code = pdf_open_contents(pdev, pdf_in_stream);
+ if (code < 0)
+ return code;
+ pdf_put_matrix(pdev, "q ", pctm, "cm\n");
+ pprintld1(pdev->strm, "/R%ld Do Q\n", pno->id);
+ return 0;
+}
+
+/* [ /_objdef {array} /type /array /OBJ pdfmark */
+/* [ /_objdef {dict} /type /dict /OBJ pdfmark */
+/* [ /_objdef {stream} /type /stream /OBJ pdfmark */
+private int
+pdfmark_OBJ(gx_device_pdf * pdev, gs_param_string * pairs, uint count,
+ const gs_matrix * pctm, const gs_param_string * objname)
+{
+ pdf_named_object_type type;
+ pdf_named_object *pno;
+ int code;
+
+ if (objname == 0 || count != 2 || !pdf_key_eq(&pairs[0], "type"))
+ return_error(gs_error_rangecheck);
+ if (pdf_key_eq(&pairs[1], "/array"))
+ type = named_array;
+ else if (pdf_key_eq(&pairs[1], "/dict"))
+ type = named_dict;
+ else if (pdf_key_eq(&pairs[1], "/stream"))
+ type = named_stream;
+ else
+ return_error(gs_error_rangecheck);
+ if ((code = pdfmark_find_named(pdev, objname, &pno, true)) < 0)
+ return code;
+ if (pno->type != named_unknown)
+ return_error(gs_error_rangecheck);
+ pno->type = type;
+ return 0;
+}
+
+/* [ {array} index value /PUT pdfmark */
+/* [ {stream} string|file /PUT pdfmark */
+/* Dictionaries are converted to .PUTDICT */
+private int
+pdfmark_PUT(gx_device_pdf * pdev, gs_param_string * pairs, uint count,
+ const gs_matrix * pctm, const gs_param_string * no_objname)
+{
+ pdf_named_object *pno;
+ int code;
+
+ if ((code = pdfmark_find_named(pdev, &pairs[0], &pno, false)) < 0)
+ return code;
+ switch (pno->type) {
+ case named_array:{
+ int index;
+
+ if (count != 3)
+ return_error(gs_error_rangecheck);
+ if ((code = pdfmark_scan_int(&pairs[1], &index)) < 0)
+ return code;
+ if (index < 0)
+ return_error(gs_error_rangecheck);
+ code = pdf_named_array_put(pdev, pno, index, pairs + 2);
+ break;
+ }
+ case named_stream:
+ if (count != 2)
+ return_error(gs_error_rangecheck);
+/****** NYI ******/
+ break;
+ default:
+ return_error(gs_error_rangecheck);
+ }
+ return code;
+}
+
+/* [ {dict} key value ... /.PUTDICT pdfmark */
+private int
+pdfmark_PUTDICT(gx_device_pdf * pdev, gs_param_string * pairs, uint count,
+ const gs_matrix * pctm, const gs_param_string * no_objname)
+{
+ pdf_named_object *pno;
+ int code, i;
+
+ if ((code = pdfmark_find_named(pdev, &pairs[0], &pno, false)) < 0)
+ return code;
+ if (!(count & 1) || pno->type != named_dict)
+ return_error(gs_error_rangecheck);
+ for (i = 1; code >= 0 && i < count; i += 2)
+ code = pdf_named_dict_put(pdev, pno, pairs + i, pairs + i + 1);
+ return code;
+}
+
+/* [ {array} index value ... /.PUTINTERVAL pdfmark */
+private int
+pdfmark_PUTINTERVAL(gx_device_pdf * pdev, gs_param_string * pairs, uint count,
+ const gs_matrix * pctm, const gs_param_string * no_objname)
+{
+ pdf_named_object *pno;
+ int code, index, i;
+
+ if ((code = pdfmark_find_named(pdev, &pairs[0], &pno, false)) < 0)
+ return code;
+ if (count < 2 || pno->type != named_array)
+ return_error(gs_error_rangecheck);
+ if ((code = pdfmark_scan_int(&pairs[1], &index)) < 0)
+ return code;
+ if (index < 0)
+ return_error(gs_error_rangecheck);
+ for (i = 2; code >= 0 && i < count; ++i)
+ code = pdf_named_array_put(pdev, pno, index + i - 2, &pairs[i]);
+ return code;
+}
+
+/* [ {stream} /CLOSE pdfmark */
+private int
+pdfmark_CLOSE(gx_device_pdf * pdev, gs_param_string * pairs, uint count,
+ const gs_matrix * pctm, const gs_param_string * no_objname)
+{
+ pdf_named_object *pno;
+ int code;
+
+ if (count != 1)
+ return_error(gs_error_rangecheck);
+ if ((code = pdfmark_find_named(pdev, &pairs[0], &pno, false)) < 0)
+ return code;
+ if (pno->type != named_stream || !pno->open)
+ return_error(gs_error_rangecheck);
+ /* Currently we don't do anything special when closing a stream. */
+ pno->open = false;
+ return 0;
+}
diff --git a/gs/src/gdevpsci.c b/gs/src/gdevpsci.c
new file mode 100644
index 000000000..45742205e
--- /dev/null
+++ b/gs/src/gdevpsci.c
@@ -0,0 +1,130 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gdevpsci.c */
+/* PostScript color image output device */
+#include "gdevprn.h"
+#include "stream.h"
+#include "strimpl.h"
+#include "srlx.h"
+
+/*
+ * This driver produces plane-separated, run-length-encoded, 24-bit RGB
+ * images suitable for a PostScript Level 2 printer. LZW compression would
+ * be better, but Unisys' claim to own the compression algorithm and their
+ * demand for licensing and payment even for freely distributed software
+ * rule this out.
+ */
+
+/* Define the device parameters. */
+#ifndef X_DPI
+# define X_DPI 300
+#endif
+#ifndef Y_DPI
+# define Y_DPI 300
+#endif
+
+/* The device descriptor */
+private dev_proc_print_page(psrgb_print_page);
+
+private const gx_device_procs psrgb_procs =
+prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
+ gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb);
+
+const gx_device_printer gs_psrgb_device =
+{
+ prn_device_body(gx_device_printer, psrgb_procs, "psrgb",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0, 0, 0, 0, /* margins */
+ 3, 24, 255, 255, 256, 256, psrgb_print_page)
+};
+
+/*
+ * The following setup code gets written to the PostScript file.
+ * We would have to break it up anyway because the Watcom compiler has
+ * a limit of 512 characters in a single token, so we make a virtue out of
+ * necessity and make each line a separate string.
+ */
+private const char *const psrgb_setup[] =
+{
+ "%!PS",
+ "currentpagedevice /PageSize get aload pop scale",
+ "/rgbimage {", /* <width> <height> rgbimage - */
+ " /h exch def /w exch def save",
+ " /s1 w string def /s2 w string def /s3 w string def",
+ " /f currentfile /RunLengthDecode filter def",
+ " w h 8 [w 0 0 h neg 0 h]",
+ " { f s1 readstring pop} { f s2 readstring pop} { f s3 readstring pop}",
+ " true 3 colorimage restore",
+ "} bind def"
+};
+
+/* Send the page to the printer. */
+private int
+psrgb_print_page(gx_device_printer * pdev, FILE * prn_stream)
+{
+ gs_memory_t *mem = pdev->memory;
+ int width = pdev->width;
+ byte *lbuf = gs_alloc_bytes(mem, width * 3,
+ "psrgb_print_page(lbuf)");
+ int lnum;
+ stream fs, rls;
+ stream_RLE_state rlstate;
+ byte fsbuf[200]; /* arbitrary, must be >2 */
+ byte rlsbuf[200]; /* arbitrary, must be >128 */
+
+ if (lbuf == 0)
+ return_error(gs_error_VMerror);
+ if (gdev_prn_file_is_new(pdev)) {
+ int i;
+
+ for (i = 0; i < countof(psrgb_setup); i++)
+ fprintf(prn_stream, "%s\n", psrgb_setup[i]);
+ }
+ fprintf(prn_stream, "%d %d rgbimage\n", width, pdev->height);
+ swrite_file(&fs, prn_stream, fsbuf, sizeof(fsbuf));
+ fs.memory = 0;
+ (*s_RLE_template.set_defaults) ((stream_state *) & rlstate);
+ s_std_init(&rls, rlsbuf, sizeof(rlsbuf), &s_filter_write_procs,
+ s_mode_write);
+ rls.memory = 0;
+ rlstate.memory = 0;
+ rlstate.template = &s_RLE_template;
+ (*s_RLE_template.init) ((stream_state *) & rlstate);
+ rls.state = (stream_state *) & rlstate;
+ rls.procs.process = s_RLE_template.process;
+ rls.strm = &fs;
+ for (lnum = 0; lnum < pdev->height; ++lnum) {
+ byte *data;
+ int i, c;
+
+ gdev_prn_get_bits(pdev, lnum, lbuf, &data);
+ for (c = 0; c < 3; ++c) {
+ const byte *p;
+
+ for (i = 0, p = data + c; i < width; ++i, p += 3)
+ sputc(&rls, *p);
+ }
+ }
+ sclose(&rls);
+ sflush(&fs);
+ fputs("\nshowpage\n", prn_stream);
+ gs_free_object(mem, lbuf, "psrgb_print_page(lbuf)");
+ return 0;
+}
diff --git a/gs/src/gdevpsde.c b/gs/src/gdevpsde.c
new file mode 100644
index 000000000..c68562a65
--- /dev/null
+++ b/gs/src/gdevpsde.c
@@ -0,0 +1,276 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gdevpsde.c */
+/* Embedded font writing */
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsccode.h"
+#include "gsmatrix.h"
+#include "gxfixed.h"
+#include "gxfont.h"
+#include "gxfont1.h"
+#include "stream.h"
+#include "gdevpstr.h"
+#include "gdevpsdf.h"
+
+private int
+embed_table(gs_param_list * plist, const char *key, const float *values,
+ int count)
+{
+ if (count != 0) {
+ gs_param_float_array fa;
+
+ fa.size = count;
+ fa.data = values;
+ return param_write_float_array(plist, key, &fa);
+ }
+ return 0;
+}
+
+private void
+embed_uid(stream * s, const gs_uid * puid)
+{
+ if (uid_is_UniqueID(puid))
+ pprintld1(s, "/UniqueID %ld def\n", puid->id);
+ else if (uid_is_XUID(puid)) {
+ uint i, n = uid_XUID_size(puid);
+
+ pputs(s, "/XUID [");
+ for (i = 0; i < n; ++i)
+ pprintld1(s, "%ld ", uid_XUID_values(puid)[i]);
+ pputs(s, "] def\n");
+ }
+}
+
+/* Write an embedded Type 1 font. */
+int
+psdf_embed_type1_font(stream * s, gs_font_type1 * pfont)
+{
+ const gs_type1_data *const pdata = &pfont->data;
+ gs_param_list *plist;
+ param_printer_params_t ppp;
+ int code;
+
+ ppp = param_printer_params_default;
+ ppp.item_suffix = " def\n";
+ code = psdf_alloc_param_printer(&plist, &ppp, s,
+ print_binary_ok, s->memory);
+ if (code < 0)
+ return 0;
+
+ /* Write the font header. */
+
+ pputs(s, "%!PS-AdobeFont-1.0: ");
+ pwrite(s, pfont->font_name.chars, pfont->font_name.size);
+ pputs(s, "\n11 dict begin\n");
+
+ /* Write FontInfo. Currently we don't write anything there. */
+
+ pputs(s, "/FontInfo 1 dict dup begin\n");
+ pputs(s, "end readonly def\n");
+
+ /* Write the main font dictionary. */
+
+ pputs(s, "/FontName /");
+ pwrite(s, pfont->font_name.chars, pfont->font_name.size);
+ pputs(s, " def\n");
+ pputs(s, "/Encoding ");
+ switch (pfont->encoding_index) {
+ case 0:
+ pputs(s, "StandardEncoding");
+ break;
+ case 1:
+ pputs(s, "ISOLatin1Encoding");
+ break;
+ default:{
+ gs_char i;
+
+ pputs(s, "256 array\n");
+ pputs(s, "0 1 255 {1 index exch /.notdef put} for\n");
+ for (i = 0; i < 256; ++i) {
+ gs_glyph glyph =
+ (*pfont->procs.encode_char) (NULL, (gs_font *) pfont, &i);
+ const char *namestr;
+ uint namelen;
+
+ if (glyph != gs_no_glyph &&
+ (namestr = (*pfont->procs.callbacks.glyph_name) (glyph, &namelen)) != 0 &&
+ !(namelen == 7 && !memcmp(namestr, ".notdef", 7))
+ ) {
+ pprintd1(s, "dup %d /", (int)i);
+ pwrite(s, namestr, namelen);
+ pputs(s, " put\n");
+ }
+ }
+ pputs(s, "readonly");
+ }
+ }
+ pputs(s, " def\n");
+ pprintg6(s, "/FontMatrix [%g %g %g %g %g %g] readonly def\n",
+ pfont->FontMatrix.xx, pfont->FontMatrix.xy,
+ pfont->FontMatrix.yx, pfont->FontMatrix.yy,
+ pfont->FontMatrix.tx, pfont->FontMatrix.ty);
+ embed_uid(s, &pfont->UID);
+ pprintg4(s, "/FontBBox {%g %g %g %g} readonly def\n",
+ pfont->FontBBox.p.x, pfont->FontBBox.p.y,
+ pfont->FontBBox.q.x, pfont->FontBBox.q.y);
+ {
+ private const gs_param_item_t font_items[] =
+ {
+ {"FontType", gs_param_type_int,
+ offset_of(gs_font_type1, FontType)},
+ {"PaintType", gs_param_type_int,
+ offset_of(gs_font_type1, PaintType)},
+ {"StrokeWidth", gs_param_type_float,
+ offset_of(gs_font_type1, StrokeWidth)},
+ gs_param_item_end
+ };
+
+ code = gs_param_write_items(plist, pfont, NULL, font_items);
+ if (code < 0)
+ return code;
+ }
+ pputs(s, "currentdict end\n");
+
+ /* Write the Private dictionary. */
+
+ pputs(s, "dup /Private 17 dict dup begin\n");
+ pputs(s, "/-|{string currentfile exch readstring pop}executeonly def\n");
+ pputs(s, "/|-{noaccess def}executeonly def\n");
+ pputs(s, "/|{noaccess put}executeonly def\n");
+ {
+ private const gs_param_item_t private_items[] =
+ {
+ {"lenIV", gs_param_type_int,
+ offset_of(gs_type1_data, lenIV)},
+ {"BlueFuzz", gs_param_type_int,
+ offset_of(gs_type1_data, BlueFuzz)},
+ {"BlueScale", gs_param_type_float,
+ offset_of(gs_type1_data, BlueScale)},
+ {"BlueShift", gs_param_type_float,
+ offset_of(gs_type1_data, BlueShift)},
+ {"ExpansionFactor", gs_param_type_float,
+ offset_of(gs_type1_data, ExpansionFactor)},
+ {"ForceBold", gs_param_type_bool,
+ offset_of(gs_type1_data, ForceBold)},
+ {"LanguageGroup", gs_param_type_int,
+ offset_of(gs_type1_data, LanguageGroup)},
+ {"RndStemUp", gs_param_type_bool,
+ offset_of(gs_type1_data, RndStemUp)},
+ gs_param_item_end
+ };
+ gs_type1_data defaults;
+
+ defaults.lenIV = 4;
+ defaults.BlueFuzz = 1;
+ defaults.BlueScale = 0.039625;
+ defaults.BlueShift = 7.0;
+ defaults.ExpansionFactor = 0.06;
+ defaults.ForceBold = false;
+ defaults.LanguageGroup = 0;
+ defaults.RndStemUp = true;
+ code = gs_param_write_items(plist, pdata, &defaults, private_items);
+ if (code < 0)
+ return code;
+ embed_table(plist, "BlueValues", pdata->BlueValues.values,
+ pdata->BlueValues.count);
+ embed_table(plist, "OtherBlues", pdata->OtherBlues.values,
+ pdata->OtherBlues.count);
+ embed_table(plist, "FamilyBlues", pdata->FamilyBlues.values,
+ pdata->FamilyBlues.count);
+ embed_table(plist, "FamilyOtherBlues", pdata->FamilyOtherBlues.values,
+ pdata->FamilyOtherBlues.count);
+ embed_table(plist, "StdHW", pdata->StdHW.values,
+ pdata->StdHW.count);
+ embed_table(plist, "StemSnapH", pdata->StemSnapH.values,
+ pdata->StemSnapH.count);
+ embed_table(plist, "StemSnapV", pdata->StemSnapV.values,
+ pdata->StemSnapV.count);
+ }
+ embed_uid(s, &pfont->UID);
+ pputs(s, "/MinFeature{16 16} |-\n");
+ pputs(s, "/password 5839 def\n");
+
+ /* Write the Subrs. */
+
+ {
+ int n, i;
+ gs_const_string str;
+
+ for (n = 0;
+ (*pdata->procs->subr_data) (pfont, n, false, &str) !=
+ gs_error_rangecheck;
+ )
+ ++n;
+ pprintd1(s, "/Subrs %d array\n", n);
+ for (i = 0; i < n; ++i)
+ if ((*pdata->procs->subr_data) (pfont, i, false, &str) >= 0) {
+ char buf[50];
+
+ sprintf(buf, "dup %d %u -| ", i, str.size);
+ pputs(s, buf);
+ pwrite(s, str.data, str.size);
+ pputs(s, " |\n");
+ }
+ pputs(s, "|-\n");
+ }
+
+ /* We don't write OtherSubrs -- there had better not be any! */
+
+ /* Write the CharStrings. */
+
+ {
+ int num_chars = 0;
+ gs_glyph glyph;
+ int index = 0;
+ gs_const_string gdata;
+ int code;
+
+ for (glyph = gs_no_glyph, index = 0;
+ code = (*pdata->procs->next_glyph) (pfont, &index, &glyph),
+ index != 0;
+ )
+ if (code == 0 && (*pdata->procs->glyph_data) (pfont, glyph, &gdata) >= 0)
+ ++num_chars;
+ pprintd1(s, "2 index /CharStrings %d dict dup begin\n", num_chars);
+ for (glyph = gs_no_glyph, index = 0;
+ code = (*pdata->procs->next_glyph) (pfont, &index, &glyph),
+ index != 0;
+ )
+ if (code == 0 && (*pdata->procs->glyph_data) (pfont, glyph, &gdata) >= 0) {
+ uint gssize;
+ const char *gstr =
+ (*pfont->procs.callbacks.glyph_name) (glyph, &gssize);
+
+ pputs(s, "/");
+ pwrite(s, gstr, gssize);
+ pprintd1(s, " %d -| ", gdata.size);
+ pwrite(s, gdata.data, gdata.size);
+ pputs(s, " |-\n");
+ }
+ }
+
+ /* Wrap up. */
+
+ pputs(s, "end\nend\nreadonly put\nnoaccess put\n");
+ pputs(s, "dup/FontName get exch definefont pop\n");
+ psdf_free_param_printer(plist);
+ return 0;
+}
diff --git a/gs/src/gdevpsdi.c b/gs/src/gdevpsdi.c
new file mode 100644
index 000000000..ce7e4d931
--- /dev/null
+++ b/gs/src/gdevpsdi.c
@@ -0,0 +1,317 @@
+/* Copyright (C) 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gdevpsdi.c */
+/* Image compression for PostScript and PDF writers */
+#include "math_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gscspace.h"
+#include "gdevpsdf.h"
+#include "gdevpsds.h"
+#include "jpeglib.h" /* for sdct.h */
+#include "strimpl.h"
+#include "scfx.h"
+#include "sdct.h"
+#include "slzwx.h"
+#include "spngpx.h"
+#include "srlx.h"
+#include "szlibx.h"
+
+/* ---------------- Image compression ---------------- */
+
+/* Add a filter to expand or reduce the pixel width if needed. */
+/* At least one of bpc_in and bpc_out is 8; the other is 1, 2, 4, or 8. */
+private int
+pixel_resize(psdf_binary_writer * pbw, int width, int num_components,
+ int bpc_in, int bpc_out)
+{
+ gs_memory_t *mem = pbw->dev->v_memory;
+ const stream_template *template;
+ stream_1248_state *st;
+ int code;
+
+ if (bpc_out == bpc_in)
+ return 0;
+ if (bpc_in < 8) {
+ static const stream_template *const exts[5] =
+ {
+ 0, &s_1_8_template, &s_2_8_template, 0, &s_4_8_template
+ };
+
+ template = exts[bpc_in];
+ } else {
+ static const stream_template *const rets[5] =
+ {
+ 0, &s_8_1_template, &s_8_2_template, 0, &s_8_4_template
+ };
+
+ template = rets[bpc_out];
+ }
+ st = (stream_1248_state *)
+ s_alloc_state(mem, template->stype, "pixel_resize state");
+ if (st == 0)
+ return_error(gs_error_VMerror);
+ code = psdf_encode_binary(pbw, template, (stream_state *) st);
+ if (code < 0) {
+ gs_free_object(mem, st, "pixel_resize state");
+ return code;
+ }
+ s_1248_init(st, width, num_components);
+ return 0;
+}
+
+/* Add the appropriate image compression filter, if any. */
+private int
+setup_image_compression(psdf_binary_writer * pbw, const psdf_image_params * pdip,
+ const gs_image_t * pim)
+{
+ gx_device_psdf *pdev = pbw->dev;
+ const stream_template *template = pdip->filter_template;
+ stream_state *st;
+
+ if (pdip->AutoFilter) {
+/****** AutoFilter IS NYI ******/
+ /*
+ * Even though this isn't obvious from the Adobe Tech Note,
+ * it appears that if UseFlateCompression is true, the default
+ * compressor for AutoFilter is FlateEncode, not LZWEncode.
+ */
+ template =
+ (pdev->params.UseFlateCompression &&
+ pdev->version >= psdf_version_ll3 ?
+ &s_zlibE_template : &s_LZWE_template);
+ }
+ if (!pdip->Encode || template == 0) /* no compression */
+ return 0;
+ /* Only use DCTE for 8-bit data. */
+ if (template == &s_DCTE_template &&
+ !(pdip->Downsample ?
+ pdip->Depth == 8 ||
+ (pdip->Depth == -1 && pim->BitsPerComponent == 8) :
+ pim->BitsPerComponent == 8)
+ ) {
+ /* Use LZW instead. */
+ template = &s_LZWE_template;
+ }
+ st = s_alloc_state(pdev->v_memory, template->stype,
+ "setup_image_compression");
+ if (st == 0)
+ return_error(gs_error_VMerror);
+ if (template->set_defaults)
+ (*template->set_defaults) (st);
+ if (template == &s_CFE_template) {
+ stream_CFE_state *const ss = (stream_CFE_state *) st;
+
+ if (pdip->Dict != 0 && pdip->Dict->template == &s_CFE_template) {
+ stream_state common;
+
+ common = *st; /* save generic info */
+ *ss = *(const stream_CFE_state *)pdip->Dict;
+ *st = common;
+ } else {
+ ss->K = -1;
+ ss->BlackIs1 = true;
+ }
+ ss->Columns = pim->Width;
+ ss->Rows = (ss->EndOfBlock ? 0 : pim->Height);
+ } else if (template == &s_LZWE_template ||
+ template == &s_zlibE_template) {
+ /* Add a PNGPredictor filter. */
+ int code = psdf_encode_binary(pbw, template, st);
+
+ if (code < 0) {
+ gs_free_object(pdev->v_memory, st, "setup_image_compression");
+ return code;
+ }
+ template = &s_PNGPE_template;
+ st = s_alloc_state(pdev->v_memory, template->stype,
+ "setup_image_compression");
+ if (st == 0)
+ return_error(gs_error_VMerror);
+ if (template->set_defaults)
+ (*template->set_defaults) (st);
+ {
+ stream_PNGP_state *const ss = (stream_PNGP_state *) st;
+
+ ss->Colors = gs_color_space_num_components(pim->ColorSpace);
+ ss->Columns = pim->Width;
+ }
+ } else if (template == &s_DCTE_template) {
+/****** ADD PARAMETERS FROM pdip->Dict ******/
+ } {
+ int code = psdf_encode_binary(pbw, template, st);
+
+ if (code < 0) {
+ gs_free_object(pdev->v_memory, st, "setup_image_compression");
+ return code;
+ }
+ }
+ return 0;
+}
+
+/* Add downsampling, antialiasing, and compression filters. */
+/* Uses AntiAlias, Depth, DownsampleType, Resolution. */
+private int
+setup_downsampling(psdf_binary_writer * pbw, const psdf_image_params * pdip,
+ gs_image_t * pim, floatp resolution)
+{
+ gx_device_psdf *pdev = pbw->dev;
+ const stream_template *template =
+ (pdip->DownsampleType == ds_Average ?
+ &s_Average_template : &s_Subsample_template);
+ int factor = (int)(resolution / pdip->Resolution);
+ int orig_bpc = pim->BitsPerComponent;
+ stream_state *st;
+ int code;
+
+ if (factor <= 1)
+ return setup_image_compression(pbw, pdip, pim); /* no downsampling */
+ st = s_alloc_state(pdev->v_memory, template->stype,
+ "setup_downsampling");
+ if (st == 0)
+ return_error(gs_error_VMerror);
+ if (template->set_defaults)
+ (*template->set_defaults) (st);
+ {
+ stream_Downsample_state *const ss = (stream_Downsample_state *) st;
+
+ ss->Colors = gs_color_space_num_components(pim->ColorSpace);
+ ss->Columns = pim->Width;
+ ss->XFactor = ss->YFactor = factor;
+ ss->AntiAlias = pdip->AntiAlias;
+ if (template->init)
+ (*template->init) (st);
+ pim->Width /= factor;
+ pim->Height /= factor;
+ pim->BitsPerComponent = 8;
+ gs_matrix_scale(&pim->ImageMatrix, 1.0 / factor, 1.0 / factor,
+ &pim->ImageMatrix);
+/****** NO ANTI-ALIASING YET ******/
+ if ((code = setup_image_compression(pbw, pdip, pim)) < 0 ||
+ (code = psdf_encode_binary(pbw, template, st)) < 0 ||
+ (code = pixel_resize(pbw, pim->Width, ss->Colors,
+ orig_bpc, pim->BitsPerComponent)) < 0
+ ) {
+ gs_free_object(pdev->v_memory, st, "setup_image_compression");
+ return code;
+ }
+ }
+ return 0;
+}
+
+/* Set up compression and downsampling filters for an image. */
+/* Note that this may modify the image parameters. */
+int
+psdf_setup_image_filters(gx_device_psdf * pdev, psdf_binary_writer * pbw,
+ gs_image_t * pim, const gs_matrix * pctm, const gs_imager_state * pis)
+{ /*
+ * The following algorithms are per Adobe Tech Note # 5151,
+ * "Acrobat Distiller Parameters", revised 16 September 1996
+ * for Acrobat(TM) Distiller(TM) 3.0.
+ *
+ * The control structure is a little tricky, because filter
+ * pipelines must be constructed back-to-front.
+ */
+ int code = 0;
+ psdf_image_params params;
+
+ if (pim->ImageMask) {
+ params = pdev->params.MonoImage;
+ params.Depth = 1;
+ } else {
+ int ncomp = gs_color_space_num_components(pim->ColorSpace);
+ int bpc = pim->BitsPerComponent;
+
+ /*
+ * We can compute the image resolution by:
+ * W / (W * ImageMatrix^-1 * CTM / HWResolution).
+ * We can replace W by 1 to simplify the computation.
+ */
+ double resolution;
+
+ if (pctm == 0)
+ resolution = -1;
+ else {
+ gs_point pt;
+
+ /* We could do both X and Y, but why bother? */
+ gs_distance_transform_inverse(1.0, 0.0, &pim->ImageMatrix, &pt);
+ gs_distance_transform(pt.x, pt.y, pctm, &pt);
+ resolution = 1.0 / hypot(pt.x / pdev->HWResolution[0],
+ pt.y / pdev->HWResolution[1]);
+ }
+ if (ncomp == 1) {
+ /* Monochrome or gray */
+ if (bpc == 1)
+ params = pdev->params.MonoImage;
+ else
+ params = pdev->params.GrayImage;
+ if (params.Depth == -1)
+ params.Depth = bpc;
+ /* Check for downsampling. */
+ if (params.Downsample && params.Resolution <= resolution / 2) {
+ /* Use the downsampled depth, not the original data depth. */
+ if (params.Depth == 1) {
+ params.Filter = pdev->params.MonoImage.Filter;
+ params.filter_template = pdev->params.MonoImage.filter_template;
+ params.Dict = pdev->params.MonoImage.Dict;
+ } else {
+ params.Filter = pdev->params.GrayImage.Filter;
+ params.filter_template = pdev->params.GrayImage.filter_template;
+ params.Dict = pdev->params.GrayImage.Dict;
+ }
+ code = setup_downsampling(pbw, &params, pim, resolution);
+ } else {
+ code = setup_image_compression(pbw, &params, pim);
+ }
+ } else {
+ /* Color */
+ bool cmyk_to_rgb = pdev->params.ConvertCMYKImagesToRGB &&
+ pis != 0 &&
+ gs_color_space_get_index(pim->ColorSpace) ==
+ gs_color_space_index_DeviceCMYK;
+
+ if (cmyk_to_rgb)
+ pim->ColorSpace = gs_cspace_DeviceRGB(pis);
+ params = pdev->params.ColorImage;
+ if (params.Depth == -1)
+ params.Depth = (cmyk_to_rgb ? 8 : bpc);
+ if (params.Downsample && params.Resolution <= resolution / 2) {
+ code = setup_downsampling(pbw, &params, pim, resolution);
+ } else {
+ code = setup_image_compression(pbw, &params, pim);
+ }
+ if (cmyk_to_rgb) {
+ gs_memory_t *mem = pdev->v_memory;
+ stream_C2R_state *ss = (stream_C2R_state *)
+ s_alloc_state(mem, s_C2R_template.stype, "C2R state");
+ int code = pixel_resize(pbw, pim->Width, 3, 8, bpc);
+
+ if (code < 0 ||
+ (code = psdf_encode_binary(pbw, &s_C2R_template,
+ (stream_state *) ss)) < 0 ||
+ (code = pixel_resize(pbw, pim->Width, 4, bpc, 8)) < 0
+ )
+ return code;
+ s_C2R_init(ss, pis);
+ }
+ }
+ }
+ return code;
+}
diff --git a/gs/src/gdevpsdp.c b/gs/src/gdevpsdp.c
new file mode 100644
index 000000000..d95bb5173
--- /dev/null
+++ b/gs/src/gdevpsdp.c
@@ -0,0 +1,641 @@
+/* Copyright (C) 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gdevpsdp.c */
+/* (Distiller) parameter handling for PostScript and PDF writers */
+#include "string_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gxdevice.h"
+#include "gdevpsdf.h"
+#include "gdevpstr.h"
+#include "strimpl.h" /* for short-sighted compilers */
+#include "scfx.h"
+#include "jpeglib.h" /* for sdct.h */
+#include "sdct.h"
+#include "slzwx.h"
+#include "srlx.h"
+#include "szlibx.h"
+
+/* ---------------- Get/put Distiller parameters ---------------- */
+
+/*
+ * This code handles all the Distiller parameters except the *ACSDict and
+ * *ImageDict parameter dictionaries. (It doesn't cause any of the
+ * parameters actually to have any effect.)
+ */
+
+typedef struct psdf_image_filter_name_s {
+ const char *pname;
+ const stream_template *template;
+ psdf_version min_version;
+} psdf_image_filter_name;
+typedef struct psdf_image_param_names_s {
+ const char *ACSDict; /* not used for mono */
+ const char *AntiAlias;
+ const char *AutoFilter; /* not used for mono */
+ const char *Depth;
+ const char *Dict;
+ const char *Downsample;
+ const char *DownsampleType;
+ const char *Encode;
+ const char *Filter;
+ const char *Resolution;
+} psdf_image_param_names;
+private const psdf_image_param_names Color_names =
+{
+ "ColorACSImageDict", "AntiAliasColorImages", "AutoFilterColorImages",
+ "ColorImageDepth", "ColorImageDict",
+ "DownsampleColorImages", "ColorImageDownsampleType", "EncodeColorImages",
+ "ColorImageFilter", "ColorImageResolution"
+};
+private const psdf_image_filter_name Poly_filters[] =
+{
+ {"DCTEncode", &s_DCTE_template},
+ {"FlateEncode", &s_zlibE_template, psdf_version_ll3},
+ {"LZWEncode", &s_LZWE_template},
+ {0, 0}
+};
+private const psdf_image_param_names Gray_names =
+{
+ "GrayACSImageDict", "AntiAliasGrayImages", "AutoFilterGrayImages",
+ "GrayImageDepth", "GrayImageDict",
+ "DownsampleGrayImages", "GrayImageDownsampleType", "EncodeGrayImages",
+ "GrayImageFilter", "GrayImageResolution"
+};
+private const psdf_image_param_names Mono_names =
+{
+ 0, "AntiAliasMonoImages", 0,
+ "MonoImageDepth", "MonoImageDict",
+ "DownsampleMonoImages", "MonoImageDownsampleType", "EncodeMonoImages",
+ "MonoImageFilter", "MonoImageResolution"
+};
+private const psdf_image_filter_name Mono_filters[] =
+{
+ {"CCITTFaxEncode", &s_CFE_template},
+ {"FlateEncode", &s_zlibE_template, psdf_version_ll3},
+ {"LZWEncode", &s_LZWE_template},
+ {"RunLengthEncode", &s_RLE_template},
+ {0, 0}
+};
+private const char *const AutoRotatePages_names[] =
+{
+ "None", "All", "PageByPage", 0
+};
+private const char *const ColorConversionStrategy_names[] =
+{
+ "LeaveColorUnchanged", "UseDeviceDependentColor",
+ "UseDeviceIndependentColor", 0
+};
+private const char *const DownsampleType_names[] =
+{
+ "Average", "Subsample", 0
+};
+private const char *const TransferFunctionInfo_names[] =
+{
+ "Preserve", "Apply", "Remove", 0
+};
+private const char *const UCRandBGInfo_names[] =
+{
+ "Preserve", "Remove", 0
+};
+
+/* -------- Get parameters -------- */
+
+extern stream_state_proc_get_params(s_DCTE_get_params, stream_DCT_state);
+extern stream_state_proc_get_params(s_CF_get_params, stream_CF_state);
+typedef stream_state_proc_get_params((*ss_get_params_t), stream_state);
+
+private int
+psdf_CF_get_params(gs_param_list * plist, const stream_state * ss, bool all)
+{
+ return s_CF_get_params(plist, (const stream_CF_state *)ss, all);
+}
+private int
+psdf_DCT_get_params(gs_param_list * plist, const stream_state * ss, bool all)
+{
+ return s_DCTE_get_params(plist, (const stream_DCT_state *)ss, all);
+}
+
+/*
+ * Get an image Dict parameter. Note that we return an empty dictionary if
+ * the parameter has never been set.
+ */
+private int
+psdf_get_image_dict_param(gs_param_list * plist, const gs_param_name pname,
+ stream_state * ss, ss_get_params_t get_params)
+{
+ gs_param_dict dict;
+ int code;
+
+ if (pname == 0)
+ return 0;
+ dict.size = 12; /* enough for all param dicts we know about */
+ if ((code = param_begin_write_dict(plist, pname, &dict, false)) < 0)
+ return code;
+ if (ss != 0)
+ code = (*get_params) (dict.list, ss, false);
+ param_end_write_dict(plist, pname, &dict);
+ return code;
+}
+
+/* Get a set of image-related parameters. */
+private int
+psdf_get_image_params(gs_param_list * plist,
+ const psdf_image_param_names * pnames, psdf_image_params * params)
+{
+ int code;
+ gs_param_string dsts, fs;
+
+ param_string_from_string(dsts,
+ DownsampleType_names[params->DownsampleType]);
+ if (
+ (code = psdf_get_image_dict_param(plist, pnames->ACSDict,
+ params->ACSDict,
+ psdf_DCT_get_params)) < 0 ||
+ (code = param_write_bool(plist, pnames->AntiAlias,
+ &params->AntiAlias)) < 0 ||
+ (pnames->AutoFilter != 0 &&
+ (code = param_write_bool(plist, pnames->AutoFilter,
+ &params->AutoFilter)) < 0) ||
+ (code = param_write_int(plist, pnames->Depth,
+ &params->Depth)) < 0 ||
+ (code = psdf_get_image_dict_param(plist, pnames->Dict,
+ params->Dict,
+ (params->Dict == 0 ||
+ params->Dict->template ==
+ &s_CFE_template ?
+ psdf_CF_get_params :
+ psdf_DCT_get_params))) < 0 ||
+ (code = param_write_bool(plist, pnames->Downsample,
+ &params->Downsample)) < 0 ||
+ (code = param_write_name(plist, pnames->DownsampleType,
+ &dsts)) < 0 ||
+ (code = param_write_bool(plist, pnames->Encode,
+ &params->Encode)) < 0 ||
+ (code = (params->Filter == 0 ? 0 :
+ (param_string_from_string(fs, params->Filter),
+ param_write_name(plist, pnames->Filter, &fs)))) < 0 ||
+ (code = param_write_int(plist, pnames->Resolution,
+ &params->Resolution)) < 0
+ )
+ DO_NOTHING;
+ return code;
+}
+
+/* Get parameters. */
+int
+gdev_psdf_get_params(gx_device * dev, gs_param_list * plist)
+{
+ gx_device_psdf *pdev = (gx_device_psdf *) dev;
+ int code = gdev_vector_get_params(dev, plist);
+ gs_param_string arps, ccss, tfis, ucrbgis;
+
+ if (code < 0)
+ return code;
+ param_string_from_string(arps,
+ AutoRotatePages_names[(int)pdev->params.AutoRotatePages]);
+ param_string_from_string(ccss,
+ ColorConversionStrategy_names[(int)pdev->params.ColorConversionStrategy]);
+ param_string_from_string(tfis,
+ TransferFunctionInfo_names[(int)pdev->params.TransferFunctionInfo]);
+ param_string_from_string(ucrbgis,
+ UCRandBGInfo_names[(int)pdev->params.UCRandBGInfo]);
+ if (
+ /* General parameters */
+
+ (code = param_write_bool(plist, "ASCII85EncodePages",
+ &pdev->params.ASCII85EncodePages)) < 0 ||
+ (code = param_write_name(plist, "AutoRotatePages",
+ &arps)) < 0 ||
+ (code = param_write_bool(plist, "CompressPages",
+ &pdev->params.CompressPages)) < 0 ||
+ (code = param_write_long(plist, "ImageMemory",
+ &pdev->params.ImageMemory)) < 0 ||
+ (code = param_write_bool(plist, "LZWEncodePages",
+ &pdev->params.LZWEncodePages)) < 0 ||
+ (code = param_write_bool(plist, "PreserveHalftoneInfo",
+ &pdev->params.PreserveHalftoneInfo)) < 0 ||
+ (code = param_write_bool(plist, "PreserveOPIComments",
+ &pdev->params.PreserveOPIComments)) < 0 ||
+ (code = param_write_bool(plist, "PreserveOverprintSettings",
+ &pdev->params.PreserveOverprintSettings)) < 0 ||
+ (code = param_write_name(plist, "TransferFunctionInfo", &tfis)) < 0 ||
+ (code = param_write_name(plist, "UCRandBGInfo", &ucrbgis)) < 0 ||
+ (code = param_write_bool(plist, "UseFlateCompression",
+ &pdev->params.UseFlateCompression)) < 0 ||
+
+ /* Color sampled image parameters */
+
+ (code = psdf_get_image_params(plist, &Color_names, &pdev->params.ColorImage)) < 0 ||
+ (code = param_write_name(plist, "ColorConversionStrategy",
+ &ccss)) < 0 ||
+ (code = param_write_bool(plist, "ConvertCMYKImagesToRGB",
+ &pdev->params.ConvertCMYKImagesToRGB)) < 0 ||
+ (code = param_write_bool(plist, "ConvertImagesToIndexed",
+ &pdev->params.ConvertImagesToIndexed)) < 0 ||
+
+ /* Gray sampled image parameters */
+
+ (code = psdf_get_image_params(plist, &Gray_names, &pdev->params.GrayImage)) < 0 ||
+
+ /* Mono sampled image parameters */
+
+ (code = psdf_get_image_params(plist, &Mono_names, &pdev->params.MonoImage)) < 0 ||
+
+ /* Font embedding parameters */
+
+ (code = param_write_name_array(plist, "AlwaysEmbed", &pdev->params.AlwaysEmbed)) < 0 ||
+ (code = param_write_name_array(plist, "NeverEmbed", &pdev->params.NeverEmbed)) < 0 ||
+ (code = param_write_bool(plist, "EmbedAllFonts", &pdev->params.EmbedAllFonts)) < 0 ||
+ (code = param_write_bool(plist, "SubsetFonts", &pdev->params.SubsetFonts)) < 0 ||
+ (code = param_write_int(plist, "MaxSubsetPct", &pdev->params.MaxSubsetPct)) < 0
+ );
+ return code;
+}
+
+/* -------- Put parameters -------- */
+
+extern stream_state_proc_put_params(s_DCTE_put_params, stream_DCT_state);
+extern stream_state_proc_put_params(s_CF_put_params, stream_CF_state);
+typedef stream_state_proc_put_params((*ss_put_params_t), stream_state);
+
+private int
+psdf_CF_put_params(gs_param_list * plist, stream_state * st)
+{
+ stream_CFE_state *const ss = (stream_CFE_state *) st;
+
+ (*s_CFE_template.set_defaults) (st);
+ ss->K = -1;
+ ss->BlackIs1 = true;
+ return s_CF_put_params(plist, (stream_CF_state *) ss);
+}
+private int
+psdf_DCT_put_params(gs_param_list * plist, stream_state * ss)
+{
+ return s_DCTE_put_params(plist, (stream_DCT_state *) ss);
+}
+
+/* Compare a C string and a gs_param_string. */
+bool
+psdf_key_eq(const gs_param_string * pcs, const char *str)
+{
+ return (strlen(str) == pcs->size &&
+ !strncmp(str, (const char *)pcs->data, pcs->size));
+}
+
+/* Put an enumerated value. */
+private int
+psdf_put_enum_param(gs_param_list * plist, gs_param_name param_name,
+ int *pvalue, const char *const pnames[], int ecode)
+{
+ gs_param_string ens;
+ int code = param_read_name(plist, param_name, &ens);
+
+ switch (code) {
+ case 1:
+ return ecode;
+ case 0:
+ {
+ int i;
+
+ for (i = 0; pnames[i] != 0; ++i)
+ if (psdf_key_eq(&ens, pnames[i])) {
+ *pvalue = i;
+ return 0;
+ }
+ }
+ code = gs_error_rangecheck;
+ default:
+ ecode = code;
+ param_signal_error(plist, param_name, code);
+ }
+ return code;
+}
+
+/* Put a Boolean or integer parameter. */
+int
+psdf_put_bool_param(gs_param_list * plist, gs_param_name param_name,
+ bool * pval, int ecode)
+{
+ int code;
+
+ switch (code = param_read_bool(plist, param_name, pval)) {
+ default:
+ ecode = code;
+ param_signal_error(plist, param_name, ecode);
+ case 0:
+ case 1:
+ break;
+ }
+ return ecode;
+}
+int
+psdf_put_int_param(gs_param_list * plist, gs_param_name param_name,
+ int *pval, int ecode)
+{
+ int code;
+
+ switch (code = param_read_int(plist, param_name, pval)) {
+ default:
+ ecode = code;
+ param_signal_error(plist, param_name, ecode);
+ case 0:
+ case 1:
+ break;
+ }
+ return ecode;
+}
+
+/* Put [~](Always|Never)Embed parameters. */
+private int
+psdf_put_embed_param(gs_param_list * plist, gs_param_name notpname,
+ gs_param_string_array * psa, int ecode)
+{
+ gs_param_name pname = notpname + 1;
+ int code;
+ gs_param_string_array nsa;
+
+/***** Storage management is incomplete ******/
+/***** Doesn't do incremental add/delete ******/
+ switch (code = param_read_name_array(plist, pname, psa)) {
+ default:
+ ecode = code;
+ param_signal_error(plist, pname, ecode);
+ case 0:
+ case 1:
+ break;
+ }
+ switch (code = param_read_name_array(plist, notpname, &nsa)) {
+ default:
+ ecode = code;
+ param_signal_error(plist, notpname, ecode);
+ case 0:
+ case 1:
+ break;
+ }
+ return ecode;
+}
+
+/* Put an image Dict parameter. */
+private int
+psdf_put_image_dict_param(gs_param_list * plist, const gs_param_name pname,
+ stream_state ** pss, const stream_template * template,
+ ss_put_params_t put_params, gs_memory_t * mem)
+{
+ gs_param_dict dict;
+ stream_state *ss = *pss;
+ int code;
+
+ switch (code = param_begin_read_dict(plist, pname, &dict, false)) {
+ default:
+ param_signal_error(plist, pname, code);
+ return code;
+ case 1:
+ ss = 0;
+ break;
+ case 0:{
+ stream_state *ss_new =
+ s_alloc_state(mem, template->stype, pname);
+
+ if (ss_new == 0)
+ return_error(gs_error_VMerror);
+ ss_new->template = template;
+ code = (*put_params) (dict.list, ss_new);
+ if (code < 0) {
+ param_signal_error(plist, pname, code);
+ /* Make sure we free the new state. */
+ *pss = ss_new;
+ } else
+ ss = ss_new;
+ }
+ param_end_read_dict(plist, pname, &dict);
+ }
+ if (*pss != ss) {
+ if (ss) {
+/****** FREE SUBSIDIARY OBJECTS -- HOW? ******/
+ gs_free_object(mem, *pss, pname);
+ }
+ *pss = ss;
+ }
+ return code;
+}
+
+/* Put a set of image-related parameters. */
+private int
+psdf_put_image_params(const gx_device_psdf * pdev, gs_param_list * plist,
+ const psdf_image_param_names * pnames, const psdf_image_filter_name * pifn,
+ psdf_image_params * params, int ecode)
+{
+ gs_param_string fs;
+
+ /*
+ * Since this procedure can be called before the device is open,
+ * we must use pdev->memory rather than pdev->v_memory.
+ */
+ gs_memory_t *mem = pdev->memory;
+ gs_param_name pname;
+ int dsti = params->DownsampleType;
+ int code;
+
+ if ((pname = pnames->ACSDict) != 0) {
+ code = psdf_put_image_dict_param(plist, pname, &params->ACSDict,
+ &s_DCTE_template,
+ psdf_DCT_put_params, mem);
+ if (code < 0)
+ ecode = code;
+ }
+ ecode = psdf_put_bool_param(plist, pnames->AntiAlias,
+ &params->AntiAlias, ecode);
+ if (pnames->AutoFilter)
+ ecode = psdf_put_bool_param(plist, pnames->AutoFilter,
+ &params->AutoFilter, ecode);
+ ecode = psdf_put_int_param(plist, pnames->Depth,
+ &params->Depth, ecode);
+ if ((pname = pnames->Dict) != 0) {
+ const stream_template *template;
+ ss_put_params_t put_params;
+
+ /* Hack to determine what kind of a Dict we want: */
+ if (pnames->Dict[0] == 'M')
+ template = &s_CFE_template,
+ put_params = psdf_CF_put_params;
+ else
+ template = &s_DCTE_template,
+ put_params = psdf_DCT_put_params;
+ code = psdf_put_image_dict_param(plist, pname, &params->Dict,
+ template, put_params, mem);
+ if (code < 0)
+ ecode = code;
+ }
+ ecode = psdf_put_bool_param(plist, pnames->Downsample,
+ &params->Downsample, ecode);
+ if ((ecode = psdf_put_enum_param(plist, pnames->DownsampleType,
+ &dsti, DownsampleType_names,
+ ecode)) >= 0
+ )
+ params->DownsampleType = (enum psdf_downsample_type)dsti;
+ ecode = psdf_put_bool_param(plist, pnames->Encode,
+ &params->Encode, ecode);
+ switch (code = param_read_string(plist, pnames->Filter, &fs)) {
+ case 0:
+ {
+ const psdf_image_filter_name *pn = pifn;
+
+ while (pn->pname != 0 && !psdf_key_eq(&fs, pn->pname))
+ pn++;
+ if (pn->pname == 0 || pn->min_version > pdev->version) {
+ ecode = gs_error_rangecheck;
+ goto ipe;
+ }
+ params->Filter = pn->pname;
+ params->filter_template = pn->template;
+ break;
+ }
+ default:
+ ecode = code;
+ ipe:param_signal_error(plist, pnames->Filter, ecode);
+ case 1:
+ break;
+ }
+ ecode = psdf_put_int_param(plist, pnames->Resolution,
+ &params->Resolution, ecode);
+ if (ecode >= 0) { /* Force parameters to acceptable values. */
+ if (params->Resolution < 1)
+ params->Resolution = 1;
+ switch (params->Depth) {
+ default:
+ params->Depth = -1;
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ case -1:
+ break;
+ }
+ }
+ return ecode;
+}
+
+/* Put parameters. */
+int
+gdev_psdf_put_params(gx_device * dev, gs_param_list * plist)
+{
+ gx_device_psdf *pdev = (gx_device_psdf *) dev;
+ int ecode = 0;
+ int code;
+ gs_param_name param_name;
+ psdf_distiller_params params;
+
+ /* General parameters. */
+
+ params = pdev->params;
+
+ ecode = psdf_put_bool_param(plist, "ASCII85EncodePages",
+ &params.ASCII85EncodePages, ecode);
+ {
+ int arpi = params.AutoRotatePages;
+
+ ecode = psdf_put_enum_param(plist, "AutoRotatePages", &arpi,
+ AutoRotatePages_names, ecode);
+ params.AutoRotatePages = (enum psdf_auto_rotate_pages)arpi;
+ }
+ ecode = psdf_put_bool_param(plist, "CompressPages",
+ &params.CompressPages, ecode);
+ switch (code = param_read_long(plist, (param_name = "ImageMemory"), &params.ImageMemory)) {
+ default:
+ ecode = code;
+ param_signal_error(plist, param_name, ecode);
+ case 0:
+ case 1:
+ break;
+ }
+ ecode = psdf_put_bool_param(plist, "LZWEncodePages",
+ &params.LZWEncodePages, ecode);
+ ecode = psdf_put_bool_param(plist, "PreserveHalftoneInfo",
+ &params.PreserveHalftoneInfo, ecode);
+ ecode = psdf_put_bool_param(plist, "PreserveOPIComments",
+ &params.PreserveOPIComments, ecode);
+ ecode = psdf_put_bool_param(plist, "PreserveOverprintSettings",
+ &params.PreserveOverprintSettings, ecode);
+ {
+ int tfii = params.TransferFunctionInfo;
+
+ ecode = psdf_put_enum_param(plist, "TransferFunctionInfo", &tfii,
+ TransferFunctionInfo_names, ecode);
+ params.TransferFunctionInfo = (enum psdf_transfer_function_info)tfii;
+ }
+ {
+ int ucrbgi = params.UCRandBGInfo;
+
+ ecode = psdf_put_enum_param(plist, "UCRandBGInfo", &ucrbgi,
+ UCRandBGInfo_names, ecode);
+ params.UCRandBGInfo = (enum psdf_ucr_and_bg_info)ucrbgi;
+ }
+ ecode = psdf_put_bool_param(plist, "UseFlateCompression",
+ &params.UseFlateCompression, ecode);
+
+ /* Color sampled image parameters */
+
+ ecode = psdf_put_image_params(pdev, plist, &Color_names, Poly_filters,
+ &params.ColorImage, ecode);
+ {
+ int ccsi = params.ColorConversionStrategy;
+
+ ecode = psdf_put_enum_param(plist, "ColorConversionStrategy", &ccsi,
+ ColorConversionStrategy_names, ecode);
+ params.ColorConversionStrategy =
+ (enum psdf_color_conversion_strategy)ccsi;
+ }
+ ecode = psdf_put_bool_param(plist, "ConvertCMYKImagesToRGB",
+ &params.ConvertCMYKImagesToRGB, ecode);
+ ecode = psdf_put_bool_param(plist, "ConvertImagesToIndexed",
+ &params.ConvertImagesToIndexed, ecode);
+
+ /* Gray sampled image parameters */
+
+ ecode = psdf_put_image_params(pdev, plist, &Gray_names, Poly_filters,
+ &params.GrayImage, ecode);
+
+ /* Mono sampled image parameters */
+
+ ecode = psdf_put_image_params(pdev, plist, &Mono_names, Mono_filters,
+ &params.MonoImage, ecode);
+
+ /* Font embedding parameters */
+
+ ecode = psdf_put_embed_param(plist, "~AlwaysEmbed",
+ &params.AlwaysEmbed, ecode);
+ ecode = psdf_put_embed_param(plist, "~NeverEmbed",
+ &params.NeverEmbed, ecode);
+ ecode = psdf_put_bool_param(plist, "EmbedAllFonts",
+ &params.EmbedAllFonts, ecode);
+ ecode = psdf_put_bool_param(plist, "SubsetFonts",
+ &params.SubsetFonts, ecode);
+ ecode = psdf_put_int_param(plist, "MaxSubsetPct",
+ &params.MaxSubsetPct, ecode);
+
+ if (ecode < 0)
+ return ecode;
+ code = gdev_vector_put_params(dev, plist);
+ if (code < 0)
+ return code;
+
+ pdev->params = params; /* OK to update now */
+ return 0;
+}
diff --git a/gs/src/gdevpsds.c b/gs/src/gdevpsds.c
new file mode 100644
index 000000000..a18e4b587
--- /dev/null
+++ b/gs/src/gdevpsds.c
@@ -0,0 +1,451 @@
+/* Copyright (C) 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gdevpsds.c */
+/* Image processing streams for PostScript and PDF writers */
+#include "gx.h"
+#include "memory_.h"
+#include "gserrors.h"
+#include "gxdcconv.h"
+#include "gdevpsds.h"
+
+/* ---------------- Convert between 1/2/4 and 8 bits ---------------- */
+gs_private_st_simple(st_1248_state, stream_1248_state, "stream_1248_state");
+
+/* Initialize the state. */
+private int
+s_1_init(stream_state * st)
+{
+ stream_1248_state *const ss = (stream_1248_state *) st;
+
+ ss->left = ss->samples_per_row;
+ ss->bits_per_sample = 1;
+ return 0;
+}
+private int
+s_2_init(stream_state * st)
+{
+ stream_1248_state *const ss = (stream_1248_state *) st;
+
+ ss->left = ss->samples_per_row;
+ ss->bits_per_sample = 2;
+ return 0;
+}
+private int
+s_4_init(stream_state * st)
+{
+ stream_1248_state *const ss = (stream_1248_state *) st;
+
+ ss->left = ss->samples_per_row;
+ ss->bits_per_sample = 4;
+ return 0;
+}
+
+/* Process one buffer. */
+#define begin_1248\
+ stream_1248_state * const ss = (stream_1248_state *)st;\
+ const byte *p = pr->ptr;\
+ const byte *rlimit = pr->limit;\
+ byte *q = pw->ptr;\
+ byte *wlimit = pw->limit;\
+ uint left = ss->left;\
+ int status;\
+ int n
+#define end_1248\
+ pr->ptr = p;\
+ pw->ptr = q;\
+ ss->left = left;\
+ return status
+
+/* N-to-8 expansion */
+#define foreach_N_8(in, nout)\
+ status = 0;\
+ for ( ; p < rlimit; left -= n, q += n, ++p ) {\
+ byte in = p[1];\
+ n = min(left, nout);\
+ if ( wlimit - q < n ) {\
+ status = 1;\
+ break;\
+ }\
+ switch ( n ) {\
+ case 0: left = ss->samples_per_row; continue;
+#define end_foreach\
+ }\
+ }
+private int
+s_N_8_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last)
+{
+ begin_1248;
+
+ switch (ss->bits_per_sample) {
+
+ case 1:{
+ foreach_N_8(in, 8)
+ case 8:
+ q[8] = (byte) - (in & 1);
+ case 7:
+ q[7] = (byte) - ((in >> 1) & 1);
+ case 6:
+ q[6] = (byte) - ((in >> 2) & 1);
+ case 5:
+ q[5] = (byte) - ((in >> 3) & 1);
+ case 4:
+ q[4] = (byte) - ((in >> 4) & 1);
+ case 3:
+ q[3] = (byte) - ((in >> 5) & 1);
+ case 2:
+ q[2] = (byte) - ((in >> 6) & 1);
+ case 1:
+ q[1] = (byte) - (in >> 7);
+ end_foreach;
+ }
+ break;
+
+ case 2:{
+ static const byte b2[4] =
+ {0x00, 0x55, 0xaa, 0xff};
+
+ foreach_N_8(in, 4)
+ case 4:
+ q[4] = b2[in & 3];
+ case 3:
+ q[3] = b2[(in >> 2) & 3];
+ case 2:
+ q[2] = b2[(in >> 4) & 3];
+ case 1:
+ q[1] = b2[in >> 6];
+ end_foreach;
+ }
+ break;
+
+ case 4:{
+ static const byte b4[16] =
+ {
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
+ };
+
+ foreach_N_8(in, 2)
+ case 2:
+ q[2] = b4[in & 0xf];
+ case 1:
+ q[1] = b4[in >> 4];
+ end_foreach;
+ }
+ break;
+
+ default:
+ return ERRC;
+ }
+
+ end_1248;
+}
+
+/* 8-to-N reduction */
+#define foreach_8_N(out, nin)\
+ byte out;\
+ status = 1;\
+ for ( ; q < wlimit; left -= n, p += n, *++q = out ) {\
+ n = min(left, nin);\
+ if ( rlimit - p < n ) {\
+ status = 0;\
+ break;\
+ }\
+ out = 0;\
+ switch ( n ) {\
+ case 0: left = ss->samples_per_row; continue;
+private int
+s_8_N_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last)
+{
+ begin_1248;
+
+ switch (ss->bits_per_sample) {
+
+ case 1:{
+ foreach_8_N(out, 8)
+ case 8:
+ out = p[8] >> 7;
+ case 7:
+ out |= (p[7] >> 7) << 1;
+ case 6:
+ out |= (p[6] >> 7) << 2;
+ case 5:
+ out |= (p[5] >> 7) << 3;
+ case 4:
+ out |= (p[4] >> 7) << 4;
+ case 3:
+ out |= (p[3] >> 7) << 5;
+ case 2:
+ out |= (p[2] >> 7) << 6;
+ case 1:
+ out |= p[1] & 0x80;
+ end_foreach;
+ }
+ break;
+
+ case 2:{
+ foreach_8_N(out, 4)
+ case 4:
+ out |= p[4] >> 6;
+ case 3:
+ out |= (p[3] >> 6) << 2;
+ case 2:
+ out |= (p[2] >> 6) << 4;
+ case 1:
+ out |= p[1] & 0xc0;
+ end_foreach;
+ }
+ break;
+
+ case 4:{
+ foreach_8_N(out, 2)
+ case 2:
+ out |= p[2] >> 4;
+ case 1:
+ out |= p[1] & 0xf0;
+ end_foreach;
+ }
+ break;
+
+ default:
+ return ERRC;
+ }
+
+ end_1248;
+}
+
+const stream_template s_1_8_template =
+{
+ &st_1248_state, s_1_init, s_N_8_process, 1, 8
+};
+const stream_template s_2_8_template =
+{
+ &st_1248_state, s_2_init, s_N_8_process, 1, 4
+};
+const stream_template s_4_8_template =
+{
+ &st_1248_state, s_4_init, s_N_8_process, 1, 2
+};
+
+const stream_template s_8_1_template =
+{
+ &st_1248_state, s_1_init, s_8_N_process, 8, 1
+};
+const stream_template s_8_2_template =
+{
+ &st_1248_state, s_2_init, s_8_N_process, 4, 1
+};
+const stream_template s_8_4_template =
+{
+ &st_1248_state, s_4_init, s_8_N_process, 2, 1
+};
+
+/* ---------------- CMYK => RGB conversion ---------------- */
+
+private_st_C2R_state();
+
+/* Process one buffer. */
+private int
+s_C2R_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last)
+{
+ stream_C2R_state *const ss = (stream_C2R_state *) st;
+ const byte *p = pr->ptr;
+ const byte *rlimit = pr->limit;
+ byte *q = pw->ptr;
+ byte *wlimit = pw->limit;
+
+ for (; rlimit - p >= 4 && wlimit - q >= 3; p += 4, q += 3) {
+ byte bc = p[1], bm = p[2], by = p[3], bk = p[4];
+ frac rgb[3];
+
+ color_cmyk_to_rgb(byte2frac(bc), byte2frac(bm), byte2frac(by),
+ byte2frac(bk), ss->pis, rgb);
+ q[1] = frac2byte(rgb[0]);
+ q[2] = frac2byte(rgb[1]);
+ q[3] = frac2byte(rgb[2]);
+ }
+ pr->ptr = p;
+ pw->ptr = q;
+ return (rlimit - p < 4 ? 0 : 1);
+}
+
+const stream_template s_C2R_template =
+{
+ &st_C2R_state, 0 /*NULL */ , s_C2R_process, 4, 3
+};
+
+/* ---------------- Downsampling ---------------- */
+
+/* Subsample */
+
+gs_private_st_simple(st_Subsample_state, stream_Subsample_state,
+ "stream_Subsample_state");
+
+/* Initialize the state. */
+private int
+s_Subsample_init(stream_state * st)
+{
+ stream_Subsample_state *const ss = (stream_Subsample_state *) st;
+
+ ss->x = ss->y = 0;
+ return 0;
+}
+
+/* Process one buffer. */
+private int
+s_Subsample_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last)
+{
+ stream_Subsample_state *const ss = (stream_Subsample_state *) st;
+ const byte *p = pr->ptr;
+ const byte *rlimit = pr->limit;
+ byte *q = pw->ptr;
+ byte *wlimit = pw->limit;
+ int spp = ss->Colors;
+ int width = ss->Columns;
+ int xf = ss->XFactor, yf = ss->YFactor;
+ int xf2 = xf / 2, yf2 = yf / 2;
+ int xlimit = (width / xf) * xf;
+ int x = ss->x, y = ss->y;
+ int status = 0;
+
+ for (; rlimit - p >= spp; p += spp) {
+ if (y == yf2 && x % xf == xf2 && x < xlimit) {
+ if (wlimit - q < spp) {
+ status = 1;
+ break;
+ }
+ memcpy(q + 1, p + 1, spp);
+ q += spp;
+ }
+ if (++x == width) {
+ x = 0;
+ if (++y == yf) {
+ y = 0;
+ }
+ }
+ }
+ pr->ptr = p;
+ pw->ptr = q;
+ ss->x = x, ss->y = y;
+ return status;
+}
+
+const stream_template s_Subsample_template =
+{
+ &st_Subsample_state, s_Subsample_init, s_Subsample_process, 4, 4
+};
+
+/* Average */
+
+private_st_Average_state();
+
+/* Initialize the state. */
+private int
+s_Average_init(stream_state * st)
+{
+ stream_Average_state *const ss = (stream_Average_state *) st;
+
+ ss->sum_size = ss->Colors * (ss->Columns / ss->XFactor);
+ /*
+ * We allocate an extra element of sums to avoid treating the extra
+ * samples of each input scan line as a special case, but we never
+ * do anything with it (except accumulate into it).
+ */
+ ss->sums =
+ (uint *) gs_alloc_byte_array(st->memory, ss->sum_size + 1,
+ sizeof(uint), "Average sums");
+ if (ss->sums == 0)
+ return ERRC;
+/****** WRONG ******/
+ memset(ss->sums, 0, ss->sum_size * sizeof(uint));
+ return s_Subsample_init(st);
+}
+
+/* Release the state. */
+private void
+s_Average_release(stream_state * st)
+{
+ stream_Average_state *const ss = (stream_Average_state *) st;
+
+ gs_free_object(st->memory, ss->sums, "Average sums");
+}
+
+/* Process one buffer. */
+private int
+s_Average_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last)
+{
+ stream_Average_state *const ss = (stream_Average_state *) st;
+ const byte *p = pr->ptr;
+ const byte *rlimit = pr->limit;
+ byte *q = pw->ptr;
+ byte *wlimit = pw->limit;
+ int spp = ss->Colors;
+ int width = ss->Columns;
+ int xf = ss->XFactor, yf = ss->YFactor;
+ int x = ss->x, y = ss->y;
+ uint *sums = ss->sums;
+ int status = 0;
+
+ top:while (y == yf) {
+ /* We're copying averaged values to the output. */
+ int ncopy = min(ss->sum_size - x, wlimit - q);
+
+ if (ncopy) {
+ int scale = xf * yf;
+
+ while (--ncopy >= 0)
+ *++q = (byte) (sums[x++] / scale);
+ continue;
+ }
+ if (x < ss->sum_size) {
+ status = 1;
+ goto out;
+ }
+ /* Done copying. */
+ x = y = 0;
+ memset(sums, 0, ss->sum_size * sizeof(uint));
+ break;
+ }
+ while (rlimit - p >= spp) {
+ uint *bp = sums + x / xf * spp;
+ int i;
+
+ for (i = spp; --i >= 0;)
+ *bp++ += *++p;
+ if (++x == width) {
+ x = 0;
+ ++y;
+ goto top;
+ }
+ }
+ out:pr->ptr = p;
+ pw->ptr = q;
+ ss->x = x, ss->y = y;
+ return status;
+}
+
+const stream_template s_Average_template =
+{
+ &st_Average_state, s_Average_init, s_Average_process, 4, 4,
+ s_Average_release
+};
diff --git a/gs/src/gdevpsds.h b/gs/src/gdevpsds.h
new file mode 100644
index 000000000..70d71ba87
--- /dev/null
+++ b/gs/src/gdevpsds.h
@@ -0,0 +1,101 @@
+/* Copyright (C) 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gdevpsds.h */
+/* Image processing stream interface for PostScript and PDF writers */
+
+#ifndef gdevpsds_INCLUDED
+# define gdevpsds_INCLUDED
+
+#include "strimpl.h"
+
+/* Convert between 1/2/4 bits and 8 bits. */
+typedef struct stream_1248_state_s {
+ stream_state_common;
+ /* The following are set at initialization time. */
+ uint samples_per_row; /* >0 */
+ int bits_per_sample; /* 1, 2, 4 */
+ /* The following are updated dynamically. */
+ uint left; /* # of samples left in current row */
+} stream_1248_state;
+
+/* Expand N (1, 2, 4) bits to 8. */
+extern const stream_template s_1_8_template;
+extern const stream_template s_2_8_template;
+extern const stream_template s_4_8_template;
+
+/* Reduce 8 bits to N (1, 2, 4) */
+extern const stream_template s_8_1_template;
+extern const stream_template s_8_2_template;
+extern const stream_template s_8_4_template;
+
+/* Initialize an expansion or reduction stream. */
+#define s_1248_init(ss, Columns, samples_per_pixel)\
+ ((ss)->samples_per_row = (Columns) * (samples_per_pixel),\
+ (*(ss)->template->init)((stream_state *)(ss)))
+
+/* Convert (8-bit) CMYK to RGB. */
+typedef struct stream_C2R_state_s {
+ stream_state_common;
+ /* The following are set at initialization time. */
+ const gs_imager_state *pis; /* for UCR & BG */
+} stream_C2R_state;
+
+#define private_st_C2R_state() /* in gdevpsds.c */\
+ gs_private_st_ptrs1(st_C2R_state, stream_C2R_state, "stream_C2R_state",\
+ c2r_enum_ptrs, c2r_reloc_ptrs, pis)
+extern const stream_template s_C2R_template;
+
+#define s_C2R_init(ss, pisv)\
+ ((ss)->pis = (pisv), 0)
+
+/* Downsample, possibly with anti-aliasing. */
+#define stream_Downsample_state_common\
+ stream_state_common;\
+ /* The client sets the following before initialization. */\
+ int Colors;\
+ int Columns; /* # of input columns */\
+ int XFactor, YFactor;\
+ bool AntiAlias;\
+ /* The following are updated dynamically. */\
+ int x, y /* position within input image */
+#define s_Downsample_set_defaults(ss)\
+ ((ss)->AntiAlias = false)
+typedef struct stream_Downsample_state_s {
+ stream_Downsample_state_common;
+} stream_Downsample_state;
+
+/* Subsample */
+typedef struct stream_Subsample_state_s {
+ stream_Downsample_state_common;
+} stream_Subsample_state;
+extern const stream_template s_Subsample_template;
+
+/* Average */
+typedef struct stream_Average_state_s {
+ stream_Downsample_state_common;
+ uint sum_size;
+ uint *sums; /* accumulated sums for average */
+} stream_Average_state;
+
+#define private_st_Average_state() /* in gdevpsds.c */\
+ gs_private_st_ptrs1(st_Average_state, stream_Average_state,\
+ "stream_Average_state", avg_enum_ptrs, avg_reloc_ptrs, sums)
+extern const stream_template s_Average_template;
+
+#endif /* gdevpsds_INCLUDED */
diff --git a/gs/src/gdevrops.c b/gs/src/gdevrops.c
new file mode 100644
index 000000000..97cc291e7
--- /dev/null
+++ b/gs/src/gdevrops.c
@@ -0,0 +1,196 @@
+/* Copyright (C) 1995, 1996, 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gdevrops.c */
+/* RasterOp source device */
+#include "gx.h"
+#include "gserrors.h"
+#include "gxdcolor.h"
+#include "gxdevice.h"
+#include "gdevmrop.h"
+
+/* GC procedures */
+private_st_device_rop_texture();
+#define rtdev ((gx_device_rop_texture *)vptr)
+private ENUM_PTRS_BEGIN(device_rop_texture_enum_ptrs) {
+ if (index < st_device_color_max_ptrs) {
+ gs_ptr_type_t ptype =
+ ENUM_SUPER_ELT(gx_device_rop_texture, st_device_color, texture, 0);
+
+ if (ptype)
+ return ptype;
+ return ENUM_OBJ(NULL); /* don't stop early */
+ }
+ ENUM_PREFIX(st_device_forward, st_device_color_max_ptrs);
+} ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(device_rop_texture_reloc_ptrs) {
+ RELOC_PREFIX(st_device_forward);
+ RELOC_SUPER(gx_device_rop_texture, st_device_color, texture);
+} RELOC_PTRS_END
+#undef rtdev
+
+/* Device for providing source data for RasterOp. */
+private dev_proc_fill_rectangle(rop_texture_fill_rectangle);
+private dev_proc_copy_mono(rop_texture_copy_mono);
+private dev_proc_copy_color(rop_texture_copy_color);
+
+/* The device descriptor. */
+private const gx_device_rop_texture gs_rop_texture_device = {
+ std_device_std_body(gx_device_rop_texture, 0, "rop source",
+ 0, 0, 1, 1),
+ {NULL, /* open_device */
+ gx_forward_get_initial_matrix,
+ NULL, /* default_sync_output */
+ NULL, /* output_page */
+ NULL, /* close_device */
+ gx_forward_map_rgb_color,
+ gx_forward_map_color_rgb,
+ rop_texture_fill_rectangle,
+ NULL, /* tile_rectangle */
+ rop_texture_copy_mono,
+ rop_texture_copy_color,
+ NULL, /* draw_line */
+ NULL, /* get_bits */
+ gx_forward_get_params,
+ gx_forward_put_params,
+ gx_forward_map_cmyk_color,
+ gx_forward_get_xfont_procs,
+ gx_forward_get_xfont_device,
+ gx_forward_map_rgb_alpha_color,
+ gx_forward_get_page_device,
+ NULL, /* get_alpha_bits (no alpha) */
+ gx_no_copy_alpha, /* shouldn't be called */
+ gx_forward_get_band,
+ gx_no_copy_rop, /* shouldn't be called */
+ NULL, /* fill_path */
+ NULL, /* stroke_path */
+ NULL, /* fill_mask */
+ NULL, /* fill_trapezoid */
+ NULL, /* fill_parallelogram */
+ NULL, /* fill_triangle */
+ NULL, /* draw_thin_line */
+ NULL, /* begin_image */
+ NULL, /* image_data */
+ NULL, /* end_image */
+ NULL, /* strip_tile_rectangle */
+ NULL, /* strip_copy_rop */
+ gx_forward_get_clipping_box,
+ NULL, /* begin_typed_image */
+ NULL, /* get_bits_rectangle */
+ gx_forward_map_color_rgb_alpha,
+ NULL, /* create_compositor */
+ gx_forward_get_hardware_params,
+ NULL /* text_begin */
+ },
+ 0, /* target */
+ lop_default /* log_op */
+ /* */ /* texture */
+};
+
+/* Create a RasterOp source device. */
+int
+gx_alloc_rop_texture_device(gx_device_rop_texture ** prsdev, gs_memory_t * mem,
+ client_name_t cname)
+{
+ *prsdev = gs_alloc_struct(mem, gx_device_rop_texture,
+ &st_device_rop_texture, cname);
+ return (*prsdev == 0 ? gs_note_error(gs_error_VMerror) : 0);
+}
+
+/* Initialize a RasterOp source device. */
+void
+gx_make_rop_texture_device(gx_device_rop_texture * dev, gx_device * target,
+ gs_logical_operation_t log_op, const gx_device_color * texture)
+{
+ gx_device_init((gx_device *) dev,
+ (const gx_device *)&gs_rop_texture_device,
+ NULL, true);
+ /* Drawing operations are defaulted, non-drawing are forwarded. */
+ gx_device_fill_in_procs((gx_device *) dev);
+ dev->color_info = target->color_info;
+ dev->target = target;
+ dev->log_op = log_op;
+ dev->texture = *texture;
+}
+
+/* Fill a rectangle */
+private int
+rop_texture_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
+ gx_color_index color)
+{
+ gx_device_rop_texture *const rtdev = (gx_device_rop_texture *)dev;
+ gx_rop_source_t source;
+
+ source.sdata = NULL;
+ source.sourcex = 0;
+ source.sraster = 0;
+ source.id = gx_no_bitmap_id;
+ source.scolors[0] = source.scolors[1] = color;
+ source.use_scolors = true;
+ return gx_device_color_fill_rectangle(&rtdev->texture,
+ x, y, w, h, rtdev->target,
+ rtdev->log_op, &source);
+}
+
+/* Copy a monochrome rectangle */
+private int
+rop_texture_copy_mono(gx_device * dev,
+ const byte * data, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h,
+ gx_color_index color0, gx_color_index color1)
+{
+ gx_device_rop_texture *const rtdev = (gx_device_rop_texture *)dev;
+ gx_rop_source_t source;
+ gs_logical_operation_t lop = rtdev->log_op;
+
+ source.sdata = data;
+ source.sourcex = sourcex;
+ source.sraster = raster;
+ source.id = id;
+ source.scolors[0] = color0;
+ source.scolors[1] = color1;
+ source.use_scolors = true;
+ /* Adjust the logical operation per transparent colors. */
+ if (color0 == gx_no_color_index)
+ lop = rop3_use_D_when_S_0(lop);
+ else if (color1 == gx_no_color_index)
+ lop = rop3_use_D_when_S_1(lop);
+ return gx_device_color_fill_rectangle(&rtdev->texture,
+ x, y, w, h, rtdev->target,
+ lop, &source);
+}
+
+/* Copy a color rectangle */
+private int
+rop_texture_copy_color(gx_device * dev,
+ const byte * data, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{
+ gx_device_rop_texture *const rtdev = (gx_device_rop_texture *)dev;
+ gx_rop_source_t source;
+
+ source.sdata = data;
+ source.sourcex = sourcex;
+ source.sraster = raster;
+ source.id = id;
+ source.scolors[0] = source.scolors[1] = gx_no_color_index;
+ source.use_scolors = false;
+ return gx_device_color_fill_rectangle(&rtdev->texture,
+ x, y, w, h, rtdev->target,
+ rtdev->log_op, &source);
+}
diff --git a/gs/src/gendev.c b/gs/src/gendev.c
new file mode 100644
index 000000000..f5398814d
--- /dev/null
+++ b/gs/src/gendev.c
@@ -0,0 +1,363 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gendev.c */
+/* Generate .dev configuration files */
+#include "stdpre.h"
+#include <assert.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h> /* for calloc */
+#include <string.h>
+
+/*
+ * This program generates .dev configuration files.
+ *
+ * Usage:
+ * gendev [-Z] [-n [<name_prefix> | -]] [-C [<dir> | -]]
+ * (-d <devfile> | -m <modfile> | -a <modfile>)
+ * (-<category> | <item>)*
+ *
+ * The name_prefix is for device[2], font, init, and iodev resources.
+ * ****** DOESN'T HANDLE -replace YET ******
+ * ****** DOESN'T MERGE device AND device2 ******
+ */
+
+#define DEFAULT_NAME_PREFIX "gs_"
+#define INITIAL_CATEGORY "obj"
+
+typedef struct config_s {
+ /* Set once */
+ FILE *out;
+ bool debug;
+ const char *name_prefix;
+ const char *file_prefix;
+ ulong file_id; /* for uniq_last detection */
+ /* Updated dynamically */
+#define ITEM_ID_BITS 5
+ uint item_id;
+ bool any_scan_items;
+ bool in_res_scan;
+ bool in_category; /* in_category implies in_res_scan */
+ const char *current_category;
+} config;
+static const config init_config =
+{
+ 0, /* out */
+ 0, /* debug */
+ DEFAULT_NAME_PREFIX, /* name_prefix */
+ "", /* file_prefix */
+ 0, /* file_id */
+ 0, /* item_id */
+ 0, /* any_scan_items */
+ 0, /* in_res_scan */
+ 0, /* in_category */
+ "" /* current_category */
+};
+
+static const char *indent_INCLUDED = "\t\t\t\t";
+static const char *indent_RES_SCAN = " ";
+static const char *indent_category = "\t";
+static const char *indent_SEEN = "\t ";
+static const char *indent_include = " ";
+static const char *indent_scan_item = "\t";
+static const char *indent_item = "";
+
+/* Forward definitions */
+void add_entry(P4(config *, const char *, const char *, bool));
+
+main(int argc, char *argv[])
+{
+ config conf;
+ int i, j;
+ bool dev, append;
+ const char *category = INITIAL_CATEGORY;
+ const char *fnarg;
+ FILE *out;
+ long pos;
+
+ conf = init_config;
+ /* Process command line arguments. */
+ for (i = 1; i < argc; i++) {
+ const char *arg = argv[i];
+
+ if (*arg != '-') {
+ fprintf(stderr, "-d|m|a must precede non-switches.\n", arg);
+ exit(1);
+ }
+ switch (arg[1]) {
+ case 'C': /* change directory, by analogy with make */
+ conf.file_prefix =
+ (argv[i + 1][0] == '-' ? "" : argv[i + 1]);
+ ++i;
+ continue;
+ case 'n':
+ conf.name_prefix =
+ (argv[i + 1][0] == '-' ? "" : argv[i + 1]);
+ ++i;
+ continue;
+ case 'a':
+ dev = false, append = true;
+ break;
+ case 'd':
+ dev = true, append = false;
+ break;
+ case 'm':
+ dev = false, append = false;
+ break;
+ case 'Z':
+ conf.debug = true;
+ continue;
+ default:
+ fprintf(stderr, "Unknown switch %s.\n", argv[i]);
+ exit(1);
+ }
+ break;
+ }
+ if (i == argc - 1) {
+ fprintf(stderr, "No output file name given, last argument is %s.\n",
+ argv[i]);
+ exit(1);
+ }
+ /* Must be the output file. */
+ fnarg = argv[++i];
+ {
+ char fname[100];
+
+ strcpy(fname, fnarg);
+ strcat(fname, ".dev");
+ out = fopen(fname, (append ? "a" : "w"));
+ if (out == 0) {
+ fprintf(stderr, "Can't open %s for output.\n", fname);
+ exit(1);
+ }
+ if (!append)
+ fprintf(out,
+ "/*\n * File %s created automatically by gendev.\n */\n",
+ fname);
+ }
+ conf.out = out;
+ pos = ftell(out);
+ /* We need a separate _INCLUDED flag for each batch of definitions. */
+ fprintf(out, "\n#%sifndef %s_%ld_INCLUDED\n",
+ indent_INCLUDED, fnarg, pos);
+ fprintf(out, "#%s define %s_%ld_INCLUDED\n",
+ indent_INCLUDED, fnarg, pos);
+ /* Create a "unique" hash for the output file. */
+ for (j = 0; fnarg[j] != 0; ++j)
+ conf.file_id = conf.file_id * 41 + fnarg[j];
+ conf.item_id <<= ITEM_ID_BITS;
+ /* Add the real entries. */
+ if (dev)
+ add_entry(&conf, "dev", fnarg, false);
+ for (j = i + 1; j < argc; ++j) {
+ const char *arg = argv[j];
+
+ if (arg[0] == '-')
+ category = arg + 1;
+ else
+ add_entry(&conf, category, arg, false);
+ }
+ if (conf.in_category)
+ fprintf(out, "#%sendif /* -%s */\n",
+ indent_category, conf.current_category);
+ /* Add the scanning entries, if any. */
+ if (conf.any_scan_items) {
+ if (conf.in_res_scan)
+ fprintf(out, "#%selse /* RES_SCAN */\n", indent_RES_SCAN);
+ else
+ fprintf(out, "#%sifdef RES_SCAN\n", indent_RES_SCAN);
+ conf.in_res_scan = true;
+ category = INITIAL_CATEGORY;
+ conf.item_id = 0;
+ for (j = i + 1; j < argc; ++j) {
+ const char *arg = argv[j];
+
+ if (arg[0] == '-')
+ category = arg + 1;
+ else
+ add_entry(&conf, category, arg, true);
+ }
+ }
+ if (conf.in_res_scan)
+ fprintf(out, "#%sendif /* RES_SCAN */\n", indent_RES_SCAN);
+ fprintf(out, "#%sendif /* !%s_%ld_INCLUDED */\n",
+ indent_INCLUDED, fnarg, pos);
+ fclose(out);
+ exit(0);
+}
+
+/* Add an entry to the output. */
+typedef enum {
+ uniq_none = 0,
+ uniq_first,
+ uniq_last
+} uniq_mode;
+void
+write_item(config * pconf, const char *str, const char *category,
+ const char *item, uniq_mode mode)
+{
+ FILE *out = pconf->out;
+ char cati[80];
+
+ if (!pconf->in_res_scan) {
+ fprintf(out, "#%sifndef RES_SCAN\n", indent_RES_SCAN);
+ pconf->in_res_scan = true;
+ }
+ if (strcmp(pconf->current_category, category)) {
+ const char *paren = strchr(str, '(');
+
+ if (pconf->in_category)
+ fprintf(out, "#%sendif /* -%s */\n",
+ indent_category, pconf->current_category);
+ fprintf(out, "#%sifdef ", indent_category);
+ fwrite(str, sizeof(char), paren - str, out);
+
+ fprintf(out, "\n");
+ pconf->current_category = category;
+ pconf->in_category = true;
+ }
+ sprintf(cati, "%s_%s_", category, item);
+ switch (mode) {
+ case uniq_none:
+ fprintf(out, "%s%s\n", indent_item, str);
+ break;
+ case uniq_first:
+ fprintf(out, "#%sifndef %sSEEN\n", indent_SEEN, cati);
+ fprintf(out, "#%s define %sSEEN\n", indent_SEEN, cati);
+ write_item(pconf, str, category, item, uniq_none);
+ fprintf(out, "#%sendif\n", indent_SEEN, cati);
+ break;
+ case uniq_last:
+ fprintf(out, "#%sif %sSEEN == %lu\n", indent_SEEN, cati,
+ pconf->file_id + pconf->item_id++);
+ write_item(pconf, str, category, item, uniq_none);
+ fprintf(out, "#%sendif\n", indent_SEEN, cati);
+ pconf->any_scan_items = true;
+ break;
+ }
+}
+void
+write_scan_item(config * pconf, const char *str, const char *category,
+ const char *item, uniq_mode mode)
+{
+ FILE *out = pconf->out;
+ char cati[80];
+
+ sprintf(cati, "%s_%s_", category, item);
+ switch (mode) {
+ case uniq_none:
+ break;
+ case uniq_first:
+ break;
+ case uniq_last:
+ fprintf(out, "#%sundef %sSEEN\n", indent_scan_item, cati);
+ fprintf(out, "#%s define %sSEEN %lu\n", indent_scan_item, cati,
+ pconf->file_id + pconf->item_id++);
+ }
+}
+void
+add_entry(config * pconf, const char *category, const char *item, bool scan)
+{
+ char str[80];
+ uniq_mode mode = uniq_first;
+
+ if (pconf->debug && !scan)
+ printf("Adding %s %s;\n", category, item);
+ str[0] = 0;
+ switch (category[0]) { /* just an accelerator */
+#define is_cat(str) !strcmp(category, str)
+ case 'd':
+ if (is_cat("dev"))
+ sprintf(str, "device_(%s%s_device)\n",
+ pconf->name_prefix, item);
+ else if (is_cat("dev2"))
+ sprintf(str, "device2_(%s%s_device)\n",
+ pconf->name_prefix, item);
+ break;
+ case 'e':
+ if (is_cat("emulator"))
+ sprintf(str, "emulator_(\"%s\",%d)",
+ item, strlen(item));
+ break;
+ case 'f':
+ if (is_cat("font"))
+ sprintf(str, "font_(\"0.font_%s\",%sf_%s,zf_%s)",
+ item, pconf->name_prefix, item, item);
+ break;
+ case 'i':
+ if (is_cat("include")) {
+ int len = strlen(item);
+
+ if (scan)
+ return;
+ if (strcmp(pconf->current_category, category)) {
+ if (pconf->in_category) {
+ fprintf(pconf->out, "#%sendif /* -%s */\n",
+ indent_category, pconf->current_category);
+ pconf->in_category = false;
+ }
+ pconf->current_category = category;
+ }
+ if (pconf->in_res_scan) {
+ fprintf(pconf->out, "#%sendif /* RES_SCAN */\n",
+ indent_RES_SCAN);
+ pconf->in_res_scan = false;
+ }
+ if (len < 5 || strcmp(item + len - 4, ".dev"))
+ fprintf(pconf->out, "#%sinclude \"%s.dev\"\n",
+ indent_include, item);
+ else
+ fprintf(pconf->out, "#%sinclude \"%s\"\n",
+ indent_include, item);
+ return;
+ } else if (is_cat("init"))
+ sprintf(str, "init_(%s%s_init)", pconf->name_prefix, item);
+ else if (is_cat("iodev"))
+ sprintf(str, "io_device_(%siodev_%s)", pconf->name_prefix, item);
+ break;
+ case 'l':
+ if (is_cat("lib")) {
+ sprintf(str, "lib_(%s)", item);
+ mode = uniq_last;
+ }
+ break;
+ case 'o':
+ if (is_cat("obj"))
+ sprintf(str, "obj_(%s%s)", pconf->file_prefix, item);
+ else if (is_cat("oper"))
+ sprintf(str, "oper_(%s_op_defs)", item);
+ break;
+ case 'p':
+ if (is_cat("ps"))
+ sprintf(str, "psfile_(\"%s.ps\",%d)",
+ item, strlen(item) + 3);
+ break;
+#undef is_cat
+ default:
+ ;
+ }
+ if (str[0] == 0) {
+ fprintf(stderr, "Unknown category %s.\n", category);
+ exit(1);
+ }
+ if (scan)
+ write_scan_item(pconf, str, category, item, mode);
+ else
+ write_item(pconf, str, category, item, mode);
+}
diff --git a/gs/src/gp_getnv.c b/gs/src/gp_getnv.c
new file mode 100644
index 000000000..84c70374d
--- /dev/null
+++ b/gs/src/gp_getnv.c
@@ -0,0 +1,54 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gp_getnv.c */
+/* Standard implementation of gp_getenv */
+#include "stdio_.h"
+#include "string_.h"
+#include "gsmemory.h"
+#include "gstypes.h"
+#include "gp.h"
+
+/* Import the C getenv function. */
+extern char *getenv(P1(const char *));
+
+/* Get the value of an environment variable. See gp.h for details. */
+int
+gp_getenv(const char *key, char *ptr, int *plen)
+{
+ const char *str = getenv(key);
+
+ if (str) {
+ int len = strlen(str);
+
+ if (len < *plen) {
+ /* string fits */
+ strcpy(ptr, str);
+ *plen = len + 1;
+ return 0;
+ }
+ /* string doesn't fit */
+ *plen = len + 1;
+ return -1;
+ }
+ /* missing key */
+ if (*plen > 0)
+ *ptr = 0;
+ *plen = 1;
+ return 1;
+}
diff --git a/gs/src/gp_wgetv.c b/gs/src/gp_wgetv.c
new file mode 100644
index 000000000..23ea0ed9f
--- /dev/null
+++ b/gs/src/gp_wgetv.c
@@ -0,0 +1,130 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gp_wgetv.c */
+/* MS Windows implementation of gp_getenv */
+
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h> /* for getenv */
+#include <string.h>
+#include "gscdefs.h" /* for gs_product and gs_revision */
+
+/* prototypes */
+int gp_getenv_registry(HKEY hkeyroot, const char *key, const char *name,
+ char *ptr, int *plen);
+
+/* ------ Environment variables ------ */
+
+/* Get the value of an environment variable. See gp.h for details. */
+int
+gp_getenv(const char *name, char *ptr, int *plen)
+{
+ const char *str = getenv(name);
+
+ if (str) {
+ int len = strlen(str);
+
+ if (len < *plen) {
+ /* string fits */
+ strcpy(ptr, str);
+ *plen = len + 1;
+ return 0;
+ }
+ /* string doesn't fit */
+ *plen = len + 1;
+ return -1;
+ }
+ /* environment variable was not found */
+
+#ifdef __WIN32__
+ {
+ /* If using Win32, look in the registry for a value with
+ * the given name. The registry value will be under the key
+ * HKEY_CURRENT_USER\Software\Aladdin Ghostscript\N.NN
+ * or if that fails under the key
+ * HKEY_LOCAL_MACHINE\Software\Aladdin Ghostscript\N.NN
+ * where "Aladdin Ghostscript" is actually gs_product
+ * and N.NN is obtained from gs_revision.
+ */
+ DWORD version = GetVersion();
+
+ if (!(((HIWORD(version) & 0x8000) != 0)
+ && ((HIWORD(version) & 0x4000) == 0))) {
+ /* not Win32s */
+ int code;
+ char key[256];
+ sprintf(key, "Software\\%s\\%d.%d", gs_product,
+ (int)(gs_revision / 100), (int)(gs_revision % 100));
+
+ code = gp_getenv_registry(HKEY_CURRENT_USER, key, name, ptr, plen);
+ if ( code <= 0 )
+ return code; /* found it */
+
+ code = gp_getenv_registry(HKEY_LOCAL_MACHINE, key, name, ptr, plen);
+ if ( code <= 0 )
+ return code; /* found it */
+ }
+ }
+#endif
+
+ /* nothing found at all */
+
+ if (*plen > 0)
+ *ptr = 0;
+ *plen = 1;
+ return 1;
+}
+
+
+/*
+ * Get a named registry value.
+ * Key = hkeyroot\\key, named value = name.
+ * name, ptr, plen and return values are the same as in gp_getenv();
+ */
+
+int
+gp_getenv_registry(HKEY hkeyroot, const char *key, const char *name,
+ char *ptr, int *plen)
+{
+ HKEY hkey;
+ DWORD cbData, keytype;
+ BYTE b;
+ LONG rc;
+ BYTE *bptr = (BYTE *)ptr;
+
+ if (RegOpenKeyEx(hkeyroot, key, 0, KEY_READ, &hkey)
+ == ERROR_SUCCESS) {
+ keytype = REG_SZ;
+ cbData = *plen;
+ if (bptr == (char *)NULL)
+ bptr = &b; /* Registry API won't return ERROR_MORE_DATA */
+ /* if ptr is NULL */
+ rc = RegQueryValueEx(hkey, (char *)name, 0, &keytype, bptr, &cbData);
+ RegCloseKey(hkey);
+ if (rc == ERROR_SUCCESS) {
+ *plen = cbData;
+ return 0; /* found environment variable and copied it */
+ } else if (rc == ERROR_MORE_DATA) {
+ /* buffer wasn't large enough */
+ *plen = cbData;
+ return -1;
+ }
+ }
+ return 1; /* not found */
+}
diff --git a/gs/src/gpgetenv.h b/gs/src/gpgetenv.h
new file mode 100644
index 000000000..231e8bc46
--- /dev/null
+++ b/gs/src/gpgetenv.h
@@ -0,0 +1,44 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gpgetenv.h */
+/* Interface to platform-specific getenv routine */
+
+#ifndef gpgetenv_INCLUDED
+# define gpgetenv_INCLUDED
+
+/*
+ * Get a value from the environment (getenv).
+ *
+ * If the key is missing, set *ptr = 0 (if *plen > 0), set *plen = 1,
+ * and return 1.
+ *
+ * If the key is present and the length len of the value (not counting
+ * the terminating \0) is less than *plen, copy the value to ptr, set
+ * *plen = len + 1, and return 0.
+ *
+ * If the key is present and len >= *plen, set *plen = len + 1,
+ * don't store anything at ptr, and return -1.
+ *
+ * Note that *plen is the size of the buffer, not the length of the string:
+ * because of the terminating \0, the maximum string length is 1 less than
+ * the size of the buffer.
+ */
+int gp_getenv(P3(const char *key, char *ptr, int *plen));
+
+#endif /* gpgetenv_INCLUDED */
diff --git a/gs/src/gsalpha.c b/gs/src/gsalpha.c
new file mode 100644
index 000000000..6602d3b95
--- /dev/null
+++ b/gs/src/gsalpha.c
@@ -0,0 +1,42 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gsalpha.c */
+/* Graphics state alpha value access */
+#include "gx.h"
+#include "gsalpha.h"
+#include "gxdcolor.h"
+#include "gzstate.h"
+
+/* setalpha */
+int
+gs_setalpha(gs_state * pgs, floatp alpha)
+{
+ pgs->alpha =
+ (gx_color_value) (alpha < 0 ? 0 : alpha > 1 ? gx_max_color_value :
+ alpha * gx_max_color_value);
+ gx_unset_dev_color(pgs);
+ return 0;
+}
+
+/* currentalpha */
+float
+gs_currentalpha(const gs_state * pgs)
+{
+ return (float)pgs->alpha / gx_max_color_value;
+}
diff --git a/gs/src/gsalpha.h b/gs/src/gsalpha.h
new file mode 100644
index 000000000..0067fd043
--- /dev/null
+++ b/gs/src/gsalpha.h
@@ -0,0 +1,35 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gsalpha.h */
+/* API for alpha value in graphics state */
+
+#ifndef gsalpha_INCLUDED
+# define gsalpha_INCLUDED
+
+/*
+ * This tiny little file is separate so that it can be included by
+ * gsstate.c for initializing the alpha value, even in configurations
+ * that don't have full alpha support.
+ */
+
+/* Set/read alpha value. */
+int gs_setalpha(P2(gs_state *, floatp));
+float gs_currentalpha(P1(const gs_state *));
+
+#endif /* gsalpha_INCLUDED */
diff --git a/gs/src/gsalphac.c b/gs/src/gsalphac.c
new file mode 100644
index 000000000..00045ad46
--- /dev/null
+++ b/gs/src/gsalphac.c
@@ -0,0 +1,830 @@
+/* Copyright (C) 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gsalphac.c */
+/* Alpha-compositing implementation */
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsalphac.h"
+#include "gsiparam.h" /* for gs_image_alpha_t */
+#include "gsutil.h" /* for gs_next_ids */
+#include "gxalpha.h"
+#include "gxcomp.h"
+#include "gxdevice.h"
+#include "gxgetbit.h"
+#include "gxlum.h"
+
+/* ---------------- Internal definitions ---------------- */
+
+/* Define the parameters for a compositing operation. */
+typedef struct gs_composite_params_s {
+ gs_composite_op_t cop;
+ float delta; /* only for dissolve */
+ uint source_alpha; /* only if !psource->alpha */
+ uint source_values[4]; /* only if !psource->data */
+} gs_composite_params_t;
+
+/* Define the source or destination for a compositing operation. */
+#define pixel_row_fields(elt_type)\
+ elt_type *data;\
+ int bits_per_value; /* 1, 2, 4, 8, 12, 16 */\
+ int initial_x;\
+ gs_image_alpha_t alpha
+typedef struct pixel_row_s {
+ pixel_row_fields(byte);
+} pixel_row_t;
+typedef struct const_pixel_row_s {
+ pixel_row_fields(const byte);
+} const_pixel_row_t;
+
+/*
+ * Composite two arrays of (premultiplied) pixel values. Legal values of
+ * values_per_pixel are 1-4, not including alpha. Note that if pdest->alpha
+ * is "none", the alpha value for all destination pixels will be taken as
+ * unity, and any operation that could generate alpha values other than
+ * unity will return an error. "Could generate" means that there are
+ * possible values of the source and destination alpha values for which the
+ * result has non-unity alpha: the error check does not scan the actual
+ * alpha data to test whether there are any actual values that would
+ * generate a non-unity alpha result.
+ */
+int composite_values(P5(const pixel_row_t * pdest,
+ const const_pixel_row_t * psource,
+ int values_per_pixel, uint num_pixels,
+ const gs_composite_params_t * pcp));
+
+/* ---------------- Alpha-compositing objects ---------------- */
+
+/*
+ * Define which operations can generate non-unity alpha values in 3 of the 4
+ * cases of source and destination not having unity alphas. (This is always
+ * possible in the fourth case, both S & D non-unity, except for CLEAR.) We
+ * do this with a bit mask indexed by the operation, counting from the LSB.
+ * The name indicates whether S and/or D has non-unity alphas.
+ */
+#define alpha_out_notS_notD\
+ (1<<composite_Dissolve)
+#define _alpha_out_either\
+ (alpha_out_notS_notD|(1<<composite_Satop)|(1<<composite_Datop)|\
+ (1<<composite_Xor)|(1<<composite_PlusD)|(1<<composite_PlusL))
+#define alpha_out_S_notD\
+ (_alpha_out_either|(1<<composite_Copy)|(1<<composite_Sover)|\
+ (1<<composite_Din)|(1<<composite_Dout))
+#define alpha_out_notS_D\
+ (_alpha_out_either|(1<<composite_Sin)|(1<<composite_Sout)|\
+ (1<<composite_Dover)|(1<<composite_Highlight))
+
+/* ------ Object definition and creation ------ */
+
+/* Define alpha-compositing objects. */
+private composite_create_default_compositor_proc(c_alpha_create_default_compositor);
+private composite_equal_proc(c_alpha_equal);
+private composite_write_proc(c_alpha_write);
+private composite_read_proc(c_alpha_read);
+private const gs_composite_type_t gs_composite_alpha_type =
+{
+ {
+ c_alpha_create_default_compositor,
+ c_alpha_equal,
+ c_alpha_write,
+ c_alpha_read
+ }
+};
+typedef struct gs_composite_alpha_s {
+ gs_composite_common;
+ gs_composite_alpha_params_t params;
+} gs_composite_alpha_t;
+
+gs_private_st_simple(st_composite_alpha, gs_composite_alpha_t,
+ "gs_composite_alpha_t");
+
+/* Create an alpha-compositing object. */
+int
+gs_create_composite_alpha(gs_composite_t ** ppcte,
+ const gs_composite_alpha_params_t * params, gs_memory_t * mem)
+{
+ gs_composite_alpha_t *pcte;
+
+ rc_alloc_struct_0(pcte, gs_composite_alpha_t, &st_composite_alpha,
+ mem, return_error(gs_error_VMerror),
+ "gs_create_composite_alpha");
+ pcte->type = &gs_composite_alpha_type;
+ pcte->id = gs_next_ids(1);
+ pcte->params = *params;
+ *ppcte = (gs_composite_t *) pcte;
+ return 0;
+}
+
+/* ------ Object implementation ------ */
+
+#define pacte ((const gs_composite_alpha_t *)pcte)
+
+private bool
+c_alpha_equal(const gs_composite_t * pcte, const gs_composite_t * pcte2)
+{
+ return (pcte2->type == pcte->type &&
+#define pacte2 ((const gs_composite_alpha_t *)pcte2)
+ pacte2->params.op == pacte->params.op &&
+ (pacte->params.op != composite_Dissolve ||
+ pacte2->params.delta == pacte->params.delta));
+#undef pacte2
+}
+
+private int
+c_alpha_write(const gs_composite_t * pcte, byte * data, uint * psize)
+{
+ uint size = *psize;
+ uint used;
+
+ if (pacte->params.op == composite_Dissolve) {
+ used = 1 + sizeof(pacte->params.delta);
+ if (size < used) {
+ *psize = used;
+ return_error(gs_error_rangecheck);
+ }
+ memcpy(data + 1, &pacte->params.delta, sizeof(pacte->params.delta));
+ } else {
+ used = 1;
+ if (size < used) {
+ *psize = used;
+ return_error(gs_error_rangecheck);
+ }
+ }
+ *data = (byte) pacte->params.op;
+ *psize = used;
+ return 0;
+}
+
+private int
+c_alpha_read(gs_composite_t ** ppcte, const byte * data, uint size,
+ gs_memory_t * mem)
+{
+ gs_composite_alpha_params_t params;
+
+ if (size < 1 || *data > composite_op_last)
+ return_error(gs_error_rangecheck);
+ params.op = *data;
+ if (params.op == composite_Dissolve) {
+ if (size != 1 + sizeof(params.delta))
+ return_error(gs_error_rangecheck);
+ memcpy(&params.delta, data + 1, sizeof(params.delta));
+ } else {
+ if (size != 1)
+ return_error(gs_error_rangecheck);
+ }
+ return gs_create_composite_alpha(ppcte, &params, mem);
+}
+
+/* ---------------- Alpha-compositing device ---------------- */
+
+/* Define the default alpha-compositing device. */
+typedef struct gx_device_composite_alpha_s {
+ gx_device_forward_common;
+ gs_composite_alpha_params_t params;
+} gx_device_composite_alpha;
+
+gs_private_st_suffix_add0_final(st_device_composite_alpha,
+ gx_device_composite_alpha, "gx_device_composite_alpha",
+ device_c_alpha_enum_ptrs, device_c_alpha_reloc_ptrs, gx_device_finalize,
+ st_device_forward);
+/* The device descriptor. */
+private dev_proc_close_device(dca_close);
+private dev_proc_fill_rectangle(dca_fill_rectangle);
+private dev_proc_map_rgb_color(dca_map_rgb_color);
+private dev_proc_map_color_rgb(dca_map_color_rgb);
+private dev_proc_copy_mono(dca_copy_mono);
+private dev_proc_copy_color(dca_copy_color);
+private dev_proc_map_rgb_alpha_color(dca_map_rgb_alpha_color);
+private dev_proc_map_color_rgb_alpha(dca_map_color_rgb_alpha);
+private dev_proc_copy_alpha(dca_copy_alpha);
+private const gx_device_composite_alpha gs_composite_alpha_device =
+{std_device_std_body_open(gx_device_composite_alpha, 0,
+ "alpha compositor", 0, 0, 1, 1),
+ {gx_default_open_device,
+ gx_forward_get_initial_matrix,
+ gx_default_sync_output,
+ gx_default_output_page,
+ dca_close,
+ dca_map_rgb_color,
+ dca_map_color_rgb,
+ dca_fill_rectangle,
+ gx_default_tile_rectangle,
+ dca_copy_mono,
+ dca_copy_color,
+ gx_default_draw_line,
+ gx_default_get_bits,
+ gx_forward_get_params,
+ gx_forward_put_params,
+ gx_default_cmyk_map_cmyk_color, /* only called for CMYK */
+ gx_forward_get_xfont_procs,
+ gx_forward_get_xfont_device,
+ dca_map_rgb_alpha_color,
+ gx_forward_get_page_device,
+ gx_forward_get_alpha_bits,
+ dca_copy_alpha,
+ gx_forward_get_band,
+ gx_default_copy_rop,
+ gx_default_fill_path,
+ gx_default_stroke_path,
+ gx_default_fill_mask,
+ gx_default_fill_trapezoid,
+ gx_default_fill_parallelogram,
+ gx_default_fill_triangle,
+ gx_default_draw_thin_line,
+ gx_default_begin_image,
+ gx_default_image_data,
+ gx_default_end_image,
+ gx_default_strip_tile_rectangle,
+ gx_default_strip_copy_rop,
+ gx_forward_get_clipping_box,
+ gx_default_begin_typed_image,
+ gx_forward_get_bits_rectangle,
+ dca_map_color_rgb_alpha,
+ gx_no_create_compositor
+ }
+};
+
+/* Create an alpha compositor. */
+int
+c_alpha_create_default_compositor(const gs_composite_t * pcte,
+ gx_device ** pcdev, gx_device * dev, const gs_imager_state * pis,
+ gs_memory_t * mem)
+{
+ gx_device_composite_alpha *cdev;
+
+ if (pacte->params.op == composite_Copy) {
+ /* Just use the original device. */
+ *pcdev = dev;
+ return 0;
+ }
+ cdev =
+ gs_alloc_struct_immovable(mem, gx_device_composite_alpha,
+ &st_device_composite_alpha,
+ "create default alpha compositor");
+ *pcdev = (gx_device *) cdev;
+ if (cdev == 0)
+ return_error(gs_error_VMerror);
+ *(gx_device *) cdev = *dev;
+ cdev->dname = gs_composite_alpha_device.dname;
+ cdev->memory = mem;
+ cdev->stype = &st_device_composite_alpha;
+ /*
+ * Set the color_info and depth to be compatible with the target,
+ * but using standard chunky color storage, including alpha.
+ ****** CURRENTLY ALWAYS USE 8-BIT COLOR ******
+ */
+ cdev->color_info.depth =
+ (dev->color_info.num_components == 4 ? 32 /* CMYK, no alpha */ :
+ (dev->color_info.num_components + 1) * 8);
+ cdev->color_info.max_gray = cdev->color_info.max_color = 255;
+ /* No halftoning will occur, but we fill these in anyway.... */
+ cdev->color_info.dither_grays = cdev->color_info.dither_colors = 256;
+ assign_dev_procs(cdev, &gs_composite_alpha_device);
+ /*
+ * We could speed things up a little by tailoring the procedures in
+ * the device to the specific num_components, but for simplicity,
+ * we'll defer considering that until there is a demonstrated need.
+ */
+ cdev->target = dev;
+ cdev->params = pacte->params;
+ return 0;
+}
+
+/* Close the device and free its storage. */
+private int
+dca_close(gx_device * dev)
+{ /*
+ * Finalization will call close again: avoid a recursion loop.
+ */
+ set_dev_proc(dev, close_device, gx_default_close_device);
+ gs_free_object(dev->memory, dev, "dca_close");
+ return 0;
+}
+
+/* ------ (RGB) color mapping ------ */
+
+private gx_color_index
+dca_map_rgb_color(gx_device * dev,
+ gx_color_value r, gx_color_value g, gx_color_value b)
+{
+ return dca_map_rgb_alpha_color(dev, r, g, b, gx_max_color_value);
+}
+private gx_color_index
+dca_map_rgb_alpha_color(gx_device * dev,
+ gx_color_value red, gx_color_value green, gx_color_value blue,
+ gx_color_value alpha)
+{ /*
+ * We work exclusively with premultiplied color values, so we
+ * have to premultiply the color components by alpha here.
+ */
+ byte a = gx_color_value_to_byte(alpha);
+
+#define premult_(c)\
+ (((c) * a + gx_max_color_value / 2) / gx_max_color_value)
+#ifdef PREMULTIPLY_TOWARDS_WHITE
+ byte bias = ~a;
+
+# define premult(c) (premult_(c) + bias)
+#else
+# define premult(c) premult_(c)
+#endif
+ gx_color_index color;
+
+ if (dev->color_info.num_components == 1) {
+ uint lum =
+ (red * lum_red_weight + green * lum_green_weight +
+ blue * lum_blue_weight + lum_all_weights / 2) /
+ lum_all_weights;
+
+ if (a == 0xff)
+ color = gx_color_value_to_byte(lum);
+ else /* Premultiplication is necessary. */
+ color = premult(lum);
+ } else {
+ if (a == 0xff)
+ color =
+ ((uint) gx_color_value_to_byte(red) << 16) +
+ ((uint) gx_color_value_to_byte(green) << 8) +
+ gx_color_value_to_byte(blue);
+ else /* Premultiplication is necessary. */
+ color =
+ (premult(red) << 16) + (premult(green) << 8) + premult(blue);
+ }
+#undef premult
+ return (color << 8) + a;
+}
+private int
+dca_map_color_rgb(gx_device * dev, gx_color_index color,
+ gx_color_value prgb[3])
+{
+ gx_color_value red = gx_color_value_from_byte((byte) (color >> 24));
+ byte a = (byte) color;
+
+#define postdiv_(c)\
+ (((c) * 0xff + a / 2) / a)
+#ifdef PREMULTIPLY_TOWARDS_WHITE
+ byte bias = ~a;
+
+# define postdiv(c) postdiv_(c - bias)
+#else
+# define postdiv(c) postdiv_(c)
+#endif
+
+ if (dev->color_info.num_components == 1) {
+ if (a != 0xff) {
+ /* Undo premultiplication. */
+ if (a == 0)
+ red = 0;
+ else
+ red = postdiv(red);
+ }
+ prgb[0] = prgb[1] = prgb[2] = red;
+ } else {
+ gx_color_value
+ green = gx_color_value_from_byte((byte) (color >> 16)),
+ blue = gx_color_value_from_byte((byte) (color >> 8));
+
+ if (a != 0xff) {
+ /* Undo premultiplication. */
+/****** WHAT TO DO ABOUT BIG LOSS OF PRECISION? ******/
+ if (a == 0)
+ red = green = blue = 0;
+ else {
+ red = postdiv(red);
+ green = postdiv(green);
+ blue = postdiv(blue);
+ }
+ }
+ prgb[0] = red, prgb[1] = green, prgb[2] = blue;
+ }
+#undef postdiv
+ return 0;
+}
+private int
+dca_map_color_rgb_alpha(gx_device * dev, gx_color_index color,
+ gx_color_value prgba[4])
+{
+ prgba[3] = gx_color_value_from_byte((byte) color);
+ return dca_map_color_rgb(dev, color, prgba);
+}
+
+/* ------ Imaging ------ */
+
+private int
+dca_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
+ gx_color_index color)
+{ /* This is where all the real work gets done! */
+ gx_device_composite_alpha *adev = (gx_device_composite_alpha *) dev;
+ gx_device *target = adev->target;
+ byte *std_row;
+ byte *native_row;
+ gs_int_rect rect;
+ gs_get_bits_params_t std_params, native_params;
+ int code = 0;
+ int yi;
+ gs_composite_params_t cp;
+ const_pixel_row_t source;
+ pixel_row_t dest;
+
+ fit_fill(dev, x, y, w, h);
+ std_row = gs_alloc_bytes(dev->memory,
+ (dev->color_info.depth * w + 7) >> 3,
+ "dca_fill_rectangle(std)");
+ native_row = gs_alloc_bytes(dev->memory,
+ (target->color_info.depth * w + 7) >> 3,
+ "dca_fill_rectangle(native)");
+ if (std_row == 0 || native_row == 0) {
+ code = gs_note_error(gs_error_VMerror);
+ goto out;
+ }
+ rect.p.x = x, rect.q.x = x + w;
+ std_params.options =
+ gb_colors_for_device(dev) |
+ (GB_ALPHA_LAST | GB_DEPTH_8 | GB_PACKING_CHUNKY |
+ GB_RETURN_COPY | GB_RETURN_POINTER | GB_ALIGN_ANY |
+ GB_OFFSET_0 | GB_OFFSET_ANY | GB_RASTER_STANDARD |
+ GB_RASTER_ANY);
+ cp.cop = adev->params.op;
+ if (cp.cop == composite_Dissolve)
+ cp.delta = adev->params.delta;
+ {
+ gx_color_value rgba[4];
+
+/****** DOESN'T HANDLE CMYK ******/
+ (*dev_proc(dev, map_color_rgb_alpha)) (dev, color, rgba);
+ cp.source_values[0] = gx_color_value_to_byte(rgba[0]);
+ cp.source_values[1] = gx_color_value_to_byte(rgba[1]);
+ cp.source_values[2] = gx_color_value_to_byte(rgba[2]);
+ cp.source_alpha = gx_color_value_to_byte(rgba[3]);
+ }
+ source.data = 0;
+ source.bits_per_value = 8;
+ source.alpha = gs_image_alpha_none;
+ for (yi = y; yi < y + h; ++yi) {
+ /* Read a row in standard representation. */
+ rect.p.y = yi, rect.q.y = yi + 1;
+ std_params.data[0] = std_row;
+ code = (*dev_proc(target, get_bits_rectangle))
+ (target, &rect, &std_params, NULL);
+ if (code < 0)
+ break;
+ /* Do the work. */
+ dest.data = std_params.data[0];
+ dest.bits_per_value = 8;
+ dest.initial_x =
+ (std_params.options & GB_OFFSET_ANY ? std_params.x_offset : 0);
+ dest.alpha =
+ (std_params.options & GB_ALPHA_FIRST ? gs_image_alpha_first :
+ std_params.options & GB_ALPHA_LAST ? gs_image_alpha_last :
+ gs_image_alpha_none);
+ code = composite_values(&dest, &source,
+ dev->color_info.num_components, w, &cp);
+ if (code < 0)
+ break;
+ if (std_params.data[0] == std_row) {
+ /* Convert the row back to native representation. */
+ /* (Otherwise, we had a direct pointer to device data.) */
+ native_params.options =
+ (GB_COLORS_NATIVE | GB_PACKING_CHUNKY | GB_RETURN_COPY |
+ GB_OFFSET_0 | GB_RASTER_ALL | GB_ALIGN_STANDARD);
+ native_params.data[0] = native_row;
+ code = gx_get_bits_copy(target, 0, w, 1, &native_params,
+ std_params.options, std_row,
+ 0 /* raster is irrelevant */ );
+ if (code < 0)
+ break;
+ code = (*dev_proc(target, copy_color))
+ (target, native_row, 0, 0 /* raster is irrelevant */ ,
+ gx_no_bitmap_id, x, yi, w, 1);
+ if (code < 0)
+ break;
+ }
+ }
+ out:gs_free_object(dev->memory, native_row, "dca_fill_rectangle(native)");
+ gs_free_object(dev->memory, std_row, "dca_fill_rectangle(std)");
+ return code;
+}
+
+private int
+dca_copy_mono(gx_device * dev, const byte * data,
+ int dx, int raster, gx_bitmap_id id, int x, int y, int w, int h,
+ gx_color_index zero, gx_color_index one)
+{
+/****** TEMPORARY ******/
+ return gx_default_copy_mono(dev, data, dx, raster, id, x, y, w, h,
+ zero, one);
+}
+
+private int
+dca_copy_color(gx_device * dev, const byte * data,
+ int dx, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{
+/****** TEMPORARY ******/
+ return gx_default_copy_color(dev, data, dx, raster, id, x, y, w, h);
+}
+
+private int
+dca_copy_alpha(gx_device * dev, const byte * data, int data_x,
+ int raster, gx_bitmap_id id, int x, int y, int width, int height,
+ gx_color_index color, int depth)
+{
+/****** TEMPORARY ******/
+ return gx_default_copy_alpha(dev, data, data_x, raster, id, x, y,
+ width, height, color, depth);
+}
+
+/*
+ * Composite two arrays of (premultiplied) pixel values.
+ * See gsdpnext.h for the specification.
+ *
+ * The current implementation is simple but inefficient. We'll speed it up
+ * later if necessary.
+ */
+int
+composite_values(const pixel_row_t * pdest, const const_pixel_row_t * psource,
+ int values_per_pixel, uint num_pixels, const gs_composite_params_t * pcp)
+{
+ int dest_bpv = pdest->bits_per_value;
+ int source_bpv = psource->bits_per_value;
+
+ /*
+ * source_alpha_j gives the source component index for the alpha value,
+ * if the source has alpha.
+ */
+ int source_alpha_j =
+ (psource->alpha == gs_image_alpha_last ? values_per_pixel :
+ psource->alpha == gs_image_alpha_first ? 0 : -1);
+
+ /* dest_alpha_j does the same for the destination. */
+ int dest_alpha_j =
+ (pdest->alpha == gs_image_alpha_last ? values_per_pixel :
+ pdest->alpha == gs_image_alpha_first ? 0 : -1);
+
+ /* dest_vpp is the number of stored destination values. */
+ int dest_vpp = values_per_pixel + (dest_alpha_j >= 0);
+
+ /* source_vpp is the number of stored source values. */
+ int source_vpp = values_per_pixel + (source_alpha_j >= 0);
+
+ bool constant_colors = psource->data == 0;
+ uint highlight_value = (1 << dest_bpv) - 1;
+
+ sample_load_declare(sptr, sbit);
+ sample_store_declare(dptr, dbit, dbyte);
+
+ {
+ uint xbit = pdest->initial_x * dest_bpv * dest_vpp;
+
+ sample_store_setup(dbit, xbit & 7, dest_bpv);
+ dptr = pdest->data + (xbit >> 3);
+ }
+ {
+ uint xbit = psource->initial_x * source_bpv * source_vpp;
+
+ sbit = xbit & 7;
+ sptr = psource->data + (xbit >> 3);
+ }
+ {
+ uint source_max = (1 << source_bpv) - 1;
+ uint dest_max = (1 << dest_bpv) - 1;
+
+ /*
+ * We could save a little work by only setting up source_delta
+ * and dest_delta if the operation is Dissolve.
+ */
+ float source_delta = pcp->delta * dest_max / source_max;
+ float dest_delta = 1.0 - pcp->delta;
+ uint source_alpha = pcp->source_alpha;
+ uint dest_alpha = dest_max;
+
+#ifdef PREMULTIPLY_TOWARDS_WHITE
+ uint source_bias = source_max - source_alpha;
+ uint dest_bias = 0;
+ uint result_bias = 0;
+
+#endif
+ uint x;
+
+ if (!pdest->alpha) {
+ uint mask =
+ (psource->alpha || source_alpha != source_max ?
+ alpha_out_S_notD : alpha_out_notS_notD);
+
+ if ((mask >> pcp->cop) & 1) {
+ /*
+ * The operation could produce non-unity alpha values, but
+ * the destination can't store them. Return an error.
+ */
+ return_error(gs_error_rangecheck);
+ }
+ }
+ /* Preload the output byte buffer if necessary. */
+ sample_store_preload(dbyte, dptr, dbit, dest_bpv);
+
+ for (x = 0; x < num_pixels; ++x) {
+ int j;
+ uint result_alpha = dest_alpha;
+
+/* get_value does not increment the source pointer. */
+#define get_value(v, ptr, bit, bpv, vmax)\
+ sample_load16(v, ptr, bit, bpv)
+
+/* put_value increments the destination pointer. */
+#define put_value(v, ptr, bit, bpv, bbyte)\
+ sample_store_next16(v, ptr, bit, bpv, bbyte)
+
+#define advance(ptr, bit, bpv)\
+ sample_next(ptr, bit, bpv)
+
+ /* Get destination alpha value. */
+ if (dest_alpha_j >= 0) {
+ int dabit = dbit + dest_bpv * dest_alpha_j;
+ const byte *daptr = dptr + (dabit >> 3);
+
+ get_value(dest_alpha, daptr, dabit & 7, dest_bpv, dest_max);
+#ifdef PREMULTIPLY_TOWARDS_WHITE
+ dest_bias = dest_max - dest_alpha;
+#endif
+ }
+ /* Get source alpha value. */
+ if (source_alpha_j >= 0) {
+ int sabit = sbit;
+ const byte *saptr = sptr;
+
+ if (source_alpha_j == 0)
+ advance(sptr, sbit, source_bpv);
+ else
+ advance(saptr, sabit, source_bpv * source_alpha_j);
+ get_value(source_alpha, saptr, sabit, source_bpv, source_max);
+#ifdef PREMULTIPLY_TOWARDS_WHITE
+ source_bias = source_max - source_alpha;
+#endif
+ }
+/*
+ * We are always multiplying a dest value by a source value to compute a
+ * dest value, so the denominator is always source_max. (Dissolve is the
+ * one exception.)
+ */
+#define fr(v, a) ((v) * (a) / source_max)
+#define nfr(v, a, maxv) ((v) * (maxv - (a)) / source_max)
+
+ /*
+ * Iterate over the components of a single pixel.
+ * j = 0 for alpha, 1 .. values_per_pixel for color
+ * components, regardless of the actual storage order;
+ * we arrange things so that sptr/sbit and dptr/dbit
+ * always point to the right place.
+ */
+ for (j = 0; j <= values_per_pixel; ++j) {
+ uint dest_v, source_v, result;
+
+#define set_clamped(r, v)\
+ BEGIN if ( (r = (v)) > dest_max ) r = dest_max; END
+
+ if (j == 0) {
+ source_v = source_alpha;
+ dest_v = dest_alpha;
+ } else {
+ if (constant_colors)
+ source_v = pcp->source_values[j - 1];
+ else {
+ get_value(source_v, sptr, sbit, source_bpv, source_max);
+ advance(sptr, sbit, source_bpv);
+ }
+ get_value(dest_v, dptr, dbit, dest_bpv, dest_max);
+#ifdef PREMULTIPLY_TOWARDS_WHITE
+ source_v -= source_bias;
+ dest_v -= dest_bias;
+#endif
+ }
+
+ switch (pcp->cop) {
+ case composite_Clear:
+ /*
+ * The NeXT documentation doesn't say this, but the CLEAR
+ * operation sets not only alpha but also all the color
+ * values to 0.
+ */
+ result = 0;
+ break;
+ case composite_Copy:
+ result = source_v;
+ break;
+ case composite_PlusD:
+ /*
+ * This is the only case where we have to worry about
+ * clamping a possibly negative result.
+ */
+ result = source_v + dest_v;
+ result = (result < dest_max ? 0 : result - dest_max);
+ break;
+ case composite_PlusL:
+ set_clamped(result, source_v + dest_v);
+ break;
+ case composite_Sover:
+ set_clamped(result, source_v + nfr(dest_v, source_alpha, source_max));
+ break;
+ case composite_Dover:
+ set_clamped(result, nfr(source_v, dest_alpha, dest_max) + dest_v);
+ break;
+ case composite_Sin:
+ result = fr(source_v, dest_alpha);
+ break;
+ case composite_Din:
+ result = fr(dest_v, source_alpha);
+ break;
+ case composite_Sout:
+ result = nfr(source_v, dest_alpha, dest_max);
+ break;
+ case composite_Dout:
+ result = nfr(dest_v, source_alpha, source_max);
+ break;
+ case composite_Satop:
+ set_clamped(result, fr(source_v, dest_alpha) +
+ nfr(dest_v, source_alpha, source_max));
+ break;
+ case composite_Datop:
+ set_clamped(result, nfr(source_v, dest_alpha, dest_max) +
+ fr(dest_v, source_alpha));
+ break;
+ case composite_Xor:
+ set_clamped(result, nfr(source_v, dest_alpha, dest_max) +
+ nfr(dest_v, source_alpha, source_max));
+ break;
+ case composite_Highlight:
+ /*
+ * Bizarre but true: this operation converts white and
+ * light gray into each other, and leaves all other values
+ * unchanged. We only implement it properly for gray-scale
+ * devices.
+ */
+ if (j != 0 && !((source_v ^ highlight_value) & ~1))
+ result = source_v ^ 1;
+ else
+ result = source_v;
+ break;
+ case composite_Dissolve:
+ /*
+ * In this case, and only this case, we need to worry about
+ * source and dest having different bpv values. For the
+ * moment, we wimp out and do everything in floating point.
+ */
+ result = (uint) (source_v * source_delta + dest_v * dest_delta);
+ break;
+ default:
+ return_error(gs_error_rangecheck);
+ }
+ /*
+ * Store the result. We don't have to worry about
+ * destinations that don't store alpha, because we don't
+ * even compute an alpha value in that case.
+ */
+#ifdef PREMULTIPLY_TOWARDS_WHITE
+ if (j == 0) {
+ result_alpha = result;
+ result_bias = dest_max - result_alpha;
+ if (dest_alpha_j != 0)
+ continue;
+ } else {
+ result += result_bias;
+ }
+#else
+ if (j == 0 && dest_alpha_j != 0) {
+ result_alpha = result;
+ continue;
+ }
+#endif
+ put_value(result, dptr, dbit, dest_bpv, dbyte);
+ }
+ /* Skip a trailing source alpha value. */
+ if (source_alpha_j > 0)
+ advance(sptr, sbit, source_bpv);
+ /* Store a trailing destination alpha value. */
+ if (dest_alpha_j > 0)
+ put_value(result_alpha, dptr, dbit, dest_bpv, dbyte);
+#undef get_value
+#undef put_value
+#undef advance
+ }
+ /* Store any partial output byte. */
+ sample_store_flush(dptr, dbit, dest_bpv, dbyte);
+ }
+ return 0;
+}
diff --git a/gs/src/gsalphac.h b/gs/src/gsalphac.h
new file mode 100644
index 000000000..69d70a03e
--- /dev/null
+++ b/gs/src/gsalphac.h
@@ -0,0 +1,65 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gsalphac.h */
+/* Alpha-compositing interface */
+
+#ifndef gsalphac_INCLUDED
+# define gsalphac_INCLUDED
+
+#include "gscompt.h"
+
+/*
+ * Define the compositing operations. These values must match the ones in
+ * dpsNeXT.h.
+ */
+typedef enum {
+ composite_Clear = 0,
+ composite_Copy,
+ composite_Sover,
+ composite_Sin,
+ composite_Sout,
+ composite_Satop,
+ composite_Dover,
+ composite_Din,
+ composite_Dout,
+ composite_Datop,
+ composite_Xor,
+ composite_PlusD,
+ composite_PlusL,
+#define composite_last composite_PlusL
+ composite_Highlight, /* (only for compositerect) */
+#define compositerect_last composite_Highlight
+ composite_Dissolve /* (not for PostScript composite operators) */
+#define composite_op_last composite_Dissolve
+} gs_composite_op_t;
+
+/*
+ * Define parameters for alpha-compositing.
+ */
+typedef struct gs_composite_alpha_params_s {
+ gs_composite_op_t op;
+ float delta; /* only for Dissolve */
+} gs_composite_alpha_params_t;
+
+/* Create an alpha-compositing object. */
+int gs_create_composite_alpha(P3(gs_composite_t ** ppcte,
+ const gs_composite_alpha_params_t * params,
+ gs_memory_t * mem));
+
+#endif /* gsalphac_INCLUDED */
diff --git a/gs/src/gscdevn.c b/gs/src/gscdevn.c
new file mode 100644
index 000000000..4f3b4f760
--- /dev/null
+++ b/gs/src/gscdevn.c
@@ -0,0 +1,178 @@
+/* Copyright (C) 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gscdevn.c */
+/* DeviceN color space and operation definition */
+#include "gx.h"
+#include "gserrors.h"
+#include "gsrefct.h"
+#include "gsmatrix.h" /* for gscolor2.h */
+#include "gxcspace.h"
+
+gs_private_st_composite(st_color_space_DeviceN, gs_paint_color_space,
+ "gs_color_space_DeviceN", cs_DeviceN_enum_ptrs, cs_DeviceN_reloc_ptrs);
+
+/* Define the DeviceN color space type. */
+cs_declare_procs(private, gx_concretize_DeviceN, gx_install_DeviceN,
+ gx_adjust_cspace_DeviceN);
+private cs_proc_num_components(gx_num_components_DeviceN);
+private cs_proc_base_space(gx_alt_space_DeviceN);
+private cs_proc_restrict_color(gx_restrict_DeviceN);
+private cs_proc_concrete_space(gx_concrete_space_DeviceN);
+private cs_proc_remap_concrete_color(gx_remap_concrete_DeviceN);
+private cs_proc_init_color(gx_init_DeviceN);
+const gs_color_space_type gs_color_space_type_DeviceN = {
+ gs_color_space_index_DeviceN, true, false,
+ &st_color_space_DeviceN, gx_num_components_DeviceN,
+ gx_alt_space_DeviceN,
+ gx_init_DeviceN, gx_restrict_DeviceN,
+ gx_concrete_space_DeviceN,
+ gx_concretize_DeviceN, gx_remap_concrete_DeviceN,
+ gx_default_remap_color, gx_install_DeviceN,
+ gx_adjust_cspace_DeviceN, gx_no_adjust_color_count
+};
+
+/* ------ Internal routines ------ */
+
+/* Return the number of components of a DeviceN space. */
+private int
+gx_num_components_DeviceN(const gs_color_space * pcs)
+{
+ return pcs->params.device_n.num_components;
+}
+
+/* Return the alternate space of a DeviceN space. */
+private const gs_color_space *
+gx_alt_space_DeviceN(const gs_color_space * pcs)
+{
+ return (const gs_color_space *)&(pcs->params.device_n.alt_space);
+}
+
+/* Initialize a DeviceN color. */
+/****** DOESN'T WORK IF num_components > 4 ******/
+private void
+gx_init_DeviceN(gs_client_color * pcc, const gs_color_space * pcs)
+{
+ int i;
+
+ for (i = 0; i < pcs->params.device_n.num_components; ++i)
+ pcc->paint.values[i] = 1.0;
+}
+
+/* Force a DeviceN color into legal range. */
+private void
+gx_restrict_DeviceN(gs_client_color * pcc, const gs_color_space * pcs)
+{
+ int i;
+
+ for (i = 0; i < pcs->params.device_n.num_components; ++i) {
+ floatp value = pcc->paint.values[i];
+
+ pcc->paint.values[i] = (value <= 0 ? 0 : value >= 1 ? 1 : value);
+ }
+}
+
+/* Remap a DeviceN color. */
+private const gs_color_space *
+gx_concrete_space_DeviceN(const gs_color_space * pcs,
+ const gs_imager_state * pis)
+{ /* We don't support concrete DeviceN spaces yet. */
+ const gs_color_space *pacs =
+ (const gs_color_space *)&pcs->params.device_n.alt_space;
+
+ return cs_concrete_space(pacs, pis);
+}
+
+private int
+gx_concretize_DeviceN(const gs_client_color * pc, const gs_color_space * pcs,
+ frac * pconc, const gs_imager_state * pis)
+{
+ int code;
+ gs_client_color cc;
+ const gs_color_space *pacs =
+ (const gs_color_space *)&pcs->params.device_n.alt_space;
+
+ /* We always map into the alternate color space. */
+ code = (*pcs->params.device_n.tint_transform)
+ (&pcs->params.device_n, pc->paint.values, &cc.paint.values[0],
+ pcs->params.device_n.tint_transform_data);
+ if (code < 0)
+ return code;
+ return (*pacs->type->concretize_color) (&cc, pacs, pconc, pis);
+}
+
+private int
+gx_remap_concrete_DeviceN(const frac * pconc,
+ gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
+ gs_color_select_t select)
+{ /* We don't support concrete DeviceN colors yet. */
+ return_error(gs_error_rangecheck);
+}
+
+/* Install a DeviceN color space. */
+private int
+gx_install_DeviceN(gs_color_space * pcs, gs_state * pgs)
+{ /*
+ * Give an error if any of the separation names are duplicated.
+ * We can't check this any earlier.
+ */
+ const gs_separation_name *names = pcs->params.device_n.names;
+ uint i, j;
+
+ for (i = 1; i < pcs->params.device_n.num_components; ++i)
+ for (j = 0; j < i; ++j)
+ if (names[i] == names[j])
+ return_error(gs_error_rangecheck);
+ return (*pcs->params.device_n.alt_space.type->install_cspace)
+ ((gs_color_space *) & pcs->params.device_n.alt_space, pgs);
+}
+
+/* Adjust the reference count of a DeviceN color space. */
+private void
+gx_adjust_cspace_DeviceN(const gs_color_space * pcs, gs_memory_t * mem,
+ int delta)
+{
+ (*pcs->params.device_n.alt_space.type->adjust_cspace_count)
+ ((const gs_color_space *)&pcs->params.device_n.alt_space, mem, delta);
+}
+
+/* GC procedures */
+
+#define pcs ((gs_color_space *)vptr)
+
+private
+ENUM_PTRS_BEGIN(cs_DeviceN_enum_ptrs)
+{
+ return ENUM_USING(*pcs->params.device_n.alt_space.type->stype,
+ &pcs->params.device_n.alt_space,
+ sizeof(pcs->params.device_n.alt_space), index - 2);
+}
+ENUM_PTR(0, gs_color_space, params.device_n.names);
+ENUM_PTR(1, gs_color_space, params.device_n.tint_transform_data);
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(cs_DeviceN_reloc_ptrs)
+{
+ RELOC_PTR(gs_color_space, params.device_n.names);
+ RELOC_PTR(gs_color_space, params.device_n.tint_transform_data);
+ RELOC_USING(*pcs->params.device_n.alt_space.type->stype,
+ &pcs->params.device_n.alt_space,
+ sizeof(gs_base_color_space));
+}
+RELOC_PTRS_END
+
+#undef pcs
diff --git a/gs/src/gscolor3.c b/gs/src/gscolor3.c
new file mode 100644
index 000000000..a38028f55
--- /dev/null
+++ b/gs/src/gscolor3.c
@@ -0,0 +1,67 @@
+/* Copyright (C) 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gscolor3.c */
+/* "Operators" for LanguageLevel 3 color facilities */
+#include "gx.h"
+#include "gserrors.h"
+#include "gscspace.h" /* for gscolor2.h */
+#include "gsmatrix.h" /* for gscolor2.h */
+#include "gscolor2.h"
+#include "gscolor3.h"
+#include "gspath.h"
+#include "gzstate.h"
+#include "gxshade.h"
+
+/* setsmoothness */
+int
+gs_setsmoothness(gs_state * pgs, floatp smoothness)
+{
+ pgs->smoothness =
+ (smoothness < 0 ? 0 : smoothness > 1 ? 1 : smoothness);
+ return 0;
+}
+
+/* currentsmoothness */
+float
+gs_currentsmoothness(const gs_state * pgs)
+{
+ return pgs->smoothness;
+}
+
+/* shfill */
+int
+gs_shfill(gs_state * pgs, const gs_shading_t * psh)
+{
+ int code = gs_gsave(pgs);
+ gs_rect rect;
+
+ if (code < 0)
+ return code;
+/****** DOESN'T USE Background, BBox ******/
+ if ((code = gs_setcolorspace(pgs, psh->params.ColorSpace)) < 0 ||
+ (code = gs_clippath(pgs)) < 0 ||
+ (code = gs_pathbbox(pgs, &rect)) < 0 ||
+ (code = gs_shading_fill_rectangle(psh, &rect,
+ gs_currentdevice(pgs),
+ (gs_imager_state *) pgs)) < 0
+ )
+ DO_NOTHING;
+ gs_grestore(pgs);
+ return code;
+}
diff --git a/gs/src/gscolor3.h b/gs/src/gscolor3.h
new file mode 100644
index 000000000..f17a994d2
--- /dev/null
+++ b/gs/src/gscolor3.h
@@ -0,0 +1,35 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gscolor3.h */
+/* Client interface to LanguageLevel 3 color facilities */
+
+#ifndef gscolor3_INCLUDED
+# define gscolor3_INCLUDED
+
+/* Smooth shading */
+#ifndef gs_shading_t_DEFINED
+# define gs_shading_t_DEFINED
+typedef struct gs_shading_s gs_shading_t;
+
+#endif
+int gs_setsmoothness(P2(gs_state *, floatp));
+float gs_currentsmoothness(P1(const gs_state *));
+int gs_shfill(P2(gs_state *, const gs_shading_t *));
+
+#endif /* gscolor3_INCLUDED */
diff --git a/gs/src/gscompt.h b/gs/src/gscompt.h
new file mode 100644
index 000000000..ed041769b
--- /dev/null
+++ b/gs/src/gscompt.h
@@ -0,0 +1,53 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gscompt.h */
+/* Abstract types for compositing objects */
+
+#ifndef gscompt_INCLUDED
+# define gscompt_INCLUDED
+
+/*
+ * Compositing is the next-to-last step in the rendering pipeline.
+ * It occurs after color correction but before halftoning (if needed).
+ *
+ * gs_composite_t is the abstract superclass for compositing functions such
+ * as RasterOp functions or alpha-based compositing. Concrete subclasses
+ * must provide a default implementation (presumably based on
+ * get_bits_rectangle and copy_color) for devices that provide no optimized
+ * implementation of their own.
+ *
+ * A client that wants to produce composited output asks the target device
+ * to create an appropriate compositing device based on the target device
+ * and the gs_composite_t (and possibly other elements of the imager state).
+ * If the target device doesn't have its own implementation for the
+ * requested function, format, and state, it passes the buck to the
+ * gs_composite_t, which may make further tests for special cases before
+ * creating and returning a compositing device that uses the default
+ * implementation.
+ */
+typedef struct gs_composite_s gs_composite_t;
+
+/*
+ * To enable fast cache lookup and equality testing, compositing functions,
+ * like halftones, black generation functions, etc., carry a unique ID (time
+ * stamp).
+ */
+gs_id gs_composite_id(P1(const gs_composite_t * pcte));
+
+#endif /* gscompt_INCLUDED */
diff --git a/gs/src/gscparam.c b/gs/src/gscparam.c
new file mode 100644
index 000000000..b7592f894
--- /dev/null
+++ b/gs/src/gscparam.c
@@ -0,0 +1,474 @@
+/* Copyright (C) 1995, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gscparam.c */
+/* Default implementation of parameter lists */
+#include "memory_.h"
+#include "string_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsparam.h"
+#include "gsstruct.h"
+
+/* Forward references */
+typedef union c_param_value_s {
+ GS_PARAM_VALUE_UNION(gs_c_param_list);
+} gs_c_param_value;
+/*typedef struct gs_c_param_s gs_c_param; *//* in gsparam.h */
+
+/* Define the GC type for a parameter list. */
+private_st_c_param_list();
+
+/* Lengths corresponding to various gs_param_type_xxx types */
+const byte gs_param_type_sizes[] = {
+ GS_PARAM_TYPE_SIZES(sizeof(gs_c_param_list))
+};
+
+/* Lengths of *actual* data-containing type pointed to or contained by gs_param_type_xxx's */
+const byte gs_param_type_base_sizes[] = {
+ GS_PARAM_TYPE_BASE_SIZES(0)
+};
+
+/*
+ * Define a parameter list element. We use gs_param_type_any to identify
+ * elements that have been requested but not yet written. The reading
+ * procedures must recognize such elements as undefined, and ignore them.
+ */
+struct gs_c_param_s {
+ gs_c_param *next;
+ gs_param_name key;
+ gs_c_param_value value;
+ gs_param_type type;
+ void *alternate_typed_data;
+};
+
+/* Parameter values aren't really simple, */
+/* but since parameter lists are transient, it doesn't matter. */
+gs_private_st_ptrs2(st_c_param, gs_c_param, "gs_c_param",
+ c_param_enum_ptrs, c_param_reloc_ptrs, next, alternate_typed_data);
+
+/* ---------------- Utilities ---------------- */
+
+private gs_c_param *
+c_param_find(const gs_c_param_list * plist, gs_param_name pkey, bool any)
+{
+ gs_c_param *pparam = plist->head;
+
+ for (; pparam != 0; pparam = pparam->next)
+ if (!strcmp(pparam->key, pkey))
+ return (pparam->type != gs_param_type_any || any ? pparam : 0);
+ return 0;
+}
+
+/* ---------------- Writing parameters to a list ---------------- */
+
+private param_proc_begin_xmit_collection(c_param_begin_write_collection);
+private param_proc_end_xmit_collection(c_param_end_write_collection);
+private param_proc_xmit_typed(c_param_write_typed);
+private param_proc_request(c_param_request);
+private param_proc_requested(c_param_requested);
+private const gs_param_list_procs c_write_procs =
+{
+ c_param_write_typed,
+ c_param_begin_write_collection,
+ c_param_end_write_collection,
+ NULL, /* get_next_key */
+ c_param_request,
+ c_param_requested
+};
+
+/* Initialize a list for writing. */
+void
+gs_c_param_list_write(gs_c_param_list * plist, gs_memory_t * mem)
+{
+ plist->procs = &c_write_procs;
+ plist->memory = mem;
+ plist->head = 0;
+ plist->count = 0;
+ plist->any_requested = false;
+ plist->coll_type = gs_param_collection_dict_any;
+}
+
+/* Release a list. */
+void
+gs_c_param_list_release(gs_c_param_list * plist)
+{
+ gs_c_param *pparam;
+
+ while ((pparam = plist->head) != 0) {
+ gs_c_param *next = pparam->next;
+
+ switch (pparam->type) {
+ case gs_param_type_dict:
+ case gs_param_type_dict_int_keys:
+ case gs_param_type_array:
+ gs_c_param_list_release(&pparam->value.d);
+ break;
+ case gs_param_type_string:
+ case gs_param_type_name:
+ case gs_param_type_int_array:
+ case gs_param_type_float_array:
+ case gs_param_type_string_array:
+ case gs_param_type_name_array:
+ if (!pparam->value.s.persistent)
+ gs_free_object(plist->memory, (void *)pparam->value.s.data,
+ "gs_c_param_list_release data");
+ break;
+ default:
+ break;
+ }
+ gs_free_object(plist->memory, pparam->alternate_typed_data,
+ "gs_c_param_list_release alternate data");
+ gs_free_object(plist->memory, pparam,
+ "gs_c_param_list_release entry");
+ plist->head = next;
+ plist->count--;
+ }
+}
+
+/* Add an entry to a list. Doesn't set: value, type, plist->head. */
+private gs_c_param *
+c_param_add(gs_c_param_list * plist, gs_param_name pkey)
+{
+ gs_c_param *pparam =
+ gs_alloc_struct(plist->memory, gs_c_param, &st_c_param,
+ "c_param_write entry");
+
+ if (pparam == 0)
+ return 0;
+ pparam->next = plist->head;
+ pparam->key = pkey;
+ pparam->alternate_typed_data = 0;
+ return pparam;
+}
+
+/* Write a dynamically typed parameter to a list. */
+private int
+c_param_write(gs_c_param_list * plist, gs_param_name pkey, void *pvalue,
+ gs_param_type type)
+{
+ unsigned top_level_sizeof = 0;
+ unsigned second_level_sizeof = 0;
+ gs_c_param *pparam = c_param_add(plist, pkey);
+
+ if (pparam == 0)
+ return_error(gs_error_VMerror);
+ memcpy(&pparam->value, pvalue, gs_param_type_sizes[(int)type]);
+ pparam->type = type;
+
+ /* Need deeper copies of data if it's not persistent */
+ switch (type) {
+ gs_param_string const *curr_string;
+ gs_param_string const *end_string;
+
+ case gs_param_type_string_array:
+ case gs_param_type_name_array:
+ /* Determine how much mem needed to hold actual string data */
+ curr_string = pparam->value.sa.data;
+ end_string = curr_string + pparam->value.sa.size;
+ for (; curr_string < end_string; ++curr_string)
+ if (!curr_string->persistent)
+ second_level_sizeof += curr_string->size;
+ /* fall thru */
+
+ case gs_param_type_string:
+ case gs_param_type_name:
+ case gs_param_type_int_array:
+ case gs_param_type_float_array:
+ if (!pparam->value.s.persistent) { /* Allocate & copy object pointed to by array or string */
+ byte *top_level_memory;
+
+ top_level_sizeof =
+ pparam->value.s.size * gs_param_type_base_sizes[type];
+ top_level_memory =
+ gs_alloc_bytes_immovable(plist->memory,
+ top_level_sizeof + second_level_sizeof,
+ "c_param_write data");
+ if (top_level_memory == 0) {
+ gs_free_object(plist->memory, pparam, "c_param_write entry");
+ return_error(gs_error_VMerror);
+ }
+ memcpy(top_level_memory, pparam->value.s.data, top_level_sizeof);
+ pparam->value.s.data = top_level_memory;
+
+ /* String/name arrays need to copy actual str data */
+
+ if (second_level_sizeof > 0) {
+ byte *second_level_memory =
+ top_level_memory + top_level_sizeof;
+
+ curr_string = pparam->value.sa.data;
+ end_string = curr_string + pparam->value.sa.size;
+ for (; curr_string < end_string; ++curr_string)
+ if (!curr_string->persistent) {
+ memcpy(second_level_memory,
+ curr_string->data, curr_string->size);
+ ((gs_param_string *) curr_string)->data
+ = second_level_memory;
+ second_level_memory += curr_string->size;
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ plist->head = pparam;
+ plist->count++;
+ return 0;
+}
+
+/* Individual writing routines. */
+private int
+c_param_begin_write_collection(gs_param_list * plist, gs_param_name pkey,
+ gs_param_dict * pvalue, gs_param_collection_type_t coll_type)
+{
+ gs_c_param_list *const cplist = (gs_c_param_list *)plist;
+ gs_c_param_list *dlist =
+ gs_alloc_struct(cplist->memory, gs_c_param_list, &st_c_param_list,
+ "c_param_begin_write_collection");
+
+ if (dlist == 0)
+ return_error(gs_error_VMerror);
+ gs_c_param_list_write(dlist, cplist->memory);
+ dlist->coll_type = coll_type;
+ pvalue->list = (gs_param_list *) dlist;
+ return 0;
+}
+private int
+c_param_end_write_collection(gs_param_list * plist, gs_param_name pkey,
+ gs_param_dict * pvalue)
+{
+ gs_c_param_list *const cplist = (gs_c_param_list *)plist;
+ gs_c_param_list *dlist = (gs_c_param_list *) pvalue->list;
+
+ return c_param_write(cplist, pkey, pvalue->list,
+ (dlist->coll_type == gs_param_collection_dict_int_keys ?
+ gs_param_type_dict_int_keys :
+ dlist->coll_type == gs_param_collection_array ?
+ gs_param_type_array : gs_param_type_dict));
+}
+private int
+c_param_write_typed(gs_param_list * plist, gs_param_name pkey,
+ gs_param_typed_value * pvalue)
+{
+ gs_c_param_list *const cplist = (gs_c_param_list *)plist;
+ gs_param_collection_type_t coll_type;
+
+ switch (pvalue->type) {
+ case gs_param_type_dict:
+ coll_type = gs_param_collection_dict_any;
+ break;
+ case gs_param_type_dict_int_keys:
+ coll_type = gs_param_collection_dict_int_keys;
+ break;
+ case gs_param_type_array:
+ coll_type = gs_param_collection_array;
+ break;
+ default:
+ return c_param_write(cplist, pkey, &pvalue->value, pvalue->type);
+ }
+ return c_param_begin_write_collection
+ (plist, pkey, &pvalue->value.d, coll_type);
+}
+
+/* Other procedures */
+
+private int
+c_param_request(gs_param_list * plist, gs_param_name pkey)
+{
+ gs_c_param_list *const cplist = (gs_c_param_list *)plist;
+ gs_c_param *pparam;
+
+ cplist->any_requested = true;
+ if (c_param_find(cplist, pkey, true))
+ return 0;
+ pparam = c_param_add(cplist, pkey);
+ if (pparam == 0)
+ return_error(gs_error_VMerror);
+ pparam->type = gs_param_type_any; /* mark as undefined */
+ cplist->head = pparam;
+ return 0;
+}
+
+private int
+c_param_requested(const gs_param_list * plist, gs_param_name pkey)
+{
+ const gs_c_param_list *const cplist = (const gs_c_param_list *)plist;
+
+ return (!cplist->any_requested ? -1 :
+ c_param_find(cplist, pkey, true) != 0);
+}
+
+/* ---------------- Reading from a list to parameters ---------------- */
+
+private param_proc_begin_xmit_collection(c_param_begin_read_collection);
+private param_proc_end_xmit_collection(c_param_end_read_collection);
+private param_proc_xmit_typed(c_param_read_typed);
+private param_proc_next_key(c_param_get_next_key);
+private param_proc_get_policy(c_param_read_get_policy);
+private param_proc_signal_error(c_param_read_signal_error);
+private param_proc_commit(c_param_read_commit);
+private const gs_param_list_procs c_read_procs =
+{
+ c_param_read_typed,
+ c_param_begin_read_collection,
+ c_param_end_read_collection,
+ c_param_get_next_key,
+ NULL, /* request, N/A */
+ NULL, /* requested, N/A */
+ c_param_read_get_policy,
+ c_param_read_signal_error,
+ c_param_read_commit
+};
+
+/* Switch a list from writing to reading. */
+void
+gs_c_param_list_read(gs_c_param_list * plist)
+{
+ plist->procs = &c_read_procs;
+}
+
+/* Generic routine for reading a parameter from a list. */
+
+private int
+c_param_read_typed(gs_param_list * plist, gs_param_name pkey,
+ gs_param_typed_value * pvalue)
+{
+ gs_c_param_list *const cplist = (gs_c_param_list *)plist;
+ gs_param_type req_type = pvalue->type;
+ gs_c_param *pparam = c_param_find(cplist, pkey, false);
+ int code;
+
+ if (pparam == 0)
+ return 1;
+ pvalue->type = pparam->type;
+ switch (pvalue->type) {
+ case gs_param_type_dict:
+ case gs_param_type_dict_int_keys:
+ case gs_param_type_array:
+ gs_c_param_list_read(&pparam->value.d);
+ pvalue->value.d.list = (gs_param_list *) & pparam->value.d;
+ pvalue->value.d.size = pparam->value.d.count;
+ return 0;
+ default:
+ break;
+ }
+ memcpy(&pvalue->value, &pparam->value,
+ gs_param_type_sizes[(int)pparam->type]);
+ code = param_coerce_typed(pvalue, req_type, NULL);
+/****** SHOULD LET param_coerce_typed DO THIS ******/
+ if (code == gs_error_typecheck &&
+ req_type == gs_param_type_float_array &&
+ pvalue->type == gs_param_type_int_array
+ ) {
+ /* Convert int array to float dest */
+ gs_param_float_array fa;
+ int element;
+
+ fa.size = pparam->value.ia.size;
+ fa.persistent = false;
+
+ if (pparam->alternate_typed_data == 0) {
+ if ((pparam->alternate_typed_data
+ = (void *)gs_alloc_bytes_immovable(cplist->memory,
+ fa.size * sizeof(float),
+ "gs_c_param_read alternate float array")) == 0)
+ return_error(gs_error_VMerror);
+
+ for (element = 0; element < fa.size; ++element)
+ ((float *)(pparam->alternate_typed_data))[element]
+ = (float)pparam->value.ia.data[element];
+ }
+ fa.data = (float *)pparam->alternate_typed_data;
+
+ pvalue->value.fa = fa;
+ return 0;
+ }
+ return code;
+}
+
+/* Individual reading routines. */
+private int
+c_param_begin_read_collection(gs_param_list * plist, gs_param_name pkey,
+ gs_param_dict * pvalue, gs_param_collection_type_t coll_type)
+{
+ gs_c_param_list *const cplist = (gs_c_param_list *)plist;
+ gs_c_param *pparam = c_param_find(cplist, pkey, false);
+
+ if (pparam == 0)
+ return 1;
+ switch (pparam->type) {
+ case gs_param_type_dict:
+ if (coll_type != gs_param_collection_dict_any)
+ return_error(gs_error_typecheck);
+ break;
+ case gs_param_type_dict_int_keys:
+ if (coll_type == gs_param_collection_array)
+ return_error(gs_error_typecheck);
+ break;
+ case gs_param_type_array:
+ break;
+ default:
+ return_error(gs_error_typecheck);
+ }
+ gs_c_param_list_read(&pparam->value.d);
+ pvalue->list = (gs_param_list *) & pparam->value.d;
+ pvalue->size = pparam->value.d.count;
+ return 0;
+}
+private int
+c_param_end_read_collection(gs_param_list * plist, gs_param_name pkey,
+ gs_param_dict * pvalue)
+{
+ return 0;
+}
+
+/* Other procedures */
+private int /* ret 0 ok, 1 if EOF, or -ve err */
+c_param_get_next_key(gs_param_list * plist, gs_param_enumerator_t * penum,
+ gs_param_key_t * key)
+{
+ gs_c_param_list *const cplist = (gs_c_param_list *)plist;
+ gs_c_param *pparam =
+ (penum->pvoid ? ((gs_c_param *) (penum->pvoid))->next :
+ cplist->head);
+
+ if (pparam == 0)
+ return 1;
+ penum->pvoid = pparam;
+ key->data = (const byte *)pparam->key; /* was const char * */
+ key->size = strlen(pparam->key);
+ return 0;
+}
+private int
+c_param_read_get_policy(gs_param_list * plist, gs_param_name pkey)
+{
+ return gs_param_policy_ignore;
+}
+private int
+c_param_read_signal_error(gs_param_list * plist, gs_param_name pkey, int code)
+{
+ return code;
+}
+private int
+c_param_read_commit(gs_param_list * plist)
+{
+ return 0;
+}
diff --git a/gs/src/gscpixel.c b/gs/src/gscpixel.c
new file mode 100644
index 000000000..a9c38e88b
--- /dev/null
+++ b/gs/src/gscpixel.c
@@ -0,0 +1,83 @@
+/* Copyright (C) 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gscpixel.c */
+/* DevicePixel color space and operation definition */
+#include "gx.h"
+#include "gserrors.h"
+#include "gsrefct.h"
+#include "gxcspace.h"
+#include "gscpixel.h"
+#include "gxdevice.h"
+
+/* Define the DevicePixel color space type. */
+private cs_proc_restrict_color(gx_restrict_DevicePixel);
+private cs_proc_remap_concrete_color(gx_remap_concrete_DevicePixel);
+private cs_proc_concretize_color(gx_concretize_DevicePixel);
+private const gs_color_space_type gs_color_space_type_DevicePixel = {
+ gs_color_space_index_DevicePixel, true, false,
+ &st_base_color_space, gx_num_components_1,
+ gx_no_base_space,
+ gx_init_paint_1, gx_restrict_DevicePixel,
+ gx_same_concrete_space,
+ gx_concretize_DevicePixel, gx_remap_concrete_DevicePixel,
+ gx_default_remap_color, gx_no_install_cspace,
+ gx_no_adjust_cspace_count, gx_no_adjust_color_count
+};
+
+/* Create a DevicePixel color space. */
+void
+gs_cs_init_DevicePixel(gs_color_space * pcs, int depth)
+{
+ pcs->type = &gs_color_space_type_DevicePixel;
+ pcs->params.pixel.depth = depth;
+}
+
+/* ------ Internal routines ------ */
+
+/* Force a DevicePixel color into legal range. */
+private void
+gx_restrict_DevicePixel(gs_client_color * pcc, const gs_color_space * pcs)
+{
+/****** NOT ENOUGH BITS IN float OR frac ******/
+ floatp pixel = pcc->paint.values[0];
+ ulong max_value = (1L << pcs->params.pixel.depth) - 1;
+
+ pcc->paint.values[0] = (pixel < 0 ? 0 : min(pixel, max_value));
+}
+
+
+/* Remap a DevicePixel color. */
+
+private int
+gx_concretize_DevicePixel(const gs_client_color * pc, const gs_color_space * pcs,
+ frac * pconc, const gs_imager_state * pis)
+{
+/****** NOT ENOUGH BITS IN float OR frac ******/
+ pconc[0] = (frac) (ulong) pc->paint.values[0];
+ return 0;
+}
+
+private int
+gx_remap_concrete_DevicePixel(const frac * pconc,
+ gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
+ gs_color_select_t select)
+{
+ color_set_pure(pdc, pconc[0] & ((1 << dev->color_info.depth) - 1));
+ return 0;
+}
diff --git a/gs/src/gscpixel.h b/gs/src/gscpixel.h
new file mode 100644
index 000000000..544964982
--- /dev/null
+++ b/gs/src/gscpixel.h
@@ -0,0 +1,28 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gscpixel.h */
+/* Requires gscspace.h */
+
+#ifndef gscpixel_INCLUDED
+# define gscpixel_INCLUDED
+
+/* Create a DevicePixel color space. */
+void gs_cs_init_DevicePixel(P2(gs_color_space * pcs, int depth));
+
+#endif /* gscpixel_INCLUDED */
diff --git a/gs/src/gscrdp.c b/gs/src/gscrdp.c
new file mode 100644
index 000000000..6d874cc74
--- /dev/null
+++ b/gs/src/gscrdp.c
@@ -0,0 +1,623 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gscrdp.c */
+/* CIE color rendering dictionary creation */
+#include "math_.h"
+#include "memory_.h"
+#include "gx.h"
+#include "gsdevice.h"
+#include "gserrors.h"
+#include "gsmatrix.h" /* for gscolor2.h */
+#include "gxcspace.h"
+#include "gscolor2.h" /* for gs_set/currentcolorrendering */
+#include "gscrdp.h"
+#include "gxarith.h"
+
+/* Define the CRD type that we use here. */
+#define CRD_TYPE 101
+
+/* ---------------- Writing ---------------- */
+
+/* Internal procedures for writing parameter values. */
+private void
+store_vector3(float *p, const gs_vector3 * pvec)
+{
+ p[0] = pvec->u, p[1] = pvec->v, p[2] = pvec->w;
+}
+private int
+write_floats(gs_param_list * plist, gs_param_name key,
+ const float *values, int size, gs_memory_t * mem)
+{
+ float *p = (float *)
+ gs_alloc_byte_array(mem, size, sizeof(float), "write_floats");
+ gs_param_float_array fa;
+
+ if (p == 0)
+ return_error(gs_error_VMerror);
+ memcpy(p, values, size * sizeof(float));
+
+ fa.data = p;
+ fa.size = size;
+ fa.persistent = true;
+ return param_write_float_array(plist, key, &fa);
+}
+private int
+write_vector3(gs_param_list * plist, gs_param_name key,
+ const gs_vector3 * pvec, gs_memory_t * mem)
+{
+ float values[3];
+
+ store_vector3(values, pvec);
+ return write_floats(plist, key, values, 3, mem);
+}
+private int
+write_matrix3(gs_param_list * plist, gs_param_name key,
+ const gs_matrix3 * pmat, gs_memory_t * mem)
+{
+ float values[9];
+
+ if (!memcmp(pmat, &Matrix3_default, sizeof(*pmat)))
+ return 0;
+ store_vector3(values, &pmat->cu);
+ store_vector3(values + 3, &pmat->cv);
+ store_vector3(values + 6, &pmat->cw);
+ return write_floats(plist, key, values, 9, mem);
+}
+private int
+write_range3(gs_param_list * plist, gs_param_name key,
+ const gs_range3 * prange, gs_memory_t * mem)
+{
+ float values[6];
+
+ if (!memcmp(prange, &Range3_default, sizeof(*prange)))
+ return 0;
+ values[0] = prange->ranges[0].rmin, values[1] = prange->ranges[0].rmax;
+ values[2] = prange->ranges[1].rmin, values[3] = prange->ranges[1].rmax;
+ values[4] = prange->ranges[2].rmin, values[5] = prange->ranges[2].rmax;
+ return write_floats(plist, key, values, 6, mem);
+}
+private int
+write_proc3(gs_param_list * plist, gs_param_name key,
+ const gs_cie_render * pcrd, const gs_cie_render_proc3 * procs,
+ const gs_range3 * domain, gs_memory_t * mem)
+{
+ float *values;
+ uint size = gx_cie_cache_size;
+ gs_param_float_array fa;
+ int i;
+
+ if (!memcmp(procs, &Encode_default, sizeof(*procs)))
+ return 0;
+ values = (float *)gs_alloc_byte_array(mem, size * 3, sizeof(float),
+ "write_proc3");
+
+ if (values == 0)
+ return_error(gs_error_VMerror);
+ for (i = 0; i < 3; ++i) {
+ double base = domain->ranges[i].rmin;
+ double scale = (domain->ranges[i].rmax - base) / (size - 1);
+ int j;
+
+ for (j = 0; j < size; ++j)
+ values[i * size + j] =
+ (*procs->procs[i]) (j * scale + base, pcrd);
+ }
+ fa.data = values;
+ fa.size = size * 3;
+ fa.persistent = true;
+ return param_write_float_array(plist, key, &fa);
+}
+
+/* Write a CRD as a device parameter. */
+int
+param_write_cie_render1(gs_param_list * plist, gs_param_name key,
+ const gs_cie_render * pcrd, gs_memory_t * mem)
+{
+ gs_param_dict dict;
+ int code, dcode;
+
+ dict.size = 20;
+ if ((code = param_begin_write_dict(plist, key, &dict, false)) < 0)
+ return code;
+ code = param_put_cie_render1(dict.list, pcrd, mem);
+ dcode = param_end_write_dict(plist, key, &dict);
+ return (code < 0 ? code : dcode);
+}
+
+/* Write a CRD directly to a parameter list. */
+int
+param_put_cie_render1(gs_param_list * plist, const gs_cie_render * pcrd,
+ gs_memory_t * mem)
+{
+ int crd_type = CRD_TYPE;
+ int code;
+
+ if (pcrd->TransformPQR.proc_name) {
+ gs_param_string pn, pd;
+
+ param_string_from_string(pn, pcrd->TransformPQR.proc_name);
+ pn.size++; /* include terminating null */
+ pd.data = pcrd->TransformPQR.proc_data.data;
+ pd.size = pcrd->TransformPQR.proc_data.size;
+ pd.persistent = true; /****** WRONG ******/
+ if ((code = param_write_name(plist, "TransformPQRName", &pn)) < 0 ||
+ (code = param_write_string(plist, "TransformPQRData", &pd)) < 0
+ )
+ return code;
+ }
+ else if (pcrd->TransformPQR.proc != TransformPQR_default.proc) {
+ /* We have no way to represent the procedure, so return an error. */
+ return_error(gs_error_rangecheck);
+ }
+ if ((code = param_write_int(plist, "ColorRenderingType", &crd_type)) < 0 ||
+ (code = write_vector3(plist, "WhitePoint", &pcrd->points.WhitePoint, mem)) < 0
+ )
+ return code;
+ if (memcmp(&pcrd->points.BlackPoint, &BlackPoint_default,
+ sizeof(pcrd->points.BlackPoint))) {
+ if ((code = write_vector3(plist, "BlackPoint", &pcrd->points.BlackPoint, mem)) < 0)
+ return code;
+ }
+ if ((code = write_matrix3(plist, "MatrixPQR", &pcrd->MatrixPQR, mem)) < 0 ||
+ (code = write_range3(plist, "RangePQR", &pcrd->RangePQR, mem)) < 0 ||
+ /* TransformPQR is handled separately */
+ (code = write_matrix3(plist, "MatrixLMN", &pcrd->MatrixLMN, mem)) < 0 ||
+ (code = write_proc3(plist, "EncodeLMNValues", pcrd,
+ &pcrd->EncodeLMN, &pcrd->DomainLMN, mem)) < 0 ||
+ (code = write_range3(plist, "RangeLMN", &pcrd->RangeLMN, mem)) < 0 ||
+ (code = write_matrix3(plist, "MatrixABC", &pcrd->MatrixABC, mem)) < 0 ||
+ (code = write_proc3(plist, "EncodeABCValues", pcrd,
+ &pcrd->EncodeABC, &pcrd->DomainABC, mem)) < 0 ||
+ (code = write_range3(plist, "RangeABC", &pcrd->RangeABC, mem)) < 0
+ )
+ return code;
+ if (pcrd->RenderTable.lookup.table) {
+ int n = pcrd->RenderTable.lookup.n;
+ int m = pcrd->RenderTable.lookup.m;
+ int na = pcrd->RenderTable.lookup.dims[0];
+ int *size = (int *)
+ gs_alloc_byte_array(mem, n + 1, sizeof(int), "RenderTableSize");
+
+ /*
+ * In principle, we should use gs_alloc_struct_array with a
+ * type descriptor for gs_param_string. However, it is widely
+ * assumed that parameter lists are transient, and don't require
+ * accurate GC information; so we can get away with allocating
+ * the string table as bytes.
+ */
+ gs_param_string *table =
+ (gs_param_string *)
+ gs_alloc_byte_array(mem, na, sizeof(gs_param_string),
+ "RenderTableTable");
+ gs_param_int_array ia;
+
+ if (size == 0 || table == 0)
+ code = gs_note_error(gs_error_VMerror);
+ else {
+ memcpy(size, pcrd->RenderTable.lookup.dims, sizeof(int) * n);
+
+ size[n] = m;
+ ia.data = size;
+ ia.size = n + 1;
+ ia.persistent = true;
+ code = param_write_int_array(plist, "RenderTableSize", &ia);
+ }
+ if (code >= 0) {
+ gs_param_string_array sa;
+ int a;
+
+ for (a = 0; a < na; ++a)
+ table[a].data = pcrd->RenderTable.lookup.table[a].data,
+ table[a].size = pcrd->RenderTable.lookup.table[a].size,
+ table[a].persistent = true;
+ sa.data = table;
+ sa.size = na;
+ sa.persistent = true;
+ code = param_write_string_array(plist, "RenderTableTable", &sa);
+ if (code >= 0 && !pcrd->caches.RenderTableT_is_identity) {
+ /****** WRITE RenderTableTValues LIKE write_proc3 ******/
+ uint size = gx_cie_cache_size;
+ float *values =
+ (float *)gs_alloc_byte_array(mem, size * m,
+ sizeof(float),
+ "write_proc3");
+ gs_param_float_array fa;
+ int i;
+
+ if (values == 0)
+ return_error(gs_error_VMerror);
+ for (i = 0; i < m; ++i) {
+ double scale = 255.0 / (size - 1);
+ int j;
+
+ for (j = 0; j < size; ++j)
+ values[i * size + j] =
+ frac2float((*pcrd->RenderTable.T.procs[i])
+ (j * scale, pcrd));
+ }
+ fa.data = values;
+ fa.size = size * m;
+ fa.persistent = true;
+ code = param_write_float_array(plist, "RenderTableTValues",
+ &fa);
+ }
+ }
+ if (code < 0) {
+ gs_free_object(mem, table, "RenderTableTable");
+ gs_free_object(mem, size, "RenderTableSize");
+ return code;
+ }
+ }
+ return code;
+}
+
+/* ---------------- Reading ---------------- */
+
+/* Internal procedures for reading parameter values. */
+private void
+load_vector3(gs_vector3 * pvec, const float *p)
+{
+ pvec->u = p[0], pvec->v = p[1], pvec->w = p[2];
+}
+private int
+read_floats(gs_param_list * plist, gs_param_name key, float *values, int count)
+{
+ gs_param_float_array fa;
+ int code = param_read_float_array(plist, key, &fa);
+
+ if (code)
+ return code;
+ if (fa.size != count)
+ return_error(gs_error_rangecheck);
+ memcpy(values, fa.data, sizeof(float) * count);
+
+ return 0;
+}
+private int
+read_vector3(gs_param_list * plist, gs_param_name key,
+ gs_vector3 * pvec, const gs_vector3 * dflt)
+{
+ float values[3];
+ int code = read_floats(plist, key, values, 3);
+
+ switch (code) {
+ case 1: /* not defined */
+ if (dflt)
+ *pvec = *dflt;
+ break;
+ case 0:
+ load_vector3(pvec, values);
+ default: /* error */
+ break;
+ }
+ return code;
+}
+private int
+read_matrix3(gs_param_list * plist, gs_param_name key, gs_matrix3 * pmat)
+{
+ float values[9];
+ int code = read_floats(plist, key, values, 9);
+
+ switch (code) {
+ case 1: /* not defined */
+ *pmat = Matrix3_default;
+ break;
+ case 0:
+ load_vector3(&pmat->cu, values);
+ load_vector3(&pmat->cv, values + 3);
+ load_vector3(&pmat->cw, values + 6);
+ default: /* error */
+ break;
+ }
+ return code;
+}
+private int
+read_range3(gs_param_list * plist, gs_param_name key, gs_range3 * prange)
+{
+ float values[6];
+ int code = read_floats(plist, key, values, 6);
+
+ switch (code) {
+ case 1: /* not defined */
+ *prange = Range3_default;
+ break;
+ case 0:
+ prange->ranges[0].rmin = values[0];
+ prange->ranges[0].rmax = values[1];
+ prange->ranges[1].rmin = values[2];
+ prange->ranges[1].rmax = values[3];
+ prange->ranges[2].rmin = values[4];
+ prange->ranges[2].rmax = values[5];
+ default: /* error */
+ break;
+ }
+ return code;
+}
+private int
+read_proc3(gs_param_list * plist, gs_param_name key,
+ float values[gx_cie_cache_size * 3])
+{
+ return read_floats(plist, key, values, gx_cie_cache_size * 3);
+}
+
+/* Read a CRD from a device parameter. */
+int
+gs_cie_render1_param_initialize(gs_cie_render * pcrd, gs_param_list * plist,
+ gs_param_name key, gx_device * dev)
+{
+ gs_param_dict dict;
+ int code = param_begin_read_dict(plist, key, &dict, false);
+ int dcode;
+
+ if (code < 0)
+ return code;
+ code = param_get_cie_render1(pcrd, dict.list, dev);
+ dcode = param_end_read_dict(plist, key, &dict);
+ if (code < 0)
+ return code;
+ if (dcode < 0)
+ return dcode;
+ gs_cie_render_init(pcrd);
+ gs_cie_render_sample(pcrd);
+ return gs_cie_render_complete(pcrd);
+}
+
+/* Define the structure for passing Encode values as "client data". */
+typedef struct encode_data_s {
+ float lmn[gx_cie_cache_size * 3]; /* EncodeLMN */
+ float abc[gx_cie_cache_size * 3]; /* EncodeABC */
+ float t[gx_cie_cache_size * 4]; /* RenderTable.T */
+} encode_data_t;
+
+/* Define procedures that retrieve the Encode values read from the list. */
+private float
+encode_from_data(floatp v, const float values[gx_cie_cache_size],
+ const gs_range * range)
+{
+ return (v <= range->rmin ? values[0] :
+ v >= range->rmax ? values[gx_cie_cache_size - 1] :
+ values[(int)((v - range->rmin) / (range->rmax - range->rmin) *
+ (gx_cie_cache_size - 1) + 0.5)]);
+}
+/*
+ * The repetitive boilerplate in the next 10 procedures really sticks in
+ * my craw, but I've got a mandate not to use macros....
+ */
+private float
+encode_lmn_0_from_data(floatp v, const gs_cie_render * pcrd)
+{
+ const encode_data_t *data = pcrd->client_data;
+
+ return encode_from_data(v, &data->lmn[0],
+ &pcrd->DomainLMN.ranges[0]);
+}
+private float
+encode_lmn_1_from_data(floatp v, const gs_cie_render * pcrd)
+{
+ const encode_data_t *data = pcrd->client_data;
+
+ return encode_from_data(v, &data->lmn[gx_cie_cache_size],
+ &pcrd->DomainLMN.ranges[1]);
+}
+private float
+encode_lmn_2_from_data(floatp v, const gs_cie_render * pcrd)
+{
+ const encode_data_t *data = pcrd->client_data;
+
+ return encode_from_data(v, &data->lmn[gx_cie_cache_size * 2],
+ &pcrd->DomainLMN.ranges[2]);
+}
+private float
+encode_abc_0_from_data(floatp v, const gs_cie_render * pcrd)
+{
+ const encode_data_t *data = pcrd->client_data;
+
+ return encode_from_data(v, &data->abc[0],
+ &pcrd->DomainABC.ranges[0]);
+}
+private float
+encode_abc_1_from_data(floatp v, const gs_cie_render * pcrd)
+{
+ const encode_data_t *data = pcrd->client_data;
+
+ return encode_from_data(v, &data->abc[gx_cie_cache_size],
+ &pcrd->DomainABC.ranges[1]);
+}
+private float
+encode_abc_2_from_data(floatp v, const gs_cie_render * pcrd)
+{
+ const encode_data_t *data = pcrd->client_data;
+
+ return encode_from_data(v, &data->abc[gx_cie_cache_size * 2],
+ &pcrd->DomainABC.ranges[2]);
+}
+private frac
+render_table_t_0_from_data(byte v, const gs_cie_render * pcrd)
+{
+ const encode_data_t *data = pcrd->client_data;
+
+ return float2frac(encode_from_data(v / 255.0,
+ &data->t[0],
+ &Range3_default.ranges[0]));
+}
+private frac
+render_table_t_1_from_data(byte v, const gs_cie_render * pcrd)
+{
+ const encode_data_t *data = pcrd->client_data;
+
+ return float2frac(encode_from_data(v / 255.0,
+ &data->t[gx_cie_cache_size],
+ &Range3_default.ranges[0]));
+}
+private frac
+render_table_t_2_from_data(byte v, const gs_cie_render * pcrd)
+{
+ const encode_data_t *data = pcrd->client_data;
+
+ return float2frac(encode_from_data(v / 255.0,
+ &data->t[gx_cie_cache_size * 2],
+ &Range3_default.ranges[0]));
+}
+private frac
+render_table_t_3_from_data(byte v, const gs_cie_render * pcrd)
+{
+ const encode_data_t *data = pcrd->client_data;
+
+ return float2frac(encode_from_data(v / 255.0,
+ &data->t[gx_cie_cache_size * 3],
+ &Range3_default.ranges[0]));
+}
+private const gs_cie_render_proc3 EncodeLMN_from_data = {
+ {encode_lmn_0_from_data, encode_lmn_1_from_data, encode_lmn_2_from_data}
+};
+private const gs_cie_render_proc3 EncodeABC_from_data = {
+ {encode_abc_0_from_data, encode_abc_1_from_data, encode_abc_2_from_data}
+};
+private const gs_cie_render_table_procs RenderTableT_from_data = {
+ {render_table_t_0_from_data, render_table_t_1_from_data,
+ render_table_t_2_from_data, render_table_t_3_from_data
+ }
+};
+
+/* Read a CRD directly from a parameter list. */
+int
+param_get_cie_render1(gs_cie_render * pcrd, gs_param_list * plist,
+ gx_device * dev)
+{
+ encode_data_t data;
+ gs_param_int_array rt_size;
+ int crd_type;
+ int code, code_lmn, code_abc, code_rt, code_t;
+ gs_param_string pname, pdata;
+
+ if ((code = param_read_int(plist, "ColorRenderingType", &crd_type)) < 0 ||
+ crd_type != CRD_TYPE ||
+ (code = read_vector3(plist, "WhitePoint", &pcrd->points.WhitePoint,
+ NULL)) < 0 ||
+ (code = read_vector3(plist, "BlackPoint", &pcrd->points.BlackPoint,
+ &BlackPoint_default)) < 0 ||
+ (code = read_matrix3(plist, "MatrixPQR", &pcrd->MatrixPQR)) < 0 ||
+ (code = read_range3(plist, "RangePQR", &pcrd->RangePQR)) < 0 ||
+ /* TransformPQR is handled specially below. */
+ (code = read_matrix3(plist, "MatrixLMN", &pcrd->MatrixLMN)) < 0 ||
+ (code_lmn = code =
+ read_proc3(plist, "EncodeLMNValues", data.lmn)) < 0 ||
+ (code = read_range3(plist, "RangeLMN", &pcrd->RangeLMN)) < 0 ||
+ (code = read_matrix3(plist, "MatrixABC", &pcrd->MatrixABC)) < 0 ||
+ (code_abc = code =
+ read_proc3(plist, "EncodeABCValues", data.abc)) < 0 ||
+ (code = read_range3(plist, "RangeABC", &pcrd->RangeABC)) < 0
+ )
+ return code;
+ /* Handle the sampled functions. */
+ switch (code = param_read_string(plist, "TransformPQRName", &pname)) {
+ default: /* error */
+ return code;
+ case 1: /* missing */
+ pcrd->TransformPQR = TransformPQR_default;
+ break;
+ case 0: /* specified */
+ /* The procedure name must be null-terminated: */
+ /* see param_put_cie_render1 above. */
+ if (pname.size < 1 || pname.data[pname.size - 1] != 0)
+ return_error(gs_error_rangecheck);
+ pcrd->TransformPQR.proc = TransformPQR_lookup_proc_name;
+ pcrd->TransformPQR.proc_name = (char *)pname.data;
+ switch (code = param_read_string(plist, "TransformPQRData", &pdata)) {
+ default: /* error */
+ return code;
+ case 1: /* missing */
+ pcrd->TransformPQR.proc_data.data = 0;
+ pcrd->TransformPQR.proc_data.size = 0;
+ break;
+ case 0:
+ pcrd->TransformPQR.proc_data.data = pdata.data;
+ pcrd->TransformPQR.proc_data.size = pdata.size;
+ }
+ pcrd->TransformPQR.driver_name = gs_devicename(dev);
+ break;
+ }
+ pcrd->client_data = &data;
+ if (code_lmn > 0)
+ pcrd->EncodeLMN = Encode_default;
+ else
+ pcrd->EncodeLMN = EncodeLMN_from_data;
+ if (code_abc > 0)
+ pcrd->EncodeABC = Encode_default;
+ else
+ pcrd->EncodeABC = EncodeABC_from_data;
+ code_rt = code = param_read_int_array(plist, "RenderTableSize", &rt_size);
+ if (code == 1) {
+ if (pcrd->RenderTable.lookup.table) {
+ gs_free_object(pcrd->rc.memory,
+ (void *)pcrd->RenderTable.lookup.table, /* break const */
+ "param_get_cie_render1(RenderTable)");
+ pcrd->RenderTable.lookup.table = 0;
+ }
+ pcrd->RenderTable.T = RenderTableT_default;
+ code_t = 1;
+ } else if (code < 0)
+ return code;
+ else if (rt_size.size != 4)
+ return_error(gs_error_rangecheck);
+ else {
+ gs_param_string_array rt_values;
+ gs_const_string *table;
+ int n, m, j;
+
+ code = param_read_string_array(plist, "RenderTableTable", &rt_values);
+ if (code < 0)
+ return code;
+ else if (code > 0 ||
+ rt_values.size != rt_size.data[3] *
+ rt_size.data[1] * rt_size.data[2])
+ return_error(gs_error_rangecheck);
+ pcrd->RenderTable.lookup.n = n = rt_size.size - 1;
+ pcrd->RenderTable.lookup.m = m = rt_size.data[n];
+ if (n > 4 || m > 4)
+ return_error(gs_error_rangecheck);
+ memcpy(pcrd->RenderTable.lookup.dims, rt_size.data, n * sizeof(int));
+ /****** ALLOCATE table = RenderTable.lookup.table ******/
+ for (j = 0; j < pcrd->RenderTable.lookup.dims[0]; ++j) {
+ table[j].data = rt_values.data[j].data;
+ table[j].size = rt_values.data[j].size;
+ }
+ pcrd->RenderTable.lookup.table = table;
+ pcrd->RenderTable.T = RenderTableT_from_data;
+ code_t = code = read_floats(plist, "RenderTableTValues", data.t,
+ gx_cie_cache_size * m);
+ if (code > 0)
+ pcrd->RenderTable.T = RenderTableT_default;
+ else if (code == 0)
+ pcrd->RenderTable.T = RenderTableT_from_data;
+ }
+ if ((code = gs_cie_render_init(pcrd)) >= 0 &&
+ (code = gs_cie_render_sample(pcrd)) >= 0
+ )
+ code = gs_cie_render_complete(pcrd);
+ /* Clean up before exiting. */
+ pcrd->client_data = 0;
+ if (code_lmn == 0)
+ pcrd->EncodeLMN = EncodeLMN_from_cache;
+ if (code_abc == 0)
+ pcrd->EncodeABC = EncodeABC_from_cache;
+ if (code_t == 0)
+ pcrd->RenderTable.T = RenderTableT_from_cache;
+ return code;
+}
diff --git a/gs/src/gscrdp.h b/gs/src/gscrdp.h
new file mode 100644
index 000000000..42ce950ad
--- /dev/null
+++ b/gs/src/gscrdp.h
@@ -0,0 +1,98 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gscrdp.h */
+/* Interface for device-specified CRDs */
+
+#ifndef gscrdp_INCLUDED
+# define gscrdp_INCLUDED
+
+#include "gscie.h"
+#include "gsparam.h"
+
+/*
+ * A driver can provide any number of its own CRDs through (read-only)
+ * device parameters whose values are slightly modified PostScript-style
+ * dictionaries. The driver doesn't need to concern itself with how the
+ * parameters are encoded: it simply constructs a CRD and calls
+ * param_write_cie_render1.
+ */
+int param_write_cie_render1(P4(gs_param_list * plist, gs_param_name key,
+ const gs_cie_render * pcrd,
+ gs_memory_t * mem));
+
+/*
+ * For internal use, we also provide an API that writes the CRD directly
+ * into a parameter list, rather than as a named parameter in a larger
+ * list.
+ */
+int param_put_cie_render1(P3(gs_param_list * plist, const gs_cie_render * pcrd,
+ gs_memory_t * mem));
+
+/*
+ * Client code that wants to initialize a CRD from a device parameter
+ * uses the following complementary procedure. The customary way to
+ * use this is:
+
+ gs_c_param_list list;
+ ...
+ gs_c_param_list_write(&list, mem);
+ gs_c_param_request(&list, "ParamName");
+ code = gs_getdeviceparams(dev, &list);
+ << error if code < 0 >>
+ gs_c_param_list_read(&list);
+ code = gs_cie_render1_param_initialize(pcrd, &list, "ParamName", dev);
+ gs_c_param_list_release(&list);
+ << error if code < 0 >>
+
+ * where "ParamName" is the parameter name, e.g., "CRDDefault".
+ */
+int gs_cie_render1_param_initialize(P4(gs_cie_render * pcrd,
+ gs_param_list * plist,
+ gs_param_name key,
+ gx_device * dev));
+
+/*
+ * Again, we provide an internal procedure that doesn't involve a
+ * parameter name.
+ */
+int param_get_cie_render1(P3(gs_cie_render * pcrd,
+ gs_param_list * plist,
+ gx_device * dev));
+
+/*
+ * The actual representation of the CRD is a slightly modified PostScript
+ * ColorRenderingType 1 dictionary. THE FOLLOWING IS SUBJECT TO CHANGE
+ * WITHOUT NOTICE. Specifically, the following keys are different:
+ * ColorRenderingType = 101
+ * (Instead of TransformPQR = [T1 T2 T3]:)
+ * TransformPQRName = procedure name (a name)
+ * TransformPQRData = procedure data (a string)
+ * (Instead of EncodeLMN/ABC = [E1 E2 E3]:)
+ * EncodeLMN/ABCValues = [V1,1 V1,2 ... V3,N], where Vi,j is the
+ * j'th sampled value of the i'th encoding array, mapped linearly
+ * to the corresponding domain (see gscie.h)
+ * (Instead of RenderTable = [NA NB NC table m T1 ... Tm]:)
+ * RenderTableSize = [NA NB NC m]
+ * RenderTableTable = table (an array of strings)
+ * RenderTableTValues = [V1,1 V1,2 ... Vm,N] (see above)
+ * The PostScript setcolorrendering operator selects the correct operator
+ * according to the ColorRenderingType key.
+ */
+
+#endif /* gscrdp_INCLUDED */
diff --git a/gs/src/gsdpnext.h b/gs/src/gsdpnext.h
new file mode 100644
index 000000000..c2c00d8a6
--- /dev/null
+++ b/gs/src/gsdpnext.h
@@ -0,0 +1,28 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gsdpnext.h */
+/* API for NeXT DPS facilities */
+
+#ifndef gsdpnext_INCLUDED
+# define gsdpnext_INCLUDED
+
+#include "gsalpha.h"
+#include "gsalphac.h"
+
+#endif /* gsdpnext_INCLUDED */
diff --git a/gs/src/gsfunc3.c b/gs/src/gsfunc3.c
new file mode 100644
index 000000000..b9463cdfd
--- /dev/null
+++ b/gs/src/gsfunc3.c
@@ -0,0 +1,355 @@
+/* Copyright (C) 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gsfunc3.c */
+/* Implementation of LL3 Functions */
+#include "math_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsfunc3.h"
+#include "gxfunc.h"
+
+/* ---------------- Exponential Interpolation functions ---------------- */
+
+typedef struct gs_function_ElIn_s {
+ gs_function_head_t head;
+ gs_function_ElIn_params_t params;
+} gs_function_ElIn_t;
+
+private_st_function_ElIn();
+
+/* Evaluate an Exponential Interpolation function. */
+private int
+fn_ElIn_evaluate(const gs_function_t * pfn_common, const float *in, float *out)
+{
+ const gs_function_ElIn_t *const pfn =
+ (const gs_function_ElIn_t *)pfn_common;
+ double arg = in[0], raised;
+ int i;
+
+ if (arg < pfn->params.Domain[0])
+ arg = pfn->params.Domain[0];
+ else if (arg > pfn->params.Domain[1])
+ arg = pfn->params.Domain[1];
+ raised = pow(arg, pfn->params.N);
+ for (i = 0; i < pfn->params.n; ++i) {
+ float v0 = (pfn->params.C0 == 0 ? 0.0 : pfn->params.C0[i]);
+ float v1 = (pfn->params.C1 == 0 ? 1.0 : pfn->params.C1[i]);
+ double value = v0 + raised * (v1 - v0);
+
+ if (pfn->params.Range) {
+ float r0 = pfn->params.Range[2 * i],
+ r1 = pfn->params.Range[2 * i + 1];
+
+ if (value < r0)
+ value = r0;
+ else if (value > r1)
+ value = r1;
+ }
+ out[i] = value;
+ }
+ return 0;
+}
+
+/* Test whether an Exponential function is monotonic. (They always are.) */
+private int
+fn_ElIn_is_monotonic(const gs_function_t * pfn_common,
+ const float *lower, const float *upper, bool must_know)
+{
+ const gs_function_ElIn_t *const pfn =
+ (const gs_function_ElIn_t *)pfn_common;
+
+ if (lower[0] > pfn->params.Domain[1] ||
+ upper[0] < pfn->params.Domain[0]
+ )
+ return_error(gs_error_rangecheck);
+ return 1;
+}
+
+/* Free the parameters of an Exponential Interpolation function. */
+void
+gs_function_ElIn_free_params(gs_function_ElIn_params_t * params,
+ gs_memory_t * mem)
+{
+ gs_free_object(mem, (void *)params->C1, "C1"); /* break const */
+ gs_free_object(mem, (void *)params->C0, "C0"); /* break const */
+ fn_common_free_params((gs_function_params_t *) params, mem);
+}
+
+/* Allocate and initialize an Exponential Interpolation function. */
+int
+gs_function_ElIn_init(gs_function_t ** ppfn,
+ const gs_function_ElIn_params_t * params,
+ gs_memory_t * mem)
+{
+ static const gs_function_head_t function_ElIn_head =
+ {
+ function_type_ExponentialInterpolation,
+ (fn_evaluate_proc_t) fn_ElIn_evaluate,
+ (fn_is_monotonic_proc_t) fn_ElIn_is_monotonic,
+ (fn_free_params_proc_t) gs_function_ElIn_free_params,
+ fn_common_free
+ };
+ int code;
+
+ *ppfn = 0; /* in case of error */
+ code = fn_check_mnDR((const gs_function_params_t *)params, 1, params->n);
+ if (code < 0)
+ return code;
+ if ((params->C0 == 0 || params->C1 == 0) && params->n != 1)
+ return_error(gs_error_rangecheck);
+ if (params->N != floor(params->N)) {
+ /* Non-integral exponent, all inputs must be non-negative. */
+ if (params->Domain[0] < 0)
+ return_error(gs_error_rangecheck);
+ }
+ if (params->N < 0) {
+ /* Negative exponent, input must not be zero. */
+ if (params->Domain[0] <= 0 && params->Domain[1] >= 0)
+ return_error(gs_error_rangecheck);
+ } {
+ gs_function_ElIn_t *pfn =
+ gs_alloc_struct(mem, gs_function_ElIn_t, &st_function_ElIn,
+ "gs_function_ElIn_init");
+
+ if (pfn == 0)
+ return_error(gs_error_VMerror);
+ pfn->params = *params;
+ pfn->params.m = 1;
+ pfn->head = function_ElIn_head;
+ *ppfn = (gs_function_t *) pfn;
+ }
+ return 0;
+}
+
+/* ---------------- 1-Input Stitching functions ---------------- */
+
+typedef struct gs_function_1ItSg_s {
+ gs_function_head_t head;
+ gs_function_1ItSg_params_t params;
+} gs_function_1ItSg_t;
+
+private_st_function_1ItSg();
+
+/* Evaluate a 1-Input Stitching function. */
+private int
+fn_1ItSg_evaluate(const gs_function_t * pfn_common, const float *in, float *out)
+{
+ const gs_function_1ItSg_t *const pfn =
+ (const gs_function_1ItSg_t *)pfn_common;
+ float arg = in[0], b0, b1, e0, encoded;
+ int k = pfn->params.k;
+ int i;
+
+ if (arg < pfn->params.Domain[0]) {
+ arg = pfn->params.Domain[0];
+ i = 0;
+ } else if (arg > pfn->params.Domain[1]) {
+ arg = pfn->params.Domain[1];
+ i = k - 1;
+ } else {
+ for (i = 0; i < k - 1; ++i)
+ if (arg <= pfn->params.Bounds[i])
+ break;
+ }
+ b0 = (i == 0 ? pfn->params.Domain[0] : pfn->params.Bounds[i - 1]);
+ b1 = (i == k - 1 ? pfn->params.Domain[1] : pfn->params.Bounds[i]);
+ e0 = pfn->params.Encode[2 * i];
+ encoded =
+ (arg - b0) * (pfn->params.Encode[2 * i + 1] - e0) / (b1 - b0) + e0;
+ return gs_function_evaluate(pfn->params.Functions[i], &encoded, out);
+}
+
+/* Test whether a 1-Input Stitching function is monotonic. */
+private int
+fn_1ItSg_is_monotonic(const gs_function_t * pfn_common,
+ const float *lower, const float *upper, bool must_know)
+{
+ const gs_function_1ItSg_t *const pfn =
+ (const gs_function_1ItSg_t *)pfn_common;
+
+ if (lower[0] > pfn->params.Domain[1] ||
+ upper[0] < pfn->params.Domain[0]
+ )
+ return_error(gs_error_rangecheck);
+/****** NYI ******/
+ return gs_error_undefined;
+}
+
+/* Free the parameters of a 1-Input Stitching function. */
+void
+gs_function_1ItSg_free_params(gs_function_1ItSg_params_t * params,
+ gs_memory_t * mem)
+{
+ gs_free_object(mem, (void *)params->Encode, "Encode"); /* break const */
+ gs_free_object(mem, (void *)params->Bounds, "Bounds"); /* break const */
+ fn_free_functions((gs_function_t **) params->Functions, /* break const */
+ params->k, mem);
+ fn_common_free_params((gs_function_params_t *) params, mem);
+}
+
+/* Allocate and initialize a 1-Input Stitching function. */
+int
+gs_function_1ItSg_init(gs_function_t ** ppfn,
+ const gs_function_1ItSg_params_t * params, gs_memory_t * mem)
+{
+ static const gs_function_head_t function_1ItSg_head =
+ {
+ function_type_1InputStitching,
+ (fn_evaluate_proc_t) fn_1ItSg_evaluate,
+ (fn_is_monotonic_proc_t) fn_1ItSg_is_monotonic,
+ (fn_free_params_proc_t) gs_function_1ItSg_free_params,
+ fn_common_free
+ };
+ int n = (params->Range == 0 ? 0 : params->n);
+ float prev = params->Domain[0];
+ int i;
+
+ *ppfn = 0; /* in case of error */
+ for (i = 0; i < params->k; ++i) {
+ const gs_function_t *psubfn = params->Functions[i];
+
+ if (psubfn->params.m != 1)
+ return_error(gs_error_rangecheck);
+ if (n == 0)
+ n = psubfn->params.n;
+ else if (psubfn->params.n != n)
+ return_error(gs_error_rangecheck);
+ /* There are only k - 1 Bounds, not k. */
+ if (i < params->k - 1) {
+ if (params->Bounds[i] <= prev)
+ return_error(gs_error_rangecheck);
+ prev = params->Bounds[i];
+ }
+ }
+ if (params->Domain[1] < prev)
+ return_error(gs_error_rangecheck);
+ fn_check_mnDR((const gs_function_params_t *)params, 1, n);
+ {
+ gs_function_1ItSg_t *pfn =
+ gs_alloc_struct(mem, gs_function_1ItSg_t, &st_function_1ItSg,
+ "gs_function_1ItSg_init");
+
+ if (pfn == 0)
+ return_error(gs_error_VMerror);
+ pfn->params = *params;
+ pfn->params.m = 1;
+ pfn->params.n = n;
+ pfn->head = function_1ItSg_head;
+ *ppfn = (gs_function_t *) pfn;
+ }
+ return 0;
+}
+
+/* ---------------- Arrayed Output functions ---------------- */
+
+typedef struct gs_function_AdOt_s {
+ gs_function_head_t head;
+ gs_function_AdOt_params_t params;
+} gs_function_AdOt_t;
+
+private_st_function_AdOt();
+
+/* Evaluate an Arrayed Output function. */
+private int
+fn_AdOt_evaluate(const gs_function_t * pfn_common, const float *in, float *out)
+{
+ const gs_function_AdOt_t *const pfn =
+ (const gs_function_AdOt_t *)pfn_common;
+ int i;
+
+ for (i = 0; i < pfn->params.n; ++i) {
+ int code =
+ gs_function_evaluate(pfn->params.Functions[i], in, out + i);
+
+ if (code < 0)
+ return code;
+ }
+ return 0;
+}
+
+/* Test whether an Arrayed Output function is monotonic. */
+private int
+fn_AdOt_is_monotonic(const gs_function_t * pfn_common,
+ const float *lower, const float *upper, bool must_know)
+{
+ const gs_function_AdOt_t *const pfn =
+ (const gs_function_AdOt_t *)pfn_common;
+ int i;
+
+ for (i = 0; i < pfn->params.n; ++i) {
+ int code =
+ gs_function_is_monotonic(pfn->params.Functions[i], lower, upper,
+ must_know);
+
+ if (code <= 0)
+ return code;
+ }
+ return 1;
+}
+
+/* Free the parameters of an Arrayed Output function. */
+void
+gs_function_AdOt_free_params(gs_function_AdOt_params_t * params,
+ gs_memory_t * mem)
+{
+ fn_free_functions((gs_function_t **) params->Functions, /* break const */
+ params->n, mem);
+ fn_common_free_params((gs_function_params_t *) params, mem);
+}
+
+/* Allocate and initialize an Arrayed Output function. */
+int
+gs_function_AdOt_init(gs_function_t ** ppfn,
+ const gs_function_AdOt_params_t * params, gs_memory_t * mem)
+{
+ static const gs_function_head_t function_AdOt_head =
+ {
+ function_type_ArrayedOutput,
+ (fn_evaluate_proc_t) fn_AdOt_evaluate,
+ (fn_is_monotonic_proc_t) fn_AdOt_is_monotonic,
+ (fn_free_params_proc_t) gs_function_AdOt_free_params,
+ fn_common_free
+ };
+ int m = params->m, n = params->n;
+ int i;
+
+ *ppfn = 0; /* in case of error */
+ if (m <= 0 || n <= 0)
+ return_error(gs_error_rangecheck);
+ for (i = 0; i < n; ++i) {
+ const gs_function_t *psubfn = params->Functions[i];
+
+ if (psubfn->params.m != m || psubfn->params.n != 1)
+ return_error(gs_error_rangecheck);
+ }
+ {
+ gs_function_AdOt_t *pfn =
+ gs_alloc_struct(mem, gs_function_AdOt_t, &st_function_AdOt,
+ "gs_function_AdOt_init");
+
+ if (pfn == 0)
+ return_error(gs_error_VMerror);
+ pfn->params = *params;
+ pfn->params.Domain = 0;
+ pfn->params.Range = 0;
+ pfn->head = function_AdOt_head;
+ *ppfn = (gs_function_t *) pfn;
+ }
+ return 0;
+}
diff --git a/gs/src/gsfunc3.h b/gs/src/gsfunc3.h
new file mode 100644
index 000000000..5eca1cd59
--- /dev/null
+++ b/gs/src/gsfunc3.h
@@ -0,0 +1,108 @@
+/* Copyright (C) 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gsfunc3.h */
+/* Definitions for LL3 Functions */
+
+#ifndef gsfunc3_INCLUDED
+# define gsfunc3_INCLUDED
+
+#include "gsfunc.h"
+#include "gsdsrc.h"
+
+/* ---------------- Types and structures ---------------- */
+
+/*
+ * Define the Function types.
+ * See gsfunc.h for why gs_function_type_t can't be an enum type.
+ */
+enum {
+ function_type_ExponentialInterpolation = 2,
+ function_type_1InputStitching = 3,
+ /* For internal use only */
+ function_type_ArrayedOutput = -1
+};
+
+/* Define Exponential Interpolation functions. */
+typedef struct gs_function_ElIn_params_s {
+ gs_function_params_common;
+ const float *C0; /* n, optional */
+ const float *C1; /* n, optional */
+ float N;
+} gs_function_ElIn_params_t;
+
+#define private_st_function_ElIn() /* in gsfunc.c */\
+ gs_private_st_suffix_add2(st_function_ElIn, gs_function_ElIn_t,\
+ "gs_function_ElIn_t", function_ElIn_enum_ptrs, function_ElIn_reloc_ptrs,\
+ st_function, params.C0, params.C1)
+
+/* Define 1-Input Stitching functions. */
+typedef struct gs_function_1ItSg_params_s {
+ gs_function_params_common;
+ int k;
+ const gs_function_t *const *Functions; /* k */
+ const float *Bounds; /* k - 1 */
+ const float *Encode; /* 2 x k */
+} gs_function_1ItSg_params_t;
+
+#define private_st_function_1ItSg() /* in gsfunc.c */\
+ gs_private_st_suffix_add3(st_function_1ItSg, gs_function_1ItSg_t,\
+ "gs_function_1ItSg_t", function_1ItSg_enum_ptrs, function_1ItSg_reloc_ptrs,\
+ st_function, params.Functions, params.Bounds, params.Encode)
+
+/*
+ * Define Arrayed Output functions. These consist of n m x 1 functions
+ * whose outputs are assembled into the output of the arrayed function.
+ * We use them to handle certain PostScript constructs that can accept
+ * either a single n-output function or n 1-output functions.
+ *
+ * Note that for this type, and only this type, both Domain and Range
+ * are ignored (0).
+ */
+typedef struct gs_function_AdOt_params_s {
+ gs_function_params_common;
+ const gs_function_t *const *Functions; /* n */
+} gs_function_AdOt_params_t;
+
+#define private_st_function_AdOt() /* in gsfunc.c */\
+ gs_private_st_suffix_add1(st_function_AdOt, gs_function_AdOt_t,\
+ "gs_function_AdOt_t", function_AdOt_enum_ptrs, function_AdOt_reloc_ptrs,\
+ st_function, params.Functions)
+
+/* ---------------- Procedures ---------------- */
+
+/* Allocate and initialize functions of specific types. */
+int gs_function_ElIn_init(P3(gs_function_t ** ppfn,
+ const gs_function_ElIn_params_t * params,
+ gs_memory_t * mem));
+int gs_function_1ItSg_init(P3(gs_function_t ** ppfn,
+ const gs_function_1ItSg_params_t * params,
+ gs_memory_t * mem));
+int gs_function_AdOt_init(P3(gs_function_t ** ppfn,
+ const gs_function_AdOt_params_t * params,
+ gs_memory_t * mem));
+
+/* Free parameters of specific types. */
+void gs_function_ElIn_free_params(P2(gs_function_ElIn_params_t * params,
+ gs_memory_t * mem));
+void gs_function_1ItSg_free_params(P2(gs_function_1ItSg_params_t * params,
+ gs_memory_t * mem));
+void gs_function_AdOt_free_params(P2(gs_function_AdOt_params_t * params,
+ gs_memory_t * mem));
+
+#endif /* gsfunc3_INCLUDED */
diff --git a/gs/src/gsiparm2.h b/gs/src/gsiparm2.h
new file mode 100644
index 000000000..859db6e7c
--- /dev/null
+++ b/gs/src/gsiparm2.h
@@ -0,0 +1,64 @@
+/* Copyright (C) 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gsiparm2.h */
+/* ImageType 2 image parameter definition */
+
+#ifndef gsiparm2_INCLUDED
+# define gsiparm2_INCLUDED
+
+#include "gsiparam.h"
+
+/* Opaque type for a path */
+#ifndef gx_path_DEFINED
+# define gx_path_DEFINED
+typedef struct gx_path_s gx_path;
+
+#endif
+
+/*
+ * See Section 7.1 of the Adobe PostScript Version 3010 Supplement
+ * for a definition of ImageType 2 images.
+ */
+
+typedef struct gs_image2_s {
+ gs_image_common;
+ gs_state *DataSource;
+ float XOrigin, YOrigin;
+ float Width, Height;
+ /*
+ * If UnpaintedPath is not 0, any unpainted path will be appended to it.
+ */
+ gx_path *UnpaintedPath;
+ bool PixelCopy;
+} gs_image2_t;
+
+/* ImageType 2 images compute the source size differently. */
+#define image2_type_data\
+ gx_begin_image2, gx_image2_source_size, 2
+#define image2_enum_procs_data\
+ 0/*num_planes*/, gx_no_image_plane_data, gx_ignore_end_image
+
+/*
+ * Initialize an ImageType 2 image. Defaults:
+ * UnpaintedPath = 0
+ * PixelCopy = false
+ */
+void gs_image2_t_init(P1(gs_image2_t * pim));
+
+#endif /* gsiparm2_INCLUDED */
diff --git a/gs/src/gsmalloc.c b/gs/src/gsmalloc.c
new file mode 100644
index 000000000..cf6048b8b
--- /dev/null
+++ b/gs/src/gsmalloc.c
@@ -0,0 +1,389 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gsmalloc.c */
+/* C heap allocator */
+#include "malloc_.h"
+#include "gdebug.h"
+#include "gstypes.h"
+#include "gsmemory.h"
+#include "gsmdebug.h"
+#include "gsstruct.h" /* for st_bytes */
+#include "gsmalloc.h"
+
+/* ------ Heap allocator ------ */
+
+/*
+ * An implementation of Ghostscript's memory manager interface
+ * that works directly with the C heap. We keep track of all allocated
+ * blocks so we can free them at cleanup time.
+ */
+/* Raw memory procedures */
+private gs_memory_proc_alloc_bytes(gs_heap_alloc_bytes);
+private gs_memory_proc_resize_object(gs_heap_resize_object);
+private gs_memory_proc_free_object(gs_heap_free_object);
+private gs_memory_proc_status(gs_heap_status);
+private gs_memory_proc_free_all(gs_heap_free_all);
+
+/* Object memory procedures */
+private gs_memory_proc_alloc_struct(gs_heap_alloc_struct);
+private gs_memory_proc_alloc_byte_array(gs_heap_alloc_byte_array);
+private gs_memory_proc_alloc_struct_array(gs_heap_alloc_struct_array);
+private gs_memory_proc_object_size(gs_heap_object_size);
+private gs_memory_proc_object_type(gs_heap_object_type);
+private gs_memory_proc_alloc_string(gs_heap_alloc_string);
+private gs_memory_proc_resize_string(gs_heap_resize_string);
+private gs_memory_proc_free_string(gs_heap_free_string);
+private gs_memory_proc_register_root(gs_heap_register_root);
+private gs_memory_proc_unregister_root(gs_heap_unregister_root);
+private gs_memory_proc_enable_free(gs_heap_enable_free);
+private const gs_memory_procs_t gs_malloc_memory_procs =
+{
+ /* Raw memory procedures */
+ gs_heap_alloc_bytes,
+ gs_heap_resize_object,
+ gs_heap_free_object,
+ gs_heap_status,
+ gs_heap_free_all,
+ /* Object memory procedures */
+ gs_heap_alloc_bytes,
+ gs_heap_alloc_struct,
+ gs_heap_alloc_struct,
+ gs_heap_alloc_byte_array,
+ gs_heap_alloc_byte_array,
+ gs_heap_alloc_struct_array,
+ gs_heap_alloc_struct_array,
+ gs_heap_object_size,
+ gs_heap_object_type,
+ gs_heap_alloc_string,
+ gs_heap_alloc_string,
+ gs_heap_resize_string,
+ gs_heap_free_string,
+ gs_heap_register_root,
+ gs_heap_unregister_root,
+ gs_heap_enable_free
+};
+
+/* We must make sure that malloc_blocks leave the block aligned. */
+/*typedef struct gs_malloc_block_s gs_malloc_block_t; */
+#define malloc_block_data\
+ gs_malloc_block_t *next;\
+ gs_malloc_block_t *prev;\
+ uint size;\
+ gs_memory_type_ptr_t type;\
+ client_name_t cname
+struct malloc_block_data_s {
+ malloc_block_data;
+};
+struct gs_malloc_block_s {
+ malloc_block_data;
+/* ANSI C does not allow zero-size arrays, so we need the following */
+/* unnecessary and wasteful workaround: */
+#define _npad (-size_of(struct malloc_block_data_s) & 7)
+ byte _pad[(_npad == 0 ? 8 : _npad)]; /* pad to double */
+#undef _npad
+};
+
+/* Define the default allocator. */
+gs_malloc_memory_t *gs_malloc_memory_default;
+
+/* Initialize a malloc allocator. */
+private long heap_available(P0());
+gs_malloc_memory_t *
+gs_malloc_memory_init(void)
+{
+ gs_malloc_memory_t *mem = malloc(sizeof(gs_malloc_memory_t));
+
+ mem->procs = gs_malloc_memory_procs;
+ mem->allocated = 0;
+ mem->limit = max_long;
+ mem->used = 0;
+ mem->max_used = 0;
+ return mem;
+}
+/*
+ * Estimate the amount of available memory by probing with mallocs.
+ * We may under-estimate by a lot, but that's better than winding up with
+ * a seriously inflated address space. This is quite a hack!
+ */
+#define max_malloc_probes 20
+#define malloc_probe_size 64000
+private long
+heap_available(void)
+{
+ long avail = 0;
+ void *probes[max_malloc_probes];
+ uint n;
+
+ for (n = 0; n < max_malloc_probes; n++) {
+ if ((probes[n] = malloc(malloc_probe_size)) == 0)
+ break;
+ if_debug2('a', "[a]heap_available probe[%d]=0x%lx\n",
+ n, (ulong) probes[n]);
+ avail += malloc_probe_size;
+ }
+ while (n)
+ free(probes[--n]);
+ return avail;
+}
+
+/* Allocate various kinds of blocks. */
+private byte *
+gs_heap_alloc_bytes(gs_memory_t * mem, uint size, client_name_t cname)
+{
+ gs_malloc_memory_t *mmem = (gs_malloc_memory_t *) mem;
+ byte *ptr = 0;
+
+#ifdef DEBUG
+ const char *msg;
+ static const char *const ok_msg = "OK";
+
+# define set_msg(str) (msg = (str))
+#else
+# define set_msg(str) DO_NOTHING
+#endif
+
+ if (size > mmem->limit - sizeof(gs_malloc_block_t)) {
+ /* Definitely too large to allocate; also avoids overflow. */
+ set_msg("exceeded limit");
+ } else {
+ uint added = size + sizeof(gs_malloc_block_t);
+
+ if (mmem->limit - added < mmem->used)
+ set_msg("exceeded limit");
+ else if ((ptr = (byte *) malloc(added)) == 0)
+ set_msg("failed");
+ else {
+ gs_malloc_block_t *bp = (gs_malloc_block_t *) ptr;
+
+ if (mmem->allocated)
+ mmem->allocated->prev = bp;
+ bp->next = mmem->allocated;
+ bp->prev = 0;
+ bp->size = size;
+ bp->type = &st_bytes;
+ bp->cname = cname;
+ mmem->allocated = bp;
+ set_msg(ok_msg);
+ ptr = (byte *) (bp + 1);
+ gs_alloc_fill(ptr, gs_alloc_fill_alloc, size);
+ mmem->used += size + sizeof(gs_malloc_block_t);
+ if (mmem->used > mmem->max_used)
+ mmem->max_used = mmem->used;
+ }
+ }
+#ifdef DEBUG
+ if (gs_debug_c('a') || msg != ok_msg)
+ dlprintf4("[a+]gs_malloc(%s)(%u) = 0x%lx: %s\n",
+ client_name_string(cname), size, (ulong) ptr, msg);
+#endif
+ return ptr;
+#undef set_msg
+}
+private void *
+gs_heap_alloc_struct(gs_memory_t * mem, gs_memory_type_ptr_t pstype,
+ client_name_t cname)
+{
+ void *ptr =
+ gs_heap_alloc_bytes(mem, gs_struct_type_size(pstype), cname);
+
+ if (ptr == 0)
+ return 0;
+ ((gs_malloc_block_t *) ptr)[-1].type = pstype;
+ return ptr;
+}
+private byte *
+gs_heap_alloc_byte_array(gs_memory_t * mem, uint num_elements, uint elt_size,
+ client_name_t cname)
+{
+ ulong lsize = (ulong) num_elements * elt_size;
+
+ if (lsize != (uint) lsize)
+ return 0;
+ return gs_heap_alloc_bytes(mem, (uint) lsize, cname);
+}
+private void *
+gs_heap_alloc_struct_array(gs_memory_t * mem, uint num_elements,
+ gs_memory_type_ptr_t pstype, client_name_t cname)
+{
+ void *ptr =
+ gs_heap_alloc_byte_array(mem, num_elements,
+ gs_struct_type_size(pstype), cname);
+
+ if (ptr == 0)
+ return 0;
+ ((gs_malloc_block_t *) ptr)[-1].type = pstype;
+ return ptr;
+}
+private void *
+gs_heap_resize_object(gs_memory_t * mem, void *obj, uint new_num_elements,
+ client_name_t cname)
+{
+ gs_malloc_memory_t *mmem = (gs_malloc_memory_t *) mem;
+ gs_malloc_block_t *ptr = (gs_malloc_block_t *) obj - 1;
+ gs_memory_type_ptr_t pstype = ptr->type;
+ uint old_size = gs_object_size(mem, obj) + sizeof(gs_malloc_block_t);
+ uint new_size =
+ gs_struct_type_size(pstype) * new_num_elements +
+ sizeof(gs_malloc_block_t);
+ gs_malloc_block_t *new_ptr =
+ (gs_malloc_block_t *) gs_realloc(ptr, old_size, new_size);
+
+ if (new_ptr == 0)
+ return 0;
+ if (new_ptr->prev)
+ new_ptr->prev->next = new_ptr;
+ else
+ mmem->allocated = new_ptr;
+ if (new_ptr->next)
+ new_ptr->next->prev = new_ptr;
+ new_ptr->size = new_size - sizeof(gs_malloc_block_t);
+ mmem->used -= old_size;
+ mmem->used += new_size;
+ if (new_size > old_size)
+ gs_alloc_fill((byte *) new_ptr + old_size,
+ gs_alloc_fill_alloc, new_size - old_size);
+ return new_ptr + 1;
+}
+private uint
+gs_heap_object_size(gs_memory_t * mem, const void *ptr)
+{
+ return ((const gs_malloc_block_t *)ptr)[-1].size;
+}
+private gs_memory_type_ptr_t
+gs_heap_object_type(gs_memory_t * mem, const void *ptr)
+{
+ return ((const gs_malloc_block_t *)ptr)[-1].type;
+}
+private void
+gs_heap_free_object(gs_memory_t * mem, void *ptr, client_name_t cname)
+{
+ gs_malloc_memory_t *mmem = (gs_malloc_memory_t *) mem;
+ gs_malloc_block_t *bp = mmem->allocated;
+
+ if (gs_debug_c('a'))
+ dlprintf3("[a-]gs_free(%s) 0x%lx(%u)\n",
+ client_name_string(cname), (ulong) ptr,
+ (ptr == 0 ? 0 : ((gs_malloc_block_t *) ptr)[-1].size));
+ if (ptr == 0)
+ return;
+ if (ptr == bp + 1) {
+ mmem->allocated = bp->next;
+ mmem->used -= bp->size + sizeof(gs_malloc_block_t);
+
+ if (mmem->allocated)
+ mmem->allocated->prev = 0;
+ gs_alloc_fill(bp, gs_alloc_fill_free,
+ bp->size + sizeof(gs_malloc_block_t));
+ free(bp);
+ } else {
+ gs_malloc_block_t *np;
+
+ for (; (np = bp->next) != 0; bp = np) {
+ if (ptr == np + 1) {
+ bp->next = np->next;
+ if (np->next)
+ np->next->prev = bp;
+ mmem->used -= np->size + sizeof(gs_malloc_block_t);
+ gs_alloc_fill(np, gs_alloc_fill_free,
+ np->size + sizeof(gs_malloc_block_t));
+ free(np);
+ return;
+ }
+ }
+ lprintf2("%s: free 0x%lx not found!\n",
+ client_name_string(cname), (ulong) ptr);
+ free((char *)((gs_malloc_block_t *) ptr - 1));
+ }
+}
+private byte *
+gs_heap_alloc_string(gs_memory_t * mem, uint nbytes, client_name_t cname)
+{
+ return gs_heap_alloc_bytes(mem, nbytes, cname);
+}
+private byte *
+gs_heap_resize_string(gs_memory_t * mem, byte * data, uint old_num, uint new_num,
+ client_name_t cname)
+{
+ if (gs_heap_object_type(mem, data) != &st_bytes)
+ lprintf2("%s: resizing non-string 0x%lx!\n",
+ client_name_string(cname), (ulong) data);
+ return gs_heap_resize_object(mem, data, new_num, cname);
+}
+private void
+gs_heap_free_string(gs_memory_t * mem, byte * data, uint nbytes,
+ client_name_t cname)
+{
+/****** SHOULD CHECK SIZE IF DEBUGGING ******/
+ gs_heap_free_object(mem, data, cname);
+}
+private void
+gs_heap_register_root(gs_memory_t * mem, gs_gc_root_t * rp, gs_ptr_type_t ptype,
+ void **up, client_name_t cname)
+{
+}
+private void
+gs_heap_unregister_root(gs_memory_t * mem, gs_gc_root_t * rp,
+ client_name_t cname)
+{
+}
+private void
+gs_heap_status(gs_memory_t * mem, gs_memory_status_t * pstat)
+{
+ gs_malloc_memory_t *mmem = (gs_malloc_memory_t *) mem;
+
+ pstat->allocated = mmem->used + heap_available();
+ pstat->used = mmem->used;
+}
+private void
+gs_heap_enable_free(gs_memory_t * mem, bool enable)
+{
+ if (enable)
+ mem->procs.free_object = gs_heap_free_object,
+ mem->procs.free_string = gs_heap_free_string;
+ else
+ mem->procs.free_object = gs_ignore_free_object,
+ mem->procs.free_string = gs_ignore_free_string;
+}
+
+/* Release all memory acquired by this allocator. */
+private void
+gs_heap_free_all(gs_memory_t * mem)
+{
+ gs_malloc_memory_t *const mmem = (gs_malloc_memory_t *) mem;
+ gs_malloc_block_t *bp = mmem->allocated;
+ gs_malloc_block_t *np;
+
+ for (; bp != 0; bp = np) {
+ np = bp->next;
+ if (gs_debug_c('a'))
+ dlprintf3("[a]gs_malloc_release(%s) 0x%lx(%u)\n",
+ client_name_string(bp->cname), (ulong) (bp + 1),
+ bp->size);
+ gs_alloc_fill(bp + 1, gs_alloc_fill_free, bp->size);
+ free(bp);
+ }
+}
+
+/* Release all malloc'ed blocks, and free the allocator. */
+void
+gs_malloc_memory_release(gs_malloc_memory_t * mem)
+{
+ gs_free_all((gs_memory_t *) mem);
+ free(mem);
+}
diff --git a/gs/src/gsmalloc.h b/gs/src/gsmalloc.h
new file mode 100644
index 000000000..ca1ae51a3
--- /dev/null
+++ b/gs/src/gsmalloc.h
@@ -0,0 +1,71 @@
+/* Copyright (C) 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gsmalloc.h */
+/* Client interface to default (C heap) allocator */
+/* Requires gsmemory.h */
+
+#ifndef gsmalloc_INCLUDED
+# define gsmalloc_INCLUDED
+
+/* Define a memory manager that allocates directly from the C heap. */
+typedef struct gs_malloc_block_s gs_malloc_block_t;
+typedef struct gs_malloc_memory_s {
+ gs_memory_common;
+ gs_malloc_block_t *allocated;
+ long limit;
+ long used;
+ long max_used;
+} gs_malloc_memory_t;
+
+/* Allocate and initialize a malloc memory manager. */
+gs_malloc_memory_t *gs_malloc_memory_init(P0());
+
+/* Release all the allocated blocks, and free the memory manager. */
+void gs_malloc_memory_release(P1(gs_malloc_memory_t *));
+
+/*
+ * Define a default allocator that allocates from the C heap.
+ * (We would really like to get rid of this.)
+ */
+
+extern gs_malloc_memory_t *gs_malloc_memory_default;
+
+#define gs_memory_default (*(gs_memory_t *)gs_malloc_memory_default)
+
+/*
+ * The following procedures are historical artifacts that we hope to
+ * get rid of someday.
+ */
+#define gs_malloc_init()\
+ (gs_malloc_memory_default = gs_malloc_memory_init())
+#define gs_malloc_release()\
+ (gs_malloc_memory_release(gs_malloc_memory_default),\
+ gs_malloc_memory_default = 0)
+#define gs_malloc(nelts, esize, cname)\
+ (void *)gs_alloc_byte_array(&gs_memory_default, nelts, esize, cname)
+#define gs_free(data, nelts, esize, cname)\
+ gs_free_object(&gs_memory_default, data, cname)
+
+/* Define an accessor for the limit on the total allocated heap space. */
+#define gs_malloc_limit (gs_malloc_memory_default->limit)
+
+/* Define an accessor for the maximum amount ever allocated from the heap. */
+#define gs_malloc_max (gs_malloc_memory_default->max_used)
+
+#endif /* gsmalloc_INCLUDED */
diff --git a/gs/src/gsnorop.c b/gs/src/gsnorop.c
new file mode 100644
index 000000000..163a65267
--- /dev/null
+++ b/gs/src/gsnorop.c
@@ -0,0 +1,113 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gsnorop.c */
+/* Stubs for unimplemented RasterOp */
+#include "gx.h"
+#include "gserrors.h"
+#include "gsrop.h"
+#include "gxdevcli.h"
+#include "gdevmrop.h"
+
+/* Stub accessors to logical operation in graphics state. */
+
+gs_logical_operation_t
+gs_current_logical_op(const gs_state * pgs)
+{
+ return lop_default;
+}
+
+int
+gs_set_logical_op(gs_state * pgs, gs_logical_operation_t lop)
+{
+ return (lop == lop_default ? 0 : gs_note_error(gs_error_rangecheck));
+}
+
+/* Stub RasterOp implementations for memory devices. */
+
+int
+mem_mono_strip_copy_rop(gx_device * dev,
+ const byte * sdata, int sourcex, uint sraster, gx_bitmap_id id,
+ const gx_color_index * scolors,
+ const gx_strip_bitmap * textures, const gx_color_index * tcolors,
+ int x, int y, int width, int height,
+ int phase_x, int phase_y, gs_logical_operation_t lop)
+{
+ return_error(gs_error_rangecheck);
+}
+
+int
+mem_gray_strip_copy_rop(gx_device * dev,
+ const byte * sdata, int sourcex, uint sraster, gx_bitmap_id id,
+ const gx_color_index * scolors,
+ const gx_strip_bitmap * textures, const gx_color_index * tcolors,
+ int x, int y, int width, int height,
+ int phase_x, int phase_y, gs_logical_operation_t lop)
+{
+ return_error(gs_error_rangecheck);
+}
+
+int
+mem_gray8_rgb24_strip_copy_rop(gx_device * dev,
+ const byte * sdata, int sourcex, uint sraster, gx_bitmap_id id,
+ const gx_color_index * scolors,
+ const gx_strip_bitmap * textures, const gx_color_index * tcolors,
+ int x, int y, int width, int height,
+ int phase_x, int phase_y, gs_logical_operation_t lop)
+{
+ return_error(gs_error_rangecheck);
+}
+
+/* Stub default implementations of device procedures. */
+
+int
+gx_default_copy_rop(gx_device * dev,
+ const byte * sdata, int sourcex, uint sraster, gx_bitmap_id id,
+ const gx_color_index * scolors,
+ const gx_tile_bitmap * texture, const gx_color_index * tcolors,
+ int x, int y, int width, int height,
+ int phase_x, int phase_y, gs_logical_operation_t lop)
+{
+ return_error(gs_error_unknownerror); /* not implemented */
+}
+
+int
+gx_default_strip_copy_rop(gx_device * dev,
+ const byte * sdata, int sourcex, uint sraster, gx_bitmap_id id,
+ const gx_color_index * scolors,
+ const gx_strip_bitmap * textures, const gx_color_index * tcolors,
+ int x, int y, int width, int height,
+ int phase_x, int phase_y, gs_logical_operation_t lop)
+{
+ return_error(gs_error_unknownerror); /* not implemented */
+}
+
+/* Stub RasterOp source devices. */
+
+int
+gx_alloc_rop_texture_device(gx_device_rop_texture ** prsdev, gs_memory_t * mem,
+ client_name_t cname)
+{
+ return_error(gs_error_rangecheck);
+}
+
+void
+gx_make_rop_texture_device(gx_device_rop_texture * dev, gx_device * target,
+ gs_logical_operation_t log_op, const gx_device_color * texture)
+{ /* Never called. */
+}
diff --git a/gs/src/gsptype2.h b/gs/src/gsptype2.h
new file mode 100644
index 000000000..95e7f9489
--- /dev/null
+++ b/gs/src/gsptype2.h
@@ -0,0 +1,46 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gsptype2.h */
+/* Client interface to PatternType 2 Patterns */
+
+#ifndef gsptype2_INCLUDED
+# define gsptype2_INCLUDED
+
+#include "gspcolor.h"
+
+/* ---------------- Types and structures ---------------- */
+
+#ifndef gs_shading_t_DEFINED
+# define gs_shading_t_DEFINED
+typedef struct gs_shading_s gs_shading_t;
+
+#endif
+
+/* PatternType 2 template */
+typedef struct gs_pattern2_template_s {
+ gs_pattern_template_common;
+ const gs_shading_t *Shading;
+} gs_pattern2_template_t;
+
+/* ---------------- Procedures ---------------- */
+
+/* Initialize a PatternType 2 pattern. */
+void gs_pattern2_init(P1(gs_pattern2_template_t *));
+
+#endif /* gsptype2_INCLUDED */
diff --git a/gs/src/gsrect.h b/gs/src/gsrect.h
new file mode 100644
index 000000000..9b4044622
--- /dev/null
+++ b/gs/src/gsrect.h
@@ -0,0 +1,55 @@
+/* Copyright (C) 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gsrect.h */
+/* Rectangle utilities */
+
+#ifndef gsrect_INCLUDED
+# define gsrect_INCLUDED
+
+/* Check whether one rectangle is included entirely within another. */
+#define rect_within(inner, outer)\
+ (inner.q.y <= outer.q.y && inner.q.x <= outer.q.x &&\
+ inner.p.y >= outer.p.y && inner.p.x >= outer.p.x)
+
+/*
+ * Intersect two rectangles, replacing the first. The result may be
+ * anomalous (q < p) if the intersection is empty.
+ */
+#define rect_intersect(to, from)\
+ BEGIN\
+ if ( from.p.x > to.p.x ) to.p.x = from.p.x;\
+ if ( from.q.x < to.q.x ) to.q.x = from.q.x;\
+ if ( from.p.y > to.p.y ) to.p.y = from.p.y;\
+ if ( from.q.y < to.q.y ) to.q.y = from.q.y;\
+ END
+
+/*
+ * Calculate the difference of two rectangles, a list of up to 4 rectangles.
+ * Return the number of rectangles in the list, and set the first rectangle
+ * to the intersection. The resulting first rectangle is guaranteed not to
+ * be anomalous (q < p) iff it was not anomalous originally.
+ *
+ * Note that unlike the macros above, we need different versions of this
+ * depending on the data type of the individual values: we'll only implement
+ * the variations that we need.
+ */
+int int_rect_difference(P3(gs_int_rect * outer, const gs_int_rect * inner,
+ gs_int_rect * diffs /*[4] */ ));
+
+#endif /* gsrect_INCLUDED */
diff --git a/gs/src/gsropc.c b/gs/src/gsropc.c
new file mode 100644
index 000000000..4c99238e1
--- /dev/null
+++ b/gs/src/gsropc.c
@@ -0,0 +1,310 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gsropc.c */
+/* RasterOp-compositing implementation */
+#include "gx.h"
+#include "gserrors.h"
+#include "gsutil.h" /* for gs_next_ids */
+#include "gxdcolor.h"
+#include "gxdevice.h"
+#include "gxdevmem.h"
+#include "gxropc.h"
+
+/* ------ Object definition and creation ------ */
+
+/* Define RasterOp-compositing objects. */
+private composite_create_default_compositor_proc(c_rop_create_default_compositor);
+private composite_equal_proc(c_rop_equal);
+private composite_write_proc(c_rop_write);
+private composite_read_proc(c_rop_read);
+private const gs_composite_type_t gs_composite_rop_type =
+{
+ {
+ c_rop_create_default_compositor,
+ c_rop_equal,
+ c_rop_write,
+ c_rop_read
+ }
+};
+
+private_st_composite_rop();
+
+/* Create a RasterOp-compositing object. */
+int
+gs_create_composite_rop(gs_composite_t ** ppcte,
+ const gs_composite_rop_params_t * params, gs_memory_t * mem)
+{
+ gs_composite_rop_t *pcte;
+
+ rc_alloc_struct_0(pcte, gs_composite_rop_t, &st_composite_rop,
+ mem, return_error(gs_error_VMerror),
+ "gs_create_composite_rop");
+ pcte->type = &gs_composite_rop_type;
+ pcte->id = gs_next_ids(1);
+ pcte->params = *params;
+ *ppcte = (gs_composite_t *) pcte;
+ return 0;
+}
+
+/* ------ Object implementation ------ */
+
+#define prcte ((const gs_composite_rop_t *)pcte)
+
+private bool
+c_rop_equal(const gs_composite_t * pcte, const gs_composite_t * pcte2)
+{
+ return (pcte2->type == pcte->type &&
+#define prcte2 ((const gs_composite_rop_t *)pcte2)
+ prcte2->params.log_op == prcte->params.log_op &&
+ (prcte->params.texture == 0 ? prcte2->params.texture == 0 :
+ prcte2->params.texture != 0 &&
+ gx_device_color_equal(prcte->params.texture,
+ prcte2->params.texture)));
+#undef prcte2
+}
+
+private int
+c_rop_write(const gs_composite_t * pcte, byte * data, uint * psize)
+{
+/****** NYI ******/
+}
+
+private int
+c_rop_read(gs_composite_t ** ppcte, const byte * data, uint size,
+ gs_memory_t * mem)
+{
+/****** NYI ******/
+}
+
+/* ---------------- RasterOp-compositing device ---------------- */
+
+/* Define the default RasterOp-compositing device. */
+typedef struct gx_device_composite_rop_s {
+ gx_device_forward_common;
+ gs_composite_rop_params_t params;
+} gx_device_composite_rop;
+
+gs_private_st_suffix_add1_final(st_device_composite_rop,
+ gx_device_composite_rop, "gx_device_composite_rop",
+ device_c_rop_enum_ptrs, device_c_rop_reloc_ptrs, gx_device_finalize,
+ st_device_forward, params.texture);
+/* The device descriptor. */
+private dev_proc_close_device(dcr_close);
+private dev_proc_fill_rectangle(dcr_fill_rectangle);
+private dev_proc_copy_mono(dcr_copy_mono);
+private dev_proc_copy_color(dcr_copy_color);
+private dev_proc_copy_alpha(dcr_copy_alpha);
+private const gx_device_composite_rop gs_composite_rop_device =
+{std_device_std_body_open(gx_device_composite_rop, 0,
+ "RasterOp compositor", 0, 0, 1, 1),
+ {gx_default_open_device,
+ gx_forward_get_initial_matrix,
+ gx_forward_sync_output,
+ gx_forward_output_page,
+ dcr_close,
+ gx_forward_map_rgb_color,
+ gx_forward_map_color_rgb,
+ dcr_fill_rectangle,
+ gx_default_tile_rectangle,
+ dcr_copy_mono,
+ dcr_copy_color,
+ gx_default_draw_line,
+ gx_default_get_bits,
+ gx_forward_get_params,
+ gx_forward_put_params,
+ gx_forward_map_cmyk_color,
+ gx_forward_get_xfont_procs,
+ gx_forward_get_xfont_device,
+ gx_forward_map_rgb_alpha_color,
+ gx_forward_get_page_device,
+ gx_forward_get_alpha_bits,
+ dcr_copy_alpha,
+ gx_forward_get_band,
+ gx_default_copy_rop,
+ gx_default_fill_path,
+ gx_default_stroke_path,
+ gx_default_fill_mask,
+ gx_default_fill_trapezoid,
+ gx_default_fill_parallelogram,
+ gx_default_fill_triangle,
+ gx_default_draw_thin_line,
+ gx_default_begin_image,
+ gx_default_image_data,
+ gx_default_end_image,
+ gx_default_strip_tile_rectangle,
+ gx_default_strip_copy_rop,
+ gx_forward_get_clipping_box,
+ gx_default_begin_typed_image,
+ gx_forward_get_bits_rectangle,
+ gx_forward_map_color_rgb_alpha,
+ gx_no_create_compositor
+ }
+};
+
+/* Create a RasterOp compositor. */
+int
+c_rop_create_default_compositor(const gs_composite_t * pcte,
+ gx_device ** pcdev, gx_device * dev, const gs_imager_state * pis,
+ gs_memory_t * mem)
+{
+ gs_logical_operation_t log_op = prcte->params.log_op;
+ const gx_device_color *texture = prcte->params.texture;
+ gx_device_composite_rop *cdev;
+
+#if 0 /*************** */
+ if (<<operation is identity >>) {
+ /* Just use the original device. */
+ *pcdev = dev;
+ return 0;
+ }
+#endif /*************** */
+ cdev =
+ gs_alloc_struct_immovable(mem, gx_device_composite_rop,
+ &st_device_composite_rop,
+ "create default RasterOp compositor");
+ *pcdev = (gx_device *) cdev;
+ if (cdev == 0)
+ return_error(gs_error_VMerror);
+ *(gx_device *) cdev = *dev;
+ cdev->dname = gs_composite_rop_device.dname;
+ cdev->memory = mem;
+ cdev->stype = &st_device_composite_rop;
+ cdev->color_info = dev->color_info;
+ assign_dev_procs(cdev, &gs_composite_rop_device);
+ /*
+ * Check for memory devices, and select the correct RasterOp
+ * implementation based on depth and device color space.
+ ****** NYI ******
+ */
+ cdev->target = dev;
+ cdev->params = prcte->params;
+ return 0;
+}
+
+/* Close the device and free its storage. */
+private int
+dcr_close(gx_device * dev)
+{ /*
+ * Finalization will call close again: avoid a recursion loop.
+ */
+ set_dev_proc(dev, close_device, gx_default_close_device);
+ gs_free_object(dev->memory, dev, "dcr_close");
+ return 0;
+}
+
+/* ------ Imaging ------ */
+
+/* Import the existing RasterOp implementations. */
+extern dev_proc_strip_copy_rop(mem_mono_strip_copy_rop);
+extern dev_proc_strip_copy_rop(mem_gray_strip_copy_rop);
+extern dev_proc_strip_copy_rop(mem_gray8_rgb24_strip_copy_rop);
+extern dev_proc_strip_copy_rop(gx_default_strip_copy_rop);
+
+private int
+dcr_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
+ gx_color_index color)
+{
+ gx_device_composite_rop *rdev = (gx_device_composite_rop *) dev;
+
+ /*
+ * This is where all the work gets done right now.
+ * Sooner or later, we'll have to do the right thing here....
+ */
+ gs_logical_operation_t log_op = rdev->params.log_op;
+ const gx_device_color *texture = rdev->params.texture;
+ gx_color_index colors[2];
+ gx_color_index tcolors[2];
+
+ dev_proc_strip_copy_rop((*copy)) = gx_default_strip_copy_rop;
+
+ colors[0] = colors[1] = color;
+ if (gs_device_is_memory(dev)) {
+/****** SHOULD CHECK FOR STANDARD COLOR REPRESENTATION ******/
+ switch (dev->color_info.depth) {
+ case 1:
+ copy = mem_mono_strip_copy_rop;
+ break;
+ case 2:
+ case 4:
+ copy = mem_gray_strip_copy_rop;
+ break;
+ case 8:
+ case 24:
+ copy = mem_gray8_rgb24_strip_copy_rop;
+ break;
+ case 16:
+ case 32:
+/****** NOT IMPLEMENTED ******/
+ }
+ }
+ if (texture == 0) {
+ return (*copy)
+ (dev, (const byte *)0, 0, 0, gx_no_bitmap_id,
+ (const gx_color_index *)0, (const gx_strip_bitmap *)0, colors,
+ x, y, w, h, 0, 0, log_op);
+ }
+ /* Apply the texture, whatever it may be. */
+ if (gx_dc_is_pure(texture)) {
+ tcolors[0] = tcolors[1] = texture->colors.pure;
+ return (*copy)
+ (dev, (const byte *)0, 0, 0, gx_no_bitmap_id, colors,
+ (const gx_strip_bitmap *)0, tcolors,
+ x, y, w, h, 0, 0, log_op);
+ } else if (gx_dc_is_binary_halftone(texture)) {
+ tcolors[0] = texture->colors.binary.color[0];
+ tcolors[1] = texture->colors.binary.color[1];
+ return (*copy)
+ (dev, (const byte *)0, 0, 0, gx_no_bitmap_id, colors,
+ &texture->colors.binary.b_tile->tiles, tcolors,
+ x, y, w, h, texture->phase.x, texture->phase.y, log_op);
+ } else if (gx_dc_is_colored_halftone(texture)) {
+/****** NO CAN DO ******/
+ } else
+/****** WHAT ABOUT PATTERNS? ******/
+ return_error(gs_error_rangecheck);
+}
+
+private int
+dcr_copy_mono(gx_device * dev, const byte * data,
+ int dx, int raster, gx_bitmap_id id, int x, int y, int w, int h,
+ gx_color_index zero, gx_color_index one)
+{
+/****** TEMPORARY ******/
+ return gx_default_copy_mono(dev, data, dx, raster, id, x, y, w, h,
+ zero, one);
+}
+
+private int
+dcr_copy_color(gx_device * dev, const byte * data,
+ int dx, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{
+/****** TEMPORARY ******/
+ return gx_default_copy_color(dev, data, dx, raster, id, x, y, w, h);
+}
+
+private int
+dcr_copy_alpha(gx_device * dev, const byte * data, int data_x,
+ int raster, gx_bitmap_id id, int x, int y, int width, int height,
+ gx_color_index color, int depth)
+{
+/****** TEMPORARY ******/
+ return gx_default_copy_alpha(dev, data, data_x, raster, id, x, y,
+ width, height, color, depth);
+}
diff --git a/gs/src/gsropc.h b/gs/src/gsropc.h
new file mode 100644
index 000000000..bc4cf51d8
--- /dev/null
+++ b/gs/src/gsropc.h
@@ -0,0 +1,54 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gsropc.h */
+/* RasterOp-compositing interface */
+
+#ifndef gsropc_INCLUDED
+# define gsropc_INCLUDED
+
+#include "gscompt.h"
+#include "gsropt.h"
+
+/*
+ * Define parameters for RasterOp-compositing.
+ * There are two kinds of RasterOp compositing operations.
+ * If texture == 0, the input data are the texture, and the source is
+ * implicitly all 0 (black). If texture != 0, it defines the texture,
+ * and the input data are the source. Note that in the latter case,
+ * the client (the caller of gs_create_composite_rop) promises that
+ * *texture will not change.
+ */
+
+#ifndef gx_device_color_DEFINED
+# define gx_device_color_DEFINED
+typedef struct gx_device_color_s gx_device_color;
+
+#endif
+
+typedef struct gs_composite_rop_params_s {
+ gs_logical_operation_t log_op;
+ const gx_device_color *texture;
+} gs_composite_rop_params_t;
+
+/* Create a RasterOp-compositing object. */
+int gs_create_composite_rop(P3(gs_composite_t ** ppcte,
+ const gs_composite_rop_params_t * params,
+ gs_memory_t * mem));
+
+#endif /* gsropc_INCLUDED */
diff --git a/gs/src/gsshade.c b/gs/src/gsshade.c
new file mode 100644
index 000000000..b789caa83
--- /dev/null
+++ b/gs/src/gsshade.c
@@ -0,0 +1,304 @@
+/* Copyright (C) 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gsshade.c */
+/* Constructors for shadings */
+#include "gx.h"
+#include "gscspace.h"
+#include "gserrors.h"
+#include "gsstruct.h" /* for extern_st */
+#include "gxshade.h"
+
+/* ---------------- Generic services ---------------- */
+
+/* GC descriptors */
+private_st_shading();
+private_st_shading_mesh();
+
+/* Check ColorSpace, BBox, and Function (if present). */
+/* Free variables: params. */
+#define check_CBFD(function, domain, m)\
+ BEGIN\
+ int code = check_CBFD_proc((const gs_shading_params_t *)(params),\
+ function, domain, m);\
+ if ( code < 0 ) return code;\
+ END
+#define check_CBF(m) check_CBFD(params->Function, params->Domain, m)
+private int
+check_CBFD_proc(const gs_shading_params_t * params,
+ const gs_function_t * function, const float *domain, int m)
+{
+ int ncomp = gs_color_space_num_components(params->ColorSpace);
+
+ if (ncomp < 0 ||
+ (params->have_BBox &&
+ (params->BBox.p.x > params->BBox.q.x ||
+ params->BBox.p.y > params->BBox.q.y))
+ )
+ return_error(gs_error_rangecheck);
+ if (function != 0) {
+ if (function->params.m != m || function->params.n != ncomp)
+ return_error(gs_error_rangecheck);
+ /*
+ * The Adobe documentation says that the function's domain must
+ * be a superset of the domain defined in the shading dictionary.
+ * However, Adobe implementations apparently don't necessarily
+ * check this ahead of time; therefore, we do the same.
+ */
+#if 0 /*************** */
+ {
+ int i;
+
+ for (i = 0; i < m; ++i)
+ if (function->params.Domain[2 * i] > domain[2 * i] ||
+ function->params.Domain[2 * i + 1] < domain[2 * i + 1]
+ )
+ return_error(gs_error_rangecheck);
+ }
+#endif /*************** */
+ }
+ return 0;
+}
+
+/* Check parameters for a mesh shading. */
+/* Free variables: params. */
+#define check_mesh()\
+ BEGIN\
+ int code = check_mesh_proc((const gs_shading_mesh_params_t *)(params),\
+ (params)->Function, (params)->Decode);\
+ if ( code < 0 ) return code;\
+ END
+private int
+check_mesh_proc(const gs_shading_mesh_params_t * params,
+ const gs_function_t * function, const float *decode)
+{
+ if (!data_source_is_array(params->DataSource)) {
+ check_CBFD(function, decode, 1);
+ switch (params->BitsPerCoordinate) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ case 12:
+ case 16:
+ case 24:
+ case 32:
+ break;
+ default:
+ return_error(gs_error_rangecheck);
+ }
+ switch (params->BitsPerComponent) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ case 12:
+ case 16:
+ break;
+ default:
+ return_error(gs_error_rangecheck);
+ }
+ }
+ return 0;
+}
+
+/* Allocate and initialize a shading. */
+/* Free variables: mem, params, ppsh. */
+#define alloc_shading(shtype, sttype, stype, sfrproc, cname)\
+ BEGIN\
+ shtype *psh = gs_alloc_struct(mem, shtype, sttype, cname);\
+ if ( psh == 0 )\
+ return_error(gs_error_VMerror);\
+ psh->head.type = stype;\
+ psh->head.fill_rectangle = sfrproc;\
+ psh->params = *params;\
+ *ppsh = (gs_shading_t *)psh;\
+ END
+#define alloc_return_shading(shtype, sttype, stype, sfrproc, cname)\
+ BEGIN\
+ alloc_shading(shtype, sttype, stype, sfrproc, cname);\
+ return 0;\
+ END
+
+/* ---------------- Function-based shading ---------------- */
+
+private_st_shading_Fb();
+
+/* Allocate and initialize a Function-based shading. */
+int
+gs_shading_Fb_init(gs_shading_t ** ppsh,
+ const gs_shading_Fb_params_t * params, gs_memory_t * mem)
+{
+ gs_matrix imat;
+
+ check_CBF(2);
+ if (gs_matrix_invert(&params->Matrix, &imat) < 0)
+ return_error(gs_error_rangecheck);
+ alloc_return_shading(gs_shading_Fb_t, &st_shading_Fb,
+ shading_type_Function_based,
+ gs_shading_Fb_fill_rectangle,
+ "gs_shading_Fb_init");
+}
+
+/* ---------------- Axial shading ---------------- */
+
+private_st_shading_A();
+
+/* Allocate and initialize an Axial shading. */
+int
+gs_shading_A_init(gs_shading_t ** ppsh,
+ const gs_shading_A_params_t * params, gs_memory_t * mem)
+{
+ check_CBF(1);
+ alloc_return_shading(gs_shading_A_t, &st_shading_A,
+ shading_type_Axial,
+ gs_shading_A_fill_rectangle,
+ "gs_shading_A_init");
+}
+
+/* ---------------- Radial shading ---------------- */
+
+private_st_shading_R();
+
+/* Allocate and initialize a Radial shading. */
+int
+gs_shading_R_init(gs_shading_t ** ppsh,
+ const gs_shading_R_params_t * params, gs_memory_t * mem)
+{
+ check_CBF(1);
+ if ((params->Domain != 0 && params->Domain[0] == params->Domain[1]) ||
+ params->Coords[2] < 0 || params->Coords[5] < 0
+ )
+ return_error(gs_error_rangecheck);
+ alloc_return_shading(gs_shading_R_t, &st_shading_R,
+ shading_type_Radial,
+ gs_shading_R_fill_rectangle,
+ "gs_shading_R_init");
+}
+
+/* ---------------- Free-form Gouraud triangle mesh shading ---------------- */
+
+private_st_shading_FfGt();
+
+/* Allocate and return a shading with BitsPerFlag. */
+#define alloc_return_BPF_shading(shtype, sttype, stype, sfrproc, bpf, cname)\
+ BEGIN\
+ alloc_shading(shtype, sttype, stype, sfrproc, cname);\
+ ((shtype *)(*ppsh))->params.BitsPerFlag = bpf;\
+ return 0;\
+ END
+
+/* Allocate and initialize a Free-form Gouraud triangle mesh shading. */
+int
+gs_shading_FfGt_init(gs_shading_t ** ppsh,
+ const gs_shading_FfGt_params_t * params, gs_memory_t * mem)
+{
+ int bpf;
+
+ if (params->Decode != 0 && params->Decode[0] == params->Decode[1])
+ return_error(gs_error_rangecheck);
+ check_mesh();
+ if (!data_source_is_array(params->DataSource))
+ switch (bpf = params->BitsPerFlag) {
+ case 2:
+ case 4:
+ case 8:
+ break;
+ default:
+ return_error(gs_error_rangecheck);
+ } else
+ bpf = 2;
+ alloc_return_BPF_shading(gs_shading_FfGt_t, &st_shading_FfGt,
+ shading_type_Free_form_Gouraud_triangle,
+ gs_shading_FfGt_fill_rectangle, bpf,
+ "gs_shading_FfGt_init");
+}
+
+/* -------------- Lattice-form Gouraud triangle mesh shading -------------- */
+
+private_st_shading_LfGt();
+
+/* Allocate and initialize a Lattice-form Gouraud triangle mesh shading. */
+int
+gs_shading_LfGt_init(gs_shading_t ** ppsh,
+ const gs_shading_LfGt_params_t * params, gs_memory_t * mem)
+{
+ check_mesh();
+ if (params->VerticesPerRow < 2)
+ return_error(gs_error_rangecheck);
+ alloc_return_shading(gs_shading_LfGt_t, &st_shading_LfGt,
+ shading_type_Lattice_form_Gouraud_triangle,
+ gs_shading_LfGt_fill_rectangle,
+ "gs_shading_LfGt_init");
+}
+
+/* ---------------- Coons patch mesh shading ---------------- */
+
+private_st_shading_Cp();
+
+/* Allocate and initialize a Coons patch mesh shading. */
+int
+gs_shading_Cp_init(gs_shading_t ** ppsh,
+ const gs_shading_Cp_params_t * params, gs_memory_t * mem)
+{
+ int bpf;
+
+ check_mesh();
+ if (!data_source_is_array(params->DataSource))
+ switch (bpf = params->BitsPerFlag) {
+ case 2:
+ case 4:
+ case 8:
+ break;
+ default:
+ return_error(gs_error_rangecheck);
+ } else
+ bpf = 2;
+ alloc_return_BPF_shading(gs_shading_Cp_t, &st_shading_Cp,
+ shading_type_Coons_patch,
+ gs_shading_Cp_fill_rectangle, bpf,
+ "gs_shading_Cp_init");
+}
+
+/* ---------------- Tensor product patch mesh shading ---------------- */
+
+private_st_shading_Tpp();
+
+/* Allocate and initialize a Tensor product patch mesh shading. */
+int
+gs_shading_Tpp_init(gs_shading_t ** ppsh,
+ const gs_shading_Tpp_params_t * params, gs_memory_t * mem)
+{
+ int bpf;
+
+ check_mesh();
+ if (!data_source_is_array(params->DataSource))
+ switch (bpf = params->BitsPerFlag) {
+ case 2:
+ case 4:
+ case 8:
+ break;
+ default:
+ return_error(gs_error_rangecheck);
+ } else
+ bpf = 2;
+ alloc_return_BPF_shading(gs_shading_Tpp_t, &st_shading_Tpp,
+ shading_type_Tensor_product_patch,
+ gs_shading_Tpp_fill_rectangle, bpf,
+ "gs_shading_Tpp_init");
+}
diff --git a/gs/src/gsshade.h b/gs/src/gsshade.h
new file mode 100644
index 000000000..02f67b60d
--- /dev/null
+++ b/gs/src/gsshade.h
@@ -0,0 +1,222 @@
+/* Copyright (C) 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gsshade.h */
+/* Definitions for shading */
+
+#ifndef gsshade_INCLUDED
+# define gsshade_INCLUDED
+
+#include "gsccolor.h"
+#include "gscspace.h"
+#include "gsdsrc.h"
+#include "gsfunc.h"
+#include "gsmatrix.h"
+
+/* ---------------- Types and structures ---------------- */
+
+/* Define the shading types. */
+typedef enum {
+ shading_type_Function_based = 1,
+ shading_type_Axial = 2,
+ shading_type_Radial = 3,
+ shading_type_Free_form_Gouraud_triangle = 4,
+ shading_type_Lattice_form_Gouraud_triangle = 5,
+ shading_type_Coons_patch = 6,
+ shading_type_Tensor_product_patch = 7
+} gs_shading_type_t;
+
+/*
+ * Define information common to all shading types.
+ * We separate the private part from the parameters so that
+ * clients can create statically initialized parameter structures.
+ */
+#define gs_shading_params_common\
+ gs_color_space *ColorSpace;\
+ gs_client_color *Background;\
+ bool have_BBox;\
+ gs_rect BBox;\
+ bool AntiAlias
+
+/* Define a generic shading, for use as the target type of pointers. */
+typedef struct gs_shading_params_s {
+ gs_shading_params_common;
+} gs_shading_params_t;
+
+#ifndef gs_shading_t_DEFINED
+# define gs_shading_t_DEFINED
+typedef struct gs_shading_s gs_shading_t;
+
+#endif
+#ifndef gx_device_DEFINED
+# define gx_device_DEFINED
+typedef struct gx_device_s gx_device;
+
+#endif
+#define shading_fill_rectangle_proc(proc)\
+ int proc(P4(const gs_shading_t *psh, const gs_rect *rect, gx_device *dev,\
+ gs_imager_state *pis))
+typedef shading_fill_rectangle_proc((*shading_fill_rectangle_proc_t));
+typedef struct gs_shading_head_s {
+ gs_shading_type_t type;
+ shading_fill_rectangle_proc_t fill_rectangle;
+} gs_shading_head_t;
+struct gs_shading_s {
+ gs_shading_head_t head;
+ gs_shading_params_t params;
+};
+
+#define ShadingType(psh) ((psh)->head.type)
+#define private_st_shading() /* in gsshade.c */\
+ gs_private_st_ptrs2(st_shading, gs_shading_t, "gs_shading_t",\
+ shading_enum_ptrs, shading_reloc_ptrs,\
+ params.ColorSpace, params.Background)
+
+/* Define Function-based shading. */
+typedef struct gs_shading_Fb_params_s {
+ gs_shading_params_common;
+ float Domain[4];
+ gs_matrix Matrix;
+ gs_function_t *Function;
+} gs_shading_Fb_params_t;
+
+#define private_st_shading_Fb() /* in gsshade.c */\
+ gs_private_st_suffix_add1(st_shading_Fb, gs_shading_Fb_t,\
+ "gs_shading_Fb_t", shading_Fb_enum_ptrs, shading_Fb_reloc_ptrs,\
+ st_shading, params.Function)
+
+/* Define Axial shading. */
+typedef struct gs_shading_A_params_s {
+ gs_shading_params_common;
+ float Coords[4];
+ float Domain[2];
+ gs_function_t *Function;
+ bool Extend[2];
+} gs_shading_A_params_t;
+
+#define private_st_shading_A() /* in gsshade.c */\
+ gs_private_st_suffix_add1(st_shading_A, gs_shading_A_t,\
+ "gs_shading_A_t", shading_A_enum_ptrs, shading_A_reloc_ptrs,\
+ st_shading, params.Function)
+
+/* Define Radial shading. */
+typedef struct gs_shading_R_params_s {
+ gs_shading_params_common;
+ float Coords[6];
+ float Domain[2];
+ gs_function_t *Function;
+ bool Extend[2];
+} gs_shading_R_params_t;
+
+#define private_st_shading_R() /* in gsshade.c */\
+ gs_private_st_suffix_add1(st_shading_R, gs_shading_R_t,\
+ "gs_shading_R_t", shading_R_enum_ptrs, shading_R_reloc_ptrs,\
+ st_shading, params.Function)
+
+/* Define common parameters for mesh shading. */
+#define gs_shading_mesh_params_common\
+ gs_shading_params_common;\
+ gs_data_source_t DataSource;\
+ int BitsPerCoordinate;\
+ int BitsPerComponent;\
+ float *Decode;\
+ gs_function_t *Function
+/* The following are for internal use only. */
+typedef struct gs_shading_mesh_params_s {
+ gs_shading_mesh_params_common;
+} gs_shading_mesh_params_t;
+typedef struct gs_shading_mesh_s {
+ gs_shading_head_t head;
+ gs_shading_mesh_params_t params;
+} gs_shading_mesh_t;
+
+#define private_st_shading_mesh() /* in gsshade.c */\
+ gs_private_st_suffix_add2(st_shading_mesh, gs_shading_mesh_t,\
+ "gs_shading_mesh_t", shading_mesh_enum_ptrs, shading_mesh_reloc_ptrs,\
+ st_shading, params.Decode, params.Function)
+
+/* Define Free-form Gouraud triangle mesh shading. */
+typedef struct gs_shading_FfGt_params_s {
+ gs_shading_mesh_params_common;
+ int BitsPerFlag;
+} gs_shading_FfGt_params_t;
+
+#define private_st_shading_FfGt() /* in gsshade.c */\
+ gs_private_st_suffix_add0_local(st_shading_FfGt, gs_shading_FfGt_t,\
+ "gs_shading_FfGt_t", shading_mesh_enum_ptrs, shading_mesh_reloc_ptrs,\
+ st_shading_mesh)
+
+/* Define Lattice-form Gouraud triangle mesh shading. */
+typedef struct gs_shading_LfGt_params_s {
+ gs_shading_mesh_params_common;
+ int VerticesPerRow;
+} gs_shading_LfGt_params_t;
+
+#define private_st_shading_LfGt() /* in gsshade.c */\
+ gs_private_st_suffix_add0_local(st_shading_LfGt, gs_shading_LfGt_t,\
+ "gs_shading_LfGt_t", shading_mesh_enum_ptrs, shading_mesh_reloc_ptrs,\
+ st_shading_mesh)
+
+/* Define Coons patch mesh shading. */
+typedef struct gs_shading_Cp_params_s {
+ gs_shading_mesh_params_common;
+ int BitsPerFlag;
+} gs_shading_Cp_params_t;
+
+#define private_st_shading_Cp() /* in gsshade.c */\
+ gs_private_st_suffix_add0_local(st_shading_Cp, gs_shading_Cp_t,\
+ "gs_shading_Cp_t", shading_mesh_enum_ptrs, shading_mesh_reloc_ptrs,\
+ st_shading_mesh)
+
+/* Define Tensor product patch mesh shading. */
+typedef struct gs_shading_Tpp_params_s {
+ gs_shading_mesh_params_common;
+ int BitsPerFlag;
+} gs_shading_Tpp_params_t;
+
+#define private_st_shading_Tpp() /* in gsshade.c */\
+ gs_private_st_suffix_add0_local(st_shading_Tpp, gs_shading_Tpp_t,\
+ "gs_shading_Tpp_t", shading_mesh_enum_ptrs, shading_mesh_reloc_ptrs,\
+ st_shading_mesh)
+
+/* ---------------- Procedures ---------------- */
+
+/* Create (initialize) shadings of specific types. */
+int gs_shading_Fb_init(P3(gs_shading_t ** ppsh,
+ const gs_shading_Fb_params_t * params,
+ gs_memory_t * mem));
+int gs_shading_A_init(P3(gs_shading_t ** ppsh,
+ const gs_shading_A_params_t * params,
+ gs_memory_t * mem));
+int gs_shading_R_init(P3(gs_shading_t ** ppsh,
+ const gs_shading_R_params_t * params,
+ gs_memory_t * mem));
+int gs_shading_FfGt_init(P3(gs_shading_t ** ppsh,
+ const gs_shading_FfGt_params_t * params,
+ gs_memory_t * mem));
+int gs_shading_LfGt_init(P3(gs_shading_t ** ppsh,
+ const gs_shading_LfGt_params_t * params,
+ gs_memory_t * mem));
+int gs_shading_Cp_init(P3(gs_shading_t ** ppsh,
+ const gs_shading_Cp_params_t * params,
+ gs_memory_t * mem));
+int gs_shading_Tpp_init(P3(gs_shading_t ** ppsh,
+ const gs_shading_Tpp_params_t * params,
+ gs_memory_t * mem));
+
+#endif /* gsshade_INCLUDED */
diff --git a/gs/src/gstext.c b/gs/src/gstext.c
new file mode 100644
index 000000000..352ee355c
--- /dev/null
+++ b/gs/src/gstext.c
@@ -0,0 +1,336 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gstext.c */
+/* Driver text interface support */
+#include "std.h"
+#include "gstypes.h"
+#include "gdebug.h"
+#include "gserror.h"
+#include "gserrors.h"
+#include "gsmemory.h"
+#include "gsstruct.h"
+#include "gstypes.h"
+#include "gxdevcli.h"
+#include "gxpath.h"
+#include "gxtext.h"
+#include "gzstate.h"
+
+/* GC descriptors */
+public_st_gs_text_params();
+public_st_gs_text_enum();
+
+#define tptr ((gs_text_params_t *)vptr)
+
+private
+ENUM_PTRS_BEGIN(text_params_enum_ptrs) return 0;
+
+case 0:
+if (tptr->operation & TEXT_FROM_STRING)
+{
+gs_const_string str;
+
+str.data = tptr->data.bytes;
+str.size = tptr->size;
+return ENUM_CONST_STRING(&str);
+}
+if (tptr->operation & TEXT_FROM_BYTES)
+ return ENUM_OBJ(tptr->data.bytes);
+if (tptr->operation & TEXT_FROM_CHARS)
+ return ENUM_OBJ(tptr->data.chars);
+if (tptr->operation & TEXT_FROM_GLYPHS)
+ return ENUM_OBJ(tptr->data.glyphs);
+return ENUM_OBJ(NULL);
+case 1:
+return ENUM_OBJ(tptr->operation & TEXT_REPLACE_X_WIDTHS ?
+ tptr->x_widths : NULL);
+case 2:
+return ENUM_OBJ(tptr->operation & TEXT_REPLACE_Y_WIDTHS ?
+ tptr->y_widths : NULL);
+ENUM_PTRS_END
+
+private RELOC_PTRS_BEGIN(text_params_reloc_ptrs)
+{
+ if (tptr->operation & TEXT_FROM_STRING) {
+ gs_const_string str;
+
+ str.data = tptr->data.bytes;
+ str.size = tptr->size;
+ RELOC_CONST_STRING_VAR(str);
+ tptr->data.bytes = str.data;
+ } else if (tptr->operation & TEXT_FROM_BYTES)
+ RELOC_OBJ_VAR(tptr->data.bytes);
+ else if (tptr->operation & TEXT_FROM_CHARS)
+ RELOC_OBJ_VAR(tptr->data.chars);
+ else if (tptr->operation & TEXT_FROM_GLYPHS)
+ RELOC_OBJ_VAR(tptr->data.glyphs);
+ if (tptr->operation & TEXT_REPLACE_X_WIDTHS)
+ RELOC_OBJ_VAR(tptr->x_widths);
+ if (tptr->operation & TEXT_REPLACE_Y_WIDTHS)
+ RELOC_OBJ_VAR(tptr->y_widths);
+}
+RELOC_PTRS_END
+
+#undef tptr
+
+#define eptr ((gs_text_enum_t *)vptr)
+
+private ENUM_PTRS_BEGIN(text_enum_enum_ptrs) ENUM_USING(st_gs_text_params, &eptr->text, sizeof(eptr->text), index - 1);
+case 0:
+return ENUM_OBJ(gx_device_enum_ptr(eptr->dev));
+ENUM_PTRS_END
+
+private RELOC_PTRS_BEGIN(text_enum_reloc_ptrs)
+{
+ RELOC_USING(st_gs_text_params, &eptr->text, sizeof(eptr->text));
+ gx_device_reloc_ptr(eptr->dev, gcst);
+}
+RELOC_PTRS_END
+
+#undef eptr
+
+/* Begin processing text. */
+int
+gx_device_text_begin(gx_device * dev, gs_imager_state * pis,
+ const gs_text_params_t * text, const gs_font * font,
+ gx_path * path, /* unless DO_NONE & !RETURN_WIDTH */
+ const gx_device_color * pdcolor, /* DO_DRAW */
+ const gx_clip_path * pcpath, /* DO_DRAW */
+ gs_memory_t * mem, gs_text_enum_t ** ppte)
+{
+ if (TEXT_OPERATION_IS_INVALID(text->operation))
+ return_error(gs_error_rangecheck);
+ {
+ gx_path *tpath =
+ ((text->operation & TEXT_DO_NONE) &&
+ !(text->operation & TEXT_RETURN_WIDTH) ? 0 : path);
+ int code =
+ (*dev_proc(dev, text_begin))
+ (dev, pis, text, font, tpath,
+ (text->operation & TEXT_DO_DRAW ? pdcolor : 0),
+ (text->operation & TEXT_DO_DRAW ? pcpath : 0),
+ mem, ppte);
+ gs_text_enum_t *pte = *ppte;
+
+ if (code < 0)
+ return code;
+ pte->text = *text;
+ pte->dev = dev;
+ pte->index = 0;
+ return code;
+ }
+}
+
+/* Begin processing text based on a graphics state. */
+int
+gs_text_begin(gs_state * pgs, const gs_text_params_t * text,
+ gs_memory_t * mem, gs_text_enum_t ** ppte)
+{
+ gx_clip_path *pcpath = 0;
+
+ if (text->operation & TEXT_DO_DRAW) {
+ int code = gx_effective_clip_path(pgs, &pcpath);
+
+ if (code < 0)
+ return code;
+ gx_set_dev_color(pgs);
+ }
+ return gx_device_text_begin(pgs->device, (gs_imager_state *) pgs,
+ text, pgs->font, pgs->path, pgs->dev_color,
+ pcpath, mem, ppte);
+}
+
+/* Begin PostScript-equivalent text operations. */
+int
+gs_show_begin(gs_state * pgs, const byte * str, uint size,
+ gs_memory_t * mem, gs_text_enum_t ** ppte)
+{
+ gs_text_params_t text;
+
+ text.operation = TEXT_FROM_STRING | TEXT_DO_DRAW | TEXT_RETURN_WIDTH;
+ text.data.bytes = str, text.size = size;
+ return gs_text_begin(pgs, &text, mem, ppte);
+}
+int
+gs_ashow_begin(gs_state * pgs, floatp ax, floatp ay, const byte * str, uint size,
+ gs_memory_t * mem, gs_text_enum_t ** ppte)
+{
+ gs_text_params_t text;
+
+ text.operation = TEXT_FROM_STRING | TEXT_ADD_TO_ALL_WIDTHS |
+ TEXT_DO_DRAW | TEXT_RETURN_WIDTH;
+ text.data.bytes = str, text.size = size;
+ text.delta_all.x = ax;
+ text.delta_all.y = ay;
+ return gs_text_begin(pgs, &text, mem, ppte);
+}
+int
+gs_widthshow_begin(gs_state * pgs, floatp cx, floatp cy, gs_char chr,
+ const byte * str, uint size,
+ gs_memory_t * mem, gs_text_enum_t ** ppte)
+{
+ gs_text_params_t text;
+
+ text.operation = TEXT_FROM_STRING | TEXT_ADD_TO_SPACE_WIDTH |
+ TEXT_DO_DRAW | TEXT_RETURN_WIDTH;
+ text.data.bytes = str, text.size = size;
+ text.delta_space.x = cx;
+ text.delta_space.y = cy;
+ text.space.s_char = chr;
+ return gs_text_begin(pgs, &text, mem, ppte);
+}
+int
+gs_awidthshow_begin(gs_state * pgs, floatp cx, floatp cy, gs_char chr,
+ floatp ax, floatp ay, const byte * str, uint size,
+ gs_memory_t * mem, gs_text_enum_t ** ppte)
+{
+ gs_text_params_t text;
+
+ text.operation = TEXT_FROM_STRING |
+ TEXT_ADD_TO_ALL_WIDTHS | TEXT_ADD_TO_SPACE_WIDTH |
+ TEXT_DO_DRAW | TEXT_RETURN_WIDTH;
+ text.data.bytes = str, text.size = size;
+ text.delta_space.x = cx;
+ text.delta_space.y = cy;
+ text.space.s_char = chr;
+ text.delta_all.x = ax;
+ text.delta_all.y = ay;
+ return gs_text_begin(pgs, &text, mem, ppte);
+}
+int
+gs_kshow_begin(gs_state * pgs, const byte * str, uint size,
+ gs_memory_t * mem, gs_text_enum_t ** ppte)
+{
+ gs_text_params_t text;
+
+ text.operation = TEXT_FROM_STRING | TEXT_DO_DRAW | TEXT_INTERVENE |
+ TEXT_RETURN_WIDTH;
+ text.data.bytes = str, text.size = size;
+ return gs_text_begin(pgs, &text, mem, ppte);
+}
+int
+gs_xyshow_begin(gs_state * pgs, const byte * str, uint size,
+ const float *x_widths, const float *y_widths,
+ gs_memory_t * mem, gs_text_enum_t ** ppte)
+{
+ gs_text_params_t text;
+
+ text.operation = TEXT_FROM_STRING |
+ TEXT_REPLACE_X_WIDTHS | TEXT_REPLACE_Y_WIDTHS |
+ TEXT_DO_DRAW | TEXT_INTERVENE | TEXT_RETURN_WIDTH;
+ text.data.bytes = str, text.size = size;
+ text.x_widths = x_widths;
+ text.y_widths = y_widths;
+ return gs_text_begin(pgs, &text, mem, ppte);
+}
+int
+gs_glyphshow_begin(gs_state * pgs, gs_glyph glyph,
+ gs_memory_t * mem, gs_text_enum_t ** ppte)
+{
+ gs_text_params_t text;
+
+/****** SET glyphs ******/
+ text.size = 1;
+ text.operation = TEXT_FROM_GLYPHS | TEXT_DO_DRAW | TEXT_RETURN_WIDTH;
+ return gs_text_begin(pgs, &text, mem, ppte);
+}
+int
+gs_cshow_begin(gs_state * pgs, const byte * str, uint size,
+ gs_memory_t * mem, gs_text_enum_t ** ppte)
+{
+ gs_text_params_t text;
+
+ text.operation = TEXT_FROM_STRING | TEXT_DO_NONE;
+ text.data.bytes = str, text.size = size;
+ return gs_text_begin(pgs, &text, mem, ppte);
+}
+int
+gs_stringwidth_begin(gs_state * pgs, const byte * str, uint size,
+ gs_memory_t * mem, gs_text_enum_t ** ppte)
+{
+ gs_text_params_t text;
+
+ text.operation = TEXT_FROM_STRING | TEXT_DO_NONE | TEXT_RETURN_WIDTH;
+ text.data.bytes = str, text.size = size;
+ return gs_text_begin(pgs, &text, mem, ppte);
+}
+int
+gs_charpath_begin(gs_state * pgs, const byte * str, uint size, bool stroke_path,
+ gs_memory_t * mem, gs_text_enum_t ** ppte)
+{
+ gs_text_params_t text;
+
+ text.operation = TEXT_FROM_STRING | TEXT_RETURN_WIDTH |
+ (stroke_path ? TEXT_DO_TRUE_CHARPATH : TEXT_DO_FALSE_CHARPATH);
+ text.data.bytes = str, text.size = size;
+ return gs_text_begin(pgs, &text, mem, ppte);
+}
+int
+gs_charboxpath_begin(gs_state * pgs, const byte * str, uint size,
+ bool stroke_path, gs_memory_t * mem, gs_text_enum_t ** ppte)
+{
+ gs_text_params_t text;
+
+ text.operation = TEXT_FROM_STRING | TEXT_RETURN_WIDTH |
+ (stroke_path ? TEXT_DO_TRUE_CHARBOXPATH : TEXT_DO_FALSE_CHARBOXPATH);
+ text.data.bytes = str, text.size = size;
+ return gs_text_begin(pgs, &text, mem, ppte);
+}
+int
+gs_glyphpath_begin(gs_state * pgs, gs_glyph glyph, bool stroke_path,
+ gs_memory_t * mem, gs_text_enum_t ** ppte)
+{
+ gs_text_params_t text;
+
+ text.operation = TEXT_FROM_GLYPHS | TEXT_RETURN_WIDTH |
+ (stroke_path ? TEXT_DO_TRUE_CHARPATH : TEXT_DO_FALSE_CHARPATH);
+/****** SET glyphs ******/
+ text.size = 1;
+ return gs_text_begin(pgs, &text, mem, ppte);
+}
+
+/* Process text after 'begin'. */
+int
+gs_text_process(gs_text_enum_t * pte)
+{
+ return pte->procs->process(pte);
+}
+
+/* Set text metrics and optionally enable caching. */
+int
+gs_text_setcharwidth(gs_text_enum_t * pte, const double wxy[2])
+{
+ return pte->procs->set_cache(pte, wxy, TEXT_SET_CHAR_WIDTH);
+}
+int
+gs_text_setcachedevice(gs_text_enum_t * pte, const double wbox[6])
+{
+ return pte->procs->set_cache(pte, wbox, TEXT_SET_CACHE_DEVICE);
+}
+int
+gs_text_setcachedevice2(gs_text_enum_t * pte, const double wbox2[10])
+{
+ return pte->procs->set_cache(pte, wbox2, TEXT_SET_CACHE_DEVICE2);
+}
+
+/* Release the text processing structures. */
+void
+gs_text_release(gs_text_enum_t * pte, client_name_t cname)
+{
+ rc_decrement_only(pte, cname);
+}
diff --git a/gs/src/gstext.h b/gs/src/gstext.h
new file mode 100644
index 000000000..9182b11b6
--- /dev/null
+++ b/gs/src/gstext.h
@@ -0,0 +1,223 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gstext.h */
+/* Driver interface for text */
+
+#ifndef gstext_INCLUDED
+# define gstext_INCLUDED
+
+#include "gsccode.h"
+#include "gsrefct.h"
+
+/* EVERYTHING IN THIS FILE IS SUBJECT TO CHANGE WITHOUT NOTICE. */
+
+/*
+ * Note that like get_params and get_hardware_params, but unlike all other
+ * driver procedures, text display must return information to the generic
+ * code:
+ * *show except [x][y]show: the string escapement a.k.a. "width").
+ * charpath, .glyphpath: the entire character description.
+ * .charboxpath: the character bounding box.
+ */
+
+/*
+ * Define the set of possible text operations. While we define this as
+ * a bit mask for convenience in testing, only certain combinations are
+ * meaningful. Specifically, the following are errors:
+ * - No FROM or DO.
+ * The following are undefined:
+ * - More than one FROM or DO.
+ * - Both ADD_TO and REPLACE.
+ */
+#define TEXT_HAS_MORE_THAN_ONE_(op, any_)\
+ ( ((op) & any_) & (((op) & any_) - 1) )
+#define TEXT_OPERATION_IS_INVALID(op)\
+ (!((op) & TEXT_FROM_ANY_) ||\
+ !((op) & TEXT_DO_ANY_) ||\
+ TEXT_HAS_MORE_THAN_ONE_(op, TEXT_FROM_ANY_) ||\
+ TEXT_HAS_MORE_THAN_ONE_(op, TEXT_DO_ANY_) ||\
+ (((op) & TEXT_ADD_ANY_) && ((op) & TEXT_REPLACE_ANY_))\
+ )
+
+ /* Define the representation of the text itself. */
+#define TEXT_FROM_STRING 0x00001
+#define TEXT_FROM_BYTES 0x00002
+#define TEXT_FROM_CHARS 0x00004
+#define TEXT_FROM_GLYPHS 0x00008
+#define TEXT_FROM_ANY_ /* internal use only, see above */\
+ (TEXT_FROM_STRING | TEXT_FROM_BYTES | TEXT_FROM_CHARS | TEXT_FROM_GLYPHS)
+ /* Define how to compute escapements. */
+#define TEXT_ADD_TO_ALL_WIDTHS 0x00010
+#define TEXT_ADD_TO_SPACE_WIDTH 0x00020
+#define TEXT_ADD_ANY_ /* internal use only, see above */\
+ (TEXT_ADD_TO_ALL_WIDTHS | TEXT_ADD_TO_SPACE_WIDTH)
+#define TEXT_REPLACE_X_WIDTHS 0x00040
+#define TEXT_REPLACE_Y_WIDTHS 0x00080
+#define TEXT_REPLACE_ANY_ /* internal use only, see above */\
+ (TEXT_REPLACE_X_WIDTHS | TEXT_REPLACE_Y_WIDTHS)
+ /* Define what result should be produced. */
+#define TEXT_DO_NONE 0x00100 /* stringwidth or cshow only */
+#define TEXT_DO_DRAW 0x00200
+#define TEXT_DO_FALSE_CHARPATH 0x00400
+#define TEXT_DO_TRUE_CHARPATH 0x00800
+#define TEXT_DO_FALSE_CHARBOXPATH 0x01000
+#define TEXT_DO_TRUE_CHARBOXPATH 0x02000
+#define TEXT_DO_ANY_CHARPATH\
+ (TEXT_DO_FALSE_CHARPATH | TEXT_DO_TRUE_CHARPATH |\
+ TEXT_DO_FALSE_CHARBOXPATH | TEXT_DO_TRUE_CHARBOXPATH)
+#define TEXT_DO_ANY_ /* internal use only, see above */\
+ (TEXT_DO_NONE | TEXT_DO_DRAW | TEXT_DO_ANY_CHARPATH)
+ /* Define whether the client intervenes between characters. */
+#define TEXT_INTERVENE 0x10000
+ /* Define whether to return the width. */
+#define TEXT_RETURN_WIDTH 0x20000
+
+/*
+ * Define the structure of parameters passed in for text display.
+ * Note that the implementation does not modify any of these; the client
+ * must not modify them after initialization.
+ */
+typedef struct gs_text_params_s {
+ /* The client must set the following in all cases. */
+ uint operation; /* TEXT_xxx mask */
+ union sd_ {
+ const byte *bytes; /* FROM_STRING, FROM_BYTES */
+ const gs_char *chars; /* FROM_CHARS */
+ const gs_glyph *glyphs; /* FROM_GLYPHS */
+ } data;
+ uint size; /* number of data elements */
+ /* The following are used only in the indicated cases. */
+ gs_point delta_all; /* ADD_TO_ALL_WIDTHS */
+ gs_point delta_space; /* ADD_TO_SPACE_WIDTH */
+ union s_ {
+ gs_char s_char; /* ADD_TO_SPACE_WIDTH & !FROM_GLYPHS */
+ gs_glyph s_glyph; /* ADD_TO_SPACE_WIDTH & FROM_GLYPHS */
+ } space;
+ /* If x_widths == y_widths, widths are taken in pairs. */
+ /* Either one may be NULL, meaning widths = 0. */
+ const float *x_widths; /* REPLACE_X_WIDTHS */
+ const float *y_widths; /* REPLACE_Y_WIDTHS */
+} gs_text_params_t;
+
+#define st_gs_text_params_max_ptrs 3
+/*extern_st(st_gs_text_params); */
+#define public_st_gs_text_params() /* in gstext.c */\
+ gs_public_st_composite(st_gs_text_params, gs_text_params_t,\
+ "gs_text_params", text_params_enum_ptrs, text_params_reloc_ptrs)
+
+/* Define the abstract type for the object procedures. */
+typedef struct gs_text_enum_procs_s gs_text_enum_procs_t;
+
+/*
+ * Define the common part of the structure that tracks the state of text
+ * display. All implementations of text_begin must allocate one of these
+ * using rc_alloc_struct_1; implementations may subclass and extend it.
+ * Note that it includes a copy of the text parameters.
+ */
+#ifndef gx_device_DEFINED
+# define gx_device_DEFINED
+typedef struct gx_device_s gx_device;
+
+#endif
+#define gs_text_enum_common\
+ /* The following are set at initialization, and const thereafter. */\
+ gs_text_params_t text;\
+ const gs_text_enum_procs_t *procs;\
+ gx_device *dev;\
+ /* The following change dynamically. */\
+ rc_header rc;\
+ uint index /* index within string */
+typedef struct gs_text_enum_s {
+ gs_text_enum_common;
+} gs_text_enum_t;
+
+#define st_gs_text_enum_max_ptrs st_gs_text_params_max_ptrs
+/*extern_st(st_gs_text_enum); */
+#define public_st_gs_text_enum() /* in gstext.c */\
+ gs_public_st_composite(st_gs_text_enum, gs_text_enum_t, "gs_text_enum_t",\
+ text_enum_enum_ptrs, text_enum_reloc_ptrs)
+
+/* Begin processing text. */
+/* Note that these take a graphics state argument. */
+#ifndef gs_state_DEFINED
+# define gs_state_DEFINED
+typedef struct gs_state_s gs_state;
+
+#endif
+int gs_text_begin(P4(gs_state * pgs, const gs_text_params_t * text,
+ gs_memory_t * mem, gs_text_enum_t ** ppenum));
+
+/* Begin the PostScript-equivalent text operators. */
+int
+ gs_show_begin(P5(gs_state *, const byte *, uint,
+ gs_memory_t *, gs_text_enum_t **)), gs_ashow_begin(P7(gs_state *, floatp, floatp, const byte *, uint,
+ gs_memory_t *, gs_text_enum_t **)),
+ gs_widthshow_begin(P8(gs_state *, floatp, floatp, gs_char,
+ const byte *, uint,
+ gs_memory_t *, gs_text_enum_t **)), gs_awidthshow_begin(P10(gs_state *, floatp, floatp, gs_char,
+ floatp, floatp, const byte *, uint,
+ gs_memory_t *, gs_text_enum_t **)),
+ gs_kshow_begin(P5(gs_state *, const byte *, uint,
+ gs_memory_t *, gs_text_enum_t **)), gs_xyshow_begin(P7(gs_state *, const byte *, uint,
+ const float *, const float *,
+ gs_memory_t *, gs_text_enum_t **)),
+ gs_glyphshow_begin(P4(gs_state *, gs_glyph,
+ gs_memory_t *, gs_text_enum_t **)), gs_cshow_begin(P5(gs_state *, const byte *, uint,
+ gs_memory_t *, gs_text_enum_t **)),
+ gs_stringwidth_begin(P5(gs_state *, const byte *, uint,
+ gs_memory_t *, gs_text_enum_t **)), gs_charpath_begin(P6(gs_state *, const byte *, uint, bool,
+ gs_memory_t *, gs_text_enum_t **)),
+ gs_glyphpath_begin(P5(gs_state *, gs_glyph, bool,
+ gs_memory_t *, gs_text_enum_t **)), gs_charboxpath_begin(P6(gs_state *, const byte *, uint, bool,
+ gs_memory_t *, gs_text_enum_t **));
+
+/*
+ * Define the possible return values from gs_text_process. The client
+ * should call text_process until it returns 0 (successful completion) or a
+ * negative (error) value.
+ */
+
+ /*
+ * The client must render a character: obtain the code from
+ * gs_show_current_char, do whatever is necessary, and then
+ * call gs_text_process again.
+ */
+#define TEXT_PROCESS_RENDER 1
+
+ /*
+ * The client has asked to intervene between characters.
+ * Obtain the previous and next codes from gs_show_previous_char
+ * and gs_kshow_next_char, do whatever is necessary, and then
+ * call gs_text_process again.
+ */
+#define TEXT_PROCESS_INTERVENE 2
+
+/* Process text after 'begin'. */
+int gs_text_process(P1(gs_text_enum_t * penum));
+
+/* Set text metrics and optionally enable caching. */
+int
+ gs_text_setcharwidth(P2(gs_text_enum_t * penum, const double wxy[2])),
+ gs_text_setcachedevice(P2(gs_text_enum_t * penum, const double wbox[6])),
+ gs_text_setcachedevice2(P2(gs_text_enum_t * penum, const double wbox2[10]));
+
+/* Release the text processing structures. */
+void gs_text_release(P2(gs_text_enum_t * penum, client_name_t cname));
+
+#endif /* gstext_INCLUDED */
diff --git a/gs/src/gstrap.c b/gs/src/gstrap.c
new file mode 100644
index 000000000..555f88667
--- /dev/null
+++ b/gs/src/gstrap.c
@@ -0,0 +1,184 @@
+/* Copyright (C) 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gstrap.c */
+/* Setting trapping parameters and zones */
+#include "string_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gstrap.h"
+
+/* Parameter utilities, copied from gdevpsdf.c. */
+/* These should be merged.... */
+
+/* Compare a C string and a gs_param_string. */
+private bool
+trap_key_eq(const gs_param_string * pcs, const char *str)
+{
+ return (strlen(str) == pcs->size &&
+ !strncmp(str, (const char *)pcs->data, pcs->size));
+}
+
+/* Put an enumerated value. */
+private int
+trap_put_enum_param(gs_param_list * plist, gs_param_name param_name,
+ int *pvalue, const char *const pnames[], int ecode)
+{
+ gs_param_string ens;
+ int code = param_read_name(plist, param_name, &ens);
+
+ switch (code) {
+ case 1:
+ return ecode;
+ case 0:
+ {
+ int i;
+
+ for (i = 0; pnames[i] != 0; ++i)
+ if (trap_key_eq(&ens, pnames[i])) {
+ *pvalue = i;
+ return 0;
+ }
+ }
+ code = gs_error_rangecheck;
+ default:
+ ecode = code;
+ param_signal_error(plist, param_name, code);
+ }
+ return code;
+}
+
+/* Put a Boolean, integer, or float parameter. */
+private int
+trap_put_bool_param(gs_param_list * plist, gs_param_name param_name,
+ bool * pval, int ecode)
+{
+ int code;
+
+ switch (code = param_read_bool(plist, param_name, pval)) {
+ default:
+ ecode = code;
+ param_signal_error(plist, param_name, ecode);
+ case 0:
+ case 1:
+ break;
+ }
+ return ecode;
+}
+private int
+trap_put_int_param(gs_param_list * plist, gs_param_name param_name,
+ int *pval, int ecode)
+{
+ int code;
+
+ switch (code = param_read_int(plist, param_name, pval)) {
+ default:
+ ecode = code;
+ param_signal_error(plist, param_name, ecode);
+ case 0:
+ case 1:
+ break;
+ }
+ return ecode;
+}
+private bool
+check_unit(float *pval)
+{
+ return (*pval >= 0 && *pval <= 1);
+}
+private bool
+check_positive(float *pval)
+{
+ return (*pval > 0);
+}
+private int
+trap_put_float_param(gs_param_list * plist, gs_param_name param_name,
+ float *pval, bool(*check) (P1(float *pval)), int ecode)
+{
+ int code;
+
+ switch (code = param_read_float(plist, param_name, pval)) {
+ case 0:
+ if ((*check) (pval))
+ return 0;
+ code = gs_error_rangecheck;
+ default:
+ ecode = code;
+ param_signal_error(plist, param_name, ecode);
+ break;
+ case 1:
+ break;
+ }
+ return ecode;
+}
+
+/* settrapparams */
+int
+gs_settrapparams(gs_trap_params_t * pparams, gs_param_list * plist)
+{
+ gs_trap_params_t params;
+ int ecode = 0;
+ static const char *const trap_placement_names[] =
+ {
+ gs_trap_placement_names, 0
+ };
+
+ params = *pparams;
+ ecode = trap_put_float_param(plist, "BlackColorLimit",
+ &params.BlackColorLimit,
+ check_unit, ecode);
+ ecode = trap_put_float_param(plist, "BlackDensityLimit",
+ &params.BlackDensityLimit,
+ check_positive, ecode);
+ ecode = trap_put_float_param(plist, "BlackWidth",
+ &params.BlackWidth,
+ check_positive, ecode);
+ ecode = trap_put_bool_param(plist, "Enabled",
+ &params.Enabled, ecode);
+ ecode = trap_put_bool_param(plist, "ImageInternalTrapping",
+ &params.ImageInternalTrapping, ecode);
+ ecode = trap_put_int_param(plist, "ImageResolution",
+ &params.ImageResolution, ecode);
+ if (params.ImageResolution <= 0)
+ param_signal_error(plist, "ImageResolution",
+ ecode = gs_error_rangecheck);
+ ecode = trap_put_bool_param(plist, "ImageToObjectTrapping",
+ &params.ImageToObjectTrapping, ecode);
+ {
+ int placement = params.ImageTrapPlacement;
+
+ ecode = trap_put_enum_param(plist, "ImageTrapPlacement",
+ &placement, trap_placement_names, ecode);
+ params.ImageTrapPlacement = placement;
+ }
+ ecode = trap_put_float_param(plist, "SlidingTrapLimit",
+ &params.SlidingTrapLimit,
+ check_unit, ecode);
+ ecode = trap_put_float_param(plist, "StepLimit",
+ &params.StepLimit, check_unit, ecode);
+ ecode = trap_put_float_param(plist, "TrapColorScaling",
+ &params.TrapColorScaling,
+ check_unit, ecode);
+ ecode = trap_put_float_param(plist, "TrapWidth",
+ &params.TrapWidth,
+ check_positive, ecode);
+ if (ecode < 0)
+ return ecode;
+ *pparams = params;
+ return 0;
+}
diff --git a/gs/src/gstrap.h b/gs/src/gstrap.h
new file mode 100644
index 000000000..968a51ae4
--- /dev/null
+++ b/gs/src/gstrap.h
@@ -0,0 +1,75 @@
+/* Copyright (C) 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gstrap.h */
+/* Definitions for trapping parameters and zones */
+
+#ifndef gstrap_INCLUDED
+# define gstrap_INCLUDED
+
+#include "gsparam.h"
+
+/* ---------------- Types and structures ---------------- */
+
+/* Opaque type for a path */
+#ifndef gx_path_DEFINED
+# define gx_path_DEFINED
+typedef struct gx_path_s gx_path;
+
+#endif
+
+/* Define the placement of image traps. */
+typedef enum {
+ tp_Center,
+ tp_Choke,
+ tp_Spread,
+ tp_Normal
+} gs_trap_placement_t;
+
+#define gs_trap_placement_names\
+ "Center", "Choke", "Spread", "Normal"
+
+/* Define a trapping parameter set. */
+typedef struct gs_trap_params_s {
+ float BlackColorLimit; /* 0-1 */
+ float BlackDensityLimit; /* > 0 */
+ float BlackWidth; /* > 0 */
+ /* ColorantZoneDetails; */
+ bool Enabled;
+ /* HalftoneName; */
+ bool ImageInternalTrapping;
+ int ImageResolution;
+ bool ImageToObjectTrapping;
+ gs_trap_placement_t ImageTrapPlacement;
+ float SlidingTrapLimit; /* 0-1 */
+ float StepLimit; /* 0-1 */
+ float TrapColorScaling; /* 0-1 */
+ float TrapWidth; /* > 0 */
+} gs_trap_params_t;
+
+/* Define a trapping zone. ****** SUBJECT TO CHANGE ****** */
+typedef struct gs_trap_zone_s {
+ gs_trap_params_t params;
+ gx_path *zone;
+} gs_trap_zone_t;
+
+/* ---------------- Procedures ---------------- */
+
+int gs_settrapparams(P2(gs_trap_params_t * params, gs_param_list * list));
+
+#endif /* gstrap_INCLUDED */
diff --git a/gs/src/gxalpha.h b/gs/src/gxalpha.h
new file mode 100644
index 000000000..5cf4659ec
--- /dev/null
+++ b/gs/src/gxalpha.h
@@ -0,0 +1,68 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gxalpha.h */
+/* Internal machinery for alpha channel support */
+
+#ifndef gxalpha_INCLUDED
+# define gxalpha_INCLUDED
+
+/*
+ * As discussed in the classic Porter & Duff paper on compositing,
+ * supporting alpha channel properly involves premultiplying color values
+ * that are associated with non-unity alpha values. After considerable
+ * thrashing around trying to read between the lines of the spotty NeXT
+ * documentation, we've concluded that the correct approach is to
+ * premultiply towards whatever the color value 0 represents in the device's
+ * native color space: black for DeviceGray and DeviceRGB (displays and some
+ * file formats), white for DeviceCMYK (color printers), with a special hack
+ * for monochrome printers TBD. This makes things very easy internally, at
+ * the expense of some inconsistency at the boundaries.
+ *
+ * For the record, the only places apparently affected by this decision
+ * are the following:
+ * - alphaimage, if it doesn't assume premultiplication (see below)
+ * - readimage
+ * - The cmap_rgb_alpha_ procedures in gxcmap.c
+ * - [color]image, if they are supposed to use currentalpha (see below)
+ * - The compositing code in gsalphac.c
+ *
+ * The NeXT documentation also is very unclear as to how readimage,
+ * alphaimage, and [color]image are supposed to work. Our current
+ * interpretation is the following:
+ *
+ * - readimage reads pixels exactly as the device stores them
+ * (converted into DeviceGray or DeviceRGB space if the device
+ * uses a palette). Pixels with non-unity alpha come out
+ * premultiplied, however the device stores them.
+ *
+ * - alphaimage assumes the pixels are premultiplied as appropriate
+ * for the relevant color space. This makes alphaimage and
+ * readimage complementary, i.e., the output of readimage is
+ * suitable as the input of alphaimage.
+ *
+ * - [color]image disregard currentalpha, and treat all input as
+ * opaque (alpha = 1). */
+/*
+ * Just in case we ever change our minds about the direction of
+ * premultiplication, uncommenting the following preprocessor definition is
+ * supposed to produce premultiplication towards white.
+ */
+/*#define PREMULTIPLY_TOWARDS_WHITE */
+
+#endif /* gxalpha_INCLUDED */
diff --git a/gs/src/gxbitfmt.h b/gs/src/gxbitfmt.h
new file mode 100644
index 000000000..c0c80399b
--- /dev/null
+++ b/gs/src/gxbitfmt.h
@@ -0,0 +1,189 @@
+/* Copyright (C) 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gxbitfmt.h */
+/* Definitions for bitmap storage formats */
+
+#ifndef gxbitfmt_INCLUDED
+# define gxbitfmt_INCLUDED
+
+/*
+ * Several operations, such as the get_bits_rectangle driver procedure, can
+ * take and/or produce data in a flexible variety of formats; the ability to
+ * describe how bitmap data is stored is useful in other contexts as well.
+ * We define bitmap storage formats using a bit mask: this allows a
+ * procedure to ask for, or offer to provide, data in more than one format.
+ */
+
+typedef ulong gx_bitmap_format_t;
+
+ /*
+ * Define the supported color space alternatives.
+ */
+
+#define GB_COLORS_NATIVE (1L<<0) /* native representation (DevicePixel) */
+#define GB_COLORS_GRAY (1L<<1) /* DeviceGray */
+#define GB_COLORS_RGB (1L<<2) /* DeviceRGB */
+#define GB_COLORS_CMYK (1L<<3) /* DeviceCMYK */
+
+#define GB_COLORS_STANDARD_ALL\
+ (GB_COLORS_GRAY | GB_COLORS_RGB | GB_COLORS_CMYK)
+#define GB_COLORS_ALL\
+ (GB_COLORS_NATIVE | GB_COLORS_STANDARD_ALL)
+#define gb_colors_for_device(dev)\
+ ((dev)->color_info.num_components == 4 ? GB_COLORS_CMYK :\
+ (dev)->color_info.num_components == 3 ? GB_COLORS_RGB : GB_COLORS_GRAY)
+#define GB_COLORS_NAMES\
+ "colors_native", "colors_Gray", "colors_RGB", "colors_CMYK"
+
+ /*
+ * Define whether alpha information is included. For GB_COLORS_NATIVE,
+ * all values other than GB_ALPHA_NONE are equivalent.
+ */
+
+#define GB_ALPHA_NONE (1L<<4) /* no alpha */
+#define GB_ALPHA_FIRST (1L<<5) /* include alpha as first component */
+#define GB_ALPHA_LAST (1L<<6) /* include alpha as last component */
+ /*unused*/ /*(1L<<7)*/
+
+#define GB_ALPHA_ALL\
+ (GB_ALPHA_NONE | GB_ALPHA_FIRST | GB_ALPHA_LAST)
+#define GB_ALPHA_NAMES\
+ "alpha_none", "alpha_first", "alpha_last", "?alpha_unused?"
+
+ /*
+ * Define the supported depths per component for GB_COLORS_STANDARD.
+ */
+
+#define GB_DEPTH_1 (1L<<8)
+#define GB_DEPTH_2 (1L<<9)
+#define GB_DEPTH_4 (1L<<10)
+#define GB_DEPTH_8 (1L<<11)
+#define GB_DEPTH_12 (1L<<12)
+#define GB_DEPTH_16 (1L<<13)
+ /*unused1*/ /*(1L<<14)*/
+ /*unused2*/ /*(1L<<15)*/
+
+#define GB_DEPTH_ALL\
+ (GB_DEPTH_1 | GB_DEPTH_2 | GB_DEPTH_4 | GB_DEPTH_8 |\
+ GB_DEPTH_12 | GB_DEPTH_16)
+#define GB_DEPTH_NAMES\
+ "depth_1", "depth_2", "depth_4", "depth_8",\
+ "depth_12", "depth_16", "?depth_unused1?", "?depth_unused2?"
+
+/* Find the maximum depth of an options mask. */
+#define GB_OPTIONS_MAX_DEPTH(opt)\
+"\
+\000\001\002\002\004\004\004\004\010\010\010\010\010\010\010\010\
+\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\
+\020\020\020\020\020\020\020\020\020\020\020\020\020\020\020\020\
+\020\020\020\020\020\020\020\020\020\020\020\020\020\020\020\020\
+"[((opt) >> 8) & 0x3f]
+/* Find the depth of an options mask with exactly 1 bit set. */
+#define GB_OPTIONS_DEPTH(opt)\
+ ((((opt) >> 8) & 0xf) |\
+ "\000\000\014\020"[((opt) >> 12) & 3])
+
+ /*
+ * Define the supported packing formats. Currently, GB_PACKING_PLANAR is
+ * only partially supported, and GB_PACKING_BIT_PLANAR is hardly supported
+ * at all.
+ */
+
+#define GB_PACKING_CHUNKY (1L<<16)
+#define GB_PACKING_PLANAR (1L<<17) /* 1 plane per component */
+#define GB_PACKING_BIT_PLANAR (1L<<18) /* 1 plane per bit */
+ /*unused*/ /*(1L<<19)*/
+
+#define GB_PACKING_ALL\
+ (GB_PACKING_CHUNKY | GB_PACKING_PLANAR | GB_PACKING_BIT_PLANAR)
+#define GB_PACKING_NAMES\
+ "packing_chunky", "packing_planar", "packing_bit_planar", "?packing_unused?"
+
+ /*
+ * Define the possible methods of returning data.
+ */
+
+#define GB_RETURN_COPY (1L<<20) /* copy to client's buffer */
+#define GB_RETURN_POINTER (1L<<21) /* return pointers to data */
+
+#define GB_RETURN_ALL\
+ (GB_RETURN_COPY | GB_RETURN_POINTER)
+#define GB_RETURN_NAMES\
+ "return_copy", "return_pointer"
+
+ /*
+ * Define the allowable alignments. This is only relevant for
+ * GB_RETURN_POINTER: for GB_RETURN_COPY, any alignment is acceptable.
+ */
+
+#define GB_ALIGN_STANDARD (1L<<22) /* require standard bitmap alignment */
+#define GB_ALIGN_ANY (1L<<23) /* any alignment is acceptable */
+
+#define GB_ALIGN_ALL\
+ (GB_ALIGN_ANY | GB_ALIGN_STANDARD)
+#define GB_ALIGN_NAMES\
+ "align_any", "align_standard"
+
+ /*
+ * Define the allowable X offsets. GB_OFFSET_ANY is only relevant for
+ * GB_RETURN_POINTER: for GB_RETURN_COPY, clients must specify the
+ * offset so they know how much space to allocate.
+ */
+
+#define GB_OFFSET_0 (1L<<24) /* no offsetting */
+#define GB_OFFSET_SPECIFIED (1L<<25) /* client-specified offset */
+#define GB_OFFSET_ANY (1L<<26) /* any offset is acceptable */
+ /* (for GB_RETURN_POINTER only) */
+ /*unused*/ /*(1L<<27)*/
+
+#define GB_OFFSET_ALL\
+ (GB_OFFSET_0 | GB_OFFSET_SPECIFIED | GB_OFFSET_ANY)
+#define GB_OFFSET_NAMES\
+ "offset_0", "offset_specified", "offset_any", "?offset_unused?"
+
+ /*
+ * Define the allowable rasters. GB_RASTER_ANY is only relevant for
+ * GB_RETURN_POINTER, for the same reason as GB_OFFSET_ANY.
+ * Note also that if GB_ALIGN_STANDARD and GB_RASTER_SPECIFIED are
+ * both chosen and more than one scan line is being transferred,
+ * the raster value must also be aligned (i.e., 0 mod align_bitmap_mod).
+ * Implementors are not required to check this.
+ */
+
+ /*
+ * Standard raster is bitmap_raster(dev->width) for return_ptr,
+ * bitmap_raster(x_offset + width) for return_copy,
+ * padding per alignment.
+ */
+#define GB_RASTER_STANDARD (1L<<28)
+#define GB_RASTER_SPECIFIED (1L<<29) /* any client-specified raster */
+#define GB_RASTER_ANY (1L<<30) /* any raster is acceptable (for */
+ /* GB_RETURN_POINTER only) */
+
+#define GB_RASTER_ALL\
+ (GB_RASTER_STANDARD | GB_RASTER_SPECIFIED | GB_RASTER_ANY)
+#define GB_RASTER_NAMES\
+ "raster_standard", "raster_specified", "raster_any"
+
+/* Define names for debugging printout. */
+#define GX_BITMAP_FORMAT_NAMES\
+ GB_COLORS_NAMES, GB_ALPHA_NAMES, GB_DEPTH_NAMES, GB_PACKING_NAMES,\
+ GB_RETURN_NAMES, GB_ALIGN_NAMES, GB_OFFSET_NAMES, GB_RASTER_NAMES
+
+#endif /* gxbitfmt_INCLUDED */
diff --git a/gs/src/gxbitops.h b/gs/src/gxbitops.h
new file mode 100644
index 000000000..9a8e25460
--- /dev/null
+++ b/gs/src/gxbitops.h
@@ -0,0 +1,136 @@
+/* Copyright (C) 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gxbitops.h */
+/* Internal definitions for bitmap operations */
+
+#ifndef gxbitops_INCLUDED
+# define gxbitops_INCLUDED
+
+#include "gsbitops.h"
+
+/*
+ * Macros for processing bitmaps in the largest possible chunks.
+ * Bits within a byte are always stored big-endian;
+ * bytes are likewise stored in left-to-right order, i.e., big-endian.
+ * Note that this is the format used for the source of copy_mono.
+ * It used to be the case that bytes were stored in the natural
+ * platform order, and the client had force them into big-endian order
+ * by calling gdev_mem_ensure_byte_order, but this no longer necessary.
+ *
+ * Note that we use type uint for register variables holding a chunk:
+ * for this reason, the chunk size cannot be larger than uint.
+ */
+/* Generic macros for chunk accessing. */
+#define cbytes(ct) size_of(ct) /* sizeof may be unsigned */
+# define chunk_bytes cbytes(chunk)
+/* The clog2_bytes macro assumes that ints are 2, 4, or 8 bytes in size. */
+#define clog2_bytes(ct) (size_of(ct) == 8 ? 3 : size_of(ct)>>1)
+# define chunk_log2_bytes clog2_bytes(chunk)
+#define cbits(ct) (size_of(ct)*8) /* sizeof may be unsigned */
+# define chunk_bits cbits(chunk)
+#define clog2_bits(ct) (clog2_bytes(ct)+3)
+# define chunk_log2_bits clog2_bits(chunk)
+#define cbit_mask(ct) (cbits(ct)-1)
+# define chunk_bit_mask cbit_mask(chunk)
+#define calign_bytes(ct)\
+ (sizeof(ct) == 1 ? 1:\
+ sizeof(ct) == sizeof(short) ? arch_align_short_mod :\
+ sizeof(ct) == sizeof(int) ? arch_align_int_mod : arch_align_long_mod)
+# define chunk_align_bytes calign_bytes(chunk)
+#define calign_bit_mask(ct) (calign_bytes(ct)*8-1)
+# define chunk_align_bit_mask calign_bit_mask(chunk)
+/*
+ * The obvious definition for cmask is:
+ * #define cmask(ct) ((ct)~(ct)0)
+ * but this doesn't work on the VAX/VMS compiler, which fails to truncate
+ * the value to 16 bits when ct is ushort.
+ * Instead, we have to generate the mask with no extra 1-bits.
+ * We can't do this in the obvious way:
+ * #define cmask(ct) ((1 << (size_of(ct) * 8)) - 1)
+ * because some compilers won't allow a shift of the full type size.
+ * Instead, we have to do something really awkward:
+ */
+#define cmask(ct) ((ct) (((((ct)1 << (size_of(ct)*8-2)) - 1) << 2) + 3))
+# define chunk_all_bits cmask(chunk)
+/*
+ * The obvious definition for chi_bits is:
+ * #define chi_bits(ct,n) (cmask(ct)-(cmask(ct)>>(n)))
+ * but this doesn't work on the DEC/MIPS compilers.
+ * Instead, we have to restrict chi_bits to only working for values of n
+ * between 0 and cbits(ct)-1, and use
+ */
+#define chi_bits(ct,n) (ct)(~(ct)1 << (cbits(ct)-1 - (n)))
+# define chunk_hi_bits(n) chi_bits(chunk,n)
+
+/* Define whether this is a machine where chunks are long, */
+/* but the machine can't shift a long by its full width. */
+#define arch_cant_shift_full_chunk\
+ (arch_is_big_endian && !arch_ints_are_short && !arch_can_shift_full_long)
+
+/* Pointer arithmetic macros. */
+#define inc_ptr(ptr,delta)\
+ (ptr = (void *)((byte *)ptr + (delta)))
+
+/* Define macros for setting up left- and right-end masks. */
+/* These are used for monobit operations, and for filling */
+/* with 2- and 4-bit-per-pixel patterns. */
+
+/*
+ * Define the chunk size for monobit copying operations.
+ */
+#if arch_is_big_endian
+# define mono_copy_chunk uint
+# define set_mono_right_mask(var, w)\
+ (var = ((w) == chunk_bits ? chunk_all_bits : chunk_hi_bits(w)))
+/*
+ * We have to split the following statement because of a bug in the Xenix C
+ * compiler (it produces a signed rather than an unsigned shift if we don't
+ * split).
+ */
+# define set_mono_thin_mask(var, w, bit)\
+ set_mono_right_mask(var, w), var >>= (bit)
+/*
+ * We have to split the following statement in two because of a bug
+ * in the DEC VAX/VMS C compiler.
+ */
+# define set_mono_left_mask(var, bit)\
+ (var = chunk_all_bits, var >>= (bit))
+#else
+# define mono_copy_chunk bits16
+extern const bits16 mono_copy_masks[17];
+
+# if mono_fill_chunk_bytes == 2
+# define mono_fill_masks mono_copy_masks
+# else
+extern const bits32 mono_fill_masks[33];
+
+# endif
+/*
+ * We define mono_masks as either mono_fill_masks or
+ * mono_copy_masks before using the following macros.
+ */
+# define set_mono_left_mask(var, bit)\
+ (var = mono_masks[bit])
+# define set_mono_thin_mask(var, w, bit)\
+ (var = ~mono_masks[(w) + (bit)] & mono_masks[bit])
+# define set_mono_right_mask(var, ebit)\
+ (var = ~mono_masks[ebit])
+#endif
+
+#endif /* gxbitops_INCLUDED */
diff --git a/gs/src/gxclrast.c b/gs/src/gxclrast.c
new file mode 100644
index 000000000..ec0b1746d
--- /dev/null
+++ b/gs/src/gxclrast.c
@@ -0,0 +1,2232 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gxclrast.c */
+/* Command list interpreter/rasterizer */
+#include "memory_.h"
+#include "gx.h"
+#include "gp.h" /* for gp_fmode_rb */
+#include "gpcheck.h"
+#include "gserrors.h"
+#include "gsbitops.h"
+#include "gsparams.h"
+#include "gsstate.h" /* (should only be imager state) */
+#include "gxdcolor.h"
+#include "gxdevice.h"
+#include "gscoord.h" /* requires gsmatrix.h */
+#include "gsdevice.h" /* for gs_deviceinitialmatrix */
+#include "gxdevmem.h" /* must precede gxcldev.h */
+#include "gxcldev.h"
+#include "gxclpath.h"
+#include "gxcmap.h"
+#include "gxcspace.h" /* for gs_color_space_type */
+#include "gxgetbit.h"
+#include "gxpaint.h" /* for gx_fill/stroke_params */
+#include "gxhttile.h"
+#include "gdevht.h"
+#include "gzpath.h"
+#include "gzcpath.h"
+#include "gzacpath.h"
+#include "stream.h"
+#include "strimpl.h"
+
+/* We need color space types for constructing temporary color spaces. */
+extern const gs_color_space_type gs_color_space_type_Indexed;
+
+/* Print a bitmap for tracing */
+#ifdef DEBUG
+private void
+cmd_print_bits(const byte * data, int width, int height, int raster)
+{
+ int i, j;
+
+ dlprintf3("[L]width=%d, height=%d, raster=%d\n",
+ width, height, raster);
+ for (i = 0; i < height; i++) {
+ const byte *row = data + i * raster;
+
+ dlprintf("[L]");
+ for (j = 0; j < raster; j++)
+ dprintf1(" %02x", row[j]);
+ dputc('\n');
+ }
+}
+#else
+# define cmd_print_bits(data, width, height, raster) DO_NOTHING
+#endif
+
+/* Get a variable-length integer operand. */
+#define cmd_getw(var, p)\
+ BEGIN\
+ if ( *p < 0x80 ) var = *p++;\
+ else { const byte *_cbp; var = cmd_get_w(p, &_cbp); p = _cbp; }\
+ END
+private long
+cmd_get_w(const byte * p, const byte ** rp)
+{
+ long val = *p++ & 0x7f;
+ int shift = 7;
+
+ for (; val += (long)(*p & 0x7f) << shift, *p++ > 0x7f; shift += 7);
+ *rp = p;
+ return val;
+}
+
+/*
+ * Define the structure for keeping track of the command reading buffer.
+ *
+ * The ptr member is not used, since normally we want it kept in a
+ * register.
+ */
+typedef struct command_buf_s {
+ byte *data; /* actual buffer, guaranteed aligned */
+ uint size;
+ /*const byte *ptr;*/ /* next byte to be read (see above) */
+ const byte *limit; /* refill warning point */
+ const byte *end; /* byte just beyond valid data */
+ stream *s; /* for refilling buffer */
+ int end_status;
+} command_buf_t;
+
+/* Set the end of a command buffer. */
+private void
+set_cb_end(command_buf_t *pcb, const byte *end)
+{
+ pcb->end = end;
+ pcb->limit = pcb->data + (pcb->size - cmd_largest_size + 1);
+ if ( pcb->limit > pcb->end )
+ pcb->limit = pcb->end;
+}
+
+/* Read more data into a command buffer. */
+private const byte *
+top_up_cbuf(command_buf_t *pcb, const byte *cbp)
+{
+ uint nread;
+ byte *cb_top = pcb->data + (pcb->end - cbp);
+
+ memmove(pcb->data, cbp, pcb->end - cbp);
+ nread = pcb->end - cb_top;
+ pcb->end_status = sgets(pcb->s, cb_top, nread, &nread);
+ if ( nread == 0 ) {
+ /* No data for this band at all. */
+ *cb_top = cmd_opv_end_run;
+ nread = 1;
+ }
+ set_cb_end(pcb, cb_top + nread);
+ process_interrupts();
+ return pcb->data;
+}
+
+/* Read data from the command buffer and stream. */
+private const byte *
+cmd_read_data(command_buf_t *pcb, byte *ptr, uint rsize, const byte *cbp)
+{
+ if (pcb->end - cbp >= rsize) {
+ memcpy(ptr, cbp, rsize);
+ return cbp + rsize;
+ } else {
+ uint cleft = pcb->end - cbp;
+ uint rleft = rsize - cleft;
+
+ memcpy(ptr, cbp, cleft);
+ sgets(pcb->s, ptr + cleft, rleft, &rleft);
+ return pcb->end;
+ }
+}
+
+/*
+ * Render one band to a specified target device. Note that if
+ * action == setup, target may be 0.
+ */
+private const byte *cmd_read_rect(P3(int, gx_cmd_rect *, const byte *));
+private const byte *cmd_read_matrix(P2(gs_matrix *, const byte *));
+private void clist_unpack_short_bits(P5(byte *, const byte *, int, int, uint));
+private int cmd_select_map(P7(cmd_map_index, bool, gs_imager_state *,
+ gx_ht_order *, frac **, uint *, gs_memory_t *));
+private int cmd_resize_halftone(P3(gx_device_halftone *, uint, gs_memory_t *));
+private int cmd_install_ht_order(P3(gx_ht_order *, const gx_ht_order *,
+ gs_memory_t *));
+private int clist_decode_segment(P7(gx_path *, int, fixed[6],
+ gs_fixed_point *, int, int,
+ segment_notes));
+int
+clist_playback_band(clist_playback_action playback_action,
+ gx_device_clist_reader *cdev, stream *s,
+ gx_device *target, int x0, int y0, gs_memory_t * mem)
+{
+ /* cbuf must be maximally aligned, but still be a byte *. */
+ typedef union { void *p; double d; long l; } aligner_t;
+ aligner_t cbuf_storage[cbuf_size / sizeof(aligner_t) + 1];
+ command_buf_t cbuf;
+ /* data_bits is for short copy_* bits and copy_* compressed, */
+ /* must be aligned */
+#define data_bits_size cbuf_size
+ byte *data_bits;
+ register const byte *cbp;
+ int dev_depth = cdev->color_info.depth;
+ int dev_depth_bytes = (dev_depth + 7) >> 3;
+ gx_device *tdev;
+ gx_clist_state state;
+ gx_color_index *set_colors;
+ tile_slot *state_slot;
+ gx_strip_bitmap state_tile; /* parameters for reading tiles */
+ tile_slot tile_bits; /* parameters of current tile */
+ gs_int_point tile_phase;
+ gx_path path;
+ bool in_path;
+ gs_fixed_point ppos;
+ gx_clip_path clip_path;
+ bool use_clip;
+ gx_clip_path *pcpath;
+ gx_device_cpath_accum clip_accum;
+ gs_fixed_rect target_box;
+ struct _cas {
+ bool lop_enabled;
+ gs_fixed_point fill_adjust;
+ } clip_save;
+ gs_imager_state imager_state;
+ gx_device_color dev_color;
+ float dash_pattern[cmd_max_dash];
+ gx_fill_params fill_params;
+ gx_stroke_params stroke_params;
+ gx_device_halftone dev_ht;
+ gs_halftone_type halftone_type;
+ gx_ht_order *porder;
+ uint ht_data_index;
+ gs_image_t image;
+ int image_num_planes;
+ gs_int_rect image_rect;
+ gs_color_space color_space; /* only used for indexed spaces */
+ const gs_color_space *pcs;
+ gx_image_enum_common_t *image_info;
+ segment_notes notes;
+ int data_x;
+ int code = 0;
+
+#define cmd_get_value(var, cbp)\
+ memcpy(&var, cbp, sizeof(var));\
+ cbp += sizeof(var)
+#define cmd_read(ptr, rsize, cbp)\
+ cbp = cmd_read_data(&cbuf, ptr, rsize, cbp)
+#define cmd_read_short_bits(ptr, bw, ht, ras, cbp)\
+ cbp = cmd_read_data(&cbuf, ptr, (bw) * (ht), cbp);\
+ clist_unpack_short_bits(ptr, ptr, bw, ht, ras)
+
+ cbuf.data = (byte *)cbuf_storage;
+ cbuf.size = cbuf_size;
+ cbuf.s = s;
+ cbuf.end_status = 0;
+ set_cb_end(&cbuf, cbuf.data + cbuf.size);
+ cbp = cbuf.end;
+in: /* Initialize for a new page. */
+ tdev = target;
+ set_colors = state.colors;
+ use_clip = false;
+ pcpath = NULL;
+ notes = sn_none;
+ data_x = 0;
+ {
+ static const gx_clist_state cls_initial = { cls_initial_values };
+
+ state = cls_initial;
+ }
+ state_tile.id = gx_no_bitmap_id;
+ state_tile.shift = state_tile.rep_shift = 0;
+ tile_phase.x = tile_phase.y = 0;
+ gx_path_init_local(&path, mem);
+ in_path = false;
+ /*
+ * Initialize the clipping region to the full page.
+ * (Since we also initialize use_clip to false, this is arbitrary.)
+ */
+ {
+ gs_fixed_rect cbox;
+
+ gx_cpath_init_local(&clip_path, mem);
+ cbox.p.x = 0;
+ cbox.p.y = 0;
+ cbox.q.x = cdev->width;
+ cbox.q.y = cdev->height;
+ gx_cpath_from_rectangle(&clip_path, &cbox);
+ }
+ if (target != 0)
+ (*dev_proc(target, get_clipping_box))(target, &target_box);
+ imager_state = clist_imager_state_initial;
+ imager_state.line_params.dash.pattern = dash_pattern;
+ code = gs_imager_state_initialize(&imager_state, mem);
+ if (code < 0)
+ goto out;
+ imager_state.halftone = 0; /* never referenced */
+ memset(&dev_ht, 0, sizeof(dev_ht));
+ dev_ht.order.levels = 0; /* clear pointers explicitly, just in case */
+ dev_ht.order.bits = 0;
+ dev_ht.order.transfer = 0;
+ dev_ht.components = 0;
+ imager_state.dev_ht = &dev_ht;
+ imager_state.ht_cache = 0;
+ if (tdev != 0)
+ gx_set_cmap_procs(&imager_state, tdev);
+ gx_imager_setscreenphase(&imager_state, -x0, -y0, gs_color_select_all);
+ halftone_type = ht_type_none;
+ fill_params.fill_zero_width = false;
+ pcs = gs_cspace_DeviceGray(&imager_state);
+ data_bits = gs_alloc_bytes(mem, data_bits_size,
+ "clist_playback_band(data_bits)");
+ if (data_bits == 0) {
+ code = gs_note_error(gs_error_VMerror);
+ goto out;
+ }
+ while (code >= 0) {
+ int op;
+ int compress, depth, raster;
+ byte *source;
+ gx_color_index colors[2];
+ gx_color_index *pcolor;
+ gs_logical_operation_t log_op;
+ tile_slot bits; /* parameters for reading bits */
+
+ /* Make sure the buffer contains a full command. */
+ if (cbp >= cbuf.limit) {
+ if (cbuf.end_status < 0) { /* End of file or error. */
+ if (cbp == cbuf.end) {
+ code = (cbuf.end_status == EOFC ? 0 :
+ gs_note_error(gs_error_ioerror));
+ break;
+ }
+ } else {
+ cbp = top_up_cbuf(&cbuf, cbp);
+ }
+ }
+ op = *cbp++;
+#ifdef DEBUG
+ if (gs_debug_c('L')) {
+ const char *const *sub = cmd_sub_op_names[op >> 4];
+
+ if (sub)
+ dlprintf1("[L]%s:", sub[op & 0xf]);
+ else
+ dlprintf2("[L]%s %d:", cmd_op_names[op >> 4], op & 0xf);
+ }
+#endif
+ switch (op >> 4) {
+ case cmd_op_misc >> 4:
+ switch (op) {
+ case cmd_opv_end_run:
+ if_debug0('L', "\n");
+ continue;
+ case cmd_opv_set_tile_size:
+ {
+ uint rep_width, rep_height;
+ byte bd = *cbp++;
+
+ tile_bits.cb_depth = (bd & 31) + 1;
+ cmd_getw(rep_width, cbp);
+ cmd_getw(rep_height, cbp);
+ if (bd & 0x20) {
+ cmd_getw(tile_bits.x_reps, cbp);
+ tile_bits.width =
+ rep_width * tile_bits.x_reps;
+ } else {
+ tile_bits.x_reps = 1,
+ tile_bits.width = rep_width;
+ }
+ if (bd & 0x40) {
+ cmd_getw(tile_bits.y_reps, cbp);
+ tile_bits.height =
+ rep_height * tile_bits.y_reps;
+ } else {
+ tile_bits.y_reps = 1,
+ tile_bits.height = rep_height;
+ }
+ if (bd & 0x80)
+ cmd_getw(tile_bits.rep_shift, cbp);
+ else
+ tile_bits.rep_shift = 0;
+ if_debug6('L', " depth=%d size=(%d,%d), rep_size=(%d,%d), rep_shift=%d\n",
+ tile_bits.cb_depth, tile_bits.width,
+ tile_bits.height, rep_width,
+ rep_height, tile_bits.rep_shift);
+ tile_bits.shift =
+ (tile_bits.rep_shift == 0 ? 0 :
+ (tile_bits.rep_shift *
+ (tile_bits.height / rep_height))
+ % rep_width);
+ tile_bits.cb_raster =
+ bitmap_raster(tile_bits.width *
+ tile_bits.cb_depth);
+ }
+ continue;
+ case cmd_opv_set_tile_phase:
+ cmd_getw(state.tile_phase.x, cbp);
+ cmd_getw(state.tile_phase.y, cbp);
+ if_debug2('L', " (%d,%d)\n",
+ state.tile_phase.x,
+ state.tile_phase.y);
+ goto set_phase;
+ case cmd_opv_set_tile_bits:
+ bits = tile_bits;
+ compress = 0;
+ stb:{
+ uint rep_width = bits.width / bits.x_reps;
+ uint rep_height = bits.height / bits.y_reps;
+ uint index;
+ ulong offset;
+ uint width_bits = rep_width * bits.cb_depth;
+ uint width_bytes;
+ uint bytes =
+ clist_bitmap_bytes(width_bits, rep_height,
+ compress |
+ (rep_width < bits.width ?
+ decompress_spread : 0) |
+ decompress_elsewhere,
+ &width_bytes,
+ (uint *) & raster);
+ byte *data;
+
+ cmd_getw(index, cbp);
+ cmd_getw(offset, cbp);
+ if_debug2('L', " index=%d offset=%lu\n",
+ state.tile_index, offset);
+ state.tile_index = index;
+ cdev->tile_table[state.tile_index].offset =
+ offset;
+ state_slot =
+ (tile_slot *) (cdev->chunk.data + offset);
+ *state_slot = bits;
+ state_tile.data = data =
+ (byte *) (state_slot + 1);
+#ifdef DEBUG
+ state_slot->index = state.tile_index;
+#endif
+ if (compress) { /* Decompress the image data. */
+ /* We'd like to share this code */
+ /* with the similar code in copy_*, */
+ /* but right now we don't see how. */
+ stream_cursor_read r;
+ stream_cursor_write w;
+
+ /* We don't know the data length a */
+ /* priori, so to be conservative, */
+ /* we read the uncompressed size. */
+ uint cleft = cbuf.end - cbp;
+
+ if (cleft < bytes) {
+ uint nread = cbuf_size - cleft;
+
+ memmove(cbuf.data, cbp, cleft);
+ cbuf.end_status = sgets(s, cbuf.data + cleft, nread, &nread);
+ set_cb_end(&cbuf, cbuf.data + cleft + nread);
+ cbp = cbuf.data;
+ }
+ r.ptr = cbp - 1;
+ r.limit = cbuf.end - 1;
+ w.ptr = data - 1;
+ w.limit = w.ptr + bytes;
+ switch (compress) {
+ case cmd_compress_rle:
+ {
+ stream_RLD_state sstate;
+
+ clist_rld_init(&sstate);
+ (*s_RLD_template.process)
+ ((stream_state *) & sstate, &r, &w, true);
+ }
+ break;
+ case cmd_compress_cfe:
+ {
+ stream_CFD_state sstate;
+
+ clist_cfd_init(&sstate,
+ width_bytes << 3 /*width_bits */ ,
+ rep_height, mem);
+ (*s_CFD_template.process)
+ ((stream_state *) & sstate, &r, &w, true);
+ (*s_CFD_template.release)
+ ((stream_state *) & sstate);
+ }
+ break;
+ default:
+ goto bad_op;
+ }
+ cbp = r.ptr + 1;
+ } else if (rep_height > 1 &&
+ width_bytes != bits.cb_raster
+ ) {
+ cmd_read_short_bits(data, width_bytes,
+ rep_height, bits.cb_raster, cbp);
+ } else {
+ cmd_read(data, bytes, cbp);
+ }
+ if (bits.width > rep_width)
+ bits_replicate_horizontally(data,
+ rep_width * bits.cb_depth, rep_height,
+ bits.cb_raster,
+ bits.width * bits.cb_depth,
+ bits.cb_raster);
+ if (bits.height > rep_height)
+ bits_replicate_vertically(data,
+ rep_height, bits.cb_raster,
+ bits.height);
+#ifdef DEBUG
+ if (gs_debug_c('L'))
+ cmd_print_bits(data, bits.width,
+ bits.height,
+ bits.cb_raster);
+#endif
+ }
+ goto stp;
+ case cmd_opv_set_bits:
+ compress = *cbp & 3;
+ bits.cb_depth = *cbp++ >> 2;
+ cmd_getw(bits.width, cbp);
+ cmd_getw(bits.height, cbp);
+ if_debug4('L', " compress=%d depth=%d size=(%d,%d)",
+ compress, bits.cb_depth,
+ bits.width, bits.height);
+ bits.cb_raster =
+ bitmap_raster(bits.width * bits.cb_depth);
+ bits.x_reps = bits.y_reps = 1;
+ bits.shift = bits.rep_shift = 0;
+ goto stb;
+ case cmd_opv_set_tile_color:
+ set_colors = state.tile_colors;
+ if_debug0('L', "\n");
+ continue;
+ case cmd_opv_set_misc:
+ {
+ uint cb = *cbp++;
+
+ switch (cb >> 6) {
+ case cmd_set_misc_lop >> 6:
+ cmd_getw(state.lop, cbp);
+ state.lop = (state.lop << 6) + (cb & 0x3f);
+ if_debug1('L', " lop=0x%x\n", state.lop);
+ if (state.lop_enabled)
+ imager_state.log_op = state.lop;
+ break;
+ case cmd_set_misc_data_x >> 6:
+ if (cb & 0x20)
+ cmd_getw(data_x, cbp);
+ else
+ data_x = 0;
+ data_x = (data_x << 5) + (cb & 0x1f);
+ if_debug1('L', " data_x=%d\n", data_x);
+ break;
+ case cmd_set_misc_map >> 6:
+ {
+ frac *mdata;
+ uint count;
+
+ code = cmd_select_map(cb & 0x1f,
+ cb & 0x20,
+ &imager_state,
+ porder, &mdata,
+ &count, mem);
+
+ if (code < 0)
+ goto out;
+ if (mdata) {
+ cmd_read((byte *) mdata, count, cbp);
+#ifdef DEBUG
+ if (gs_debug_c('L')) {
+ uint i;
+
+ for (i = 0; i < count / sizeof(*mdata); ++i)
+ dprintf1(" 0x%04x", mdata[i]);
+ dputc('\n');
+ }
+ } else {
+ if_debug0('L', " none\n");
+#endif
+ }
+ }
+ /* Recompute the effective transfer, */
+ /* in case this was a transfer map. */
+ gx_imager_set_effective_xfer(
+ &imager_state);
+ break;
+ case cmd_set_misc_halftone >> 6:
+ halftone_type = cb & 0x3f;
+ {
+ uint num_comp;
+
+ cmd_getw(num_comp, cbp);
+ if_debug2('L', " halftone type=%d num_comp=%u\n",
+ halftone_type, num_comp);
+ code = cmd_resize_halftone(&dev_ht,
+ num_comp, mem);
+ if (code < 0)
+ goto out;
+ }
+ break;
+ default:
+ goto bad_op;
+ }
+ }
+ continue;
+ case cmd_opv_enable_lop:
+ state.lop_enabled = true;
+ imager_state.log_op = state.lop;
+ if_debug0('L', "\n");
+ continue;
+ case cmd_opv_disable_lop:
+ state.lop_enabled = false;
+ imager_state.log_op = lop_default;
+ if_debug0('L', "\n");
+ continue;
+ case cmd_opv_set_ht_order:
+ {
+ int index;
+ gx_ht_order order;
+
+ cmd_getw(index, cbp);
+ if (index == 0)
+ porder = &dev_ht.order;
+ else {
+ gx_ht_order_component *pcomp =
+ &dev_ht.components[index - 1];
+
+ cmd_getw(pcomp->cname, cbp);
+ if_debug1('L', " cname=%lu",
+ (ulong) pcomp->cname);
+ porder = &pcomp->corder;
+ }
+ order = *porder;
+ cmd_getw(order.width, cbp);
+ cmd_getw(order.height, cbp);
+ cmd_getw(order.raster, cbp);
+ cmd_getw(order.shift, cbp);
+ cmd_getw(order.num_levels, cbp);
+ cmd_getw(order.num_bits, cbp);
+ if_debug7('L', " index=%d size=(%d,%d) raster=%d shift=%d num_levels=%d num_bits=%d\n",
+ index, order.width, order.height,
+ order.raster, order.shift,
+ order.num_levels, order.num_bits);
+ code =
+ cmd_install_ht_order(porder, &order, mem);
+ if (code < 0)
+ goto out;
+ }
+ ht_data_index = 0;
+ continue;
+ case cmd_opv_set_ht_data:
+ {
+ int n = *cbp++;
+
+ if (ht_data_index < porder->num_levels) { /* Setting levels */
+ byte *lptr = (byte *)
+ (porder->levels + ht_data_index);
+
+ cmd_read(lptr, n * sizeof(*porder->levels),
+ cbp);
+#ifdef DEBUG
+ if (gs_debug_c('L')) {
+ int i;
+
+ dprintf1(" levels[%u]", ht_data_index);
+ for (i = 0; i < n; ++i)
+ dprintf1(" %u",
+ porder->levels[ht_data_index + i]);
+ dputc('\n');
+ }
+#endif
+ } else { /* Setting bits */
+ byte *bptr = (byte *)
+ (porder->bits +
+ (ht_data_index - porder->num_levels));
+
+ cmd_read(bptr, n * sizeof(*porder->bits),
+ cbp);
+#ifdef DEBUG
+ if (gs_debug_c('L')) {
+ int i;
+
+ dprintf1(" bits[%u]", ht_data_index - porder->num_levels);
+ for (i = 0; i < n; ++i) {
+ const gx_ht_bit *pb =
+ &porder->bits[ht_data_index - porder->num_levels + i];
+
+ dprintf2(" (%u,0x%lx)",
+ pb->offset,
+ (ulong) pb->mask);
+ }
+ dputc('\n');
+ }
+#endif
+ }
+ ht_data_index += n;
+ }
+ /* If this is the end of the data, */
+ /* install the (device) halftone. */
+ if (porder ==
+ (dev_ht.components != 0 ?
+ &dev_ht.components[0].corder :
+ &dev_ht.order) &&
+ ht_data_index == porder->num_levels +
+ porder->num_bits
+ ) { /* Make sure we have a halftone cache. */
+ uint i;
+
+ if (imager_state.ht_cache == 0) {
+ gx_ht_cache *pcache =
+ gx_ht_alloc_cache(mem,
+ porder->num_levels + 2,
+ gx_ht_cache_default_bits());
+
+ if (pcache == 0) {
+ code = gs_note_error(gs_error_VMerror);
+ goto out;
+ }
+ imager_state.ht_cache = pcache;
+ }
+ for (i = 1; i < dev_ht.num_comp; ++i) {
+ gx_ht_order *pco =
+ &dev_ht.components[i].corder;
+
+ if (!pco->cache) {
+ gx_ht_cache *pcache =
+ gx_ht_alloc_cache(mem, 1,
+ pco->raster * (pco->num_bits /
+ pco->width));
+
+ if (pcache == 0) {
+ code = gs_note_error(gs_error_VMerror);
+ goto out;
+ }
+ pco->cache = pcache;
+ gx_ht_init_cache(pcache, pco);
+ }
+ }
+ if (dev_ht.num_comp) {
+ dev_ht.components[0].corder.cache =
+ imager_state.ht_cache;
+ dev_ht.order =
+ dev_ht.components[0].corder;
+ }
+ gx_imager_dev_ht_install(&imager_state,
+ &dev_ht, halftone_type,
+ (const gx_device *)cdev);
+ }
+ continue;
+ case cmd_opv_end_page:
+ if_debug0('L', "\n");
+ /*
+ * Do end-of-page cleanup, then reinitialize if
+ * there are more pages to come.
+ */
+ goto out;
+ case cmd_opv_delta2_color0:
+ pcolor = &set_colors[0];
+ goto delta2_c;
+ case cmd_opv_delta2_color1:
+ pcolor = &set_colors[1];
+ delta2_c:set_colors = state.colors;
+ {
+ gx_color_index b = ((uint) * cbp << 8) + cbp[1];
+
+ cbp += 2;
+ if (dev_depth > 24)
+ *pcolor +=
+ ((b & 0xf000) << 12) + ((b & 0x0f00) << 8) +
+ ((b & 0x00f0) << 4) + (b & 0x000f) -
+ cmd_delta2_32_bias;
+ else
+ *pcolor +=
+ ((b & 0xf800) << 5) + ((b & 0x07e0) << 3) +
+ (b & 0x001f) - cmd_delta2_24_bias;
+ }
+ if_debug1('L', " 0x%lx\n", *pcolor);
+ continue;
+ case cmd_opv_set_copy_color:
+ state.color_is_alpha = 0;
+ if_debug0('L', "\n");
+ continue;
+ case cmd_opv_set_copy_alpha:
+ state.color_is_alpha = 1;
+ if_debug0('L', "\n");
+ continue;
+ default:
+ goto bad_op;
+ }
+ /*NOTREACHED */
+ case cmd_op_set_color0 >> 4:
+ pcolor = &set_colors[0];
+ goto set_color;
+ case cmd_op_set_color1 >> 4:
+ pcolor = &set_colors[1];
+ set_color:set_colors = state.colors;
+ switch (op & 0xf) {
+ case 0:
+ break;
+ case 15: /* special handling because this may */
+ /* require more bits than depth */
+ *pcolor = gx_no_color_index;
+ goto setc;
+ default:
+ switch (dev_depth_bytes) {
+ case 4:
+ {
+ gx_color_index b =
+ ((gx_color_index) (op & 0xf) << 8) + *cbp++;
+
+ *pcolor +=
+ ((b & 07000) << 15) + ((b & 0700) << 10) +
+ ((b & 070) << 5) + (b & 7) -
+ cmd_delta1_32_bias;
+ goto setc;
+ }
+ case 3:
+ {
+ gx_color_index b = *cbp++;
+
+ *pcolor +=
+ ((gx_color_index) (op & 0xf) << 16) +
+ ((b & 0xf0) << 4) + (b & 0x0f) -
+ cmd_delta1_24_bias;
+ goto setc;
+ }
+ case 2:
+ break;
+ case 1:
+ *pcolor += (gx_color_index) (op & 0xf) - 8;
+ goto setc;
+ }
+ }
+ {
+ gx_color_index color = 0;
+
+ switch (dev_depth_bytes) {
+ case 4:
+ color |= (gx_color_index) * cbp++ << 24;
+ case 3:
+ color |= (gx_color_index) * cbp++ << 16;
+ case 2:
+ color |= (gx_color_index) * cbp++ << 8;
+ case 1:
+ color |= (gx_color_index) * cbp++;
+ }
+ *pcolor = color;
+ }
+ setc:if_debug1('L', " 0x%lx\n", *pcolor);
+ continue;
+ case cmd_op_fill_rect >> 4:
+ case cmd_op_tile_rect >> 4:
+ cbp = cmd_read_rect(op, &state.rect, cbp);
+ break;
+ case cmd_op_fill_rect_short >> 4:
+ case cmd_op_tile_rect_short >> 4:
+ state.rect.x += *cbp + cmd_min_short;
+ state.rect.width += cbp[1] + cmd_min_short;
+ if (op & 0xf) {
+ state.rect.height += (op & 0xf) + cmd_min_dxy_tiny;
+ cbp += 2;
+ } else {
+ state.rect.y += cbp[2] + cmd_min_short;
+ state.rect.height += cbp[3] + cmd_min_short;
+ cbp += 4;
+ }
+ break;
+ case cmd_op_fill_rect_tiny >> 4:
+ case cmd_op_tile_rect_tiny >> 4:
+ if (op & 8)
+ state.rect.x += state.rect.width;
+ else {
+ int txy = *cbp++;
+
+ state.rect.x += (txy >> 4) + cmd_min_dxy_tiny;
+ state.rect.y += (txy & 0xf) + cmd_min_dxy_tiny;
+ }
+ state.rect.width += (op & 7) + cmd_min_dw_tiny;
+ break;
+ case cmd_op_copy_mono >> 4:
+ depth = 1;
+ goto copy;
+ case cmd_op_copy_color_alpha >> 4:
+ if (state.color_is_alpha) {
+ if (!(op & 8))
+ depth = *cbp++;
+ } else
+ depth = dev_depth;
+ copy:cmd_getw(state.rect.x, cbp);
+ cmd_getw(state.rect.y, cbp);
+ if (op & 8) { /* Use the current "tile". */
+#ifdef DEBUG
+ if (state_slot->index != state.tile_index) {
+ lprintf2("state_slot->index = %d, state.tile_index = %d!\n",
+ state_slot->index,
+ state.tile_index);
+ code = gs_note_error(gs_error_ioerror);
+ goto out;
+ }
+#endif
+ depth = state_slot->cb_depth;
+ state.rect.width = state_slot->width;
+ state.rect.height = state_slot->height;
+ raster = state_slot->cb_raster;
+ source = (byte *) (state_slot + 1);
+ } else { /* Read width, height, bits. */
+ /* depth was set already. */
+ uint width_bits, width_bytes;
+ uint bytes;
+
+ cmd_getw(state.rect.width, cbp);
+ cmd_getw(state.rect.height, cbp);
+ width_bits = state.rect.width * depth;
+ bytes =
+ clist_bitmap_bytes(width_bits,
+ state.rect.height,
+ op & 3, &width_bytes,
+ (uint *) & raster);
+ /* copy_mono and copy_color/alpha */
+ /* ensure that the bits will fit in a single buffer, */
+ /* even after decompression if compressed. */
+#ifdef DEBUG
+ if (bytes > cbuf_size) {
+ lprintf6("bitmap size exceeds buffer! width=%d raster=%d height=%d\n file pos %ld buf pos %d/%d\n",
+ state.rect.width, raster,
+ state.rect.height,
+ stell(s), (int)(cbp - cbuf.data),
+ (int)(cbuf.end - cbuf.data));
+ code = gs_note_error(gs_error_ioerror);
+ goto out;
+ }
+#endif
+ if (op & 3) { /* Decompress the image data. */
+ stream_cursor_read r;
+ stream_cursor_write w;
+
+ /* We don't know the data length a priori, */
+ /* so to be conservative, we read */
+ /* the uncompressed size. */
+ uint cleft = cbuf.end - cbp;
+
+ if (cleft < bytes) {
+ uint nread = cbuf_size - cleft;
+
+ memmove(cbuf.data, cbp, cleft);
+ cbuf.end_status = sgets(s, cbuf.data + cleft, nread, &nread);
+ set_cb_end(&cbuf, cbuf.data + cleft + nread);
+ cbp = cbuf.data;
+ }
+ r.ptr = cbp - 1;
+ r.limit = cbuf.end - 1;
+ w.ptr = data_bits - 1;
+ w.limit = w.ptr + data_bits_size;
+ switch (op & 3) {
+ case cmd_compress_rle:
+ {
+ stream_RLD_state sstate;
+
+ clist_rld_init(&sstate);
+ /* The process procedure can't fail. */
+ (*s_RLD_template.process)
+ ((stream_state *) & sstate, &r, &w, true);
+ }
+ break;
+ case cmd_compress_cfe:
+ {
+ stream_CFD_state sstate;
+
+ clist_cfd_init(&sstate,
+ width_bytes << 3 /*state.rect.width */ ,
+ state.rect.height, mem);
+ /* The process procedure can't fail. */
+ (*s_CFD_template.process)
+ ((stream_state *) & sstate, &r, &w, true);
+ (*s_CFD_template.release)
+ ((stream_state *) & sstate);
+ }
+ break;
+ default:
+ goto bad_op;
+ }
+ cbp = r.ptr + 1;
+ source = data_bits;
+ } else if (state.rect.height > 1 &&
+ width_bytes != raster
+ ) {
+ source = data_bits;
+ cmd_read_short_bits(source, width_bytes,
+ state.rect.height,
+ raster, cbp);
+ } else {
+ cmd_read(cbuf.data, bytes, cbp);
+ source = cbuf.data;
+ }
+#ifdef DEBUG
+ if (gs_debug_c('L')) {
+ dprintf2(" depth=%d, data_x=%d\n",
+ depth, data_x);
+ cmd_print_bits(source, state.rect.width,
+ state.rect.height, raster);
+ }
+#endif
+ }
+ break;
+ case cmd_op_delta_tile_index >> 4:
+ state.tile_index += (int)(op & 0xf) - 8;
+ goto sti;
+ case cmd_op_set_tile_index >> 4:
+ state.tile_index =
+ ((op & 0xf) << 8) + *cbp++;
+ sti:state_slot =
+ (tile_slot *) (cdev->chunk.data +
+ cdev->tile_table[state.tile_index].offset);
+ if_debug2('L', " index=%u offset=%lu\n",
+ state.tile_index,
+ cdev->tile_table[state.tile_index].offset);
+ state_tile.data = (byte *) (state_slot + 1);
+ stp:state_tile.size.x = state_slot->width;
+ state_tile.size.y = state_slot->height;
+ state_tile.raster = state_slot->cb_raster;
+ state_tile.rep_width = state_tile.size.x /
+ state_slot->x_reps;
+ state_tile.rep_height = state_tile.size.y /
+ state_slot->y_reps;
+ state_tile.rep_shift = state_slot->rep_shift;
+ state_tile.shift = state_slot->shift;
+ set_phase:tile_phase.x =
+ (state.tile_phase.x + x0) % state_tile.size.x;
+ /*
+ * The true tile height for shifted tiles is not
+ * size.y: see gxbitmap.h for the computation.
+ */
+ {
+ int full_height;
+
+ if (state_tile.shift == 0)
+ full_height = state_tile.size.y;
+ else
+ full_height = state_tile.rep_height *
+ (state_tile.rep_width /
+ igcd(state_tile.rep_shift,
+ state_tile.rep_width));
+ tile_phase.y =
+ (state.tile_phase.y + y0) % full_height;
+ }
+ gx_imager_setscreenphase(&imager_state,
+ -(state.tile_phase.x + x0),
+ -(state.tile_phase.y + y0),
+ gs_color_select_all);
+ continue;
+ case cmd_op_misc2 >> 4:
+ switch (op) {
+ case cmd_opv_set_flatness:
+ cmd_get_value(imager_state.flatness, cbp);
+ if_debug1('L', " %g\n", imager_state.flatness);
+ continue;
+ case cmd_opv_set_fill_adjust:
+ cmd_get_value(imager_state.fill_adjust.x, cbp);
+ cmd_get_value(imager_state.fill_adjust.y, cbp);
+ if_debug2('L', " (%g,%g)\n",
+ fixed2float(imager_state.fill_adjust.x),
+ fixed2float(imager_state.fill_adjust.y));
+ continue;
+ case cmd_opv_set_ctm:
+ {
+ gs_matrix mat;
+
+ cbp = cmd_read_matrix(&mat, cbp);
+ mat.tx -= x0;
+ mat.ty -= y0;
+ gs_imager_setmatrix(&imager_state, &mat);
+ if_debug6('L', " [%g %g %g %g %g %g]\n",
+ mat.xx, mat.xy, mat.yx, mat.yy,
+ mat.tx, mat.ty);
+ }
+ continue;
+ case cmd_opv_set_line_width:
+ {
+ float width;
+
+ cmd_get_value(width, cbp);
+ if_debug1('L', " %g\n", width);
+ gx_set_line_width(&imager_state.line_params, width);
+ }
+ continue;
+ case cmd_opv_set_misc2:
+ {
+ uint cb = *cbp;
+
+ switch (cb >> 6) {
+ case cmd_set_misc2_cap_join >> 6:
+ imager_state.line_params.cap =
+ (gs_line_cap) ((cb >> 3) & 7);
+ imager_state.line_params.join =
+ (gs_line_join) (cb & 7);
+ if_debug2('L', " cap=%d join=%d\n",
+ imager_state.line_params.cap,
+ imager_state.line_params.join);
+ break;
+ case cmd_set_misc2_ac_op_sa >> 6:
+ imager_state.accurate_curves =
+ (cb & 4) != 0;
+ imager_state.overprint = (cb & 2) != 0;
+ imager_state.stroke_adjust = cb & 1;
+ if_debug3('L', " AC=%d OP=%d SA=%d\n",
+ imager_state.accurate_curves,
+ imager_state.overprint,
+ imager_state.stroke_adjust);
+ break;
+ case cmd_set_misc2_notes >> 6:
+ notes = (segment_notes) (cb & 0x3f);
+ if_debug1('L', " notes=%d\n", notes);
+ break;
+ case cmd_set_misc2_alpha >> 6:
+ memcpy(&imager_state.alpha, cbp + 1,
+ sizeof(imager_state.alpha));
+ cbp += sizeof(imager_state.alpha);
+ break;
+ default:
+ goto bad_op;
+ }
+ }
+ cbp++;
+ continue;
+ case cmd_opv_set_miter_limit:
+ {
+ float limit;
+
+ cmd_get_value(limit, cbp);
+ if_debug1('L', " %g\n", limit);
+ gx_set_miter_limit(&imager_state.line_params, limit);
+ }
+ continue;
+ case cmd_opv_set_dash:
+ {
+ int nb = *cbp++;
+ int n = nb & 0x3f;
+ float dot_length, offset;
+
+ cmd_get_value(dot_length, cbp);
+ cmd_get_value(offset, cbp);
+ memcpy(dash_pattern, cbp, n * sizeof(float));
+
+ gx_set_dash(&imager_state.line_params.dash,
+ dash_pattern, n, offset,
+ NULL);
+ gx_set_dash_adapt(&imager_state.line_params.dash,
+ (nb & 0x80) != 0);
+ gx_set_dot_length(&imager_state.line_params,
+ dot_length,
+ (nb & 0x40) != 0);
+#ifdef DEBUG
+ if (gs_debug_c('L')) {
+ int i;
+
+ dprintf4(" dot=%g(mode %d) adapt=%d offset=%g [",
+ dot_length,
+ (nb & 0x40) != 0,
+ (nb & 0x80) != 0, offset);
+ for (i = 0; i < n; ++i)
+ dprintf1("%g ", dash_pattern[i]);
+ dputs("]\n");
+ }
+#endif
+ cbp += n * sizeof(float);
+ }
+ break;
+ case cmd_opv_enable_clip:
+ pcpath = (use_clip ? &clip_path : NULL);
+ if_debug0('L', "\n");
+ break;
+ case cmd_opv_disable_clip:
+ pcpath = NULL;
+ if_debug0('L', "\n");
+ break;
+ case cmd_opv_begin_clip:
+ pcpath = NULL;
+ if_debug0('L', "\n");
+ code = gx_cpath_reset(&clip_path);
+ if (code < 0)
+ goto out;
+ gx_cpath_accum_begin(&clip_accum, mem);
+ gx_cpath_accum_set_cbox(&clip_accum,
+ &target_box);
+ tdev = (gx_device *) & clip_accum;
+ clip_save.lop_enabled = state.lop_enabled;
+ clip_save.fill_adjust =
+ imager_state.fill_adjust;
+ state.lop_enabled = false;
+ imager_state.log_op = lop_default;
+ imager_state.fill_adjust.x =
+ imager_state.fill_adjust.y = fixed_half;
+ break;
+ case cmd_opv_end_clip:
+ if_debug0('L', "\n");
+ gx_cpath_accum_end(&clip_accum, &clip_path);
+ gx_cpath_set_outside(&clip_path, *cbp++);
+ tdev = target;
+ /*
+ * If the entire band falls within the clip
+ * path, no clipping is needed.
+ */
+ {
+ gs_fixed_rect cbox;
+
+ gx_cpath_inner_box(&clip_path, &cbox);
+ use_clip =
+ !(cbox.p.x <= target_box.p.x &&
+ cbox.q.x >= target_box.q.x &&
+ cbox.p.y <= target_box.p.y &&
+ cbox.q.y >= target_box.q.y);
+ }
+ pcpath = (use_clip ? &clip_path : NULL);
+ state.lop_enabled = clip_save.lop_enabled;
+ imager_state.log_op =
+ (state.lop_enabled ? state.lop :
+ lop_default);
+ imager_state.fill_adjust =
+ clip_save.fill_adjust;
+ break;
+ case cmd_opv_set_color_space:
+ {
+ byte b = *cbp++;
+ int index = b >> 4;
+
+ if_debug2('L', " %d%s\n", index,
+ (b & 8 ? " (indexed)" : ""));
+ switch (index) {
+ case gs_color_space_index_DeviceGray:
+ pcs = gs_cspace_DeviceGray(&imager_state);
+ break;
+ case gs_color_space_index_DeviceRGB:
+ pcs = gs_cspace_DeviceRGB(&imager_state);
+ break;
+ case gs_color_space_index_DeviceCMYK:
+ pcs = gs_cspace_DeviceCMYK(&imager_state);
+ break;
+ default:
+ goto bad_op; /* others are NYI */
+ }
+ if (b & 8) {
+ int num_comp =
+ gs_color_space_num_components(pcs);
+
+ color_space.type = &gs_color_space_type_Indexed;
+ color_space.params.indexed.base_space.type = pcs->type;
+ cmd_getw(color_space.params.indexed.hival,
+ cbp);
+ color_space.params.indexed.use_proc =
+ (b & 4) != 0;
+/****** SET map ******/
+ pcs = &color_space;
+ }
+ }
+ break;
+ case cmd_opv_begin_image:
+ {
+ byte b = *cbp++;
+ int bpci = b >> 5;
+ static const byte bpc[6] =
+ {1, 1, 2, 4, 8, 12};
+ gx_drawing_color devc;
+ int num_components;
+ gs_image_format_t format;
+
+ if (bpci == 0)
+ gs_image_t_init_mask(&image, false);
+ else
+ gs_image_t_init(&image, pcs);
+ if (b & (1 << 4)) {
+ byte b2 = *cbp++;
+
+ format = b2 >> 6;
+ image.Interpolate = (b2 & (1 << 5)) != 0;
+ image.Alpha =
+ (gs_image_alpha_t) ((b2 >> 3) & 3);
+ } else {
+ format = gs_image_format_chunky;
+ }
+ cmd_getw(image.Width, cbp);
+ cmd_getw(image.Height, cbp);
+ if_debug4('L', " BPCi=%d I=%d size=(%d,%d)",
+ bpci, (b & 0x10) != 0,
+ image.Width, image.Height);
+ if (b & (1 << 3)) { /* Non-standard ImageMatrix */
+ cbp = cmd_read_matrix(
+ &image.ImageMatrix, cbp);
+ if_debug6('L', " matrix=[%g %g %g %g %g %g]",
+ image.ImageMatrix.xx,
+ image.ImageMatrix.xy,
+ image.ImageMatrix.yx,
+ image.ImageMatrix.yy,
+ image.ImageMatrix.tx,
+ image.ImageMatrix.ty);
+ } else {
+ image.ImageMatrix.xx = image.Width;
+ image.ImageMatrix.xy = 0;
+ image.ImageMatrix.yx = 0;
+ image.ImageMatrix.yy = -image.Height;
+ image.ImageMatrix.tx = 0;
+ image.ImageMatrix.ty = image.Height;
+ }
+ image.BitsPerComponent = bpc[bpci];
+ if (bpci == 0) {
+ num_components = 1;
+ } else {
+ image.ColorSpace = pcs;
+ if (gs_color_space_get_index(pcs) == gs_color_space_index_Indexed) {
+ image.Decode[0] = 0;
+ image.Decode[1] =
+ (1 << image.BitsPerComponent) - 1;
+ } else {
+ static const float decode01[] =
+ {
+ 0, 1, 0, 1, 0, 1, 0, 1, 0, 1
+ };
+
+ memcpy(image.Decode, decode01,
+ sizeof(image.Decode));
+ }
+ num_components =
+ gs_color_space_num_components(pcs);
+ }
+ switch (format) {
+ case gs_image_format_chunky:
+ image_num_planes = 1;
+ break;
+ case gs_image_format_component_planar:
+ image_num_planes = num_components;
+ break;
+ case gs_image_format_bit_planar:
+ image_num_planes = num_components *
+ image.BitsPerComponent;
+ break;
+ default:
+ goto bad_op;
+ }
+ if (b & (1 << 2)) { /* Non-standard Decode */
+ byte dflags = *cbp++;
+ int i;
+
+ for (i = 0; i < num_components * 2;
+ dflags <<= 2, i += 2
+ )
+ switch ((dflags >> 6) & 3) {
+ case 0: /* default */
+ break;
+ case 1: /* swapped default */
+ image.Decode[i] =
+ image.Decode[i + 1];
+ image.Decode[i + 1] = 0;
+ break;
+ case 3:
+ cmd_get_value(image.Decode[i],
+ cbp);
+ /* falls through */
+ case 2:
+ cmd_get_value(image.Decode[i + 1],
+ cbp);
+ }
+#ifdef DEBUG
+ if (gs_debug_c('L')) {
+ dputs(" decode=[");
+ for (i = 0; i < num_components * 2;
+ ++i
+ )
+ dprintf1("%g ", image.Decode[i]);
+ dputc(']');
+ }
+#endif
+ }
+ image.adjust = false;
+ if (b & (1 << 1)) {
+ if (image.ImageMask)
+ image.adjust = true;
+ else
+ image.CombineWithColor = true;
+ if_debug1('L', " %s",
+ (image.ImageMask ? " adjust" :
+ " CWC"));
+ }
+ if (b & (1 << 0)) { /* Non-standard rectangle */
+ uint diff;
+
+ cmd_getw(image_rect.p.x, cbp);
+ cmd_getw(image_rect.p.y, cbp);
+ cmd_getw(diff, cbp);
+ image_rect.q.x = image.Width - diff;
+ cmd_getw(diff, cbp);
+ image_rect.q.y = image.Height - diff;
+ if_debug4('L', " rect=(%d,%d),(%d,%d)",
+ image_rect.p.x, image_rect.p.y,
+ image_rect.q.x, image_rect.q.y);
+ } else {
+ image_rect.p.x = 0;
+ image_rect.p.y = 0;
+ image_rect.q.x = image.Width;
+ image_rect.q.y = image.Height;
+ }
+ if_debug0('L', "\n");
+ color_set_pure(&devc, state.colors[1]);
+ code = (*dev_proc(tdev, begin_image))
+ (tdev, &imager_state, &image, format,
+ &image_rect, &devc, pcpath, mem,
+ &image_info);
+ if (code < 0)
+ goto out;
+ }
+ break;
+ case cmd_opv_image_data:
+ {
+ uint height;
+
+ cmd_getw(height, cbp);
+ if (height == 0) {
+ if_debug0('L', " done image\n");
+ code = gx_device_end_image(tdev,
+ image_info, true);
+ } else {
+ uint bytes_per_plane, nbytes;
+ const byte *data;
+ byte *data_on_heap = 0;
+ const byte *planes[64];
+
+/****** DOESN'T HANDLE #PLANES YET *****/
+
+ cmd_getw(bytes_per_plane, cbp);
+ if_debug2('L', " height=%u raster=%u\n",
+ height, bytes_per_plane);
+ nbytes = bytes_per_plane *
+ image_num_planes * height;
+ if ( cbuf.end - cbp < nbytes)
+ cbp = top_up_cbuf(&cbuf, cbp);
+ if (cbuf.end - cbp >= nbytes) {
+ data = cbp;
+ cbp += nbytes;
+ } else {
+ uint cleft = cbuf.end - cbp;
+ uint rleft = nbytes - cleft;
+ byte *rdata;
+
+ if (nbytes > cbuf.end - cbuf.data) { /* Allocate a separate buffer. */
+ rdata = data_on_heap =
+ gs_alloc_bytes(mem, nbytes,
+ "clist image_data");
+ if (rdata == 0) {
+ code = gs_note_error(gs_error_VMerror);
+ goto out;
+ }
+ } else
+ rdata = cbuf.data;
+ memmove(rdata, cbp, cleft);
+ sgets(s, rdata + cleft, rleft,
+ &rleft);
+ data = rdata;
+ cbp = cbuf.end; /* force refill */
+ }
+#ifdef DEBUG
+ if (gs_debug_c('L'))
+ cmd_print_bits(data, image_rect.q.x -
+ image_rect.p.x,
+ image_num_planes * height,
+ bytes_per_plane);
+#endif
+ {
+ int plane;
+
+ for (plane = 0;
+ plane < image_num_planes;
+ ++plane
+ )
+ planes[plane] = data +
+ bytes_per_plane * height * plane;
+ }
+ code = gx_device_image_data(tdev,
+ image_info, planes, data_x,
+ bytes_per_plane, height);
+ if (data_on_heap)
+ gs_free_object(mem, data_on_heap,
+ "clist image_data");
+ data_x = 0;
+ }
+ }
+ if (code < 0)
+ goto out;
+ continue;
+ case cmd_opv_set_color:
+ {
+#define dcb dev_color.colors.colored.c_base
+#define dcl dev_color.colors.colored.c_level
+ byte b = *cbp++;
+ int i;
+
+ switch (b >> 4) {
+ case 0:
+ dcb[0] = (b >> 3) & 1;
+ dcb[1] = (b >> 2) & 1;
+ dcb[2] = (b >> 1) & 1;
+ dcb[3] = b & 1;
+ break;
+ case 1:
+ dcb[0] = ((b & 0xf) << 1) + (*cbp >> 7);
+ dcb[1] = (*cbp >> 2) & 0x1f;
+ dcb[2] = ((*cbp & 3) << 3) + (cbp[1] >> 5);
+ dcb[3] = cbp[1] & 0x1f;
+ cbp += 2;
+ break;
+ default:
+ goto bad_op;
+ }
+ for (i = 0; i < imager_state.dev_ht->num_comp; ++i)
+ cmd_getw(dcl[i], cbp);
+ if_debug10('L', " format %d num_comp=%d base=(%u,%u,%u,%u) level=(%u,%u,%u,%u)\n",
+ b >> 4,
+ imager_state.dev_ht->num_comp,
+ dcb[0], dcb[1], dcb[2], dcb[3],
+ dcl[0], dcl[1], dcl[2], dcl[3]);
+ color_finish_set_cmyk_halftone(&dev_color,
+ imager_state.dev_ht);
+#undef dcb
+#undef dcl
+ }
+ continue;
+ case cmd_opv_put_params: {
+ gs_c_param_list param_list;
+ uint cleft;
+ uint rleft;
+ bool alloc_data_on_heap = false;
+ byte *param_buf;
+ uint param_length;
+
+ cmd_get_value(param_length, cbp);
+ if_debug1('L', " length=%d\n", param_length);
+ code = 0;
+ if (param_length == 0)
+ break;
+
+ /* Make sure entire serialized param list is in cbuf */
+ /* + force void* alignment */
+ cbp = top_up_cbuf(&cbuf, cbp);
+ if (cbuf.end - cbp >= param_length) {
+ param_buf = (byte *)cbp;
+ cbp += param_length;
+ } else {
+ /* NOTE: param_buf must be maximally aligned */
+ param_buf = gs_alloc_bytes(mem, param_length,
+ "clist put_params");
+ if (param_buf == 0) {
+ code = gs_note_error(gs_error_VMerror);
+ goto out;
+ }
+ alloc_data_on_heap = true;
+ cleft = cbuf.end - cbp;
+ rleft = param_length - cleft;
+ memmove(param_buf, cbp, cleft);
+ sgets(s, param_buf + cleft, rleft, &rleft);
+ cbp = cbuf.end; /* force refill */
+ }
+
+ /*
+ * Create a gs_c_param_list & expand into it.
+ * NB that gs_c_param_list doesn't copy objects into
+ * it, but rather keeps *pointers* to what's passed.
+ * That's OK because the serialized format keeps enough
+ * space to hold expanded versions of the structures,
+ * but this means we cannot deallocate source buffer
+ * until the gs_c_param_list is deleted.
+ */
+ gs_c_param_list_write(&param_list, mem);
+ code = gs_param_list_unserialize
+ ( (gs_param_list *)&param_list, param_buf );
+ if (code >= 0 && code != param_length)
+ code = gs_error_unknownerror; /* must match */
+ if (code >= 0) {
+ gs_c_param_list_read(&param_list);
+ code = (*dev_proc(cdev, put_params))
+ ((gx_device *)cdev,
+ (gs_param_list *)&param_list);
+ }
+ gs_c_param_list_release(&param_list);
+ if (alloc_data_on_heap)
+ gs_free_object(mem, param_buf, "clist put_params");
+ if (code < 0)
+ goto out;
+ if (playback_action == playback_action_setup)
+ goto out;
+ }
+ break;
+ default:
+ goto bad_op;
+ }
+ continue;
+ case cmd_op_segment >> 4:
+ {
+ fixed vs[6];
+ int i, code;
+
+ if (!in_path) {
+ ppos.x = int2fixed(state.rect.x);
+ ppos.y = int2fixed(state.rect.y);
+ if_debug2('L', " (%d,%d)", state.rect.x,
+ state.rect.y);
+ notes = sn_none;
+ in_path = true;
+ }
+ for (i = 0;
+ i < clist_segment_op_num_operands[op & 0xf];
+ ++i
+ ) {
+ fixed v;
+ int b = *cbp;
+
+ switch (b >> 5) {
+ case 0:
+ case 1:
+ vs[i++] =
+ ((fixed) ((b ^ 0x20) - 0x20) << 13) +
+ ((int)cbp[1] << 5) + (cbp[2] >> 3);
+ if_debug1('L', " %g", fixed2float(vs[i - 1]));
+ cbp += 2;
+ v = (int)((*cbp & 7) ^ 4) - 4;
+ break;
+ case 2:
+ case 3:
+ v = (b ^ 0x60) - 0x20;
+ break;
+ case 4:
+ case 5:
+ /*
+ * Without the following cast, C's
+ * brain-damaged coercion rules cause the
+ * result to be considered unsigned, and not
+ * sign-extended on machines where
+ * sizeof(long) > sizeof(int).
+ */
+ v = (((b ^ 0xa0) - 0x20) << 8) + (int)*++cbp;
+ break;
+ case 6:
+ v = (b ^ 0xd0) - 0x10;
+ vs[i] =
+ ((v << 8) + cbp[1]) << (_fixed_shift - 2);
+ if_debug1('L', " %g", fixed2float(vs[i]));
+ cbp += 2;
+ continue;
+ default /*case 7 */ :
+ v = (int)(*++cbp ^ 0x80) - 0x80;
+ for (b = 0; b < sizeof(fixed) - 3; ++b)
+ v = (v << 8) + *++cbp;
+ break;
+ }
+ cbp += 3;
+ /* Absent the cast in the next statement, */
+ /* the Borland C++ 4.5 compiler incorrectly */
+ /* sign-extends the result of the shift. */
+ vs[i] = (v << 16) + (uint) (cbp[-2] << 8) + cbp[-1];
+ if_debug1('L', " %g", fixed2float(vs[i]));
+ }
+ if_debug0('L', "\n");
+ code = clist_decode_segment(&path, op, vs, &ppos,
+ x0, y0, notes);
+ if (code < 0)
+ goto out;
+ }
+ continue;
+ case cmd_op_path >> 4:
+ {
+ gx_device_color devc;
+ gx_device_color *pdevc;
+ gx_ht_tile ht_tile;
+
+ if_debug0('L', "\n");
+ switch (op) {
+ case cmd_opv_fill:
+ fill_params.rule = gx_rule_winding_number;
+ goto fill_pure;
+ case cmd_opv_eofill:
+ fill_params.rule = gx_rule_even_odd;
+ fill_pure:color_set_pure(&devc, state.colors[1]);
+ pdevc = &devc;
+ goto fill;
+ case cmd_opv_htfill:
+ fill_params.rule = gx_rule_winding_number;
+ goto fill_ht;
+ case cmd_opv_hteofill:
+ fill_params.rule = gx_rule_even_odd;
+ fill_ht:ht_tile.tiles = state_tile;
+ color_set_binary_tile(&devc,
+ state.tile_colors[0],
+ state.tile_colors[1],
+ &ht_tile);
+ pdevc = &devc;
+ pdevc->phase = tile_phase;
+ goto fill;
+ case cmd_opv_colorfill:
+ fill_params.rule = gx_rule_winding_number;
+ goto fill_color;
+ case cmd_opv_coloreofill:
+ fill_params.rule = gx_rule_even_odd;
+ fill_color:pdevc = &dev_color;
+ pdevc->phase = tile_phase;
+ code =
+ gx_color_load(pdevc, &imager_state, tdev);
+ if (code < 0)
+ break;
+ fill:fill_params.adjust = imager_state.fill_adjust;
+ fill_params.flatness = imager_state.flatness;
+ code = gx_fill_path_only(&path, tdev,
+ &imager_state,
+ &fill_params,
+ pdevc, pcpath);
+ break;
+ case cmd_opv_stroke:
+ color_set_pure(&devc, state.colors[1]);
+ pdevc = &devc;
+ goto stroke;
+ case cmd_opv_htstroke:
+ ht_tile.tiles = state_tile;
+ color_set_binary_tile(&devc,
+ state.tile_colors[0],
+ state.tile_colors[1],
+ &ht_tile);
+ pdevc = &devc;
+ pdevc->phase = tile_phase;
+ goto stroke;
+ case cmd_opv_colorstroke:
+ pdevc = &dev_color;
+ pdevc->phase = tile_phase;
+ code =
+ gx_color_load(pdevc, &imager_state, tdev);
+ if (code < 0)
+ break;
+ stroke:stroke_params.flatness = imager_state.flatness;
+ code = gx_stroke_path_only(&path,
+ (gx_path *) 0, tdev,
+ &imager_state, &stroke_params,
+ pdevc, pcpath);
+ break;
+ default:
+ goto bad_op;
+ }
+ }
+ if (in_path) { /* path might be empty! */
+ state.rect.x = fixed2int_var(ppos.x);
+ state.rect.y = fixed2int_var(ppos.y);
+ in_path = false;
+ }
+ gx_path_free(&path, "clist_render_band");
+ gx_path_init_local(&path, mem);
+ if (code < 0)
+ goto out;
+ continue;
+ default:
+ bad_op:lprintf5("Bad op %02x band y0 = %d file pos %ld buf pos %d/%d\n",
+ op, y0, stell(s), (int)(cbp - cbuf.data), (int)(cbuf.end - cbuf.data));
+ {
+ const byte *pp;
+
+ for (pp = cbuf.data; pp < cbuf.end; pp += 10) {
+ dlprintf1("%4d:", (int)(pp - cbuf.data));
+ dprintf10(" %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ pp[0], pp[1], pp[2], pp[3], pp[4],
+ pp[5], pp[6], pp[7], pp[8], pp[9]);
+ }
+ }
+ code = gs_note_error(gs_error_Fatal);
+ goto out;
+ }
+ if_debug4('L', " x=%d y=%d w=%d h=%d\n",
+ state.rect.x, state.rect.y, state.rect.width,
+ state.rect.height);
+ switch (op >> 4) {
+ case cmd_op_fill_rect >> 4:
+ case cmd_op_fill_rect_short >> 4:
+ case cmd_op_fill_rect_tiny >> 4:
+ if (!state.lop_enabled) {
+ code = (*dev_proc(tdev, fill_rectangle))
+ (tdev, state.rect.x - x0, state.rect.y - y0,
+ state.rect.width, state.rect.height,
+ state.colors[1]);
+ break;
+ }
+ source = NULL;
+ data_x = 0;
+ raster = 0;
+ colors[0] = colors[1] = state.colors[1];
+ log_op = state.lop;
+ pcolor = colors;
+ do_rop:code = (*dev_proc(tdev, strip_copy_rop))
+ (tdev, source, data_x, raster, gx_no_bitmap_id,
+ pcolor, &state_tile,
+ (state.tile_colors[0] == gx_no_color_index &&
+ state.tile_colors[1] == gx_no_color_index ?
+ NULL : state.tile_colors),
+ state.rect.x - x0, state.rect.y - y0,
+ state.rect.width - data_x, state.rect.height,
+ tile_phase.x, tile_phase.y, log_op);
+ data_x = 0;
+ break;
+ case cmd_op_tile_rect >> 4:
+ case cmd_op_tile_rect_short >> 4:
+ case cmd_op_tile_rect_tiny >> 4:
+ /* Currently we don't use lop with tile_rectangle. */
+ code = (*dev_proc(tdev, strip_tile_rectangle))
+ (tdev, &state_tile,
+ state.rect.x - x0, state.rect.y - y0,
+ state.rect.width, state.rect.height,
+ state.tile_colors[0], state.tile_colors[1],
+ tile_phase.x, tile_phase.y);
+ break;
+ case cmd_op_copy_mono >> 4:
+ if (state.lop_enabled) {
+ pcolor = state.colors;
+ log_op = state.lop;
+ goto do_rop;
+ }
+ if ((op & cmd_copy_use_tile) || pcpath != NULL) { /*
+ * This call of copy_mono originated as a call
+ * of fill_mask.
+ */
+ gx_drawing_color dcolor;
+ gx_ht_tile ht_tile;
+
+ if (op & cmd_copy_ht_color) { /* Screwy C assignment rules don't allow: */
+ /* dcolor.colors = state.tile_colors; */
+ ht_tile.tiles = state_tile;
+ color_set_binary_tile(&dcolor,
+ state.tile_colors[0],
+ state.tile_colors[1], &ht_tile);
+ dcolor.phase = tile_phase;
+ } else {
+ color_set_pure(&dcolor, state.colors[1]);
+ }
+ code = (*dev_proc(tdev, fill_mask))
+ (tdev, source, data_x, raster, gx_no_bitmap_id,
+ state.rect.x - x0, state.rect.y - y0,
+ state.rect.width - data_x, state.rect.height,
+ &dcolor, 1, imager_state.log_op, pcpath);
+ } else
+ code = (*dev_proc(tdev, copy_mono))
+ (tdev, source, data_x, raster, gx_no_bitmap_id,
+ state.rect.x - x0, state.rect.y - y0,
+ state.rect.width - data_x, state.rect.height,
+ state.colors[0], state.colors[1]);
+ data_x = 0;
+ break;
+ case cmd_op_copy_color_alpha >> 4:
+ if (state.color_is_alpha) {
+/****** CAN'T DO ROP WITH ALPHA ******/
+ code = (*dev_proc(tdev, copy_alpha))
+ (tdev, source, data_x, raster, gx_no_bitmap_id,
+ state.rect.x - x0, state.rect.y - y0,
+ state.rect.width - data_x, state.rect.height,
+ state.colors[1], depth);
+ } else {
+ if (state.lop_enabled) {
+ pcolor = NULL;
+ log_op = state.lop;
+ goto do_rop;
+ }
+ code = (*dev_proc(tdev, copy_color))
+ (tdev, source, data_x, raster, gx_no_bitmap_id,
+ state.rect.x - x0, state.rect.y - y0,
+ state.rect.width - data_x, state.rect.height);
+ }
+ data_x = 0;
+ break;
+ default: /* can't happen */
+ goto bad_op;
+ }
+ }
+ /* Clean up before we exit. */
+ out:gx_cpath_free(&clip_path, "clist_render_band exit");
+ gx_path_free(&path, "clist_render_band exit");
+ if (imager_state.ht_cache)
+ gx_ht_free_cache(mem, imager_state.ht_cache);
+ gx_device_halftone_release(&dev_ht, mem);
+ gs_imager_state_release(&imager_state);
+ gs_free_object(mem, data_bits, "clist_playback_band(data_bits)");
+ if (code < 0)
+ return_error(code);
+ /* Check whether we have more pages to process. */
+ if (playback_action != playback_action_setup &&
+ (cbp < cbuf.end || !seofp(s))
+ )
+ goto in;
+ return code;
+}
+
+/* Unpack a short bitmap */
+private void
+clist_unpack_short_bits(byte * dest, const byte * src, int width_bytes,
+ int height, uint raster)
+{
+ uint bytes = width_bytes * height;
+ const byte *pdata = src + bytes;
+ byte *udata = dest + height * raster;
+
+ while (--height >= 0) {
+ udata -= raster, pdata -= width_bytes;
+ switch (width_bytes) {
+ default:
+ memmove(udata, pdata, width_bytes);
+ break;
+ case 6:
+ udata[5] = pdata[5];
+ case 5:
+ udata[4] = pdata[4];
+ case 4:
+ udata[3] = pdata[3];
+ case 3:
+ udata[2] = pdata[2];
+ case 2:
+ udata[1] = pdata[1];
+ case 1:
+ udata[0] = pdata[0];
+ case 0:; /* shouldn't happen */
+ }
+ }
+}
+
+/* Read a rectangle. */
+private const byte *
+cmd_read_rect(int op, gx_cmd_rect * prect, const byte * cbp)
+{
+ cmd_getw(prect->x, cbp);
+ if (op & 0xf)
+ prect->y += ((op >> 2) & 3) - 2;
+ else {
+ cmd_getw(prect->y, cbp);
+ }
+ cmd_getw(prect->width, cbp);
+ if (op & 0xf)
+ prect->height += (op & 3) - 2;
+ else {
+ cmd_getw(prect->height, cbp);
+ }
+ return cbp;
+}
+
+/* Read a transformation matrix. */
+private const byte *
+cmd_read_matrix(gs_matrix * pmat, const byte * cbp)
+{
+ byte b = *cbp++;
+ float coeff[6];
+ int i;
+
+ for (i = 0; i < 4; i += 2, b <<= 2)
+ if (!(b & 0xc0))
+ coeff[i] = coeff[i ^ 3] = 0.0;
+ else {
+ float value;
+
+ cmd_get_value(value, cbp);
+ coeff[i] = value;
+ switch ((b >> 6) & 3) {
+ case 1:
+ coeff[i ^ 3] = value;
+ break;
+ case 2:
+ coeff[i ^ 3] = -value;
+ break;
+ case 3:
+ cmd_get_value(coeff[i ^ 3], cbp);
+ }
+ }
+ for (; i < 6; ++i, b <<= 1)
+ if (b & 0x80) {
+ cmd_get_value(coeff[i], cbp);
+ } else
+ coeff[i] = 0.0;
+ pmat->xx = coeff[0];
+ pmat->xy = coeff[1];
+ pmat->yx = coeff[2];
+ pmat->yy = coeff[3];
+ pmat->tx = coeff[4];
+ pmat->ty = coeff[5];
+ return cbp;
+}
+
+/* Select a map for loading with data. */
+/* load = false is not possible for cmd_map_transfer*. */
+private int
+cmd_select_map(cmd_map_index map_index, bool load, gs_imager_state * pis,
+ gx_ht_order * porder, frac ** pmdata, uint * pcount, gs_memory_t * mem)
+{
+ gx_transfer_map *map;
+ gx_transfer_map **pmap;
+ const char *cname;
+
+ switch (map_index) {
+ case cmd_map_transfer:
+ if_debug0('L', " transfer");
+ map = pis->set_transfer.colored.gray;
+ pis->effective_transfer.indexed[0] =
+ pis->effective_transfer.indexed[1] =
+ pis->effective_transfer.indexed[2] =
+ pis->effective_transfer.indexed[3] =
+ map;
+ break;
+ case cmd_map_transfer_0:
+ case cmd_map_transfer_1:
+ case cmd_map_transfer_2:
+ case cmd_map_transfer_3:
+ {
+ int i = map_index - cmd_map_transfer_0;
+
+ if_debug1('L', " transfer[%d]", i);
+ rc_unshare_struct(pis->set_transfer.indexed[i], gx_transfer_map,
+ &st_transfer_map, mem,
+ return_error(gs_error_VMerror),
+ "cmd_select_map(transfer)");
+ map = pis->set_transfer.indexed[i];
+ pis->effective_transfer.indexed[i] = map;
+ }
+ break;
+ case cmd_map_ht_transfer:
+ if_debug0('L', " ht transfer");
+ /* Halftone transfer maps are never shared, but */
+ /* rc_unshare_struct is a good way to get one allocated */
+ /* if it hasn't been yet. */
+ pmap = &porder->transfer;
+ cname = "cmd_select_map(ht transfer)";
+ goto alloc;
+ case cmd_map_black_generation:
+ if_debug0('L', " black generation");
+ pmap = &pis->black_generation;
+ cname = "cmd_select_map(black generation)";
+ goto alloc;
+ case cmd_map_undercolor_removal:
+ if_debug0('L', " undercolor removal");
+ pmap = &pis->undercolor_removal;
+ cname = "cmd_select_map(undercolor removal)";
+alloc: if (!load) {
+ rc_decrement(*pmap, cname);
+ *pmap = 0;
+ *pmdata = 0;
+ *pcount = 0;
+ return 0;
+ }
+ rc_unshare_struct(*pmap, gx_transfer_map, &st_transfer_map,
+ mem, return_error(gs_error_VMerror), cname);
+ map = *pmap;
+ break;
+ default:
+ *pmdata = 0;
+ return 0;
+ }
+ map->proc = gs_mapped_transfer;
+ *pmdata = map->values;
+ *pcount = sizeof(map->values);
+ return 0;
+}
+
+/* Install a halftone order, resizing the bits and levels if necessary. */
+private int
+cmd_install_ht_order(gx_ht_order * porder, const gx_ht_order * pnew,
+ gs_memory_t * mem)
+{
+ uint *levels = porder->levels;
+ gx_ht_bit *bits = porder->bits;
+
+ /*
+ * Note that for resizing a byte array, the element size is 1 byte,
+ * not the element size given to alloc_byte_array!
+ */
+ if (pnew->num_levels > porder->num_levels) {
+ if (levels == 0)
+ levels = (uint *) gs_alloc_byte_array(mem, pnew->num_levels,
+ sizeof(*levels),
+ "ht order(levels)");
+ else
+ levels = gs_resize_object(mem, levels,
+ pnew->num_levels * sizeof(*levels),
+ "ht order(levels)");
+ if (levels == 0)
+ return_error(gs_error_VMerror);
+ /* Update porder in case we bail out. */
+ porder->levels = levels;
+ porder->num_levels = pnew->num_levels;
+ }
+ if (pnew->num_bits > porder->num_bits) {
+ if (bits == 0)
+ bits = (gx_ht_bit *) gs_alloc_byte_array(mem, pnew->num_bits,
+ sizeof(*bits),
+ "ht order(bits)");
+ else
+ bits = gs_resize_object(mem, bits,
+ pnew->num_bits * sizeof(*bits),
+ "ht order(bits)");
+ if (bits == 0)
+ return_error(gs_error_VMerror);
+ }
+ *porder = *pnew;
+ porder->levels = levels;
+ porder->bits = bits;
+ porder->full_height = ht_order_full_height(porder);
+ return 0;
+}
+
+/* Resize the halftone components array if necessary. */
+private int
+cmd_resize_halftone(gx_device_halftone * pdht, uint num_comp,
+ gs_memory_t * mem)
+{
+ if (num_comp != pdht->num_comp) {
+ gx_ht_order_component *pcomp;
+
+ /*
+ * We must be careful not to shrink or free the components array
+ * before releasing any relevant elements.
+ */
+ if (num_comp < pdht->num_comp) {
+ uint i;
+
+ /* Don't release the default order. */
+ for (i = pdht->num_comp; i-- > num_comp;)
+ if (pdht->components[i].corder.bits != pdht->order.bits)
+ gx_ht_order_release(&pdht->components[i].corder, mem, true);
+ if (num_comp == 0) {
+ gs_free_object(mem, pdht->components, "cmd_resize_halftone");
+ pcomp = 0;
+ } else {
+ pcomp = gs_resize_object(mem, pdht->components, num_comp,
+ "cmd_resize_halftone");
+ if (pcomp == 0) {
+ pdht->num_comp = num_comp; /* attempt consistency */
+ return_error(gs_error_VMerror);
+ }
+ }
+ } else {
+ /* num_comp > pdht->num_comp */
+ if (pdht->num_comp == 0)
+ pcomp = gs_alloc_struct_array(mem, num_comp,
+ gx_ht_order_component,
+ &st_ht_order_component_element,
+ "cmd_resize_halftone");
+ else
+ pcomp = gs_resize_object(mem, pdht->components, num_comp,
+ "cmd_resize_halftone");
+ if (pcomp == 0)
+ return_error(gs_error_VMerror);
+ memset(&pcomp[pdht->num_comp], 0,
+ sizeof(*pcomp) * (num_comp - pdht->num_comp));
+ }
+ pdht->num_comp = num_comp;
+ pdht->components = pcomp;
+ }
+ return 0;
+}
+
+/* ------ Path operations ------ */
+
+/* Decode a path segment. */
+private int
+clist_decode_segment(gx_path * ppath, int op, fixed vs[6],
+ gs_fixed_point * ppos, int x0, int y0, segment_notes notes)
+{
+ fixed px = ppos->x - int2fixed(x0);
+ fixed py = ppos->y - int2fixed(y0);
+ int code;
+
+#define A vs[0]
+#define B vs[1]
+#define C vs[2]
+#define D vs[3]
+#define E vs[4]
+#define F vs[5]
+
+ switch (op) {
+ case cmd_opv_rmoveto:
+ code = gx_path_add_point(ppath, px += A, py += B);
+ break;
+ case cmd_opv_rlineto:
+ code = gx_path_add_line_notes(ppath, px += A, py += B, notes);
+ break;
+ case cmd_opv_hlineto:
+ code = gx_path_add_line_notes(ppath, px += A, py, notes);
+ break;
+ case cmd_opv_vlineto:
+ code = gx_path_add_line_notes(ppath, px, py += A, notes);
+ break;
+ case cmd_opv_rrcurveto: /* a b c d e f => a b a+c b+d a+c+e b+d+f */
+ E += (C += A);
+ F += (D += B);
+curve: code = gx_path_add_curve_notes(ppath, px + A, py + B,
+ px + C, py + D,
+ px + E, py + F, notes);
+ px += E, py += F;
+ break;
+ case cmd_opv_hvcurveto: /* a b c d => a 0 a+b c a+b c+d */
+hvc: F = C + D, D = C, E = C = A + B, B = 0;
+ goto curve;
+ case cmd_opv_vhcurveto: /* a b c d => 0 a b a+c b+d a+c */
+vhc: E = B + D, F = D = A + C, C = B, B = A, A = 0;
+ goto curve;
+ case cmd_opv_nrcurveto: /* a b c d => 0 0 a b a+c b+d */
+ F = B + D, E = A + C, D = B, C = A, B = A = 0;
+ goto curve;
+ case cmd_opv_rncurveto: /* a b c d => a b a+c b+d a+c b+d */
+ F = D += B, E = C += A;
+ goto curve;
+ case cmd_opv_rmlineto:
+ if ((code = gx_path_add_point(ppath, px += A, py += B)) < 0)
+ break;
+ code = gx_path_add_line_notes(ppath, px += C, py += D, notes);
+ break;
+ case cmd_opv_rm2lineto:
+ if ((code = gx_path_add_point(ppath, px += A, py += B)) < 0 ||
+ (code = gx_path_add_line_notes(ppath, px += C, py += D,
+ notes)) < 0
+ )
+ break;
+ code = gx_path_add_line_notes(ppath, px += E, py += F, notes);
+ break;
+ case cmd_opv_vqcurveto: /* a b => VH a b TS(a,b) TS(b,a) */
+ if ((A ^ B) < 0)
+ C = -B, D = -A;
+ else
+ C = B, D = A;
+ goto vhc;
+ case cmd_opv_hqcurveto: /* a b => HV a TS(a,b) b TS(b,a) */
+ if ((A ^ B) < 0)
+ D = -A, C = B, B = -B;
+ else
+ D = A, C = B;
+ goto hvc;
+ case cmd_opv_rm3lineto:
+ if ((code = gx_path_add_point(ppath, px += A, py += B)) < 0 ||
+ (code = gx_path_add_line_notes(ppath, px += C, py += D,
+ notes)) < 0 ||
+ (code = gx_path_add_line_notes(ppath, px += E, py += F,
+ notes)) < 0
+ )
+ break;
+ code = gx_path_add_line_notes(ppath, px -= C, py -= D, notes);
+ break;
+ case cmd_opv_closepath:
+ code = gx_path_close_subpath(ppath);
+ gx_path_current_point(ppath, (gs_fixed_point *) vs);
+ px = A, py = B;
+ break;
+ default:
+ return_error(gs_error_rangecheck);
+ }
+#undef A
+#undef B
+#undef C
+#undef D
+#undef E
+#undef F
+ ppos->x = px + int2fixed(x0);
+ ppos->y = py + int2fixed(y0);
+ return code;
+}
diff --git a/gs/src/gxclutil.c b/gs/src/gxclutil.c
new file mode 100644
index 000000000..ed50beb62
--- /dev/null
+++ b/gs/src/gxclutil.c
@@ -0,0 +1,610 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gxclutil.c */
+/* Command list writing utilities. */
+
+#include "memory_.h"
+#include "string_.h"
+#include "gx.h"
+#include "gp.h"
+#include "gpcheck.h"
+#include "gserrors.h"
+#include "gxdevice.h"
+#include "gxdevmem.h" /* must precede gxcldev.h */
+#include "gxcldev.h"
+#include "gxclpath.h"
+#include "gsparams.h"
+
+#define cdev cwdev
+
+/* ---------------- Statistics ---------------- */
+
+#ifdef DEBUG
+const char *const cmd_op_names[16] =
+{cmd_op_name_strings};
+private const char *const cmd_misc_op_names[16] =
+{cmd_misc_op_name_strings};
+private const char *const cmd_misc2_op_names[16] =
+{cmd_misc2_op_name_strings};
+private const char *const cmd_segment_op_names[16] =
+{cmd_segment_op_name_strings};
+private const char *const cmd_path_op_names[16] =
+{cmd_path_op_name_strings};
+const char *const *const cmd_sub_op_names[16] =
+{cmd_misc_op_names, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, cmd_misc2_op_names, cmd_segment_op_names, cmd_path_op_names
+};
+struct stats_cmd_s {
+ ulong op_counts[256];
+ ulong op_sizes[256];
+ ulong tile_reset, tile_found, tile_added;
+ ulong same_band, other_band;
+} stats_cmd;
+extern ulong stats_cmd_diffs[5]; /* in gxclpath.c */
+int
+cmd_count_op(int op, uint size)
+{
+ stats_cmd.op_counts[op]++;
+ stats_cmd.op_sizes[op] += size;
+ if (gs_debug_c('L')) {
+ const char *const *sub = cmd_sub_op_names[op >> 4];
+
+ if (sub)
+ dlprintf2(", %s(%u)\n", sub[op & 0xf], size);
+ else
+ dlprintf3(", %s %d(%u)\n", cmd_op_names[op >> 4], op & 0xf,
+ size);
+ fflush(dstderr);
+ }
+ return op;
+}
+void
+cmd_uncount_op(int op, uint size)
+{
+ stats_cmd.op_counts[op]--;
+ stats_cmd.op_sizes[op] -= size;
+}
+#endif
+
+/* Print statistics. */
+#ifdef DEBUG
+void
+cmd_print_stats(void)
+{
+ int ci, cj;
+
+ dlprintf3("[l]counts: reset = %lu, found = %lu, added = %lu\n",
+ stats_cmd.tile_reset, stats_cmd.tile_found,
+ stats_cmd.tile_added);
+ dlprintf5(" diff 2.5 = %lu, 3 = %lu, 4 = %lu, 2 = %lu, >4 = %lu\n",
+ stats_cmd_diffs[0], stats_cmd_diffs[1], stats_cmd_diffs[2],
+ stats_cmd_diffs[3], stats_cmd_diffs[4]);
+ dlprintf2(" same_band = %lu, other_band = %lu\n",
+ stats_cmd.same_band, stats_cmd.other_band);
+ for (ci = 0; ci < 0x100; ci += 0x10) {
+ const char *const *sub = cmd_sub_op_names[ci >> 4];
+
+ if (sub != 0) {
+ dlprintf1("[l] %s =", cmd_op_names[ci >> 4]);
+ for (cj = ci; cj < ci + 0x10; cj += 2)
+ dprintf6("\n\t%s = %lu(%lu), %s = %lu(%lu)",
+ sub[cj - ci],
+ stats_cmd.op_counts[cj], stats_cmd.op_sizes[cj],
+ sub[cj - ci + 1],
+ stats_cmd.op_counts[cj + 1], stats_cmd.op_sizes[cj + 1]);
+ } else {
+ ulong tcounts = 0, tsizes = 0;
+
+ for (cj = ci; cj < ci + 0x10; cj++)
+ tcounts += stats_cmd.op_counts[cj],
+ tsizes += stats_cmd.op_sizes[cj];
+ dlprintf3("[l] %s (%lu,%lu) =\n\t",
+ cmd_op_names[ci >> 4], tcounts, tsizes);
+ for (cj = ci; cj < ci + 0x10; cj++)
+ if (stats_cmd.op_counts[cj] == 0)
+ dputs(" -");
+ else
+ dprintf2(" %lu(%lu)", stats_cmd.op_counts[cj],
+ stats_cmd.op_sizes[cj]);
+ }
+ dputs("\n");
+ }
+}
+#endif /* DEBUG */
+
+/* ---------------- Writing utilities ---------------- */
+
+/* Write the commands for one band or band range. */
+private int /* ret 0 all ok, -ve error code, or +1 ok w/low-mem warning */
+cmd_write_band(gx_device_clist_writer * cldev, int band_min, int band_max,
+ cmd_list * pcl, byte cmd_end)
+{
+ const cmd_prefix *cp = pcl->head;
+ int code_b = 0;
+ int code_c = 0;
+
+ if (cp != 0 || cmd_end != cmd_opv_end_run) {
+ clist_file_ptr cfile = cldev->page_cfile;
+ clist_file_ptr bfile = cldev->page_bfile;
+ cmd_block cb;
+ byte end = cmd_count_op(cmd_end, 1);
+
+ if (cfile == 0 || bfile == 0)
+ return_error(gs_error_ioerror);
+ cb.band_min = band_min;
+ cb.band_max = band_max;
+ cb.pos = clist_ftell(cfile);
+ if_debug3('l', "[l]writing for bands (%d,%d) at %ld\n",
+ band_min, band_max, cb.pos);
+ clist_fwrite_chars(&cb, sizeof(cb), bfile);
+ if (cp != 0) {
+ pcl->tail->next = 0; /* terminate the list */
+ for (; cp != 0; cp = cp->next) {
+#ifdef DEBUG
+ if ((const byte *)cp < cldev->cbuf ||
+ (const byte *)cp >= cldev->cend ||
+ cp->size > cldev->cend - (const byte *)cp
+ ) {
+ lprintf1("cmd_write_band error at 0x%lx\n", (ulong) cp);
+ return_error(gs_error_Fatal);
+ }
+#endif
+ clist_fwrite_chars(cp + 1, cp->size, cfile);
+ }
+ pcl->head = pcl->tail = 0;
+ }
+ clist_fwrite_chars(&end, 1, cfile);
+ process_interrupts();
+ code_b = clist_ferror_code(bfile);
+ code_c = clist_ferror_code(cfile);
+ if (code_b < 0)
+ return_error(code_b);
+ if (code_c < 0)
+ return_error(code_c);
+ }
+ return code_b | code_c;
+}
+
+/* Write out the buffered commands, and reset the buffer. */
+int /* ret 0 all-ok, -ve error code, or +1 ok w/low-mem warning */
+cmd_write_buffer(gx_device_clist_writer * cldev, byte cmd_end)
+{
+ int nbands = cldev->nbands;
+ gx_clist_state *pcls;
+ int band;
+ int code = cmd_write_band(cldev, cldev->band_range_min,
+ cldev->band_range_max,
+ &cldev->band_range_list, cmd_opv_end_run);
+ int warning = code;
+
+ for (band = 0, pcls = cldev->states;
+ code >= 0 && band < nbands; band++, pcls++
+ ) {
+ code = cmd_write_band(cldev, band, band, &pcls->list, cmd_end);
+ warning |= code;
+ }
+ cldev->cnext = cldev->cbuf;
+ cldev->ccl = 0;
+ cldev->band_range_list.head = cldev->band_range_list.tail = 0;
+#ifdef DEBUG
+ if (gs_debug_c('l'))
+ cmd_print_stats();
+#endif
+ return_check_interrupt(code != 0 ? code : warning);
+}
+
+/*
+ * Add a command to the appropriate band list, and allocate space for its
+ * data. Return the pointer to the data area. If an error or (low-memory
+ * warning) occurs, set cldev->error_code and return 0.
+ */
+#define cmd_headroom (sizeof(cmd_prefix) + arch_align_ptr_mod)
+byte *
+cmd_put_list_op(gx_device_clist_writer * cldev, cmd_list * pcl, uint size)
+{
+ byte *dp = cldev->cnext;
+
+ if (size + cmd_headroom > cldev->cend - dp) {
+ if ((cldev->error_code =
+ cmd_write_buffer(cldev, cmd_opv_end_run)) != 0) {
+ if (cldev->error_code < 0)
+ cldev->error_is_retryable = 0; /* hard error */
+ else {
+ /* upgrade lo-mem warning into an error */
+ if (!cldev->ignore_lo_mem_warnings)
+ cldev->error_code = gs_note_error(gs_error_VMerror);
+ cldev->error_is_retryable = 1;
+ }
+ return 0;
+ }
+ else
+ return cmd_put_list_op(cldev, pcl, size);
+ }
+ if (cldev->ccl == pcl) { /* We're adding another command for the same band. */
+ /* Tack it onto the end of the previous one. */
+ cmd_count_add1(stats_cmd.same_band);
+#ifdef DEBUG
+ if (pcl->tail->size > dp - (byte *) (pcl->tail + 1)) {
+ lprintf1("cmd_put_list_op error at 0x%lx\n", (ulong) pcl->tail);
+ }
+#endif
+ pcl->tail->size += size;
+ } else {
+ /* Skip to an appropriate alignment boundary. */
+ /* (We assume the command buffer itself is aligned.) */
+ cmd_prefix *cp = (cmd_prefix *)
+ (dp + ((cldev->cbuf - dp) & (arch_align_ptr_mod - 1)));
+
+ cmd_count_add1(stats_cmd.other_band);
+ dp = (byte *) (cp + 1);
+ if (pcl->tail != 0) {
+#ifdef DEBUG
+ if (pcl->tail < pcl->head ||
+ pcl->tail->size > dp - (byte *) (pcl->tail + 1)
+ ) {
+ lprintf1("cmd_put_list_op error at 0x%lx\n",
+ (ulong) pcl->tail);
+ }
+#endif
+ pcl->tail->next = cp;
+ } else
+ pcl->head = cp;
+ pcl->tail = cp;
+ cldev->ccl = pcl;
+ cp->size = size;
+ }
+ cldev->cnext = dp + size;
+ return dp;
+}
+#ifdef DEBUG
+byte *
+cmd_put_op(gx_device_clist_writer * cldev, gx_clist_state * pcls, uint size)
+{
+ if_debug3('L', "[L]band %d: size=%u, left=%u",
+ (int)(pcls - cldev->states),
+ size, (uint) (cldev->cend - cldev->cnext));
+ return cmd_put_list_op(cldev, &pcls->list, size);
+}
+#endif
+
+/* Add a command for a range of bands. */
+byte *
+cmd_put_range_op(gx_device_clist_writer * cldev, int band_min, int band_max,
+ uint size)
+{
+ if_debug4('L', "[L]band range(%d,%d): size=%u, left=%u",
+ band_min, band_max, size,
+ (uint)(cldev->cend - cldev->cnext));
+ if (cldev->ccl != 0 &&
+ (cldev->ccl != &cldev->band_range_list ||
+ band_min != cldev->band_range_min ||
+ band_max != cldev->band_range_max)
+ ) {
+ if ((cldev->error_code = cmd_write_buffer(cldev, cmd_opv_end_run)) != 0) {
+ if (cldev->error_code < 0)
+ cldev->error_is_retryable = 0; /* hard error */
+ else {
+ /* upgrade lo-mem warning into an error */
+ cldev->error_code = gs_error_VMerror;
+ cldev->error_is_retryable = 1;
+ }
+ return 0;
+ }
+ cldev->band_range_min = band_min;
+ cldev->band_range_max = band_max;
+ }
+ return cmd_put_list_op(cldev, &cldev->band_range_list, size);
+}
+
+/* Write a variable-size positive integer. */
+int
+cmd_size_w(register uint w)
+{
+ register int size = 1;
+
+ while (w > 0x7f)
+ w >>= 7, size++;
+ return size;
+}
+byte *
+cmd_put_w(register uint w, register byte * dp)
+{
+ while (w > 0x7f)
+ *dp++ = w | 0x80, w >>= 7;
+ *dp = w;
+ return dp + 1;
+}
+
+/* Define the encodings of the different settable colors. */
+const clist_select_color_t
+ clist_select_color0 = {cmd_op_set_color0, cmd_opv_delta2_color0, 0},
+ clist_select_color1 = {cmd_op_set_color1, cmd_opv_delta2_color1, 0},
+ clist_select_tile_color0 = {cmd_op_set_color0, cmd_opv_delta2_color0, 1},
+ clist_select_tile_color1 = {cmd_op_set_color1, cmd_opv_delta2_color1, 1};
+int
+cmd_put_color(gx_device_clist_writer * cldev, gx_clist_state * pcls,
+ const clist_select_color_t * select,
+ gx_color_index color, gx_color_index * pcolor)
+{
+ byte *dp;
+ long diff = (long)color - (long)(*pcolor);
+ byte op, op_delta2;
+ int code;
+
+ if (diff == 0)
+ return 0;
+ if (select->tile_color) {
+ code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_tile_color, 1);
+ if (code < 0)
+ return code;
+ }
+ op = select->set_op;
+ op_delta2 = select->delta2_op;
+ if (color == gx_no_color_index) {
+ /*
+ * We must handle this specially, because it may take more
+ * bytes than the color depth.
+ */
+ code = set_cmd_put_op(dp, cldev, pcls, op + 15, 1);
+ if (code < 0)
+ return code;
+ } else {
+ long delta;
+ byte operand;
+
+ switch ((cldev->color_info.depth + 15) >> 3) {
+ case 5:
+ if (!((delta = diff + cmd_delta1_32_bias) &
+ ~cmd_delta1_32_mask) &&
+ (operand =
+ (byte) ((delta >> 23) + ((delta >> 18) & 1))) != 0 &&
+ operand != 15
+ ) {
+ code = set_cmd_put_op(dp, cldev, pcls,
+ (byte) (op + operand), 2);
+ if (code < 0)
+ return code;
+ dp[1] = (byte) (((delta >> 10) & 0300) +
+ (delta >> 5) + delta);
+ break;
+ }
+ if (!((delta = diff + cmd_delta2_32_bias) &
+ ~cmd_delta2_32_mask)
+ ) {
+ code = set_cmd_put_op(dp, cldev, pcls, op_delta2, 3);
+ if (code < 0)
+ return code;
+ dp[1] = (byte) ((delta >> 20) + (delta >> 16));
+ dp[2] = (byte) ((delta >> 4) + delta);
+ break;
+ }
+ code = set_cmd_put_op(dp, cldev, pcls, op, 5);
+ if (code < 0)
+ return code;
+ *++dp = (byte) (color >> 24);
+ goto b3;
+ case 4:
+ if (!((delta = diff + cmd_delta1_24_bias) &
+ ~cmd_delta1_24_mask) &&
+ (operand = (byte) (delta >> 16)) != 0 &&
+ operand != 15
+ ) {
+ code = set_cmd_put_op(dp, cldev, pcls,
+ (byte) (op + operand), 2);
+ if (code < 0)
+ return code;
+ dp[1] = (byte) ((delta >> 4) + delta);
+ break;
+ }
+ if (!((delta = diff + cmd_delta2_24_bias) &
+ ~cmd_delta2_24_mask)
+ ) {
+ code = set_cmd_put_op(dp, cldev, pcls, op_delta2, 3);
+ if (code < 0)
+ return code;
+ dp[1] = ((byte) (delta >> 13) & 0xf8) +
+ ((byte) (delta >> 11) & 7);
+ dp[2] = (byte) (((delta >> 3) & 0xe0) + delta);
+ break;
+ }
+ code = set_cmd_put_op(dp, cldev, pcls, op, 4);
+ if (code < 0)
+ return code;
+b3: *++dp = (byte) (color >> 16);
+ goto b2;
+ case 3:
+ code = set_cmd_put_op(dp, cldev, pcls, op, 3);
+ if (code < 0)
+ return code;
+b2: *++dp = (byte) (color >> 8);
+ goto b1;
+ case 2:
+ if (diff >= -7 && diff < 7) {
+ code = set_cmd_put_op(dp, cldev, pcls,
+ op + (int)diff + 8, 1);
+ if (code < 0)
+ return code;
+ break;
+ }
+ code = set_cmd_put_op(dp, cldev, pcls, op, 2);
+ if (code < 0)
+ return code;
+b1: dp[1] = (byte) color;
+ }
+ }
+ *pcolor = color;
+ return 0;
+}
+
+/* Put out a command to set the tile colors. */
+int
+cmd_set_tile_colors(gx_device_clist_writer * cldev, gx_clist_state * pcls,
+ gx_color_index color0, gx_color_index color1)
+{
+ int code = 0;
+
+ if (color0 != pcls->tile_colors[0]) {
+ code = cmd_put_color(cldev, pcls,
+ &clist_select_tile_color0,
+ color0, &pcls->tile_colors[0]);
+ if (code != 0)
+ return code;
+ }
+ if (color1 != pcls->tile_colors[1])
+ code = cmd_put_color(cldev, pcls,
+ &clist_select_tile_color1,
+ color1, &pcls->tile_colors[1]);
+ return code;
+}
+
+/* Put out a command to set the tile phase. */
+int
+cmd_set_tile_phase(gx_device_clist_writer * cldev, gx_clist_state * pcls,
+ int px, int py)
+{
+ int pcsize;
+ byte *dp;
+ int code;
+
+ pcsize = 1 + cmd_size2w(px, py);
+ code =
+ set_cmd_put_op(dp, cldev, pcls, (byte)cmd_opv_set_tile_phase, pcsize);
+ if (code < 0)
+ return code;
+ ++dp;
+ cmd_putxy(pcls->tile_phase, dp);
+ pcls->tile_phase.x = px;
+ pcls->tile_phase.y = py;
+ return 0;
+}
+
+/* Write a command to enable or disable the logical operation. */
+int
+cmd_put_enable_lop(gx_device_clist_writer * cldev, gx_clist_state * pcls,
+ int enable)
+{
+ byte *dp;
+ int code = set_cmd_put_op(dp, cldev, pcls,
+ (byte)(enable ? cmd_opv_enable_lop :
+ cmd_opv_disable_lop),
+ 1);
+
+ if (code < 0)
+ return code;
+ pcls->lop_enabled = enable;
+ return 0;
+}
+
+/* Write a command to enable or disable clipping. */
+/* This routine is only called if the path extensions are included. */
+int
+cmd_put_enable_clip(gx_device_clist_writer * cldev, gx_clist_state * pcls,
+ int enable)
+{
+ byte *dp;
+ int code = set_cmd_put_op(dp, cldev, pcls,
+ (byte)(enable ? cmd_opv_enable_clip :
+ cmd_opv_disable_clip),
+ 1);
+
+ if (code < 0)
+ return code;
+ pcls->clip_enabled = enable;
+ return 0;
+}
+
+/* Write a command to set the logical operation. */
+int
+cmd_set_lop(gx_device_clist_writer * cldev, gx_clist_state * pcls,
+ gs_logical_operation_t lop)
+{
+ byte *dp;
+ uint lop_msb = lop >> 6;
+ int code = set_cmd_put_op(dp, cldev, pcls,
+ cmd_opv_set_misc, 2 + cmd_size_w(lop_msb));
+
+ if (code < 0)
+ return code;
+ dp[1] = cmd_set_misc_lop + (lop & 0x3f);
+ cmd_put_w(lop_msb, dp + 2);
+ pcls->lop = lop;
+ return 0;
+}
+
+/* Disable (if default) or enable the logical operation, setting it if */
+/* needed. */
+int
+cmd_update_lop(gx_device_clist_writer *cldev, gx_clist_state *pcls,
+ gs_logical_operation_t lop)
+{
+ int code;
+
+ if (lop == lop_default)
+ return cmd_disable_lop(cldev, pcls);
+ code = cmd_set_lop(cldev, pcls, lop);
+ if (code < 0)
+ return code;
+ return cmd_enable_lop(cldev, pcls);
+}
+
+/* Write a parameter list */
+int /* ret 0 all ok, -ve error */
+cmd_put_params(gx_device_clist_writer *cldev,
+ gs_param_list *param_list) /* NB open for READ */
+{
+ byte *dp;
+ int code;
+ byte local_buf[512]; /* arbitrary */
+ int param_length;
+
+ /* Get serialized list's length + try to get it into local var if it fits. */
+ param_length = code =
+ gs_param_list_serialize(param_list, local_buf, sizeof(local_buf));
+ if (param_length > 0) {
+ /* Get cmd buffer space for serialized */
+ code = set_cmd_put_all_op(dp, cldev, cmd_opv_put_params,
+ 1 + sizeof(unsigned) + param_length);
+ if (code < 0)
+ return code;
+
+ /* write param list to cmd list: needs to all fit in cmd buffer */
+ if_debug1('l', "[l]put_params, length=%d\n", param_length);
+ ++dp;
+ memcpy(dp, &param_length, sizeof(unsigned));
+ dp += sizeof(unsigned);
+ if (param_length > sizeof(local_buf)) {
+ int old_param_length = param_length;
+
+ param_length = code =
+ gs_param_list_serialize(param_list, dp, old_param_length);
+ if (param_length >= 0)
+ code = (old_param_length != param_length ?
+ gs_note_error(gs_error_unknownerror) : 0);
+ if (code < 0) {
+ /* error serializing: back out by writing a 0-length parm list */
+ memset(dp - sizeof(unsigned), 0, sizeof(unsigned));
+ cmd_shorten_list_op(cldev, &cldev->band_range_list,
+ old_param_length);
+ }
+ } else
+ memcpy(dp, local_buf, param_length); /* did this when computing length */
+ }
+ return code;
+}
diff --git a/gs/src/gxcomp.h b/gs/src/gxcomp.h
new file mode 100644
index 000000000..5c6151204
--- /dev/null
+++ b/gs/src/gxcomp.h
@@ -0,0 +1,107 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gxcomp.h */
+/* Definitions for implementing compositing functions */
+
+#ifndef gxcomp_INCLUDED
+# define gxcomp_INCLUDED
+
+#include "gscompt.h"
+#include "gsrefct.h"
+#include "gxbitfmt.h"
+
+/*
+ * Define the abstract superclass for all compositing function types.
+ */
+ /*typedef struct gs_composite_s gs_composite_t; *//* in gscompt.h */
+
+#ifndef gs_imager_state_DEFINED
+# define gs_imager_state_DEFINED
+typedef struct gs_imager_state_s gs_imager_state;
+
+#endif
+
+#ifndef gx_device_DEFINED
+# define gx_device_DEFINED
+typedef struct gx_device_s gx_device;
+
+#endif
+
+typedef struct gs_composite_type_procs_s {
+
+ /*
+ * Create the default compositor for a compositing function.
+ */
+#define composite_create_default_compositor_proc(proc)\
+ int proc(P5(const gs_composite_t *pcte, gx_device **pcdev,\
+ gx_device *dev, const gs_imager_state *pis, gs_memory_t *mem))
+ composite_create_default_compositor_proc((*create_default_compositor));
+
+ /*
+ * Test whether this function is equal to another one.
+ */
+#define composite_equal_proc(proc)\
+ bool proc(P2(const gs_composite_t *pcte, const gs_composite_t *pcte2))
+ composite_equal_proc((*equal));
+
+ /*
+ * Convert the representation of this function to a string
+ * for writing in a command list. *psize is the amount of space
+ * available. If it is large enough, the procedure sets *psize
+ * to the amount used and returns 0; if it is not large enough,
+ * the procedure sets *psize to the amount needed and returns a
+ * rangecheck error; in the case of any other error, *psize is
+ * not changed.
+ */
+#define composite_write_proc(proc)\
+ int proc(P3(const gs_composite_t *pcte, byte *data, uint *psize))
+ composite_write_proc((*write));
+
+ /*
+ * Convert the string representation of a function back to
+ * a structure, allocating the structure.
+ */
+#define composite_read_proc(proc)\
+ int proc(P4(gs_composite_t **ppcte, const byte *data, uint size,\
+ gs_memory_t *mem))
+ composite_read_proc((*read));
+
+} gs_composite_type_procs_t;
+typedef struct gs_composite_type_s {
+ gs_composite_type_procs_t procs;
+} gs_composite_type_t;
+
+/*
+ * Compositing objects are reference-counted, because graphics states will
+ * eventually reference them. Note that the common part has no
+ * garbage-collectible pointers and is never actually instantiated, so no
+ * structure type is needed for it.
+ */
+#define gs_composite_common\
+ const gs_composite_type_t *type;\
+ gs_id id; /* see gscompt.h */\
+ rc_header rc
+struct gs_composite_s {
+ gs_composite_common;
+};
+
+/* Replace a procedure with a macro. */
+#define gs_composite_id(pcte) ((pcte)->id)
+
+#endif /* gxcomp_INCLUDED */
diff --git a/gs/src/gxgetbit.h b/gs/src/gxgetbit.h
new file mode 100644
index 000000000..4ba26d6ba
--- /dev/null
+++ b/gs/src/gxgetbit.h
@@ -0,0 +1,95 @@
+/* Copyright (C) 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gxgetbit.h */
+/* Interface for get_bits_rectangle driver procedure */
+
+#ifndef gxgetbit_INCLUDED
+# define gxgetbit_INCLUDED
+
+#include "gxbitfmt.h"
+
+/* The parameter record typedef is also in gxdevcli.h. */
+#ifndef gs_get_bits_params_DEFINED
+# define gs_get_bits_params_DEFINED
+typedef struct gs_get_bits_params_s gs_get_bits_params_t;
+#endif
+
+/*
+ * We define the options for get_bits_rectangle here in a separate file
+ * so that the great majority of driver implementors and clients, which
+ * don't care about the details, don't need to be recompiled if the set
+ * of options changes.
+ */
+typedef gx_bitmap_format_t gs_get_bits_options_t;
+
+/*
+ * Define the parameter record passed to get_bits_rectangle.
+ * get_bits_rectangle may update members of this structure if
+ * the options allow it to choose their values, and always updates options
+ * to indicate what options were actually used (1 option per group).
+ */
+struct gs_get_bits_params_s {
+ gs_get_bits_options_t options;
+ byte *data[32];
+ int x_offset; /* in returned data */
+ uint raster;
+};
+
+/*
+ * gx_bitmap_format_t defines the options passed to get_bits_rectangle,
+ * which indicate which formats are acceptable for the returned data. If
+ * successful, get_bits_rectangle sets the options member of the parameter
+ * record to indicate what options were chosen -- 1 per group, and never the
+ * _ANY option. Note that the chosen option is not necessarily one that
+ * appeared in the original options: for example, if GB_RASTER_ANY is the
+ * only raster option originally set, the chosen option will be
+ * GB_RASTER_STANDARD or GB_RASTER_SPECIFIED.
+ *
+ * If the options mask is 0, get_bits_rectangle must set it to the
+ * complete set of supported options and return an error. This allows
+ * clients to determine what options are supported without actually doing
+ * a transfer.
+ *
+ * All devices must support at least one option in each group, and must
+ * support GB_COLORS_NATIVE.
+ *
+ * NOTE: the current default implementation supports only the following
+ * options in their respective groups (i.e., any other options must be
+ * supported directly by the device):
+ * GB_DEPTH_8
+ * GB_PACKING_CHUNKY
+ * GB_RETURN_COPY
+ * The current default implementation also requires that all devices
+ * support GB_PACKING_CHUNKY. */
+
+/* ---------------- Procedures ---------------- */
+
+/* Try to implement get_bits_rectangle by returning a pointer. */
+int gx_get_bits_return_pointer(P6(gx_device * dev, int x, int h,
+ gs_get_bits_params_t * params,
+ gs_get_bits_options_t stored,
+ byte * stored_base));
+
+/* Implement get_bits_rectangle by copying. */
+int gx_get_bits_copy(P8(gx_device * dev, int x, int w, int h,
+ gs_get_bits_params_t * params,
+ gs_get_bits_options_t stored,
+ const byte * src_base, uint dev_raster));
+
+#endif /* gxgetbit_INCLUDED */
diff --git a/gs/src/gxi12bit.c b/gs/src/gxi12bit.c
new file mode 100644
index 000000000..55303d6be
--- /dev/null
+++ b/gs/src/gxi12bit.c
@@ -0,0 +1,294 @@
+/* Copyright (C) 1994, 1995, 1996, 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gxi12bit.c */
+/* 12-bit image procedures */
+#include "gx.h"
+#include "memory_.h"
+#include "gpcheck.h"
+#include "gserrors.h"
+#include "gxfixed.h"
+#include "gxfrac.h"
+#include "gxarith.h"
+#include "gxmatrix.h"
+#include "gsccolor.h"
+#include "gspaint.h"
+#include "gxdevice.h"
+#include "gxcmap.h"
+#include "gxdcolor.h"
+#include "gxistate.h"
+#include "gzpath.h"
+#include "gxdevmem.h"
+#include "gxcpath.h"
+#include "gximage.h"
+
+/* ---------------- Unpacking procedures ---------------- */
+
+private const byte *
+sample_unpack_12(byte * bptr, int *pdata_x, const byte * data,
+ int data_x, uint dsize, const sample_lookup_t * ignore_ptab,
+ int spread)
+{
+ register frac *bufp = (frac *) bptr;
+ uint dskip = (data_x >> 1) * 3;
+ const byte *psrc = data + dskip;
+#define inc_bufp(bp, n) bp = (frac *)((byte *)(bp) + (n))
+ uint sample;
+ int left = dsize - dskip;
+
+ if ((data_x & 1) && left > 0)
+ switch (left) {
+ default:
+ sample = ((uint) (psrc[1] & 0xf) << 8) + psrc[2];
+ *bufp = bits2frac(sample, 12);
+ inc_bufp(bufp, spread);
+ psrc += 3;
+ left -= 3;
+ break;
+ case 2: /* xxxxxxxx xxxxdddd */
+ *bufp = (psrc[1] & 0xf) * (frac_1 / 15);
+ case 1: /* xxxxxxxx */
+ left = 0;
+ }
+ while (left >= 3) {
+ sample = ((uint) * psrc << 4) + (psrc[1] >> 4);
+ *bufp = bits2frac(sample, 12);
+ inc_bufp(bufp, spread);
+ sample = ((uint) (psrc[1] & 0xf) << 8) + psrc[2];
+ *bufp = bits2frac(sample, 12);
+ inc_bufp(bufp, spread);
+ psrc += 3;
+ left -= 3;
+ }
+ /* Handle trailing bytes. */
+ switch (left) {
+ case 2: /* dddddddd ddddxxxx */
+ sample = ((uint) * psrc << 4) + (psrc[1] >> 4);
+ *bufp = bits2frac(sample, 12);
+ inc_bufp(bufp, spread);
+ *bufp = (psrc[1] & 0xf) * (frac_1 / 15);
+ break;
+ case 1: /* dddddddd */
+ sample = (uint) * psrc << 4;
+ *bufp = bits2frac(sample, 12);
+ break;
+ case 0: /* Nothing more to do. */
+ ;
+ }
+ *pdata_x = 0;
+ return bptr;
+}
+
+/* ------ Strategy procedure ------ */
+
+/* Use special (slow) logic for 12-bit source values. */
+private irender_proc(image_render_frac);
+private irender_proc_t
+image_strategy_frac(gx_image_enum * penum)
+{
+ if (penum->bps > 8) {
+ if_debug0('b', "[b]render=frac\n");
+ return image_render_frac;
+ }
+ return 0;
+}
+
+void
+gs_gxi12bit_init(gs_memory_t * mem)
+{
+ image_strategies.fracs = image_strategy_frac;
+ sample_unpack_12_proc = sample_unpack_12;
+}
+
+/* ---------------- Rendering procedures ---------------- */
+
+/* ------ Rendering for 12-bit samples ------ */
+
+/* Render an image with more than 8 bits per sample. */
+/* The samples have been expanded into fracs. */
+#define longs_per_4_fracs (arch_sizeof_frac * 4 / arch_sizeof_long)
+typedef union {
+ frac v[4];
+ long all[longs_per_4_fracs]; /* for fast comparison */
+} color_fracs;
+
+#if longs_per_4_fracs == 1
+# define color_frac_eq(f1, f2)\
+ ((f1).all[0] == (f2).all[0])
+#else
+#if longs_per_4_fracs == 2
+# define color_frac_eq(f1, f2)\
+ ((f1).all[0] == (f2).all[0] && (f1).all[1] == (f2).all[1])
+#endif
+#endif
+private int
+image_render_frac(gx_image_enum * penum, const byte * buffer, int data_x,
+ uint w, int h, gx_device * dev)
+{
+ const gs_imager_state *pis = penum->pis;
+ gs_logical_operation_t lop = penum->log_op;
+ gx_dda_fixed_point pnext;
+ image_posture posture = penum->posture;
+ fixed xl, ytf;
+ fixed pdyx, pdyy; /* edge of parallelogram */
+ int yt = penum->yci, iht = penum->hci;
+ const gs_color_space *pcs = penum->pcs;
+ cs_proc_remap_color((*remap_color)) = pcs->type->remap_color;
+ gs_client_color cc;
+ int device_color = penum->device_color;
+ const gx_color_map_procs *cmap_procs = gx_device_cmap_procs(dev);
+ cmap_proc_rgb((*map_rgb)) = cmap_procs->map_rgb;
+ cmap_proc_cmyk((*map_cmyk)) = cmap_procs->map_cmyk;
+ gx_device_color devc1, devc2;
+ gx_device_color *pdevc = &devc1;
+ gx_device_color *pdevc_next = &devc2;
+ int spp = penum->spp;
+ const frac *psrc = (const frac *)buffer + data_x * spp;
+ fixed xrun; /* x at start of run */
+ int irun; /* int xrun */
+ fixed yrun; /* y ditto */
+ color_fracs run; /* run value */
+ color_fracs next; /* next sample value */
+ const frac *bufend = psrc + w;
+ int code;
+
+ if (h == 0)
+ return 0;
+ pnext = penum->dda.pixel0;
+ xrun = xl = dda_current(pnext.x);
+ irun = fixed2int_var_rounded(xrun);
+ yrun = ytf = dda_current(pnext.y);
+ pdyx = dda_current(penum->dda.row.x) - penum->cur.x;
+ pdyy = dda_current(penum->dda.row.y) - penum->cur.y;
+ if_debug4('b', "[b]y=%d w=%d xt=%f yt=%f\n",
+ penum->y, w, fixed2float(xl), fixed2float(ytf));
+ run.v[0] = run.v[1] = run.v[2] = run.v[3] = 0;
+ next.v[0] = next.v[1] = next.v[2] = next.v[3] = 0;
+ cc.paint.values[0] = cc.paint.values[1] =
+ cc.paint.values[2] = cc.paint.values[3] = 0;
+ cc.pattern = 0;
+ (*remap_color) (&cc, pcs, pdevc, pis, dev, gs_color_select_source);
+ run.v[0] = ~psrc[0]; /* force remap */
+
+ while (psrc < bufend) {
+ next.v[0] = psrc[0];
+ switch (spp) {
+ case 4: /* cmyk */
+ next.v[1] = psrc[1];
+ next.v[2] = psrc[2];
+ next.v[3] = psrc[3];
+ psrc += 4;
+ if (color_frac_eq(next, run))
+ goto inc;
+ if (device_color) {
+ (*map_cmyk) (next.v[0], next.v[1],
+ next.v[2], next.v[3],
+ pdevc_next, pis, dev,
+ gs_color_select_source);
+ goto f;
+ }
+ decode_frac(next.v[0], cc, 0);
+ decode_frac(next.v[1], cc, 1);
+ decode_frac(next.v[2], cc, 2);
+ decode_frac(next.v[3], cc, 3);
+ if_debug4('B', "[B]cc[0..3]=%g,%g,%g,%g\n",
+ cc.paint.values[0], cc.paint.values[1],
+ cc.paint.values[2], cc.paint.values[3]);
+ if_debug1('B', "[B]cc[3]=%g\n",
+ cc.paint.values[3]);
+ break;
+ case 3: /* rgb */
+ next.v[1] = psrc[1];
+ next.v[2] = psrc[2];
+ psrc += 3;
+ if (color_frac_eq(next, run))
+ goto inc;
+ if (device_color) {
+ (*map_rgb) (next.v[0], next.v[1],
+ next.v[2], pdevc_next, pis, dev,
+ gs_color_select_source);
+ goto f;
+ }
+ decode_frac(next.v[0], cc, 0);
+ decode_frac(next.v[1], cc, 1);
+ decode_frac(next.v[2], cc, 2);
+ if_debug3('B', "[B]cc[0..2]=%g,%g,%g\n",
+ cc.paint.values[0], cc.paint.values[1],
+ cc.paint.values[2]);
+ break;
+ case 1: /* gray */
+ psrc++;
+ if (next.v[0] == run.v[0])
+ goto inc;
+ if (device_color) {
+ (*map_rgb) (next.v[0], next.v[0],
+ next.v[0], pdevc_next, pis, dev,
+ gs_color_select_source);
+ goto f;
+ }
+ decode_frac(next.v[0], cc, 0);
+ if_debug1('B', "[B]cc[0]=%g\n",
+ cc.paint.values[0]);
+ break;
+ }
+ (*remap_color) (&cc, pcs, pdevc_next, pis, dev,
+ gs_color_select_source);
+f:
+ if_debug7('B', "[B]0x%x,0x%x,0x%x,0x%x -> %ld,%ld,0x%lx\n",
+ next.v[0], next.v[1], next.v[2], next.v[3],
+ pdevc_next->colors.binary.color[0],
+ pdevc_next->colors.binary.color[1],
+ (ulong) pdevc_next->type);
+ /* Even though the supplied colors don't match, */
+ /* the device colors might. */
+ if (!dev_color_eq(devc1, devc2)) {
+ /* Fill the region between xrun/irun and xl */
+ gx_device_color *ptemp;
+
+ if (posture != image_portrait) { /* Parallelogram */
+ code = (*dev_proc(dev, fill_parallelogram))
+ (dev, xrun, yrun,
+ xl - xrun, ytf - yrun, pdyx, pdyy,
+ pdevc, lop);
+ } else { /* Rectangle */
+ int xi = irun;
+ int wi = (irun = fixed2int_var_rounded(xl)) - xi;
+
+ if (wi < 0)
+ xi += wi, wi = -wi;
+ code = gx_fill_rectangle_device_rop(xi, yt,
+ wi, iht, pdevc, dev, lop);
+ }
+ if (code < 0)
+ return code;
+ ptemp = pdevc;
+ pdevc = pdevc_next;
+ pdevc_next = ptemp;
+ xrun = xl;
+ yrun = ytf;
+ }
+ run = next;
+inc:
+ xl = dda_next(pnext.x);
+ ytf = dda_next(pnext.y);
+ }
+ /* Fill the final run. */
+ code = (*dev_proc(dev, fill_parallelogram))
+ (dev, xrun, yrun, xl - xrun, ytf - yrun, pdyx, pdyy, pdevc, lop);
+ return (code < 0 ? code : 1);
+}
diff --git a/gs/src/gxicolor.c b/gs/src/gxicolor.c
new file mode 100644
index 000000000..e4e16a77e
--- /dev/null
+++ b/gs/src/gxicolor.c
@@ -0,0 +1,312 @@
+/* Copyright (C) 1992, 1995, 1996, 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gxicolor.c */
+/* Color image rendering */
+#include "gx.h"
+#include "memory_.h"
+#include "gpcheck.h"
+#include "gserrors.h"
+#include "gxfixed.h"
+#include "gxfrac.h"
+#include "gxarith.h"
+#include "gxmatrix.h"
+#include "gsccolor.h"
+#include "gspaint.h"
+#include "gzstate.h"
+#include "gxdevice.h"
+#include "gxcmap.h"
+#include "gxdcconv.h"
+#include "gxdcolor.h"
+#include "gxistate.h"
+#include "gzpath.h"
+#include "gxdevmem.h"
+#include "gxcpath.h"
+#include "gximage.h"
+
+/* ------ Strategy procedure ------ */
+
+private irender_proc(image_render_color);
+private irender_proc_t
+image_strategy_color(gx_image_enum * penum)
+{
+ return image_render_color;
+}
+
+void
+gs_gxicolor_init(gs_memory_t * mem)
+{
+ image_strategies.color = image_strategy_color;
+}
+
+/* ------ Rendering procedures ------ */
+
+/* Render a color image with 8 or fewer bits per sample. */
+typedef union {
+ byte v[4];
+ bits32 all; /* for fast comparison & clearing */
+} color_samples;
+private int
+image_render_color(gx_image_enum * penum, const byte * buffer, int data_x,
+ uint w, int h, gx_device * dev)
+{
+ const gs_imager_state *pis = penum->pis;
+ gs_logical_operation_t lop = penum->log_op;
+ gx_dda_fixed_point pnext;
+ image_posture posture = penum->posture;
+ fixed xl, ytf;
+ fixed pdyx, pdyy; /* edge of parallelogram */
+ int vci, vdi;
+ const gs_color_space *pcs = penum->pcs;
+ cs_proc_remap_color((*remap_color)) = pcs->type->remap_color;
+ gs_client_color cc;
+ bool device_color = penum->device_color;
+ const gx_color_map_procs *cmap_procs = gx_device_cmap_procs(dev);
+ cmap_proc_rgb((*map_3)) = cmap_procs->map_rgb;
+ cmap_proc_cmyk((*map_4)) =
+ (penum->alpha ? cmap_procs->map_rgb_alpha : cmap_procs->map_cmyk);
+ gx_image_clue *pic = &penum->clues[0];
+#define pdevc (&pic->dev_color)
+ gx_image_clue *pic_next = &penum->clues[1];
+#define pdevc_next (&pic_next->dev_color)
+ gx_image_clue empty_clue;
+ gx_image_clue clue_temp;
+ int spp = penum->spp;
+ const byte *psrc = buffer + data_x * spp;
+ fixed xrun; /* x at start of run */
+ fixed yrun; /* y ditto */
+ int irun; /* int x/rrun */
+ color_samples run; /* run value */
+ color_samples next; /* next sample value */
+ bool small =
+ fixed2int(any_abs(penum->x_extent.x)) < penum->rect.w &&
+ fixed2int(any_abs(penum->x_extent.y)) < penum->rect.w;
+ const byte *bufend = psrc + w;
+ bool use_cache = spp * penum->bps <= 12;
+ int code;
+
+ if (h == 0)
+ return 0;
+ pnext = penum->dda.pixel0;
+ xrun = xl = dda_current(pnext.x);
+ yrun = ytf = dda_current(pnext.y);
+ pdyx = dda_current(penum->dda.row.x) - penum->cur.x;
+ pdyy = dda_current(penum->dda.row.y) - penum->cur.y;
+ switch (posture) {
+ case image_portrait:
+ vci = penum->yci, vdi = penum->hci;
+ irun = fixed2int_var_rounded(xrun);
+ break;
+ case image_landscape:
+ vci = penum->xci, vdi = penum->wci;
+ irun = fixed2int_var_rounded(yrun);
+ break;
+ }
+
+ if_debug4('b', "[b]y=%d w=%d xt=%f yt=%f\n",
+ penum->y, w, fixed2float(xl), fixed2float(ytf));
+ run.all = 0;
+ next.all = 0;
+ /* Ensure that we don't get any false dev_color_eq hits. */
+ if (use_cache) {
+ color_set_pure(&empty_clue.dev_color, gx_no_color_index);
+ pic = &empty_clue;
+ }
+ cc.paint.values[0] = cc.paint.values[1] =
+ cc.paint.values[2] = cc.paint.values[3] = 0;
+ cc.pattern = 0;
+ run.v[0] = ~psrc[0]; /* force remap */
+ while (psrc < bufend) {
+ dda_next(pnext.x);
+#define xn dda_current(pnext.x)
+ dda_next(pnext.y);
+#define yn dda_current(pnext.y)
+#define includes_pixel_center(a, b)\
+ (fixed_floor(a < b ? (a - (fixed_half + fixed_epsilon)) ^ (b - fixed_half) :\
+ (b - (fixed_half + fixed_epsilon)) ^ (a - fixed_half)) != 0)
+#define paint_no_pixels()\
+ (small && !includes_pixel_center(xl, xn) &&\
+ !includes_pixel_center(ytf, yn) && psrc <= bufend)
+#define clue_hash3(next)\
+ &penum->clues[(next.v[0] + (next.v[1] << 2) + (next.v[2] << 4)) & 255];
+#define clue_hash4(next)\
+ &penum->clues[(next.v[0] + (next.v[1] << 2) + (next.v[2] << 4) +\
+ (next.v[3] << 6)) & 255]
+
+ if (spp == 4) { /* cmyk or rgba */
+ next.v[0] = psrc[0];
+ next.v[1] = psrc[1];
+ next.v[2] = psrc[2];
+ next.v[3] = psrc[3];
+ psrc += 4;
+map4: if (next.all == run.all || paint_no_pixels())
+ goto inc;
+ if (use_cache) {
+ pic_next = clue_hash4(next);
+ if (pic_next->key == next.all)
+ goto f;
+ /*
+ * If we are really unlucky, pic_next == pic,
+ * so mapping this color would clobber the one
+ * we're about to use for filling the run.
+ */
+ if (pic_next == pic) {
+ clue_temp = *pic;
+ pic = &clue_temp;
+ }
+ pic_next->key = next.all;
+ }
+ if (device_color) {
+ (*map_4)(byte2frac(next.v[0]), byte2frac(next.v[1]),
+ byte2frac(next.v[2]), byte2frac(next.v[3]),
+ pdevc_next, pis, dev,
+ gs_color_select_source);
+ goto mapped;
+ }
+ decode_sample(next.v[3], cc, 3);
+ if_debug1('B', "[B]cc[3]=%g\n", cc.paint.values[3]);
+ } else if (spp == 3) { /* rgb */
+ next.v[0] = psrc[0];
+ next.v[1] = psrc[1];
+ next.v[2] = psrc[2];
+ psrc += 3;
+ if (next.all == run.all || paint_no_pixels())
+ goto inc;
+ if (use_cache) {
+ pic_next = clue_hash3(next);
+ if (pic_next->key == next.all)
+ goto f;
+ /* See above re the following check. */
+ if (pic_next == pic) {
+ clue_temp = *pic;
+ pic = &clue_temp;
+ }
+ pic_next->key = next.all;
+ }
+ if (device_color) {
+ (*map_3)(byte2frac(next.v[0]), byte2frac(next.v[1]),
+ byte2frac(next.v[2]),
+ pdevc_next, pis, dev,
+ gs_color_select_source);
+ goto mapped;
+ }
+ } else if (spp == 2) { /* gray+alpha */
+ next.v[2] = next.v[1] = next.v[0] = psrc[0];
+ next.v[3] = psrc[1];
+ psrc += 2;
+ goto map4;
+ } else { /* spp == 5, cmyk+alpha */
+ /* Convert CMYK to RGB. */
+ frac rgb[3];
+
+ color_cmyk_to_rgb(byte2frac(psrc[0]), byte2frac(psrc[1]),
+ byte2frac(psrc[2]), byte2frac(psrc[3]),
+ pis, rgb);
+ /*
+ * It seems silly to do all this converting between
+ * fracs and bytes, but that's what the current
+ * APIs require.
+ */
+ next.v[0] = frac2byte(rgb[0]);
+ next.v[1] = frac2byte(rgb[1]);
+ next.v[2] = frac2byte(rgb[2]);
+ next.v[3] = psrc[4];
+ psrc += 5;
+ goto map4;
+ }
+ decode_sample(next.v[0], cc, 0);
+ decode_sample(next.v[1], cc, 1);
+ decode_sample(next.v[2], cc, 2);
+ if_debug3('B', "[B]cc[0..2]=%g,%g,%g\n",
+ cc.paint.values[0], cc.paint.values[1],
+ cc.paint.values[2]);
+ (*remap_color) (&cc, pcs, pdevc_next, pis, dev,
+ gs_color_select_source);
+mapped: if (pic == pic_next)
+ goto fill;
+f: if_debug7('B', "[B]0x%x,0x%x,0x%x,0x%x -> %ld,%ld,0x%lx\n",
+ next.v[0], next.v[1], next.v[2], next.v[3],
+ pdevc_next->colors.binary.color[0],
+ pdevc_next->colors.binary.color[1],
+ (ulong) pdevc_next->type);
+ /* Even though the supplied colors don't match, */
+ /* the device colors might. */
+ if (dev_color_eq(*pdevc, *pdevc_next))
+ goto set;
+fill: { /* Fill the region between */
+ /* xrun/irun and xl */
+ switch (posture) {
+ case image_portrait:
+ { /* Rectangle */
+ int xi = irun;
+ int wi =
+ (irun = fixed2int_var_rounded(xl)) - xi;
+
+ if (wi < 0)
+ xi += wi, wi = -wi;
+ code =
+ gx_fill_rectangle_device_rop(xi, vci,
+ wi, vdi, pdevc, dev, lop);
+ xrun = xl; /* for sake of final run */
+ }
+ break;
+ case image_landscape:
+ { /* 90 degree rotated rectangle */
+ int yi = irun;
+ int hi =
+ (irun = fixed2int_var_rounded(ytf)) - yi;
+
+ if (hi < 0)
+ yi += hi, hi = -hi;
+ code = gx_fill_rectangle_device_rop(vci, yi,
+ vdi, hi, pdevc, dev, lop);
+ yrun = ytf; /* for sake of final run */
+ }
+ break;
+ default:
+ { /* Parallelogram */
+ code = (*dev_proc(dev, fill_parallelogram))
+ (dev, xrun, yrun,
+ xl - xrun, ytf - yrun, pdyx, pdyy,
+ pdevc, lop);
+ xrun = xl;
+ yrun = ytf;
+ }
+ }
+ if (code < 0)
+ return code;
+ if (use_cache)
+ pic = pic_next;
+ else {
+ gx_image_clue *ptemp = pic;
+
+ pic = pic_next;
+ pic_next = ptemp;
+ }
+ }
+set: run.all = next.all;
+inc: xl = xn;
+ ytf = yn; /* harmless if no skew */
+#undef xn
+#undef yn
+ }
+ /* Fill the last run. */
+ code = (*dev_proc(dev, fill_parallelogram))
+ (dev, xrun, yrun, xl - xrun, ytf - yrun, pdyx, pdyy, pdevc, lop);
+ return (code < 0 ? code : 1);
+}
diff --git a/gs/src/gxidata.c b/gs/src/gxidata.c
new file mode 100644
index 000000000..1d374552e
--- /dev/null
+++ b/gs/src/gxidata.c
@@ -0,0 +1,235 @@
+/* Copyright (C) 1995, 1996, 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gxidata.c */
+/* Generic image enumeration and cleanup */
+#include "gx.h"
+#include "memory_.h"
+#include "gserrors.h"
+#include "gxdevice.h"
+#include "gxcpath.h"
+#include "gximage.h"
+
+/* Process the next piece of an ImageType 1 image. */
+int
+gx_image1_plane_data(gx_device * dev,
+ gx_image_enum_common_t * info, const gx_image_plane_t * planes, int height)
+{
+ gx_image_enum *penum = (gx_image_enum *) info;
+ int y = penum->y;
+ int y_end = min(y + height, penum->rect.h);
+ int width_spp = penum->rect.w * penum->spp;
+ int num_planes = penum->num_planes;
+
+#define bcount(plane) /* bytes per data row */\
+ (((penum->rect.w + (plane).data_x) * penum->spp / num_planes * penum->bps\
+ + 7) >> 3)
+ fixed adjust = penum->adjust;
+ ulong offsets[gs_image_max_components];
+ int ignore_data_x;
+ int code;
+
+ if (height == 0)
+ return 0;
+
+ /* Set up the clipping and/or RasterOp device if needed. */
+
+ if (penum->clip_dev) {
+ gx_device_clip *cdev = penum->clip_dev;
+
+ cdev->target = dev;
+ dev = (gx_device *) cdev;
+ }
+ if (penum->rop_dev) {
+ gx_device_rop_texture *rtdev = penum->rop_dev;
+
+ ((gx_device_forward *) rtdev)->target = dev;
+ dev = (gx_device *) rtdev;
+ }
+ /* Now render complete rows. */
+
+ memset(offsets, 0, num_planes * sizeof(offsets[0]));
+ for (; penum->y < y_end; penum->y++) {
+ int px;
+
+ /*
+ * Normally, we unpack the data into the buffer, but if
+ * there is only one plane and we don't need to expand the
+ * input samples, we may use the data directly.
+ */
+ int sourcex = planes[0].data_x;
+ const byte *buffer =
+ (*penum->unpack) (penum->buffer, &sourcex,
+ planes[0].data + offsets[0],
+ planes[0].data_x, bcount(planes[0]),
+ &penum->map[0].table, penum->spread);
+
+ offsets[0] += planes[0].raster;
+ for (px = 1; px < num_planes; ++px) {
+ (*penum->unpack) (penum->buffer + (px << penum->log2_xbytes),
+ &ignore_data_x,
+ planes[px].data + offsets[px],
+ planes[px].data_x, bcount(planes[px]),
+ &penum->map[px].table, penum->spread);
+ offsets[px] += planes[px].raster;
+ }
+#ifdef DEBUG
+ if (gs_debug_c('B')) {
+ int i, n = width_spp;
+
+ dlputs("[B]row:");
+ for (i = 0; i < n; i++)
+ dprintf1(" %02x", buffer[i]);
+ dputs("\n");
+ }
+#endif
+ penum->cur.x = dda_current(penum->dda.row.x);
+ dda_next(penum->dda.row.x);
+ penum->cur.y = dda_current(penum->dda.row.y);
+ dda_next(penum->dda.row.y);
+ if (!penum->interpolate)
+ switch (penum->posture) {
+ case image_portrait:
+ { /* Precompute integer y and height, */
+ /* and check for clipping. */
+ fixed yc = penum->cur.y, yn = dda_current(penum->dda.row.y);
+
+ if (yn < yc) {
+ fixed temp = yn;
+
+ yn = yc;
+ yc = temp;
+ }
+ yc -= adjust;
+ if (yc >= penum->clip_outer.q.y)
+ goto mt;
+ yn += adjust;
+ if (yn <= penum->clip_outer.p.y)
+ goto mt;
+ penum->yci = fixed2int_pixround(yc);
+ penum->hci = fixed2int_pixround(yn) - penum->yci;
+ if (penum->hci == 0)
+ goto mt;
+ }
+ break;
+ case image_landscape:
+ { /* Check for no pixel centers in x. */
+ fixed xc = penum->cur.x, xn = dda_current(penum->dda.row.x);
+
+ if (xn < xc) {
+ fixed temp = xn;
+
+ xn = xc;
+ xc = temp;
+ }
+ xc -= adjust;
+ if (xc >= penum->clip_outer.q.x)
+ goto mt;
+ xn += adjust;
+ if (xn <= penum->clip_outer.p.x)
+ goto mt;
+ penum->xci = fixed2int_pixround(xc);
+ penum->wci = fixed2int_pixround(xn) - penum->xci;
+ if (penum->wci == 0)
+ goto mt;
+ }
+ break;
+ case image_skewed:
+ ;
+ }
+ dda_translate(penum->dda.pixel0.x,
+ penum->cur.x - penum->prev.x);
+ dda_translate(penum->dda.pixel0.y,
+ penum->cur.y - penum->prev.y);
+ penum->prev = penum->cur;
+ code = (*penum->render) (penum, buffer, sourcex, width_spp, 1,
+ dev);
+ if (code < 0)
+ goto err;
+ mt:;
+ }
+ if (penum->y < penum->rect.h) {
+ code = 0;
+ goto out;
+ }
+ /* End of data. Render any left-over buffered data. */
+ switch (penum->posture) {
+ case image_portrait:
+ {
+ fixed yc = dda_current(penum->dda.row.y);
+
+ penum->yci = fixed2int_rounded(yc - adjust);
+ penum->hci = fixed2int_rounded(yc + adjust) - penum->yci;
+ }
+ break;
+ case image_landscape:
+ {
+ fixed xc = dda_current(penum->dda.row.x);
+
+ penum->xci = fixed2int_rounded(xc - adjust);
+ penum->wci = fixed2int_rounded(xc + adjust) - penum->xci;
+ }
+ break;
+ case image_skewed: /* pacify compilers */
+ ;
+ }
+ dda_translate(penum->dda.pixel0.x, penum->cur.x - penum->prev.x);
+ dda_translate(penum->dda.pixel0.y, penum->cur.y - penum->prev.y);
+ code = (*penum->render) (penum, NULL, 0, width_spp, 0, dev);
+ if (code < 0) {
+ penum->y--;
+ goto err;
+ }
+ code = 1;
+ goto out;
+ err: /* Error or interrupt, restore original state. */
+ while (penum->y > y) {
+ dda_previous(penum->dda.row.x);
+ dda_previous(penum->dda.row.y);
+ --(penum->y);
+ }
+ /* Note that caller must call end_image */
+ /* for both error and normal termination. */
+ out:return code;
+}
+
+/* Clean up by releasing the buffers. */
+/* Currently we ignore draw_last. */
+int
+gx_image1_end_image(gx_device * dev, gx_image_enum_common_t * info,
+ bool draw_last)
+{
+ gx_image_enum *penum = (gx_image_enum *) info;
+ gs_memory_t *mem = penum->memory;
+ stream_IScale_state *scaler = penum->scaler;
+
+#ifdef DEBUG
+ if_debug2('b', "[b]%send_image, y=%d\n",
+ (penum->y < penum->rect.h ? "premature " : ""), penum->y);
+#endif
+ gs_free_object(mem, penum->rop_dev, "image RasterOp");
+ gs_free_object(mem, penum->clip_dev, "image clipper");
+ if (scaler != 0) {
+ (*s_IScale_template.release) ((stream_state *) scaler);
+ gs_free_object(mem, scaler, "image scaler state");
+ }
+ gs_free_object(mem, penum->line, "image line");
+ gs_free_object(mem, penum->buffer, "image buffer");
+ gs_free_object(mem, penum, "gx_default_end_image");
+ return 0;
+}
diff --git a/gs/src/gxifast.c b/gs/src/gxifast.c
new file mode 100644
index 000000000..685c54f19
--- /dev/null
+++ b/gs/src/gxifast.c
@@ -0,0 +1,699 @@
+/* Copyright (C) 1989, 1995, 1996, 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gxifast.c */
+/* Fast monochrome image rendering */
+#include "gx.h"
+#include "memory_.h"
+#include "gpcheck.h"
+#include "gsbittab.h"
+#include "gserrors.h"
+#include "gxfixed.h"
+#include "gxarith.h"
+#include "gxmatrix.h"
+#include "gsccolor.h"
+#include "gspaint.h"
+#include "gsutil.h"
+#include "gxdevice.h"
+#include "gxcmap.h"
+#include "gxdcolor.h"
+#include "gxistate.h"
+#include "gzpath.h"
+#include "gxdevmem.h"
+#include "gdevmem.h" /* for mem_mono_device */
+#include "gxcpath.h"
+#include "gximage.h"
+#include "gzht.h"
+
+/* Conditionally include statistics code. */
+#ifdef DEBUG
+# define STATS
+#endif
+
+/* ------ Strategy procedure ------ */
+
+/* Use special fast logic for portrait or landscape black-and-white images. */
+private irender_proc(image_render_simple);
+private irender_proc(image_render_landscape);
+private irender_proc_t
+image_strategy_simple(gx_image_enum * penum)
+{
+ irender_proc_t rproc;
+ fixed ox = dda_current(penum->dda.pixel0.x);
+ fixed oy = dda_current(penum->dda.pixel0.y);
+
+ if (penum->use_rop || penum->spp != 1 || penum->bps != 1)
+ return 0;
+ switch (penum->posture) {
+ case image_portrait:
+ { /* Use fast portrait algorithm. */
+ long dev_width =
+ fixed2long_pixround(ox + penum->x_extent.x) -
+ fixed2long_pixround(ox);
+
+ if (dev_width != penum->rect.w) { /* Add an extra align_bitmap_mod of padding so that */
+ /* we can align scaled rows with the device. */
+ long line_size =
+ bitmap_raster(any_abs(dev_width)) + align_bitmap_mod;
+
+ if (penum->adjust != 0 || line_size > max_uint)
+ return 0;
+ /* Must buffer a scan line. */
+ penum->line_width = any_abs(dev_width);
+ penum->line_size = (uint) line_size;
+ penum->line = gs_alloc_bytes(penum->memory,
+ penum->line_size, "image line");
+ if (penum->line == 0) {
+ gx_default_end_image(penum->dev,
+ (gx_image_enum_common_t *) penum,
+ false);
+ return 0;
+ }
+ }
+ if_debug2('b', "[b]render=simple, unpack=copy; rect.w=%d, dev_width=%ld\n",
+ penum->rect.w, dev_width);
+ rproc = image_render_simple;
+ break;
+ }
+ case image_landscape:
+ { /* Use fast landscape algorithm. */
+ long dev_width =
+ fixed2long_pixround(oy + penum->x_extent.y) -
+ fixed2long_pixround(oy);
+ long line_size =
+ (dev_width = any_abs(dev_width),
+ bitmap_raster(dev_width) * 8 +
+ round_up(dev_width, 8) * align_bitmap_mod);
+
+ if ((dev_width != penum->rect.w && penum->adjust != 0) ||
+ line_size > max_uint
+ )
+ return 0;
+ /* Must buffer a group of 8N scan lines. */
+ penum->line_width = dev_width;
+ penum->line_size = (uint) line_size;
+ penum->line = gs_alloc_bytes(penum->memory,
+ penum->line_size, "image line");
+ if (penum->line == 0) {
+ gx_default_end_image(penum->dev,
+ (gx_image_enum_common_t *) penum,
+ false);
+ return 0;
+ }
+ penum->xi_next = penum->line_xy = fixed2int_var_rounded(ox);
+ if_debug3('b', "[b]render=landscape, unpack=copy; rect.w=%d, dev_width=%ld, line_size=%ld\n",
+ penum->rect.w, dev_width, line_size);
+ rproc = image_render_landscape;
+ /* Precompute values needed for rasterizing. */
+ penum->dxy =
+ float2fixed(penum->matrix.xy + fixed2float(fixed_epsilon) / 2);
+ break;
+ }
+ default:
+ return 0;
+ }
+ /* Precompute values needed for rasterizing. */
+ penum->dxx =
+ float2fixed(penum->matrix.xx + fixed2float(fixed_epsilon) / 2);
+ /* We don't want to spread the samples, */
+ /* but we have to reset unpack_bps to prevent the buffer */
+ /* pointer from being incremented by 8 bytes */
+ /* per input byte. */
+ penum->unpack = sample_unpack_copy;
+ penum->unpack_bps = 8;
+ return rproc;
+}
+
+void
+gs_gxifast_init(gs_memory_t * mem)
+{
+ image_strategies.simple = image_strategy_simple;
+}
+
+/* ------ Rendering procedures ------ */
+
+/*
+ * Scale (and possibly reverse) one scan line of a monobit image.
+ * This is used for both portrait and landscape image processing.
+ * We pass in an x offset (0 <= line_x < align_bitmap_mod * 8) so that
+ * we can align the result with the eventual device X.
+ *
+ * To be precise, the input to this routine is the w bits starting at
+ * bit data_x in buffer. These w bits expand to abs(x_extent) bits,
+ * either inverted (zero = 0xff) or not (zero = 0), starting at bit
+ * line_x in line which corresponds to coordinate
+ * fixed2int_pixround(xcur + min(x_extent, 0)). Note that the entire
+ * bytes containing the first and last output bits are affected: the
+ * other bits in those bytes are set to zero (i.e., the value of the
+ * 'zero' argument).
+ */
+#ifdef STATS
+struct stats_image_fast_s {
+ long
+ calls, all0s, all1s, runs, lbit0, byte00, byte01, byte02, byte03,
+ byte04, rbit0, lbit1, byte1, rbit1, thin, thin2, nwide, bwide,
+ nfill, bfill;
+} stats_image_fast;
+
+# define incs(stat) ++stats_image_fast.stat
+# define adds(stat, n) stats_image_fast.stat += n
+#else
+# define incs(stat) DO_NOTHING
+# define adds(stat, n) DO_NOTHING
+#endif
+private void
+image_simple_expand(byte * line, int line_x, uint raster,
+ const byte * buffer, int data_x, uint w, fixed xcur, fixed x_extent,
+ byte zero /* 0 or 0xff */ )
+{
+ int dbitx = data_x & 7;
+ byte sbit = 0x80 >> dbitx;
+ byte sbitmask = 0xff >> dbitx;
+ uint wx = dbitx + w;
+ gx_dda_fixed xl;
+ gx_dda_step_fixed dxx4, dxx8, dxx16, dxx24, dxx32;
+ register const byte *psrc = buffer + (data_x >> 3);
+
+ /*
+ * The following 3 variables define the end of the input data row.
+ * We would put them in a struct, except that no compiler that we
+ * know of will optimize individual struct members as though they
+ * were simple variables (e.g., by putting them in registers).
+ *
+ * endp points to the byte that contains the bit just beyond the
+ * end of the row. endx gives the bit number of this bit within
+ * the byte, with 0 being the *least* significant bit. endbit is
+ * a mask for this bit.
+ */
+ const byte *endp = psrc + (wx >> 3);
+ int endx = ~wx & 7;
+ byte endbit = 1 << endx;
+
+ /*
+ * The following 3 variables do the same for start of the last run
+ * of the input row (think of it as a pointer to just beyond the
+ * end of the next-to-last run).
+ */
+ const byte *stop = endp;
+ int stopx;
+ byte stopbit = endbit;
+ byte data;
+ byte one = ~zero;
+ fixed xl0;
+
+ if (w == 0)
+ return;
+ incs(calls);
+
+#define fill_row(value)\
+ memset(line + (line_x >> 3), value, raster - (line_x >> 3))
+
+ /* Scan backward for the last transition. */
+ if (stopbit == 0x80)
+ --stop, stopbit = 1;
+ else
+ stopbit <<= 1;
+ /* Now (stop, stopbit) give the last bit of the row. */
+ {
+ byte stopmask = -stopbit << 1;
+ byte last = *stop;
+
+ if (stop == psrc) /* only 1 input byte */
+ stopmask &= sbitmask;
+ if (last & stopbit) { /* The last bit is a 1: look for a 0-to-1 transition. */
+ if (~last & stopmask) { /* Transition in last byte. */
+ last |= stopbit - 1;
+ } else { /* No transition in the last byte. */
+ while (stop > psrc && stop[-1] == 0xff)
+ --stop;
+ if (stop == psrc ||
+ (stop == psrc + 1 && !(~*psrc & sbitmask))
+ ) { /* The input is all 1s. Clear the row and exit. */
+ incs(all1s);
+ fill_row(one);
+ return;
+ }
+ last = *--stop;
+ }
+ stopx = byte_bit_run_length_0[byte_reverse_bits[last]] - 1;
+ } else { /* The last bit is a 0: look for a 1-to-0 transition. */
+ if (last & stopmask) { /* Transition in last byte. */
+ last &= -stopbit;
+ } else { /* No transition in the last byte. */
+ while (stop > psrc && stop[-1] == 0)
+ --stop;
+ if (stop == psrc ||
+ (stop == psrc + 1 && !(*psrc & sbitmask))
+ ) { /* The input is all 0s. Clear the row and exit. */
+ incs(all0s);
+ fill_row(zero);
+ return;
+ }
+ last = *--stop;
+ }
+ stopx =
+ byte_bit_run_length_0[byte_reverse_bits[last ^ 0xff]] - 1;
+ }
+ if (stopx < 0)
+ stopx = 7, ++stop;
+ stopbit = 1 << stopx;
+ }
+
+ /* Pre-clear the row. */
+ fill_row(zero);
+#undef fill_row
+
+ /* Set up the DDAs. */
+ xl0 =
+ (x_extent >= 0 ?
+ fixed_fraction(fixed_pre_pixround(xcur)) :
+ fixed_fraction(fixed_pre_pixround(xcur + x_extent)) - x_extent);
+ xl0 += int2fixed(line_x);
+ dda_init(xl, xl0, x_extent, w);
+ dxx4 = xl.step;
+ dda_step_add(dxx4, xl.step);
+ dda_step_add(dxx4, dxx4);
+ dxx8 = dxx4;
+ dda_step_add(dxx8, dxx4);
+ dxx16 = dxx8;
+ dda_step_add(dxx16, dxx8);
+ dxx24 = dxx16;
+ dda_step_add(dxx24, dxx8);
+ dxx32 = dxx24;
+ dda_step_add(dxx32, dxx8);
+
+ /*
+ * Loop invariants:
+ * data = *psrc;
+ * sbit = 1 << n, 0<=n<=7.
+ */
+ for (data = *psrc;;) {
+ int x0, n, bit;
+ byte *bp;
+ static const byte lmasks[9] =
+ {0xff, 0x7f, 0x3f, 0x1f, 0xf, 7, 3, 1, 0};
+ static const byte rmasks[9] =
+ {0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff};
+
+ incs(runs);
+
+ /* Scan a run of zeros. */
+ data ^= 0xff; /* invert */
+ while (data & sbit) {
+ dda_next(xl);
+ sbit >>= 1;
+ incs(lbit0);
+ }
+ if (!sbit) { /* Scan a run of zero bytes. */
+ sw:if ((data = psrc[1]) != 0) {
+ psrc++;
+ incs(byte00);
+ } else if ((data = psrc[2]) != 0) {
+ dda_state_next(xl.state, dxx8);
+ psrc += 2;
+ incs(byte01);
+ } else if ((data = psrc[3]) != 0) {
+ dda_state_next(xl.state, dxx16);
+ psrc += 3;
+ incs(byte02);
+ } else if ((data = psrc[4]) != 0) {
+ dda_state_next(xl.state, dxx24);
+ psrc += 4;
+ incs(byte03);
+ } else {
+ dda_state_next(xl.state, dxx32);
+ psrc += 4;
+ incs(byte04);
+ goto sw;
+ }
+ if (data > 0xf)
+ sbit = 0x80;
+ else {
+ sbit = 0x08;
+ dda_state_next(xl.state, dxx4);
+ }
+ data ^= 0xff; /* invert */
+ while (data & sbit) {
+ dda_next(xl);
+ sbit >>= 1;
+ incs(rbit0);
+ }
+ }
+ x0 = dda_current_fixed2int(xl);
+ if (psrc >= stop && sbit == stopbit) { /* We've scanned the last run of 0s. */
+ /* Prepare to fill the final run of 1s. */
+ n = fixed2int(xl0 + x_extent) - x0;
+ } else { /* Scan a run of ones. */
+ /* We know the current bit is a one. */
+ data ^= 0xff; /* un-invert */
+ do {
+ dda_next(xl);
+ sbit >>= 1;
+ incs(lbit1);
+ }
+ while (data & sbit);
+ if (!sbit) { /* Scan a run of 0xff bytes. */
+ while ((data = *++psrc) == 0xff) {
+ dda_state_next(xl.state, dxx8);
+ incs(byte1);
+ }
+ if (data < 0xf0)
+ sbit = 0x80;
+ else {
+ sbit = 0x08;
+ dda_state_next(xl.state, dxx4);
+ }
+ while (data & sbit) {
+ dda_next(xl);
+ sbit >>= 1;
+ incs(rbit1);
+ }
+ }
+ n = dda_current_fixed2int(xl) - x0;
+ }
+
+ /* Fill the run in the scan line. */
+ if (n < 0)
+ x0 += n, n = -n;
+ bp = line + (x0 >> 3);
+ bit = x0 & 7;
+ if ((n += bit) <= 8) {
+ *bp ^= lmasks[bit] - lmasks[n];
+ incs(thin);
+ } else if ((n -= 8) <= 8) {
+ *bp ^= lmasks[bit];
+ bp[1] ^= rmasks[n];
+ incs(thin2);
+ } else {
+ *bp++ ^= lmasks[bit];
+ if (n >= 56) {
+ int nb = n >> 3;
+
+ memset(bp, one, nb);
+ bp += nb;
+ incs(nwide);
+ adds(bwide, nb);
+ } else {
+ adds(bfill, n >> 3);
+ while ((n -= 8) >= 0)
+ *bp++ = one;
+ incs(nfill);
+ }
+ *bp ^= rmasks[n & 7];
+ }
+ if (psrc >= stop && sbit == stopbit)
+ break;
+ }
+}
+
+/* Copy one rendered scan line to the device. */
+/* We may expand this (or its fastest case) inline someday. */
+private int
+copy_portrait(gx_image_enum * penum, const byte * data, int dx, int raster,
+ int x, int y, int w, int h, gx_device * dev)
+{
+ const gx_device_color *pdc0;
+ const gx_device_color *pdc1;
+ uint align = alignment_mod(data, align_bitmap_mod);
+
+ /*
+ * We know that the lookup table maps 1 bit to 1 bit,
+ * so it can only have 2 states: straight-through or invert.
+ */
+ if (penum->map[0].table.lookup4x1to32[0])
+ pdc0 = &penum->icolor1, pdc1 = &penum->icolor0;
+ else
+ pdc0 = &penum->icolor0, pdc1 = &penum->icolor1;
+ data -= align;
+ dx += align << 3;
+ if (gx_dc_is_pure(pdc0) && gx_dc_is_pure(pdc1)) { /* Just use copy_mono. */
+ dev_proc_copy_mono((*copy_mono)) =
+ (h == 1 || (raster & (align_bitmap_mod - 1)) == 0 ?
+ dev_proc(dev, copy_mono) : gx_copy_mono_unaligned);
+ return (*copy_mono)
+ (dev, data, dx, raster, gx_no_bitmap_id,
+ x, y, w, h, pdc0->colors.pure, pdc1->colors.pure);
+ }
+ /* At least one color isn't pure; use its fill_masked procedure. */
+ {
+ const gx_device_color *pdc;
+ bool invert;
+
+#define dc_is_null(pdc)\
+ (gx_dc_is_pure(pdc) && (pdc)->colors.pure == gx_no_color_index)
+ if (dc_is_null(pdc1)) {
+ pdc = pdc0;
+ invert = true;
+ } else {
+ if (!dc_is_null(pdc0)) {
+ int code = gx_device_color_fill_rectangle
+ (pdc0, x, y, w, h, dev, lop_default, NULL);
+
+ if (code < 0)
+ return code;
+ }
+ pdc = pdc1;
+ invert = false;
+ }
+ return (*pdc->type->fill_masked)
+ (pdc, data, dx, raster, gx_no_bitmap_id, x, y, w, h,
+ dev, lop_default, invert);
+#undef dc_is_null
+ }
+}
+
+/* Rendering procedure for a monobit image with no */
+/* skew or rotation and pure colors. */
+private int
+image_render_simple(gx_image_enum * penum, const byte * buffer, int data_x,
+ uint w, int h, gx_device * dev)
+{
+ dev_proc_copy_mono((*copy_mono)) = dev_proc(dev, copy_mono);
+ const fixed dxx = penum->dxx;
+ const byte *line;
+ uint line_width, line_size;
+ int line_x;
+ fixed xcur = dda_current(penum->dda.pixel0.x);
+ int ix = fixed2int_pixround(xcur);
+ const int iy = penum->yci, ih = penum->hci;
+ int dy;
+
+#define pdc0 (&penum->icolor0)
+#define pdc1 (&penum->icolor1)
+
+ if (h == 0)
+ return 0;
+ if (penum->line == 0) { /* A direct BitBlt is possible. */
+ line = buffer;
+ line_size = (w + 7) >> 3;
+ line_width = w;
+ line_x = 0;
+ } else if (copy_mono == dev_proc(&mem_mono_device, copy_mono) &&
+ dxx > 0 && gx_dc_is_pure(pdc1) && gx_dc_is_pure(pdc0) &&
+ /* We know the colors must be (0,1) or (1,0). */
+ (pdc0->colors.pure ^ pdc1->colors.pure) == 1 &&
+ !penum->clip_image
+ ) { /* Do the operation directly into the memory device bitmap. */
+ int ixr = fixed2int_pixround(xcur + w * dxx) - 1;
+ int line_ix;
+ int ib_left = ix >> 3, ib_right = ixr >> 3;
+ byte *scan_line = scan_line_base((gx_device_memory *) dev, iy);
+ byte save_left, save_right, mask;
+
+ line_x = ix & (align_bitmap_mod * 8 - 1);
+ line_ix = ix - line_x;
+ line_size = (ixr >> 3) + 1 - (line_ix >> 3);
+ line_width = ixr + 1 - ix;
+ /* We must save and restore any unmodified bits in */
+ /* the two edge bytes. */
+ save_left = scan_line[ib_left];
+ save_right = scan_line[ib_right];
+ image_simple_expand(scan_line + (line_ix >> 3), line_x,
+ line_size, buffer, data_x, w, xcur,
+ penum->x_extent.x,
+ ((pdc0->colors.pure == 0) !=
+ (penum->map[0].table.lookup4x1to32[0] == 0) ?
+ 0xff : 0));
+ if (ix & 7)
+ mask = (byte) (0xff00 >> (ix & 7)),
+ scan_line[ib_left] =
+ (save_left & mask) + (scan_line[ib_left] & ~mask);
+ if ((ixr + 1) & 7)
+ mask = (byte) (0xff00 >> ((ixr + 1) & 7)),
+ scan_line[ib_right] =
+ (scan_line[ib_right] & mask) + (save_right & ~mask);
+ if (ih <= 1)
+ return 1;
+/****** MAY BE UNALIGNED ******/
+ line = scan_line + (line_ix >> 3);
+ if (dxx < 0)
+ ix -= line_width;
+ for (dy = 1; dy < ih; dy++) {
+ int code = (*copy_mono) (dev, line, line_x, line_size,
+ gx_no_bitmap_id,
+ ix, iy + dy, line_width, 1,
+ (gx_color_index) 0,
+ (gx_color_index) 1);
+
+ if (code < 0)
+ return code;
+ }
+ return 0;
+ } else {
+ line = penum->line;
+ line_size = penum->line_size;
+ line_width = penum->line_width;
+ line_x = ix & (align_bitmap_mod * 8 - 1);
+ image_simple_expand(penum->line, line_x, line_size,
+ buffer, data_x, w, xcur,
+ penum->x_extent.x, 0);
+ }
+
+ /* Finally, transfer the scan line to the device. */
+ if (dxx < 0)
+ ix -= line_width;
+ for (dy = 0; dy < ih; dy++) {
+ int code = copy_portrait(penum, line, line_x, line_size,
+ ix, iy + dy, line_width, 1, dev);
+
+ if (code < 0)
+ return code;
+ }
+
+ return 1;
+#undef pdc0
+#undef pdc1
+}
+
+/* Rendering procedure for a 90 degree rotated monobit image */
+/* with pure colors. We buffer and then flip 8 scan lines at a time. */
+private int copy_landscape(P5(gx_image_enum *, int, int, bool, gx_device *));
+private int
+image_render_landscape(gx_image_enum * penum, const byte * buffer, int data_x,
+ uint w, int h, gx_device * dev)
+{
+ byte *line = penum->line;
+ uint raster = bitmap_raster(penum->line_width);
+ int ix = penum->xci, iw = penum->wci;
+ int xinc, xmod;
+ byte *row;
+ const byte *orig_row = 0;
+ bool y_neg = penum->dxy < 0;
+
+ if (is_fneg(penum->matrix.yx))
+ ix += iw, iw = -iw, xinc = -1;
+ else
+ xinc = 1;
+ /*
+ * Because of clipping, there may be discontinuous jumps in the
+ * values of ix (xci). If this happens, flush the flipping buffer.
+ */
+ if (ix != penum->xi_next) {
+ int xi = penum->xi_next;
+ int code =
+ (xinc > 0 ?
+ copy_landscape(penum, penum->line_xy, xi, y_neg, dev) :
+ copy_landscape(penum, xi, penum->line_xy, y_neg, dev));
+
+ if (code < 0)
+ return code;
+ penum->line_xy = ix;
+ }
+ if (h != 0) {
+ for (; iw != 0; iw -= xinc) {
+ if (xinc < 0)
+ --ix;
+ xmod = ix & 7;
+ row = line + xmod * raster;
+ if (orig_row == 0) {
+ image_simple_expand(row, 0, raster,
+ buffer, data_x, w,
+ dda_current(penum->dda.pixel0.y),
+ penum->x_extent.y, 0);
+ orig_row = row;
+ } else
+ memcpy(row, orig_row, raster);
+ if (xinc > 0) {
+ ++ix;
+ if (xmod == 7) {
+ int code =
+ copy_landscape(penum,
+ penum->line_xy, ix,
+ y_neg, dev);
+
+ if (code < 0)
+ return code;
+ orig_row = 0;
+ penum->line_xy = ix;
+ }
+ } else {
+ if (xmod == 0) {
+ int code =
+ copy_landscape(penum, ix,
+ penum->line_xy,
+ y_neg, dev);
+
+ if (code < 0)
+ return code;
+ orig_row = 0;
+ penum->line_xy = ix;
+ }
+ }
+ }
+ penum->xi_next = ix;
+ return 0;
+ } else { /* Put out any left-over bits. */
+ return
+ (xinc > 0 ?
+ copy_landscape(penum, penum->line_xy, ix, y_neg, dev) :
+ copy_landscape(penum, ix, penum->line_xy, y_neg, dev));
+ }
+}
+
+/* Flip and copy one group of scan lines. */
+private int
+copy_landscape(gx_image_enum * penum, int x0, int x1, bool y_neg,
+ gx_device * dev)
+{
+ byte *line = penum->line;
+ uint line_width = penum->line_width;
+ uint raster = bitmap_raster(line_width);
+ byte *flipped = line + raster * 8;
+ int w = x1 - x0;
+ int y = fixed2int_pixround(dda_current(penum->dda.pixel0.y));
+
+ if (w == 0 || line_width == 0)
+ return 0;
+ /* Flip the buffered data from raster x 8 to align_bitmap_mod x */
+ /* line_width. */
+ if (line_width > 0) {
+ int i;
+
+ for (i = (line_width - 1) >> 3; i >= 0; --i)
+ memflip8x8(line + i, raster,
+ flipped + (i << (log2_align_bitmap_mod + 3)),
+ align_bitmap_mod);
+ }
+ /* Transfer the scan lines to the device. */
+ if (w < 0)
+ x0 = x1, w = -w;
+ if (y_neg)
+ y -= line_width;
+ return copy_portrait(penum, flipped, x0 & 7, align_bitmap_mod,
+ x0, y, w, line_width, dev);
+}
diff --git a/gs/src/gxiinit.c b/gs/src/gxiinit.c
new file mode 100644
index 000000000..7a461e606
--- /dev/null
+++ b/gs/src/gxiinit.c
@@ -0,0 +1,911 @@
+/* Copyright (C) 1989, 1995, 1996, 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gxiinit.c */
+/* Image setup procedures for Ghostscript library */
+#include "gx.h"
+#include "math_.h"
+#include "memory_.h"
+#include "gpcheck.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gsutil.h"
+#include "gxfixed.h"
+#include "gxfrac.h"
+#include "gxarith.h"
+#include "gxmatrix.h"
+#include "gsccolor.h"
+#include "gspaint.h"
+#include "gzstate.h"
+#include "gxdevice.h"
+#include "gzpath.h"
+#include "gzcpath.h"
+#include "gxdevmem.h"
+#include "gximage.h"
+#include "gxiparam.h"
+#include "gdevmrop.h"
+
+/* ---------------- Generic image support ---------------- */
+
+/* Initialize the common parts of image structures. */
+void
+gs_image_common_t_init(gs_image_common_t * pic)
+{
+ gs_make_identity(&pic->ImageMatrix);
+}
+void
+gs_data_image_t_init(gs_data_image_t * pim, int num_components)
+{
+ int i;
+
+ gs_image_common_t_init((gs_image_common_t *) pim);
+ pim->Width = pim->Height = 0;
+ pim->BitsPerComponent = 1;
+ if (num_components >= 0) {
+ for (i = 0; i < num_components * 2; i += 2)
+ pim->Decode[i] = 0, pim->Decode[i + 1] = 1;
+ } else {
+ for (i = 0; i < num_components * -2; i += 2)
+ pim->Decode[i] = 1, pim->Decode[i + 1] = 0;
+ }
+ pim->Interpolate = false;
+}
+void
+gs_pixel_image_t_init(gs_pixel_image_t * pim, const gs_color_space * color_space)
+{
+ int num_components;
+
+ if (color_space == 0 ||
+ (num_components =
+ gs_color_space_num_components(color_space)) < 0
+ )
+ num_components = 0;
+ gs_data_image_t_init((gs_data_image_t *) pim, num_components);
+ pim->format = gs_image_format_chunky;
+ pim->ColorSpace = color_space;
+ pim->CombineWithColor = false;
+}
+
+/* Initialize the common part of an image-processing enumerator. */
+int
+gx_image_enum_common_init(gx_image_enum_common_t * piec,
+ const gs_image_common_t * pic, const gx_image_enum_procs_t * piep,
+ gx_device * dev, int bits_per_component, int num_components,
+ gs_image_format_t format)
+{
+ piec->image_type = pic->type;
+ piec->procs = piep;
+ piec->dev = dev;
+ piec->id = gs_next_ids(1);
+ switch (format) {
+ case gs_image_format_chunky:
+ piec->num_planes = 1;
+ piec->plane_depths[0] = bits_per_component * num_components;
+ break;
+ case gs_image_format_component_planar:
+ piec->num_planes = num_components;
+ {
+ int i;
+
+ for (i = 0; i < num_components; ++i)
+ piec->plane_depths[i] = bits_per_component;
+ }
+ break;
+ case gs_image_format_bit_planar:
+ piec->num_planes = bits_per_component * num_components;
+ {
+ int i;
+
+ for (i = 0; i < piec->num_planes; ++i)
+ piec->plane_depths[i] = 1;
+ }
+#if 0 /* **************** */
+ break;
+#endif /* **************** */
+ default:
+ return_error(gs_error_rangecheck);
+ }
+ return 0;
+}
+
+/* ---------------- ImageType 1 images ---------------- */
+
+/* Structure descriptors */
+private_st_gx_image_enum();
+public_st_gs_image_common();
+public_st_gs_data_image();
+public_st_gs_pixel_image();
+
+/* Strategy procedures */
+gx_image_strategies_t image_strategies;
+
+/* Define the image type for ImageType 1 images. */
+private const gx_image_type_t image1_type =
+{image1_type_data};
+private const gx_image_enum_procs_t image1_enum_procs =
+{image1_enum_procs_data};
+
+/* Define the procedures for initializing gs_image_ts to default values. */
+void
+gs_image_t_init(gs_image_t * pim, const gs_color_space * color_space)
+{
+ gs_pixel_image_t_init((gs_pixel_image_t *) pim, color_space);
+ pim->type = &image1_type;
+ pim->ImageMask = pim->adjust = (color_space == NULL);
+ pim->Alpha = gs_image_alpha_none;
+}
+void
+gs_image_t_init_mask(gs_image_t * pim, bool write_1s)
+{
+ gs_image_t_init(pim, NULL);
+ if (write_1s)
+ pim->Decode[0] = 1, pim->Decode[1] = 0;
+ else
+ pim->Decode[0] = 0, pim->Decode[1] = 1;
+}
+
+/* Compute the source size of an ordinary image with explicit data. */
+int
+gx_data_image_source_size(const gs_imager_state * pis,
+ const gs_image_common_t * pim, gs_int_point * psize)
+{
+ const gs_data_image_t *pdi = (const gs_data_image_t *)pim;
+
+ psize->x = pdi->Width;
+ psize->y = pdi->Height;
+ return 0;
+}
+
+/* Process the next piece of an image with no source data. */
+/* This procedure should never be called. */
+int
+gx_no_image_plane_data(gx_device * dev,
+ gx_image_enum_common_t * info, const gx_image_plane_t * planes, int height)
+{
+ return_error(gs_error_Fatal);
+}
+
+/* Clean up after processing an image with no source data. */
+/* This procedure may be called, but should do nothing. */
+int
+gx_ignore_end_image(gx_device * dev, gx_image_enum_common_t * info,
+ bool draw_last)
+{
+ return 0;
+}
+
+/* GC procedures */
+#define eptr ((gx_image_enum *)vptr)
+private
+ENUM_PTRS_BEGIN(image_enum_enum_ptrs)
+{
+ int bps;
+ gs_ptr_type_t ret;
+
+ /* Enumerate the used members of clues.dev_color. */
+ index -= gx_image_enum_num_ptrs;
+ bps = eptr->unpack_bps;
+ if (eptr->spp != 1)
+ bps = 8;
+ else if (bps > 8 || eptr->unpack == sample_unpack_copy)
+ bps = 1;
+ if (index >= (1 << bps) * st_device_color_max_ptrs) /* done */
+ return 0;
+ ret = ENUM_USING(st_device_color,
+ &eptr->clues[(index / st_device_color_max_ptrs) *
+ (255 / ((1 << bps) - 1))].dev_color,
+ sizeof(eptr->clues[0].dev_color),
+ index % st_device_color_max_ptrs);
+ if (ret == 0) /* don't stop early */
+ ENUM_RETURN(0);
+ return ret;
+}
+#define e1(i,elt) ENUM_PTR(i,gx_image_enum,elt);
+gx_image_enum_do_ptrs(e1)
+#undef e1
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(image_enum_reloc_ptrs)
+{
+ int i;
+
+#define r1(i,elt) RELOC_PTR(gx_image_enum,elt);
+ gx_image_enum_do_ptrs(r1)
+#undef r1
+ {
+ int bps = eptr->unpack_bps;
+
+ if (eptr->spp != 1)
+ bps = 8;
+ else if (bps > 8 || eptr->unpack == sample_unpack_copy)
+ bps = 1;
+ for (i = 0; i <= 255; i += 255 / ((1 << bps) - 1))
+ RELOC_USING(st_device_color,
+ &eptr->clues[i].dev_color, sizeof(gx_device_color));
+ }
+}
+RELOC_PTRS_END
+#undef eptr
+
+/* Forward declarations */
+private int color_draws_b_w(P2(gx_device * dev,
+ const gx_drawing_color * pdcolor));
+private void image_init_map(P3(byte * map, int map_size, const float *decode));
+private void image_init_colors(P9(gx_image_enum * penum, int bps, int spp,
+ bool multi, const float *decode,
+ const gs_imager_state * pis, gx_device * dev,
+ const gs_color_space * pcs, bool * pdcb));
+
+/* Procedures for unpacking the input data into bytes or fracs. */
+ /*extern sample_unpack_proc(sample_unpack_copy); *//* declared above */
+extern sample_unpack_proc(sample_unpack_1);
+extern sample_unpack_proc(sample_unpack_2);
+extern sample_unpack_proc(sample_unpack_4);
+extern sample_unpack_proc(sample_unpack_8);
+
+sample_unpack_proc((*sample_unpack_12_proc)); /* optional */
+
+/* Start processing an ImageType 1 image. */
+/* Note that since this is actually a begin_typed_image procedure, */
+/* the type of pim is the more abstract one. */
+int
+gx_begin_image1(gx_device * dev,
+ const gs_imager_state * pis, const gs_matrix * pmat,
+ const gs_image_common_t * pic, const gs_int_rect * prect,
+ const gx_drawing_color * pdcolor, const gx_clip_path * pcpath,
+ gs_memory_t * mem, gx_image_enum_common_t ** pinfo)
+{
+ const gs_image_t *pim = (const gs_image_t *)pic;
+ gs_image_format_t format = pim->format;
+ gx_image_enum *penum;
+ const int width = pim->Width;
+ const int height = pim->Height;
+ const int bps = pim->BitsPerComponent;
+ bool masked = pim->ImageMask;
+ const float *decode = pim->Decode;
+ bool multi;
+ int index_bps;
+ const gs_color_space *pcs = pim->ColorSpace;
+ gs_logical_operation_t lop = (pis ? pis->log_op : lop_default);
+ int code;
+ gs_matrix mat;
+ int log2_xbytes = (bps <= 8 ? 0 : arch_log2_sizeof_frac);
+ int spp, nplanes, spread;
+ uint bsize;
+ byte *buffer;
+ fixed mtx, mty;
+ gs_fixed_point row_extent, col_extent, x_extent, y_extent;
+ bool device_color;
+ gs_fixed_rect obox, cbox;
+ fixed adjust;
+
+ if (width < 0 || height < 0)
+ return_error(gs_error_rangecheck);
+ switch (format) {
+ case gs_image_format_chunky:
+ multi = false;
+ break;
+ case gs_image_format_component_planar:
+ multi = true;
+ break;
+ default:
+ return_error(gs_error_rangecheck);
+ }
+ switch (bps) {
+ case 1:
+ index_bps = 0;
+ break;
+ case 2:
+ index_bps = 1;
+ break;
+ case 4:
+ index_bps = 2;
+ break;
+ case 8:
+ index_bps = 3;
+ break;
+ case 12:
+ index_bps = 4;
+ break;
+ default:
+ return_error(gs_error_rangecheck);
+ }
+ if (prect) {
+ if (prect->p.x < 0 || prect->p.y < 0 ||
+ prect->q.x < prect->p.x || prect->q.y < prect->p.y ||
+ prect->q.x > width || prect->q.y > height
+ )
+ return_error(gs_error_rangecheck);
+ }
+ if (pmat == 0)
+ pmat = &ctm_only(pis);
+ if ((code = gs_matrix_invert(&pim->ImageMatrix, &mat)) < 0 ||
+ (code = gs_matrix_multiply(&mat, pmat, &mat)) < 0 ||
+ (code =
+ gs_distance_transform2fixed((const gs_matrix_fixed *)&mat,
+ (floatp) width, (floatp) 0,
+ &row_extent)) < 0 ||
+ (code =
+ gs_distance_transform2fixed((const gs_matrix_fixed *)&mat,
+ (floatp) 0, (floatp) height,
+ &col_extent)) < 0
+ )
+ return code;
+ penum = gs_alloc_struct(mem, gx_image_enum, &st_gx_image_enum,
+ "gx_default_begin_image");
+ if (penum == 0)
+ return_error(gs_error_VMerror);
+ gx_image_enum_common_init((gx_image_enum_common_t *) penum, pic,
+ &image1_enum_procs, dev, bps,
+ (masked ? 1 : cs_num_components(pcs)),
+ format);
+ if (prect) {
+ penum->rect.x = prect->p.x, penum->rect.y = prect->p.y;
+ penum->rect.w = prect->q.x - prect->p.x,
+ penum->rect.h = prect->q.y - prect->p.y;
+ if ((code =
+ gs_distance_transform2fixed((const gs_matrix_fixed *)&mat,
+ (floatp) penum->rect.w, (floatp) 0,
+ &x_extent)) < 0 ||
+ (code =
+ gs_distance_transform2fixed((const gs_matrix_fixed *)&mat,
+ (floatp) 0, (floatp) penum->rect.h,
+ &y_extent)) < 0
+ ) {
+ gs_free_object(mem, penum, "gx_default_begin_image");
+ return code;
+ }
+ } else {
+ penum->rect.x = 0, penum->rect.y = 0;
+ penum->rect.w = width, penum->rect.h = height;
+ x_extent = row_extent;
+ y_extent = col_extent;
+ }
+ if ((penum->masked = masked)) { /* This is imagemask. */
+ if (bps != 1 || multi || pcs != NULL || pim->Alpha ||
+ !((decode[0] == 0.0 && decode[1] == 1.0) ||
+ (decode[0] == 1.0 && decode[1] == 0.0))
+ ) {
+ gs_free_object(mem, penum, "gx_default_begin_image");
+ return_error(gs_error_rangecheck);
+ }
+ /* Initialize color entries 0 and 255. */
+ color_set_pure(&penum->icolor0, gx_no_color_index);
+ penum->icolor1 = *pdcolor;
+ memcpy(&penum->map[0].table.lookup4x1to32[0],
+ (decode[0] == 0 ? lookup4x1to32_inverted :
+ lookup4x1to32_identity),
+ 16 * 4);
+ penum->map[0].decoding = sd_none;
+ spp = 1;
+ adjust = (pim->adjust ? float2fixed(0.25) : fixed_0);
+ lop = rop3_know_S_0(lop);
+ } else { /* This is image, not imagemask. */
+ const gs_color_space_type *pcst = pcs->type;
+ int b_w_color;
+
+ spp = cs_num_components(pcs);
+ if (spp < 0) { /* Pattern not allowed */
+ gs_free_object(mem, penum, "gx_default_begin_image");
+ return_error(gs_error_rangecheck);
+ }
+ if (pim->Alpha)
+ ++spp;
+ if (spp == 1)
+ multi = false;
+ device_color = (*pcst->concrete_space) (pcs, pis) == pcs;
+ image_init_colors(penum, bps, spp, multi, decode, pis, dev,
+ pcs, &device_color);
+ adjust = fixed_0;
+ /* Try to transform non-default RasterOps to something */
+ /* that we implement less expensively. */
+ if (!pim->CombineWithColor)
+ lop = rop3_know_T_0(lop);
+ else {
+ if (rop3_uses_T(lop))
+ switch (color_draws_b_w(dev, pdcolor)) {
+ case 0:
+ lop = rop3_know_T_0(lop);
+ break;
+ case 1:
+ lop = rop3_know_T_1(lop);
+ break;
+ default:
+ ;
+ }
+ }
+ if (lop != rop3_S && /* if best case, no more work needed */
+ !rop3_uses_T(lop) && bps == 1 && spp == 1 &&
+ (b_w_color =
+ color_draws_b_w(dev, &penum->icolor0)) >= 0 &&
+ color_draws_b_w(dev, &penum->icolor1) == (b_w_color ^ 1)
+ ) {
+ if (b_w_color) { /* Swap the colors and invert the RasterOp source. */
+ gx_device_color dcolor;
+
+ dcolor = penum->icolor0;
+ penum->icolor0 = penum->icolor1;
+ penum->icolor1 = dcolor;
+ lop = rop3_invert_S(lop);
+ }
+ /*
+ * At this point, we know that the source pixels
+ * correspond directly to the S input for the raster op,
+ * i.e., icolor0 is black and icolor1 is white.
+ */
+ switch (lop) {
+ case rop3_D & rop3_S:
+ /* Implement this as an inverted mask writing 0s. */
+ penum->icolor1 = penum->icolor0;
+ /* (falls through) */
+ case rop3_D | rop3_not(rop3_S):
+ /* Implement this as an inverted mask writing 1s. */
+ memcpy(&penum->map[0].table.lookup4x1to32[0],
+ lookup4x1to32_inverted, 16 * 4);
+ rmask: /* Fill in the remaining parameters for a mask. */
+ penum->masked = masked = true;
+ color_set_pure(&penum->icolor0, gx_no_color_index);
+ penum->map[0].decoding = sd_none;
+ lop = rop3_T;
+ break;
+ case rop3_D & rop3_not(rop3_S):
+ /* Implement this as a mask writing 0s. */
+ penum->icolor1 = penum->icolor0;
+ /* (falls through) */
+ case rop3_D | rop3_S:
+ /* Implement this as a mask writing 1s. */
+ memcpy(&penum->map[0].table.lookup4x1to32[0],
+ lookup4x1to32_identity, 16 * 4);
+ goto rmask;
+ default:
+ ;
+ }
+ }
+ }
+ penum->device_color = device_color;
+ /*
+ * Adjust width upward for unpacking up to 7 trailing bits in
+ * the row, plus 1 byte for end-of-run, plus up to 7 leading
+ * bits for data_x offset within a packed byte.
+ */
+ bsize = ((bps > 8 ? width * 2 : width) + 15) * spp;
+ buffer = gs_alloc_bytes(mem, bsize, "image buffer");
+ if (buffer == 0) {
+ gs_free_object(mem, penum, "gx_default_begin_image");
+ return_error(gs_error_VMerror);
+ }
+ penum->bps = bps;
+ penum->unpack_bps = bps;
+ penum->log2_xbytes = log2_xbytes;
+ penum->spp = spp;
+ penum->alpha = pim->Alpha;
+ nplanes = (multi ? spp : 1);
+ penum->num_planes = nplanes;
+ spread = nplanes << log2_xbytes;
+ penum->spread = spread;
+ penum->matrix = mat;
+ penum->x_extent = x_extent;
+ penum->y_extent = y_extent;
+ penum->posture =
+ ((x_extent.y | y_extent.x) == 0 ? image_portrait :
+ (x_extent.x | y_extent.y) == 0 ? image_landscape :
+ image_skewed);
+ mtx = float2fixed(mat.tx);
+ mty = float2fixed(mat.ty);
+ penum->pis = pis;
+ penum->pcs = pcs;
+ penum->memory = mem;
+ penum->buffer = buffer;
+ penum->buffer_size = bsize;
+ penum->line = 0;
+ penum->line_size = 0;
+ /*
+ * If we're asked to interpolate in a partial image, we have to
+ * assume that the client either really only is interested in
+ * the given sub-image, or else is constructing output out of
+ * overlapping pieces.
+ */
+ penum->interpolate = pim->Interpolate;
+ penum->use_rop = lop != (masked ? rop3_T : rop3_S);
+#ifdef DEBUG
+ if (gs_debug_c('*')) {
+ if (penum->use_rop)
+ dprintf1("[%03x]", lop);
+ dprintf5("%c%d%c%dx%d ",
+ (masked ? (color_is_pure(pdcolor) ? 'm' : 'h') : 'i'),
+ bps,
+ (penum->posture == image_portrait ? ' ' :
+ penum->posture == image_landscape ? 'L' : 'T'),
+ width, height);
+ }
+#endif
+ penum->slow_loop = 0;
+ if (pcpath == 0) {
+ (*dev_proc(dev, get_clipping_box)) (dev, &obox);
+ cbox = obox;
+ penum->clip_image = 0;
+ } else
+ penum->clip_image =
+ (gx_cpath_outer_box(pcpath, &obox) | /* not || */
+ gx_cpath_inner_box(pcpath, &cbox) ?
+ 0 : image_clip_region);
+ penum->clip_outer = obox;
+ penum->clip_inner = cbox;
+ penum->log_op = rop3_T; /* rop device takes care of this */
+ penum->clip_dev = 0; /* in case we bail out */
+ penum->rop_dev = 0; /* ditto */
+ penum->scaler = 0; /* ditto */
+ /*
+ * If all four extrema of the image fall within the clipping
+ * rectangle, clipping is never required. When making this check,
+ * we must carefully take into account the fact that we only care
+ * about pixel centers.
+ */
+ {
+ fixed
+ epx = min(row_extent.x, 0) + min(col_extent.x, 0),
+ eqx = max(row_extent.x, 0) + max(col_extent.x, 0),
+ epy = min(row_extent.y, 0) + min(col_extent.y, 0),
+ eqy = max(row_extent.y, 0) + max(col_extent.y, 0);
+
+ {
+ int hwx, hwy;
+
+ switch (penum->posture) {
+ case image_portrait:
+ hwx = width, hwy = height;
+ break;
+ case image_landscape:
+ hwx = height, hwy = width;
+ break;
+ default:
+ hwx = hwy = 0;
+ }
+ /*
+ * If the image is only 1 sample wide or high,
+ * and is less than 1 device pixel wide or high,
+ * move it slightly so that it covers pixel centers.
+ * This is a hack to work around a bug in some old
+ * versions of TeX/dvips, which use 1-bit-high images
+ * to draw horizontal and vertical lines without
+ * positioning them properly.
+ */
+ if (hwx == 1 && eqx - epx < fixed_1) {
+ fixed diff =
+ arith_rshift_1(row_extent.x + col_extent.x);
+
+ mtx = (((mtx + diff) | fixed_half) & -fixed_half) - diff;
+ }
+ if (hwy == 1 && eqy - epy < fixed_1) {
+ fixed diff =
+ arith_rshift_1(row_extent.y + col_extent.y);
+
+ mty = (((mty + diff) | fixed_half) & -fixed_half) - diff;
+ }
+ }
+ if_debug11('b',
+ "[b]Image: cbox=(%g,%g),(%g,%g), obox=(%g,%g),(%g,%g)\n mt=(%g,%g) clip_image=0x%x\n",
+ fixed2float(cbox.p.x), fixed2float(cbox.p.y),
+ fixed2float(cbox.q.x), fixed2float(cbox.q.y),
+ fixed2float(obox.p.x), fixed2float(obox.p.y),
+ fixed2float(obox.q.x), fixed2float(obox.q.y),
+ fixed2float(mtx), fixed2float(mty),
+ penum->clip_image);
+ dda_init(penum->dda.row.x, mtx, col_extent.x, height);
+ dda_init(penum->dda.row.y, mty, col_extent.y, height);
+ if (penum->rect.y) {
+ dda_advance(penum->dda.row.x, penum->rect.y);
+ dda_advance(penum->dda.row.y, penum->rect.y);
+ }
+ penum->cur.x = penum->prev.x = dda_current(penum->dda.row.x);
+ penum->cur.y = penum->prev.y = dda_current(penum->dda.row.y);
+ dda_init(penum->dda.pixel0.x, penum->cur.x, row_extent.x,
+ width);
+ dda_init(penum->dda.pixel0.y, penum->cur.y, row_extent.y,
+ width);
+ if (penum->rect.x) {
+ dda_advance(penum->dda.pixel0.x, penum->rect.x);
+ dda_advance(penum->dda.pixel0.y, penum->rect.x);
+ } {
+ fixed ox = dda_current(penum->dda.pixel0.x);
+ fixed oy = dda_current(penum->dda.pixel0.y);
+
+ if (!penum->clip_image) /* i.e., not clip region */
+ penum->clip_image =
+ (fixed_pixround(ox + epx) < fixed_pixround(cbox.p.x) ?
+ image_clip_xmin : 0) +
+ (fixed_pixround(ox + eqx) >= fixed_pixround(cbox.q.x) ?
+ image_clip_xmax : 0) +
+ (fixed_pixround(oy + epy) < fixed_pixround(cbox.p.y) ?
+ image_clip_ymin : 0) +
+ (fixed_pixround(oy + eqy) >= fixed_pixround(cbox.q.y) ?
+ image_clip_ymax : 0);
+ }
+ }
+ penum->y = 0;
+ penum->adjust = adjust;
+ {
+ static const sample_unpack_proc_t procs[4] =
+ {
+ sample_unpack_1, sample_unpack_2,
+ sample_unpack_4, sample_unpack_8
+ };
+
+ if (index_bps == 4) {
+ if ((penum->unpack = sample_unpack_12_proc) == 0) { /* 12-bit samples are not supported. */
+ gx_default_end_image(dev,
+ (gx_image_enum_common_t *) penum,
+ false);
+ return_error(gs_error_rangecheck);
+ }
+ } else {
+ penum->unpack = procs[index_bps];
+ if_debug1('b', "[b]unpack=%d\n", bps);
+ }
+#define use_strategy(sp)\
+ (image_strategies.sp != 0 &&\
+ (penum->render = (*image_strategies.sp)(penum)) != 0)
+ if (
+ use_strategy(interpolate) ||
+ use_strategy(simple) ||
+ use_strategy(fracs) ||
+ use_strategy(mono) ||
+ use_strategy(color)
+ )
+ DO_NOTHING;
+#undef use_strategy
+ else { /* No available strategy can handle this image. */
+ gx_default_end_image(dev, (gx_image_enum_common_t *) penum,
+ false);
+ return_error(gs_error_rangecheck);
+ }
+ }
+ if (penum->clip_image && pcpath) { /* Set up the clipping device. */
+ gx_device_clip *cdev =
+ gs_alloc_struct(mem, gx_device_clip,
+ &st_device_clip, "image clipper");
+
+ if (cdev == 0) {
+ gx_default_end_image(dev,
+ (gx_image_enum_common_t *) penum,
+ false);
+ return_error(gs_error_VMerror);
+ }
+ gx_make_clip_device(cdev, cdev, gx_cpath_list(pcpath));
+ cdev->target = dev;
+ (*dev_proc(cdev, open_device)) ((gx_device *) cdev);
+ penum->clip_dev = cdev;
+ }
+ if (penum->use_rop) { /* Set up the RasterOp source device. */
+ gx_device_rop_texture *rtdev;
+
+ code = gx_alloc_rop_texture_device(&rtdev, mem,
+ "image RasterOp");
+ if (code < 0) {
+ gx_default_end_image(dev, (gx_image_enum_common_t *) penum,
+ false);
+ return code;
+ }
+ gx_make_rop_texture_device(rtdev,
+ (penum->clip_dev != 0 ?
+ (gx_device *) penum->clip_dev :
+ dev), lop, pdcolor);
+ penum->rop_dev = rtdev;
+ }
+#ifdef DEBUG
+ if (gs_debug_c('b')) {
+ dlprintf2("[b]Image: w=%d h=%d", width, height);
+ if (prect)
+ dprintf4(" ((%d,%d),(%d,%d))",
+ prect->p.x, prect->p.y, prect->q.x, prect->q.y);
+ dprintf6(" [%g %g %g %g %g %g]\n",
+ mat.xx, mat.xy, mat.yx, mat.yy, mat.tx, mat.ty);
+ }
+#endif
+ *pinfo = (gx_image_enum_common_t *) penum;
+ return 0;
+}
+
+/* If a drawing color is black or white, return 0 or 1 respectively, */
+/* otherwise return -1. */
+private int
+color_draws_b_w(gx_device * dev, const gx_drawing_color * pdcolor)
+{
+ if (color_is_pure(pdcolor)) {
+ gx_color_value rgb[3];
+
+ (*dev_proc(dev, map_color_rgb)) (dev, gx_dc_pure_color(pdcolor),
+ rgb);
+ if (!(rgb[0] | rgb[1] | rgb[2]))
+ return 0;
+ if ((rgb[0] & rgb[1] & rgb[2]) == gx_max_color_value)
+ return 1;
+ }
+ return -1;
+}
+
+/* Initialize the color mapping tables for a non-mask image. */
+private void
+image_init_colors(gx_image_enum * penum, int bps, int spp, bool multi,
+ const float *decode /*[spp*2] */ , const gs_imager_state * pis, gx_device * dev,
+ const gs_color_space * pcs, bool * pdcb)
+{
+ int ci;
+ static const float default_decode[] =
+ {
+ 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0
+ };
+
+ /* Initialize the color table */
+
+#define ictype(i)\
+ penum->clues[i].dev_color.type
+ switch ((spp == 1 ? bps : 8)) {
+ case 8: /* includes all color images */
+ {
+ register gx_image_clue *pcht = &penum->clues[0];
+ register int n = 64;
+
+ do {
+ pcht[0].dev_color.type =
+ pcht[1].dev_color.type =
+ pcht[2].dev_color.type =
+ pcht[3].dev_color.type =
+ gx_dc_type_none;
+ pcht[0].key = pcht[1].key =
+ pcht[2].key = pcht[3].key = 0;
+ pcht += 4;
+ }
+ while (--n > 0);
+ penum->clues[0].key = 1; /* guarantee no hit */
+ break;
+ }
+ case 4:
+ ictype(17) = ictype(2 * 17) = ictype(3 * 17) =
+ ictype(4 * 17) = ictype(6 * 17) = ictype(7 * 17) =
+ ictype(8 * 17) = ictype(9 * 17) = ictype(11 * 17) =
+ ictype(12 * 17) = ictype(13 * 17) = ictype(14 * 17) =
+ gx_dc_type_none;
+ /* falls through */
+ case 2:
+ ictype(5 * 17) = ictype(10 * 17) = gx_dc_type_none;
+#undef ictype
+ }
+
+ /* Initialize the maps from samples to intensities. */
+
+ for (ci = 0; ci < spp; ci++) {
+ sample_map *pmap = &penum->map[ci];
+
+ /* If the decoding is [0 1] or [1 0], we can fold it */
+ /* into the expansion of the sample values; */
+ /* otherwise, we have to use the floating point method. */
+
+ const float *this_decode = &decode[ci * 2];
+ const float *map_decode; /* decoding used to */
+
+ /* construct the expansion map */
+
+ const float *real_decode; /* decoding for */
+
+ /* expanded samples */
+
+ bool no_decode;
+
+ map_decode = real_decode = this_decode;
+ if (map_decode[0] == 0.0 && map_decode[1] == 1.0)
+ no_decode = true;
+ else if (map_decode[0] == 1.0 && map_decode[1] == 0.0)
+ no_decode = true,
+ real_decode = default_decode;
+ else
+ no_decode = false,
+ *pdcb = false,
+ map_decode = default_decode;
+ if (bps > 2 || multi) {
+ if (bps <= 8)
+ image_init_map(&pmap->table.lookup8[0], 1 << bps,
+ map_decode);
+ } else { /* The map index encompasses more than one pixel. */
+ byte map[4];
+ register int i;
+
+ image_init_map(&map[0], 1 << bps, map_decode);
+ switch (bps) {
+ case 1:
+ {
+ register bits32 *p = &pmap->table.lookup4x1to32[0];
+
+ if (map[0] == 0 && map[1] == 0xff)
+ memcpy((byte *) p, lookup4x1to32_identity, 16 * 4);
+ else if (map[0] == 0xff && map[1] == 0)
+ memcpy((byte *) p, lookup4x1to32_inverted, 16 * 4);
+ else
+ for (i = 0; i < 16; i++, p++)
+ ((byte *) p)[0] = map[i >> 3],
+ ((byte *) p)[1] = map[(i >> 2) & 1],
+ ((byte *) p)[2] = map[(i >> 1) & 1],
+ ((byte *) p)[3] = map[i & 1];
+ }
+ break;
+ case 2:
+ {
+ register bits16 *p = &pmap->table.lookup2x2to16[0];
+
+ for (i = 0; i < 16; i++, p++)
+ ((byte *) p)[0] = map[i >> 2],
+ ((byte *) p)[1] = map[i & 3];
+ }
+ break;
+ }
+ }
+ pmap->decode_base /* = decode_lookup[0] */ = real_decode[0];
+ pmap->decode_factor =
+ (real_decode[1] - real_decode[0]) /
+ (bps <= 8 ? 255.0 : (float)frac_1);
+ pmap->decode_max /* = decode_lookup[15] */ = real_decode[1];
+ if (no_decode)
+ pmap->decoding = sd_none;
+ else if (bps <= 4) {
+ int step = 15 / ((1 << bps) - 1);
+ int i;
+
+ pmap->decoding = sd_lookup;
+ for (i = 15 - step; i > 0; i -= step)
+ pmap->decode_lookup[i] = pmap->decode_base +
+ i * (255.0 / 15) * pmap->decode_factor;
+ } else
+ pmap->decoding = sd_compute;
+ if (spp == 1) { /* and ci == 0 *//* Pre-map entries 0 and 255. */
+ gs_client_color cc;
+
+ cc.paint.values[0] = real_decode[0];
+ (*pcs->type->remap_color) (&cc, pcs, &penum->icolor0,
+ pis, dev, gs_color_select_source);
+ cc.paint.values[0] = real_decode[1];
+ (*pcs->type->remap_color) (&cc, pcs, &penum->icolor1,
+ pis, dev, gs_color_select_source);
+ }
+ }
+
+}
+/* Construct a mapping table for sample values. */
+/* map_size is 2, 4, 16, or 256. Note that 255 % (map_size - 1) == 0, */
+/* so the division 0xffffL / (map_size - 1) is always exact. */
+private void
+image_init_map(byte * map, int map_size, const float *decode)
+{
+ float min_v = decode[0];
+ float diff_v = decode[1] - min_v;
+
+ if (diff_v == 1 || diff_v == -1) { /* We can do the stepping with integers, without overflow. */
+ byte *limit = map + map_size;
+ uint value = min_v * 0xffffL;
+ int diff = diff_v * (0xffffL / (map_size - 1));
+
+ for (; map != limit; map++, value += diff)
+ *map = value >> 8;
+ } else { /* Step in floating point, with clamping. */
+ int i;
+
+ for (i = 0; i < map_size; ++i) {
+ int value = (int)((min_v + diff_v * i / (map_size - 1)) * 255);
+
+ map[i] = (value < 0 ? 0 : value > 255 ? 255 : value);
+ }
+ }
+}
diff --git a/gs/src/gximono.c b/gs/src/gximono.c
new file mode 100644
index 000000000..e47e2e6a8
--- /dev/null
+++ b/gs/src/gximono.c
@@ -0,0 +1,477 @@
+/* Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gximono.c */
+/* General mono-component image rendering */
+#include "gx.h"
+#include "memory_.h"
+#include "gpcheck.h"
+#include "gserrors.h"
+#include "gxfixed.h"
+#include "gxarith.h"
+#include "gxmatrix.h"
+#include "gsccolor.h"
+#include "gspaint.h"
+#include "gsutil.h"
+#include "gxdevice.h"
+#include "gxcmap.h"
+#include "gxdcolor.h"
+#include "gxistate.h"
+#include "gzpath.h"
+#include "gxdevmem.h"
+#include "gdevmem.h" /* for mem_mono_device */
+#include "gxcpath.h"
+#include "gximage.h"
+#include "gzht.h"
+
+/* ------ Strategy procedure ------ */
+
+/* We can bypass X clipping for portrait mono-component images. */
+private irender_proc(image_render_mono);
+private irender_proc_t
+image_strategy_mono(gx_image_enum * penum)
+{ /* Use slow loop for imagemask with a halftone, */
+ /* or for a non-default logical operation. */
+ penum->slow_loop =
+ (penum->masked && !color_is_pure(&penum->icolor1)) ||
+ penum->use_rop;
+ if (penum->spp == 1) {
+ if (!(penum->slow_loop || penum->posture != image_portrait))
+ penum->clip_image &= ~(image_clip_xmin | image_clip_xmax);
+ if_debug0('b', "[b]render=mono\n");
+ /* Precompute values needed for rasterizing. */
+ penum->dxx =
+ float2fixed(penum->matrix.xx + fixed2float(fixed_epsilon) / 2);
+ return image_render_mono;
+ }
+ return 0;
+}
+
+void
+gs_gximono_init(gs_memory_t * mem)
+{
+ image_strategies.mono = image_strategy_mono;
+}
+
+/* ------ Rendering procedure ------ */
+
+/* Provide a fake map_gray procedure for the DevicePixel color space. */
+private void
+no_map_gray(frac pixel, gx_device_color * pdc,
+ const gs_imager_state * pis, gx_device * dev, gs_color_select_t select)
+{
+ color_set_pure(pdc, frac2byte(pixel));
+}
+
+/*
+ * Rendering procedure for general mono-component images, dealing with
+ * multiple bit-per-sample images, general transformations, and arbitrary
+ * single-component color spaces (DeviceGray, DevicePixel, CIEBasedA,
+ * Separation, Indexed). This procedure handles a single scan line.
+ */
+private int
+image_render_mono(gx_image_enum * penum, const byte * buffer, int data_x,
+ uint w, int h, gx_device * dev)
+{
+ const gs_imager_state *pis = penum->pis;
+ gs_logical_operation_t lop = penum->log_op;
+ const int masked = penum->masked;
+ const gs_color_space *pcs; /* only set for non-masks */
+
+ cmap_proc_gray((*map_gray)); /* ditto */
+ cs_proc_remap_color((*remap_color)); /* ditto */
+ gs_client_color cc;
+ gx_device_color *pdevc = &penum->icolor1; /* color for masking */
+
+ /* Make sure the cache setup matches the graphics state. */
+ /* Also determine whether all tiles fit in the cache. */
+ int tiles_fit = gx_check_tile_cache(pis);
+
+#define image_set_gray(sample_value)\
+ { pdevc = &penum->clues[sample_value].dev_color;\
+ if ( !color_is_set(pdevc) )\
+ { if ( penum->device_color )\
+ (*map_gray)(byte2frac(sample_value), pdevc, pis, dev, gs_color_select_source);\
+ else\
+ { decode_sample(sample_value, cc, 0);\
+ (*remap_color)(&cc, pcs, pdevc, pis, dev, gs_color_select_source);\
+ }\
+ }\
+ else if ( !color_is_pure(pdevc) )\
+ { if ( !tiles_fit )\
+ { code = gx_color_load_select(pdevc, pis, dev, gs_color_select_source);\
+ if ( code < 0 ) return code;\
+ }\
+ }\
+ }
+ gx_dda_fixed_point next; /* (y not used in fast loop) */
+ gx_dda_step_fixed dxx2, dxx3, dxx4; /* (not used in all loops) */
+ register const byte *psrc = buffer + data_x;
+ const byte *endp = psrc + w;
+ const byte *stop = endp;
+ fixed xrun; /* x at start of run */
+ register byte run; /* run value */
+ int htrun = /* halftone run value */
+ (masked ? 255 : -2);
+ int code = 0;
+
+ if (h == 0)
+ return 0;
+ next = penum->dda.pixel0;
+ xrun = dda_current(next.x);
+ if (!masked) {
+ pcs = penum->pcs; /* (may not be set for masks) */
+ if (penum->device_color)
+ map_gray =
+ (gs_color_space_get_index(pcs) ==
+ gs_color_space_index_DeviceGray ?
+ gx_device_cmap_procs(dev)->map_gray :
+ no_map_gray /*DevicePixel */ );
+ else
+ remap_color = pcs->type->remap_color;
+ }
+ run = *psrc;
+ /* Find the last transition in the input. */
+ {
+ byte last = stop[-1];
+
+ while (stop > psrc && stop[-1] == last)
+ --stop;
+ }
+ if (penum->slow_loop || penum->posture != image_portrait) { /* Skewed, rotated, or imagemask with a halftone. */
+ fixed yrun;
+ const fixed pdyx = dda_current(penum->dda.row.x) - penum->cur.x;
+ const fixed pdyy = dda_current(penum->dda.row.y) - penum->cur.y;
+
+ dev_proc_fill_parallelogram((*fill_pgram)) =
+ dev_proc(dev, fill_parallelogram);
+
+#define xl dda_current(next.x)
+#define ytf dda_current(next.y)
+ yrun = ytf;
+ if (masked) {
+ pdevc = &penum->icolor1;
+ code = gx_color_load(pdevc, pis, dev);
+ if (code < 0)
+ return code;
+ if (stop <= psrc)
+ goto last;
+ if (penum->posture == image_portrait) { /* We don't have to worry about the Y DDA, */
+ /* and the fill regions are rectangles. */
+ /* Calculate multiples of the DDA step. */
+ dxx2 = next.x.step;
+ dda_step_add(dxx2, next.x.step);
+ dxx3 = dxx2;
+ dda_step_add(dxx3, next.x.step);
+ dxx4 = dxx3;
+ dda_step_add(dxx4, next.x.step);
+ for (;;) { /* Skip a run of zeros. */
+ while (!psrc[0])
+ if (!psrc[1]) {
+ if (!psrc[2]) {
+ if (!psrc[3]) {
+ psrc += 4;
+ dda_state_next(next.x.state, dxx4);
+ continue;
+ }
+ psrc += 3;
+ dda_state_next(next.x.state, dxx3);
+ break;
+ }
+ psrc += 2;
+ dda_state_next(next.x.state, dxx2);
+ break;
+ } else {
+ ++psrc;
+ dda_next(next.x);
+ break;
+ }
+ xrun = xl;
+ if (psrc >= stop)
+ break;
+ for (; *psrc; ++psrc)
+ dda_next(next.x);
+ code = (*fill_pgram) (dev, xrun, yrun, xl - xrun,
+ fixed_0, fixed_0, pdyy,
+ pdevc, lop);
+ if (code < 0)
+ return code;
+ if (psrc >= stop)
+ break;
+ }
+ } else
+ for (;;) {
+ for (; !*psrc; ++psrc) {
+ dda_next(next.x);
+ dda_next(next.y);
+ }
+ yrun = ytf;
+ xrun = xl;
+ if (psrc >= stop)
+ break;
+ for (; *psrc; ++psrc) {
+ dda_next(next.x);
+ dda_next(next.y);
+ }
+ code = (*fill_pgram) (dev, xrun, yrun, xl - xrun,
+ ytf - yrun, pdyx, pdyy, pdevc, lop);
+ if (code < 0)
+ return code;
+ if (psrc >= stop)
+ break;
+ }
+ } else if (penum->posture == image_portrait ||
+ penum->posture == image_landscape
+ ) { /* Not masked, and we can fill runs quickly. */
+ if (stop <= psrc)
+ goto last;
+ for (;;) {
+ if (*psrc != run) {
+ if (run != htrun) {
+ htrun = run;
+ image_set_gray(run);
+ }
+ code = (*fill_pgram) (dev, xrun, yrun, xl - xrun,
+ ytf - yrun, pdyx, pdyy,
+ pdevc, lop);
+ if (code < 0)
+ return code;
+ yrun = ytf;
+ xrun = xl;
+ if (psrc >= stop)
+ break;
+ run = *psrc;
+ }
+ psrc++;
+ dda_next(next.x);
+ dda_next(next.y);
+ }
+ } else { /* not masked *//* Since we have to check for the end after every pixel */
+ /* anyway, we may as well avoid the last-run code. */
+ stop = endp;
+ for (;;) { /* We can't skip large constant regions quickly, */
+ /* because this leads to rounding errors. */
+ /* Just fill the region between xrun and xl. */
+ psrc++;
+ if (run != htrun) {
+ htrun = run;
+ image_set_gray(run);
+ }
+ code = (*fill_pgram) (dev, xrun, yrun, xl - xrun,
+ ytf - yrun, pdyx, pdyy, pdevc, lop);
+ if (code < 0)
+ return code;
+ yrun = ytf;
+ xrun = xl;
+ if (psrc > stop) {
+ --psrc;
+ break;
+ }
+ run = psrc[-1];
+ dda_next(next.x);
+ dda_next(next.y); /* harmless if no skew */
+ }
+ }
+ /* Fill the last run. */
+ last:if (stop < endp && (*stop || !masked)) {
+ if (!masked) {
+ image_set_gray(*stop);
+ }
+ dda_advance(next.x, endp - stop);
+ dda_advance(next.y, endp - stop);
+ code = (*fill_pgram) (dev, xrun, yrun, xl - xrun,
+ ytf - yrun, pdyx, pdyy, pdevc, lop);
+ }
+#undef xl
+#undef ytf
+ } else { /* fast loop *//* No skew, and not imagemask with a halftone. */
+ const fixed adjust = penum->adjust;
+ const fixed dxx = penum->dxx;
+ fixed xa = (dxx >= 0 ? adjust : -adjust);
+ const int yt = penum->yci, iht = penum->hci;
+
+ dev_proc_fill_rectangle((*fill_proc)) =
+ dev_proc(dev, fill_rectangle);
+ dev_proc_strip_tile_rectangle((*tile_proc)) =
+ dev_proc(dev, strip_tile_rectangle);
+ dev_proc_copy_mono((*copy_mono_proc)) =
+ dev_proc(dev, copy_mono);
+ /*
+ * If each pixel is likely to fit in a single halftone tile,
+ * determine that now (tile_offset = offset of row within tile).
+ * Don't do this for band devices; they handle halftone fills
+ * more efficiently than copy_mono.
+ */
+ int bstart;
+ int phase_x;
+ int tile_offset =
+ ((*dev_proc(dev, get_band)) (dev, yt, &bstart) == 0 ?
+ gx_check_tile_size(pis,
+ fixed2int_ceiling(any_abs(dxx) + (xa << 1)),
+ yt, iht, gs_color_select_source, &phase_x) :
+ -1);
+ int xmin = fixed2int_pixround(penum->clip_outer.p.x);
+ int xmax = fixed2int_pixround(penum->clip_outer.q.x);
+
+#define xl dda_current(next.x)
+ /* Fold the adjustment into xrun and xl, */
+ /* including the +0.5-epsilon for rounding. */
+ xrun = xrun - xa + (fixed_half - fixed_epsilon);
+ dda_translate(next.x, xa + (fixed_half - fixed_epsilon));
+ xa <<= 1;
+ /* Calculate multiples of the DDA step. */
+ dxx2 = next.x.step;
+ dda_step_add(dxx2, next.x.step);
+ dxx3 = dxx2;
+ dda_step_add(dxx3, next.x.step);
+ dxx4 = dxx3;
+ dda_step_add(dxx4, next.x.step);
+ if (stop > psrc)
+ for (;;) { /* Skip large constant regions quickly, */
+ /* but don't slow down transitions too much. */
+ skf:if (psrc[0] == run) {
+ if (psrc[1] == run) {
+ if (psrc[2] == run) {
+ if (psrc[3] == run) {
+ psrc += 4;
+ dda_state_next(next.x.state, dxx4);
+ goto skf;
+ } else {
+ psrc += 4;
+ dda_state_next(next.x.state, dxx3);
+ }
+ } else {
+ psrc += 3;
+ dda_state_next(next.x.state, dxx2);
+ }
+ } else {
+ psrc += 2;
+ dda_next(next.x);
+ }
+ } else
+ psrc++;
+ { /* Now fill the region between xrun and xl. */
+ int xi = fixed2int_var(xrun);
+ int wi = fixed2int_var(xl) - xi;
+ int xei, tsx;
+ const gx_strip_bitmap *tile;
+
+ if (wi <= 0) {
+ if (wi == 0)
+ goto mt;
+ xi += wi, wi = -wi;
+ }
+ if ((xei = xi + wi) > xmax || xi < xmin) { /* Do X clipping */
+ if (xi < xmin)
+ wi -= xmin - xi, xi = xmin;
+ if (xei > xmax)
+ wi -= xei - xmax;
+ if (wi <= 0)
+ goto mt;
+ }
+ switch (run) {
+ case 0:
+ if (masked)
+ goto mt;
+ if (!color_is_pure(&penum->icolor0))
+ goto ht;
+ code = (*fill_proc) (dev, xi, yt, wi, iht,
+ penum->icolor0.colors.pure);
+ break;
+ case 255: /* just for speed */
+ if (!color_is_pure(&penum->icolor1))
+ goto ht;
+ code = (*fill_proc) (dev, xi, yt, wi, iht,
+ penum->icolor1.colors.pure);
+ break;
+ default:
+ ht: /* Use halftone if needed */
+ if (run != htrun) {
+ image_set_gray(run);
+ htrun = run;
+ }
+ /* We open-code gx_fill_rectangle, */
+ /* because we've done some of the work for */
+ /* halftone tiles in advance. */
+ if (color_is_pure(pdevc)) {
+ code = (*fill_proc) (dev, xi, yt, wi, iht,
+ pdevc->colors.pure);
+ } else if (!color_is_binary_halftone(pdevc)) {
+ code =
+ gx_fill_rectangle_device_rop(xi, yt, wi, iht,
+ pdevc, dev, lop);
+ } else if (tile_offset >= 0 &&
+ (tile = &pdevc->colors.binary.b_tile->tiles,
+ (tsx = (xi + phase_x) % tile->rep_width) + wi <= tile->size.x)
+ ) { /* The pixel(s) fit(s) in a single (binary) tile. */
+ byte *row = tile->data + tile_offset;
+
+ code = (*copy_mono_proc)
+ (dev, row, tsx, tile->raster, gx_no_bitmap_id,
+ xi, yt, wi, iht,
+ pdevc->colors.binary.color[0],
+ pdevc->colors.binary.color[1]);
+ } else {
+ code = (*tile_proc) (dev,
+ &pdevc->colors.binary.b_tile->tiles,
+ xi, yt, wi, iht,
+ pdevc->colors.binary.color[0],
+ pdevc->colors.binary.color[1],
+ pdevc->phase.x, pdevc->phase.y);
+ }
+ }
+ if (code < 0)
+ return code;
+ mt:xrun = xl - xa; /* original xa << 1 */
+ if (psrc > stop) {
+ --psrc;
+ break;
+ }
+ run = psrc[-1];
+ }
+ dda_next(next.x);
+ }
+ /* Fill the last run. */
+ if (*stop != 0 || !masked) {
+ int xi = fixed2int_var(xrun);
+ int wi, xei;
+
+ dda_advance(next.x, endp - stop);
+ wi = fixed2int_var(xl) - xi;
+ if (wi <= 0) {
+ if (wi == 0)
+ goto lmt;
+ xi += wi, wi = -wi;
+ }
+ if ((xei = xi + wi) > xmax || xi < xmin) { /* Do X clipping */
+ if (xi < xmin)
+ wi -= xmin - xi, xi = xmin;
+ if (xei > xmax)
+ wi -= xei - xmax;
+ if (wi <= 0)
+ goto lmt;
+ }
+ image_set_gray(*stop);
+ code = gx_fill_rectangle_device_rop(xi, yt, wi, iht,
+ pdevc, dev, lop);
+ lmt:;
+ }
+ }
+#undef xl
+ return (code < 0 ? code : 1);
+}
diff --git a/gs/src/gxiscale.c b/gs/src/gxiscale.c
new file mode 100644
index 000000000..7d3846f38
--- /dev/null
+++ b/gs/src/gxiscale.c
@@ -0,0 +1,243 @@
+/* Copyright (C) 1996, 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gxiscale.c */
+/* Interpolated image procedures */
+#include "gx.h"
+#include "math_.h"
+#include "memory_.h"
+#include "gpcheck.h"
+#include "gserrors.h"
+#include "gxfixed.h"
+#include "gxfrac.h"
+#include "gxarith.h"
+#include "gxmatrix.h"
+#include "gsccolor.h"
+#include "gspaint.h"
+#include "gxdevice.h"
+#include "gxcmap.h"
+#include "gxdcolor.h"
+#include "gxistate.h"
+#include "gzpath.h"
+#include "gxdevmem.h"
+#include "gxcpath.h"
+#include "gximage.h"
+
+/* ------ Strategy procedure ------ */
+
+/* If we're interpolating, use special logic. */
+private irender_proc(image_render_interpolate);
+private irender_proc_t
+image_strategy_interpolate(gx_image_enum * penum)
+{
+ const gs_imager_state *pis = penum->pis;
+ gs_memory_t *mem = penum->memory;
+ stream_IScale_state iss;
+ stream_IScale_state *pss;
+ byte *line;
+ const gs_color_space *pcs = penum->pcs;
+ const gs_color_space *pccs;
+ gs_point dst_xy;
+
+ if (!penum->interpolate)
+ return 0;
+ if (penum->posture != image_portrait || penum->masked ||
+ penum->alpha
+ ) {
+ /* We can't handle these cases yet. Punt. */
+ penum->interpolate = false;
+ return 0;
+ }
+ iss.memory = mem;
+ /* Non-ANSI compilers require the following casts: */
+ gs_distance_transform((float)penum->rect.w, (float)penum->rect.h,
+ &penum->matrix, &dst_xy);
+ if (penum->bps <= 8 && penum->device_color) {
+ iss.BitsPerComponentIn = 8;
+ iss.MaxValueIn = 0xff;
+ } else {
+ iss.BitsPerComponentIn = sizeof(frac) * 8;
+ iss.MaxValueIn = frac_1;
+ }
+ iss.BitsPerComponentOut = sizeof(frac) * 8;
+ iss.MaxValueOut = frac_1;
+ iss.WidthOut = (int)ceil(fabs(dst_xy.x));
+ iss.HeightOut = (int)ceil(fabs(dst_xy.y));
+ iss.WidthIn = penum->rect.w;
+ iss.HeightIn = penum->rect.h;
+ pccs = cs_concrete_space(pcs, pis);
+ iss.Colors = cs_num_components(pccs);
+ /* Allocate a buffer for one source/destination line. */
+ {
+ uint in_size =
+ iss.WidthIn * iss.Colors * (iss.BitsPerComponentIn / 8);
+ uint out_size =
+ iss.WidthOut * iss.Colors *
+ max(iss.BitsPerComponentOut / 8, sizeof(gx_color_index));
+
+ line = gs_alloc_bytes(mem, max(in_size, out_size),
+ "image scale src line");
+ }
+ pss = gs_alloc_struct(mem, stream_IScale_state,
+ &st_IScale_state, "image scale state");
+ if (line == 0 || pss == 0 ||
+ (*pss = iss,
+ (*s_IScale_template.init) ((stream_state *) pss) < 0)
+ ) {
+ gs_free_object(mem, pss, "image scale state");
+ gs_free_object(mem, line, "image scale src line");
+ /* Try again without interpolation. */
+ penum->interpolate = false;
+ return 0;
+ }
+ penum->line = line;
+ penum->scaler = pss;
+ penum->line_xy = 0;
+ penum->xyi.x = fixed2int_pixround(dda_current(penum->dda.pixel0.x));
+ penum->xyi.y = fixed2int_pixround(dda_current(penum->dda.pixel0.y));
+ if_debug0('b', "[b]render=interpolate\n");
+ return image_render_interpolate;
+}
+
+void
+gs_gxiscale_init(gs_memory_t * mem)
+{
+ image_strategies.interpolate = image_strategy_interpolate;
+}
+
+/* ------ Rendering for interpolated images ------ */
+
+private int
+image_render_interpolate(gx_image_enum * penum, const byte * buffer,
+ int data_x, uint iw, int h, gx_device * dev)
+{
+ stream_IScale_state *pss = penum->scaler;
+ const gs_imager_state *pis = penum->pis;
+ const gs_color_space *pcs = penum->pcs;
+ gs_logical_operation_t lop = penum->log_op;
+ int c = pss->Colors;
+ stream_cursor_read r;
+ stream_cursor_write w;
+
+ if (h != 0) {
+ /* Convert the unpacked data to concrete values in */
+ /* the source buffer. */
+ uint row_size = pss->WidthIn * c * pss->sizeofPixelIn;
+ const byte *bdata = buffer + data_x * c * pss->sizeofPixelIn;
+
+ if (pss->sizeofPixelIn == 1) {
+ /* Easy case: 8-bit device color values. */
+ r.ptr = bdata - 1;
+ } else {
+ /* Messy case: concretize each sample. */
+ int bps = penum->bps;
+ int dc = penum->spp;
+ const byte *pdata = bdata;
+ frac *psrc = (frac *) penum->line;
+ gs_client_color cc;
+ int i;
+
+ r.ptr = (byte *) psrc - 1;
+ for (i = 0; i < pss->WidthIn; i++, psrc += c) {
+ int j;
+
+ if (bps <= 8)
+ for (j = 0; j < dc; ++pdata, ++j) {
+ decode_sample(*pdata, cc, j);
+ } else /* bps == 12 */
+ for (j = 0; j < dc; pdata += sizeof(frac), ++j) {
+ decode_frac(*(const frac *)pdata, cc, j);
+ }
+ (*pcs->type->concretize_color) (&cc, pcs, psrc,
+ pis);
+ }
+ }
+ r.limit = r.ptr + row_size;
+ } else /* h == 0 */
+ r.ptr = 0, r.limit = 0;
+
+ /*
+ * Process input and/or collect output. By construction, the pixels are
+ * 1-for-1 with the device, but the Y coordinate might be inverted.
+ */
+
+ {
+ int xo = penum->xyi.x;
+ int yo = penum->xyi.y;
+ int width = pss->WidthOut;
+ int dy;
+ const gs_color_space *pconcs = cs_concrete_space(pcs, pis);
+ int bpp = dev->color_info.depth;
+ uint raster = bitmap_raster(width * bpp);
+
+ if (penum->matrix.yy > 0)
+ dy = 1;
+ else
+ dy = -1, yo--;
+ for (;;) {
+ int ry = yo + penum->line_xy * dy;
+ int x;
+ const frac *psrc;
+ gx_device_color devc;
+ int code;
+
+ declare_line_accum(penum->line, bpp, xo);
+
+ w.limit = penum->line + width * c *
+ sizeof(gx_color_index) - 1;
+ w.ptr = w.limit - width * c *
+ (sizeof(gx_color_index) - pss->sizeofPixelOut);
+ psrc = (const frac *)(w.ptr + 1);
+ code = (*s_IScale_template.process)
+ ((stream_state *) pss, &r, &w, h == 0);
+ if (code < 0 && code != EOFC)
+ return_error(gs_error_ioerror);
+ if (w.ptr == w.limit) {
+ for (x = xo; x < xo + width; x++, psrc += c) {
+ (*pconcs->type->remap_concrete_color)
+ (psrc, &devc, pis, dev,
+ gs_color_select_source);
+ if (color_is_pure(&devc)) {
+ /* Just pack colors into a scan line. */
+ gx_color_index color = devc.colors.pure;
+
+ line_accum(color, bpp);
+ } else {
+ int rcode;
+
+ line_accum_copy(dev, penum->line, bpp,
+ xo, x, raster, ry);
+ rcode = gx_fill_rectangle_device_rop(x, ry,
+ 1, 1, &devc, dev, lop);
+ if (rcode < 0)
+ return rcode;
+ line_accum_skip(bpp);
+ l_xprev = x + 1;
+ }
+ }
+ line_accum_copy(dev, penum->line, bpp,
+ xo, x, raster, ry);
+ penum->line_xy++;
+ }
+ if ((code == 0 && r.ptr == r.limit) || code == EOFC)
+ break;
+ }
+ }
+
+ return (h == 0 ? 0 : 1);
+}
diff --git a/gs/src/gxropc.h b/gs/src/gxropc.h
new file mode 100644
index 000000000..cb3485c84
--- /dev/null
+++ b/gs/src/gxropc.h
@@ -0,0 +1,47 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gxropc.h */
+/* Internals for RasterOp compositing */
+
+#ifndef gxropc_INCLUDED
+# define gxropc_INCLUDED
+
+#include "gsropc.h"
+#include "gxcomp.h"
+
+/* Define RasterOp-compositing objects. */
+typedef struct gs_composite_rop_s {
+ gs_composite_common;
+ gs_composite_rop_params_t params;
+} gs_composite_rop_t;
+
+#define private_st_composite_rop() /* in gsropc.c */\
+ gs_private_st_ptrs1(st_composite_rop, gs_composite_rop_t,\
+ "gs_composite_rop_t", composite_rop_enum_ptrs, composite_rop_reloc_ptrs,\
+ params.texture)
+
+/*
+ * Initialize a RasterOp compositing function from parameters.
+ * We make this visible so that clients can allocate gs_composite_rop_t
+ * objects on the stack, to reduce memory manager overhead.
+ */
+void gx_init_composite_rop(P2(gs_composite_rop_t * pcte,
+ const gs_composite_rop_params_t * params));
+
+#endif /* gxropc_INCLUDED */
diff --git a/gs/src/gxshade.c b/gs/src/gxshade.c
new file mode 100644
index 000000000..3d763062c
--- /dev/null
+++ b/gs/src/gxshade.c
@@ -0,0 +1,363 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gxshade.c */
+/* Shading rendering support */
+#include "math_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsrect.h"
+#include "gxcspace.h"
+#include "gscie.h" /* requires gscspace.h */
+#include "gxdevcli.h"
+#include "gxistate.h"
+#include "gxdht.h" /* for computing # of different colors */
+#include "gxpaint.h"
+#include "gxshade.h"
+
+/* ================ Packed coordinate streams ================ */
+
+/* Forward references */
+private int cs_next_packed_value(P3(shade_coord_stream_t *, int, uint *));
+private int cs_next_array_value(P3(shade_coord_stream_t *, int, uint *));
+private int cs_next_packed_decoded(P4(shade_coord_stream_t *, int,
+ const float[2], float *));
+private int cs_next_array_decoded(P4(shade_coord_stream_t *, int,
+ const float[2], float *));
+
+/* Initialize a packed value stream. */
+void
+shade_next_init(shade_coord_stream_t * cs,
+ const gs_shading_mesh_params_t * params, const gs_imager_state * pis)
+{
+ cs->params = params;
+ cs->pctm = &pis->ctm;
+ if (data_source_is_stream(params->DataSource)) {
+ cs->s = params->DataSource.data.strm;
+ } else {
+ sread_string(&cs->ds, params->DataSource.data.str.data,
+ params->DataSource.data.str.size);
+ cs->s = &cs->ds;
+ }
+ if (data_source_is_array(params->DataSource))
+ cs->get_value = cs_next_array_value,
+ cs->get_decoded = cs_next_array_decoded;
+ else
+ cs->get_value = cs_next_packed_value,
+ cs->get_decoded = cs_next_packed_decoded;
+ cs->left = 0;
+}
+
+/* Get the next (integer) value from a packed value stream. */
+/* 1 <= num_bits <= sizeof(uint) * 8. */
+private int
+cs_next_packed_value(shade_coord_stream_t * cs, int num_bits, uint * pvalue)
+{
+ uint bits = cs->bits;
+ int left = cs->left;
+
+ if (left >= num_bits) {
+ /* We can satisfy this request with the current buffered bits. */
+ cs->left = left -= num_bits;
+ *pvalue = (bits >> left) & ((1 << num_bits) - 1);
+ return 0;
+ }
+ /* We need more bits. */
+ {
+ int needed = num_bits - left;
+ uint value = bits & ((1 << left) - 1); /* all the remaining bits */
+
+ for (; needed >= 8; needed -= 8) {
+ int b = sgetc(cs->s);
+
+ if (b < 0)
+ return_error(gs_error_rangecheck);
+ value = (value << 8) + b;
+ }
+ if (needed == 0) {
+ cs->left = 0;
+ *pvalue = value;
+ return 0;
+ } {
+ int b = sgetc(cs->s);
+
+ if (b < 0)
+ return_error(gs_error_rangecheck);
+ cs->bits = b;
+ cs->left = left = 8 - needed;
+ *pvalue = (value << needed) + (b >> left);
+ return 0;
+ }
+ }
+}
+
+/* Get the next (integer) value from an unpacked array. */
+private int
+cs_next_array_value(shade_coord_stream_t * cs, int num_bits, uint * pvalue)
+{
+ float value;
+ uint read;
+
+ if (sgets(cs->s, (byte *) & value, sizeof(float), &read) < 0 ||
+ read != sizeof(float) || value < 0 || value >= (1 << num_bits) ||
+ value != (int)value
+ )
+ return_error(gs_error_rangecheck);
+
+ *pvalue = (uint) value;
+ return 0;
+}
+
+/* Get the next decoded floating point value. */
+private int
+cs_next_packed_decoded(shade_coord_stream_t * cs, int num_bits,
+ const float decode[2], float *pvalue)
+{
+ uint value;
+ int code = next_value(cs, num_bits, &value);
+ double max_value = (double)(uint) ((1 << num_bits) - 1);
+
+ if (code < 0)
+ return code;
+ *pvalue =
+ (decode == 0 ? value / max_value :
+ decode[0] + value * (decode[1] - decode[0]) / max_value);
+ return 0;
+}
+
+/* Get the next floating point value from an array, without decoding. */
+private int
+cs_next_array_decoded(shade_coord_stream_t * cs, int num_bits,
+ const float decode[2], float *pvalue)
+{
+ float value;
+ uint read;
+
+ if (sgets(cs->s, (byte *) & value, sizeof(float), &read) < 0 ||
+ read != sizeof(float)
+ )
+ return_error(gs_error_rangecheck);
+
+ *pvalue = value;
+ return 0;
+}
+
+/* Get the next flag value. */
+/* Note that this always starts a new data byte. */
+int
+shade_next_flag(shade_coord_stream_t * cs, int BitsPerFlag)
+{
+ uint flag;
+ int code;
+
+ cs->left = 0; /* start a new byte if packed */
+ code = next_value(cs, BitsPerFlag, &flag);
+ return (code < 0 ? code : flag);
+}
+
+/* Get one or more coordinate pairs. */
+int
+shade_next_coords(shade_coord_stream_t * cs, gs_fixed_point * ppt,
+ int num_points)
+{
+ int num_bits = cs->params->BitsPerCoordinate;
+ const float *decode = cs->params->Decode;
+ int code = 0;
+ int i;
+
+ for (i = 0; i < num_points; ++i) {
+ float x, y;
+
+ if ((code = next_decoded(cs, num_bits, decode, &x)) < 0 ||
+ (code = next_decoded(cs, num_bits, decode, &y)) < 0 ||
+ (code = gs_point_transform2fixed(cs->pctm, x, y, &ppt[i])) < 0
+ )
+ break;
+ }
+ return code;
+}
+
+/* Get a color. Currently all this does is look up Indexed colors. */
+int
+shade_next_color(shade_coord_stream_t * cs, float *pc)
+{
+ const float *decode = cs->params->Decode + 4; /* skip coord decode */
+ const gs_color_space *pcs = cs->params->ColorSpace;
+ gs_color_space_index index = gs_color_space_get_index(pcs);
+ int num_bits = cs->params->BitsPerComponent;
+
+ if (index == gs_color_space_index_Indexed) {
+ uint i;
+ int code = next_value(cs, num_bits, &i);
+
+ if (code < 0)
+ return code;
+/****** DO INDEXED LOOKUP TO pc[] ******/
+ } else {
+ int i, code;
+ int ncomp = gs_color_space_num_components(pcs);
+
+ for (i = 0; i < ncomp; ++i)
+ if ((code = next_decoded(cs, num_bits, decode + i * 2, &pc[i])) < 0)
+ return code;
+ }
+ return 0;
+}
+
+/* Get the next vertex for a mesh element. */
+int
+shade_next_vertex(shade_coord_stream_t * cs, mesh_vertex_t * vertex)
+{
+ int code = shade_next_coords(cs, &vertex->p, 1);
+
+ if (code >= 0)
+ code = shade_next_color(cs, vertex->cc);
+ return code;
+}
+
+/* ================ Shading rendering ================ */
+
+/* Fill a (user space) rectangle with a shading. */
+int
+gs_shading_fill_rectangle(const gs_shading_t * psh, const gs_rect * rect,
+ gx_device * dev, gs_imager_state * pis)
+{
+ gs_rect box;
+ const gs_rect *prect;
+
+ if (psh->params.have_BBox) {
+ box = *rect;
+ rect_intersect(box, psh->params.BBox);
+ prect = &box;
+ } else {
+ prect = rect;
+ }
+ return (*psh->head.fill_rectangle) (psh, rect, dev, pis);
+}
+
+/* Initialize the common parts of the recursion state. */
+void
+shade_init_fill_state(shading_fill_state_t * pfs, const gs_shading_t * psh,
+ gx_device * dev, gs_imager_state * pis)
+{
+ const gs_color_space *pcs = psh->params.ColorSpace;
+ float max_error = pis->smoothness;
+ /*
+ * There's no point in trying to achieve smoothness beyond what
+ * the device can implement, i.e., the number of representable
+ * colors times the size of the halftone cell.
+ */
+ long num_colors =
+ max(dev->color_info.max_gray, dev->color_info.max_color) + 1;
+ const gs_range *ranges = 0;
+ int ci;
+
+ pfs->dev = dev;
+ pfs->pis = pis;
+ pfs->num_components = gs_color_space_num_components(pcs);
+top:
+ switch ( gs_color_space_get_index(pcs) )
+ {
+ case gs_color_space_index_Indexed:
+ pcs = gs_cspace_base_space(pcs);
+ goto top;
+ case gs_color_space_index_CIEDEFG:
+ ranges = pcs->params.defg->RangeDEFG.ranges;
+ break;
+ case gs_color_space_index_CIEDEF:
+ ranges = pcs->params.def->RangeDEF.ranges;
+ break;
+ case gs_color_space_index_CIEABC:
+ ranges = pcs->params.abc->RangeABC.ranges;
+ break;
+ case gs_color_space_index_CIEA:
+ ranges = &pcs->params.a->RangeA;
+ break;
+ default:
+ break;
+ }
+ if (num_colors <= 32) {
+ /****** WRONG FOR MULTI-PLANE HALFTONES ******/
+ num_colors *= pis->dev_ht->order.num_levels;
+ }
+ if (max_error < 1.0 / num_colors)
+ max_error = 1.0 / num_colors;
+ for (ci = 0; ci < pfs->num_components; ++ci)
+ pfs->cc_max_error[ci] =
+ (ranges == 0 ? max_error :
+ max_error * (ranges[ci].rmax - ranges[ci].rmin));
+}
+
+/* Transform a bounding box into device space. */
+int
+shade_bbox_transform2fixed(const gs_rect * rect, const gs_imager_state * pis,
+ gs_fixed_rect * rfixed)
+{
+ gs_rect dev_rect;
+ int code = gs_bbox_transform(rect, &ctm_only(pis), &dev_rect);
+
+ if (code >= 0) {
+ rfixed->p.x = float2fixed(dev_rect.p.x);
+ rfixed->p.y = float2fixed(dev_rect.p.y);
+ rfixed->q.x = float2fixed(dev_rect.q.x);
+ rfixed->q.y = float2fixed(dev_rect.q.y);
+ }
+ return code;
+}
+
+/* Check whether 4 colors fall within the smoothness criterion. */
+bool
+shade_colors4_converge(const gs_client_color cc[4],
+ const shading_fill_state_t * pfs)
+{
+ int ci;
+
+ for (ci = 0; ci < pfs->num_components; ++ci) {
+ float
+ c0 = cc[0].paint.values[ci], c1 = cc[1].paint.values[ci],
+ c2 = cc[2].paint.values[ci], c3 = cc[3].paint.values[ci];
+ float min01, max01, min23, max23;
+
+ if (c0 < c1)
+ min01 = c0, max01 = c1;
+ else
+ min01 = c1, max01 = c0;
+ if (c2 < c3)
+ min23 = c2, max23 = c3;
+ else
+ min23 = c3, max23 = c2;
+ if (max(max01, max23) - min(min01, min23) > pfs->cc_max_error[ci])
+ return false;
+ }
+ return true;
+}
+
+/* Fill one piece of a shading. */
+int
+shade_fill_path(const shading_fill_state_t * pfs, gx_path * ppath,
+ gx_device_color * pdevc)
+{
+ gx_fill_params params;
+
+ params.rule = -1; /* irrelevant */
+ params.adjust = pfs->pis->fill_adjust;
+ params.flatness = 0; /* irrelevant */
+ params.fill_zero_width = false;
+ return (*dev_proc(pfs->dev, fill_path)) (pfs->dev, pfs->pis, ppath,
+ &params, pdevc, NULL);
+}
diff --git a/gs/src/gxshade.h b/gs/src/gxshade.h
new file mode 100644
index 000000000..9c6798212
--- /dev/null
+++ b/gs/src/gxshade.h
@@ -0,0 +1,257 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gxshade.h */
+/* Internal definitions for shading rendering */
+
+#ifndef gxshade_INCLUDED
+# define gxshade_INCLUDED
+
+#include "gsshade.h"
+#include "gxfixed.h" /* for gxmatrix.h */
+#include "gxmatrix.h" /* for gs_matrix_fixed */
+#include "stream.h"
+
+/*
+ All shadings are defined with respect to some parameter that varies
+ continuously over some range; the shading defines a mapping from the
+ parameter values to colors and user space coordinates. Here are the
+ mappings for the 7 currently defined shading types:
+
+ Type Param space Param => color Param => User space
+ ---- ----------- -------------- -------------------
+ 1 2-D Domain Function Matrix
+ 2 1-D Domain Function + Extend perp. to Coords
+ 3 1-D Domain Function + Extend circles per Coords
+ 4,5 triangle x Gouraud interp. on Gouraud interp. on
+ 2-D in tri. Decode => corner triangle corners
+ values => Function
+ 6 patch x (u,v) Decode => bilinear Sc + Sd - Sb on each patch
+ in patch interp. on corner
+ values => Function
+ 7 see 6 see 6 Sum(i) Sum(j) Pij*Bi(u)*Bj(v)
+
+ To be able to render a portion of a shading usefully, we must be able to
+ do two things:
+
+ - Determine what range of parameter values is sufficient to cover
+ the region being filled;
+
+ - Evaluate the color at enough points to fill the region (in
+ device space).
+
+ Note that the latter may be implemented by a mix of evaluation and
+ interpolation, especially for types 3, 6, and 7 where an exact mapping
+ may be prohibitively expensive.
+
+ Except for type 3, where circles turn into ellipses, the CTM can get
+ folded into the parameter => user space mapping, since in all other
+ cases, the mapping space is closed under linear transformations of
+ the output.
+ */
+
+/* Define types and rendering procedures for the individual shadings. */
+typedef struct gs_shading_Fb_s {
+ gs_shading_head_t head;
+ gs_shading_Fb_params_t params;
+} gs_shading_Fb_t;
+
+shading_fill_rectangle_proc(gs_shading_Fb_fill_rectangle);
+typedef struct gs_shading_A_s {
+ gs_shading_head_t head;
+ gs_shading_A_params_t params;
+} gs_shading_A_t;
+
+shading_fill_rectangle_proc(gs_shading_A_fill_rectangle);
+typedef struct gs_shading_R_s {
+ gs_shading_head_t head;
+ gs_shading_R_params_t params;
+} gs_shading_R_t;
+
+shading_fill_rectangle_proc(gs_shading_R_fill_rectangle);
+typedef struct gs_shading_FfGt_s {
+ gs_shading_head_t head;
+ gs_shading_FfGt_params_t params;
+} gs_shading_FfGt_t;
+
+shading_fill_rectangle_proc(gs_shading_FfGt_fill_rectangle);
+typedef struct gs_shading_LfGt_s {
+ gs_shading_head_t head;
+ gs_shading_LfGt_params_t params;
+} gs_shading_LfGt_t;
+
+shading_fill_rectangle_proc(gs_shading_LfGt_fill_rectangle);
+typedef struct gs_shading_Cp_s {
+ gs_shading_head_t head;
+ gs_shading_Cp_params_t params;
+} gs_shading_Cp_t;
+
+shading_fill_rectangle_proc(gs_shading_Cp_fill_rectangle);
+typedef struct gs_shading_Tpp_s {
+ gs_shading_head_t head;
+ gs_shading_Tpp_params_t params;
+} gs_shading_Tpp_t;
+
+shading_fill_rectangle_proc(gs_shading_Tpp_fill_rectangle);
+
+/* We should probably get this from somewhere else.... */
+#define max_color_components 4
+
+/* Define a stream for decoding packed coordinate values. */
+typedef struct shade_coord_stream_s shade_coord_stream_t;
+struct shade_coord_stream_s {
+ stream ds; /* stream if DataSource isn't one already -- */
+ /* first for GC-ability (maybe unneeded?) */
+ stream *s; /* DataSource or &ds */
+ uint bits; /* shifted bits of current byte */
+ int left; /* # of bits left in bits */
+ const gs_shading_mesh_params_t *params;
+ const gs_matrix_fixed *pctm;
+#define next_value(cs, num_bits, pvalue)\
+ ((*(cs)->get_value)(cs, num_bits, pvalue))
+ int (*get_value) (P3(shade_coord_stream_t *, int, uint *));
+#define next_decoded(cs, num_bits, decode, pvalue)\
+ ((*(cs)->get_decoded)(cs, num_bits, decode, pvalue))
+ int (*get_decoded) (P4(shade_coord_stream_t *, int, const float[2],
+ float *));
+};
+
+/* Define one vertex of a mesh. */
+typedef struct mesh_vertex_s {
+ gs_fixed_point p;
+ float cc[max_color_components];
+} mesh_vertex_t;
+
+/* Initialize a packed value stream. */
+void shade_next_init(P3(shade_coord_stream_t * cs,
+ const gs_shading_mesh_params_t * params,
+ const gs_imager_state * pis));
+
+/* Get the next flag value. */
+int shade_next_flag(P2(shade_coord_stream_t * cs, int BitsPerFlag));
+
+/* Get one or more coordinate pairs. */
+int shade_next_coords(P3(shade_coord_stream_t * cs, gs_fixed_point * ppt,
+ int num_points));
+
+/* Get a color. Currently all this does is look up Indexed colors. */
+int shade_next_color(P2(shade_coord_stream_t * cs, float *pc));
+
+/* Get the next vertex for a mesh element. */
+int shade_next_vertex(P2(shade_coord_stream_t * cs, mesh_vertex_t * vertex));
+
+/*
+ Currently, all shading fill procedures follow the same algorithm:
+
+ - Conservatively inverse-transform the rectangle being filled to a linear
+ or rectangular range of values in the parameter space.
+
+ - Compute the color values at the extrema of the range.
+
+ - If possible, compute the parameter range corresponding to a single
+ device pixel.
+
+ - Recursively do the following, passing the parameter range and extremal
+ color values as the recursion arguments:
+
+ - If the color values are equal to within the tolerance given by the
+ smoothness in the graphics state, or if the range of parameters maps
+ to a single device pixel, fill the range with the (0) or (0,0) color.
+
+ - Otherwise, subdivide and recurse. If the parameter range is 2-D,
+ subdivide the axis with the largest color difference.
+
+ For shadings based on a function, if the function is not monotonic, the
+ smoothness test must only be applied when the parameter range extrema are
+ all interpolated from the same entries in the Function.
+
+ */
+
+/*
+ * Fill a (user space) rectangle with a shading. This is the only procedure
+ * in this file meant to be called from outside the shading machinery.
+ */
+shading_fill_rectangle_proc(gs_shading_fill_rectangle);
+
+/* Define the common structure for recursive subdivision. */
+#define shading_fill_state_common\
+ gx_device *dev;\
+ gs_imager_state *pis;\
+ int num_components; /* # of color components */\
+ float cc_max_error[max_color_components]
+typedef struct shading_fill_state_s {
+ shading_fill_state_common;
+} shading_fill_state_t;
+
+/* Initialize the common parts of the recursion state. */
+void shade_init_fill_state(P4(shading_fill_state_t * pfs,
+ const gs_shading_t * psh, gx_device * dev,
+ gs_imager_state * pis));
+
+/* Transform a bounding box into device space. */
+int shade_bbox_transform2fixed(P3(const gs_rect * rect,
+ const gs_imager_state * pis,
+ gs_fixed_rect * rfixed));
+
+/* Check whether 4 colors fall within the smoothness criterion. */
+bool shade_colors4_converge(P2(const gs_client_color cc[4],
+ const shading_fill_state_t * pfs));
+
+/* Fill one piece of a shading. */
+#ifndef gx_device_color_DEFINED
+# define gx_device_color_DEFINED
+typedef struct gx_device_color_s gx_device_color;
+
+#endif
+#ifndef gx_path_DEFINED
+# define gx_path_DEFINED
+typedef struct gx_path_s gx_path;
+
+#endif
+int shade_fill_path(P3(const shading_fill_state_t * pfs, gx_path * ppath,
+ gx_device_color * pdevc));
+
+#endif /* gxshade_INCLUDED */
+
+#if 0 /*************************************************************** */
+
+/*
+ * Here is a sketch of what will be needed to generalize Patterns for
+ * (the) new PatternType(s).
+ */
+typedef struct gs_pattern_instance_s {
+ rc_header rc; /* ?? */
+ const gs_pattern_type_t *type;
+ gs_uid XIUD; /* ?? */
+ gs_state *saved; /* ?? */
+ void *data;
+} gs_pattern_instance_t;
+typedef struct gs_pattern1_instance_data_s {
+ ...
+} gs_pattern1_instance_data_t;
+
+#define gs_pattern2_instance_data_common\
+ const gs_shading_t *shading;\
+ gx_device_color *background;\
+ const gs_color_space *color_space;\
+ gs_matrix param_to_device_matrix
+typedef struct gs_pattern2_instance_data_common_s {
+ gs_pattern2_instance_data_common;
+} gs_pattern2_instance_data_common_t;
+
+#endif /*************************************************************** */
diff --git a/gs/src/gxshade1.c b/gs/src/gxshade1.c
new file mode 100644
index 000000000..9c1b1eec9
--- /dev/null
+++ b/gs/src/gxshade1.c
@@ -0,0 +1,511 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gxshade1.c */
+/* Rendering for non-mesh shadings */
+#include "math_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsmatrix.h" /* for gscoord.h */
+#include "gscoord.h"
+#include "gspath.h"
+#include "gxcspace.h"
+#include "gxdcolor.h"
+#include "gxfarith.h"
+#include "gxfixed.h"
+#include "gxistate.h"
+#include "gxpath.h"
+#include "gxshade.h"
+
+/* ================ Utilities ================ */
+
+/* Check whether 2 colors fall within the smoothness criterion. */
+private bool
+shade_colors2_converge(const gs_client_color cc[2],
+ const shading_fill_state_t * pfs)
+{
+ int ci;
+
+ for (ci = pfs->num_components - 1; ci >= 0; --ci)
+ if (fabs(cc[1].paint.values[ci] - cc[0].paint.values[ci]) >
+ pfs->cc_max_error[ci]
+ )
+ return false;
+ return true;
+}
+
+/* Fill a user space rectangle that is also a device space rectangle. */
+private int
+shade_fill_device_rectangle(const shading_fill_state_t * pfs,
+ const gs_fixed_point * p0, const gs_fixed_point * p1, gx_device_color * pdevc)
+{
+ gs_imager_state *pis = pfs->pis;
+ fixed xmin, ymin, xmax, ymax;
+ int x, y;
+
+ if (p0->x < p1->x)
+ xmin = p0->x, xmax = p1->x;
+ else
+ xmin = p1->x, xmax = p0->x;
+ if (p0->y < p1->y)
+ ymin = p0->y, ymax = p1->y;
+ else
+ ymin = p1->y, ymax = p0->y;
+/****** CONFINE TO rect ******/
+/****** NOT QUITE RIGHT FOR PIXROUND ******/
+ xmin -= pis->fill_adjust.x;
+ xmax += pis->fill_adjust.x;
+ ymin -= pis->fill_adjust.y;
+ ymax += pis->fill_adjust.y;
+ x = fixed2int_var(xmin);
+ y = fixed2int_var(ymin);
+ return
+ gx_fill_rectangle_device_rop(x, y,
+ fixed2int_var(xmax) - x,
+ fixed2int_var(ymax) - y,
+ pdevc, pfs->dev, pis->log_op);
+}
+
+/* ================ Specific shadings ================ */
+
+/* ---------------- Function-based shading ---------------- */
+
+typedef struct Fb_fill_state_s {
+ shading_fill_state_common;
+ const gs_shading_Fb_t *psh;
+ gs_matrix_fixed ptm; /* parameter space -> device space */
+ gs_client_color cc[4];
+} Fb_fill_state_t;
+
+private int
+Fb_fill_region(Fb_fill_state_t * pfs, floatp x0, floatp y0, floatp x1,
+ floatp y1)
+{
+ const gs_shading_Fb_t *psh = pfs->psh;
+ gs_imager_state *pis = pfs->pis;
+
+ top:if (!shade_colors4_converge(pfs->cc,
+ (const shading_fill_state_t *)pfs)
+ ) {
+ /*
+ * The colors don't converge. Does the region color more than
+ * a single pixel?
+ */
+ gs_rect region;
+
+ region.p.x = x0, region.p.y = y0;
+ region.q.x = x1, region.q.y = y1;
+ gs_bbox_transform(&region, (const gs_matrix *)&pfs->ptm, &region);
+ if (region.q.x - region.p.x >= 1 || region.q.y - region.p.y >= 1)
+ goto recur;
+ {
+ /*
+ * More precisely, does the bounding box of the region,
+ * taking fill adjustment into account, span more than 1
+ * pixel center in either X or Y?
+ */
+ fixed ax = pis->fill_adjust.x;
+ int nx =
+ fixed2int_pixround(float2fixed(region.q.x) + ax) -
+ fixed2int_pixround(float2fixed(region.p.x) - ax);
+ fixed ay = pis->fill_adjust.y;
+ int ny =
+ fixed2int_pixround(float2fixed(region.q.y) + ay) -
+ fixed2int_pixround(float2fixed(region.p.y) - ay);
+
+ if ((nx > 1 && ny != 0) || (ny > 1 && nx != 0))
+ goto recur;
+ }
+ /* We could do the 1-pixel case a lot faster! */
+ }
+ /* Fill the region with the color. */
+ {
+ gx_device_color dev_color;
+ const gs_color_space *pcs = psh->params.ColorSpace;
+ gs_fixed_point pts[4];
+ int code;
+
+ if_debug0('|', "[|]... filling region\n");
+ (*pcs->type->restrict_color) (&pfs->cc[0], pcs);
+ (*pcs->type->remap_color) (&pfs->cc[0], pcs, &dev_color, pis,
+ pfs->dev, gs_color_select_texture);
+ gs_point_transform2fixed(&pfs->ptm, x0, y0, &pts[0]);
+ gs_point_transform2fixed(&pfs->ptm, x1, y1, &pts[2]);
+ if (is_xxyy(&pfs->ptm) || is_xyyx(&pfs->ptm)) {
+ code =
+ shade_fill_device_rectangle((const shading_fill_state_t *)pfs,
+ &pts[0], &pts[2], &dev_color);
+ } else {
+ gx_path *ppath = gx_path_alloc(pis->memory, "Fb_fill");
+
+ gs_point_transform2fixed(&pfs->ptm, x1, y0, &pts[1]);
+ gs_point_transform2fixed(&pfs->ptm, x0, y1, &pts[3]);
+ gx_path_add_point(ppath, pts[0].x, pts[0].y);
+ gx_path_add_lines(ppath, pts + 1, 3);
+ code = shade_fill_path((const shading_fill_state_t *)pfs,
+ ppath, &dev_color);
+ gx_path_free(ppath, "Fb_fill");
+ }
+ return code;
+ }
+
+ /*
+ * No luck. Subdivide the region and recur.
+ *
+ * We should subdivide on the axis that has the largest color
+ * discrepancy, but for now we subdivide on the axis with the
+ * largest coordinate difference.
+ */
+ recur:{
+ gs_client_color cc[4];
+ gs_function_t *pfn = psh->params.Function;
+ float v[2];
+
+ if (y1 - y0 > x1 - x0) {
+ /* Subdivide in Y. */
+ float ym = (y0 + y1) * 0.5;
+
+ if_debug1('|', "[|]dividing at y=%g\n", ym);
+ v[1] = ym;
+ v[0] = x0;
+ gs_function_evaluate(pfn, v, cc[0].paint.values);
+ v[0] = x1;
+ gs_function_evaluate(pfn, v, cc[1].paint.values);
+ cc[2].paint = pfs->cc[2].paint;
+ cc[3].paint = pfs->cc[3].paint;
+ pfs->cc[2].paint = cc[0].paint;
+ pfs->cc[3].paint = cc[1].paint;
+ Fb_fill_region(pfs, x0, y0, x1, ym);
+ y0 = ym;
+ } else {
+ /* Subdivide in X. */
+ float xm = (x0 + x1) * 0.5;
+
+ if_debug1('|', "[|]dividing at x=%g\n", xm);
+ v[0] = xm;
+ v[1] = y0;
+ gs_function_evaluate(pfn, v, cc[0].paint.values);
+ v[1] = y1;
+ gs_function_evaluate(pfn, v, cc[2].paint.values);
+ cc[1].paint = pfs->cc[1].paint;
+ cc[3].paint = pfs->cc[3].paint;
+ pfs->cc[1].paint = cc[0].paint;
+ pfs->cc[3].paint = cc[2].paint;
+ Fb_fill_region(pfs, x0, y0, xm, y1);
+ x0 = xm;
+ }
+ pfs->cc[0].paint = cc[0].paint;
+ pfs->cc[1].paint = cc[1].paint;
+ pfs->cc[2].paint = cc[2].paint;
+ pfs->cc[3].paint = cc[3].paint;
+ }
+ goto top;
+}
+
+int
+gs_shading_Fb_fill_rectangle(const gs_shading_t * psh0, const gs_rect * rect,
+ gx_device * dev, gs_imager_state * pis)
+{
+ const gs_shading_Fb_t *psh = (const gs_shading_Fb_t *)psh0;
+ gs_matrix save_ctm;
+ int xi, yi, code;
+ float x[2], y[2];
+ Fb_fill_state_t state;
+
+ shade_init_fill_state((shading_fill_state_t *) & state, psh0, dev, pis);
+ state.psh = psh;
+/****** HACK ******/
+ gs_currentmatrix((gs_state *) pis, &save_ctm);
+ gs_concat((gs_state *) pis, &psh->params.Matrix);
+ state.ptm = pis->ctm;
+ /* Compute the parameter X and Y ranges. */
+ {
+ gs_rect pbox;
+
+ gs_bbox_transform_inverse(rect, &psh->params.Matrix, &pbox);
+ x[0] = max(pbox.p.x, psh->params.Domain[0]);
+ x[1] = min(pbox.q.x, psh->params.Domain[1]);
+ y[0] = max(pbox.p.y, psh->params.Domain[2]);
+ y[1] = min(pbox.q.y, psh->params.Domain[3]);
+ }
+ for (xi = 0; xi < 2; ++xi)
+ for (yi = 0; yi < 2; ++yi) {
+ float v[2];
+
+ v[0] = x[xi], v[1] = y[yi];
+ gs_function_evaluate(psh->params.Function, v,
+ state.cc[yi * 2 + xi].paint.values);
+ }
+ code = Fb_fill_region(&state, x[0], y[0], x[1], y[1]);
+/****** HACK ******/
+ gs_setmatrix((gs_state *) pis, &save_ctm);
+ return code;
+}
+
+/* ---------------- Axial shading ---------------- */
+
+typedef struct A_fill_state_s {
+ shading_fill_state_common;
+ const gs_shading_A_t *psh;
+ gs_rect rect;
+ gs_client_color cc[2];
+ gs_point delta;
+ double length, dd;
+} A_fill_state_t;
+
+/* Note t0 and t1 vary over [0..1], not the Domain. */
+private int
+A_fill_region(A_fill_state_t * pfs, floatp t0, floatp t1)
+{
+ const gs_shading_A_t *psh = pfs->psh;
+
+ top:if (!shade_colors2_converge(pfs->cc,
+ (const shading_fill_state_t *)pfs)
+ ) {
+ /*
+ * The colors don't converge. Is the stripe less than 1 pixel wide?
+ */
+ if (pfs->length * (t1 - t0) > 1)
+ goto recur;
+ /* We could do the 1-pixel case a lot faster! */
+ }
+ /* Fill the region with the color. */
+ {
+ gx_device_color dev_color;
+ const gs_color_space *pcs = psh->params.ColorSpace;
+ gs_imager_state *pis = pfs->pis;
+ double
+ x0 = psh->params.Coords[0] + pfs->delta.x * t0, y0 = psh->params.Coords[1] + pfs->delta.y * t0;
+ double
+ x1 = psh->params.Coords[0] + pfs->delta.x * t1, y1 = psh->params.Coords[1] + pfs->delta.y * t1;
+ gs_fixed_point pts[4];
+ int code;
+
+ (*pcs->type->restrict_color) (&pfs->cc[0], pcs);
+ (*pcs->type->remap_color) (&pfs->cc[0], pcs, &dev_color, pis,
+ pfs->dev, gs_color_select_texture);
+ if (x0 == x1) {
+ /* Stripe is horizontal. */
+ x0 = pfs->rect.p.x;
+ x1 = pfs->rect.q.x;
+ } else if (y0 == y1) {
+ /* Stripe is vertical. */
+ y0 = pfs->rect.p.y;
+ y1 = pfs->rect.q.y;
+ } else {
+ /*
+ * Stripe is neither horizontal nor vertical.
+ * Extend it to the edges of the rectangle.
+ */
+ gx_path *ppath = gx_path_alloc(pis->memory, "A_fill");
+
+ /*
+ * Figuring out how far to extend the stripe is hard,
+ * since one or both of x0/y0 and x1/y1 may lie outside
+ * the rectangle but part of the stripe may lie inside.
+ * For now, we do something simple and ****** WRONG ******.
+ */
+ double dist = max(pfs->rect.q.x - pfs->rect.p.x,
+ pfs->rect.q.y - pfs->rect.p.y);
+ double denom = hypot(pfs->delta.x, pfs->delta.y);
+ double dx = dist * pfs->delta.y / denom, dy = -dist * pfs->delta.x / denom;
+
+ if_debug6('|', "[|]p0=(%g,%g), p1=(%g,%g), dxy=(%g,%g)\n",
+ x0, y0, x1, y1, dx, dy);
+ gs_point_transform2fixed(&pis->ctm, x0 - dx, y0 - dy, &pts[0]);
+ gs_point_transform2fixed(&pis->ctm, x0 + dx, y0 + dy, &pts[1]);
+ gs_point_transform2fixed(&pis->ctm, x1 + dx, y1 + dy, &pts[2]);
+ gs_point_transform2fixed(&pis->ctm, x1 - dx, y1 - dy, &pts[3]);
+ gx_path_add_point(ppath, pts[0].x, pts[0].y);
+ gx_path_add_lines(ppath, pts + 1, 3);
+ code = shade_fill_path((const shading_fill_state_t *)pfs,
+ ppath, &dev_color);
+ gx_path_free(ppath, "A_fill");
+ }
+ /* Stripe is horizontal or vertical. */
+ gs_point_transform2fixed(&pis->ctm, x0, y0, &pts[0]);
+ gs_point_transform2fixed(&pis->ctm, x1, y1, &pts[1]);
+ return
+ shade_fill_device_rectangle((const shading_fill_state_t *)pfs,
+ &pts[0], &pts[1], &dev_color);
+ }
+
+ /*
+ * No luck. Subdivide the interval and recur.
+ */
+ recur:{
+ gs_client_color ccm, cc1;
+ gs_function_t *pfn = psh->params.Function;
+ float tm = (t0 + t1) * 0.5;
+ float dm = tm * pfs->dd + psh->params.Domain[0];
+
+ cc1.paint = pfs->cc[1].paint;
+ gs_function_evaluate(pfn, &dm, ccm.paint.values);
+ pfs->cc[1].paint = ccm.paint;
+ A_fill_region(pfs, t0, tm);
+ pfs->cc[0].paint = ccm.paint;
+ pfs->cc[1].paint = cc1.paint;
+ t0 = tm;
+ goto top;
+ }
+ return 0;
+}
+
+int
+gs_shading_A_fill_rectangle(const gs_shading_t * psh0, const gs_rect * rect,
+ gx_device * dev, gs_imager_state * pis)
+{
+ const gs_shading_A_t *const psh = (const gs_shading_A_t *)psh0;
+ A_fill_state_t state;
+ float d0 = psh->params.Domain[0], d1 = psh->params.Domain[1], dd = d1 - d0;
+ float t[2];
+ gs_point dist;
+ int i;
+
+ shade_init_fill_state((shading_fill_state_t *) & state, psh0, dev, pis);
+ state.psh = psh;
+ state.rect = *rect;
+ /* Compute the parameter range. */
+ t[0] = d0;
+ t[1] = d1;
+/****** INTERSECT Domain WITH rect ******/
+ for (i = 0; i < 2; ++i)
+ gs_function_evaluate(psh->params.Function, &t[i],
+ state.cc[i].paint.values);
+ state.delta.x = psh->params.Coords[2] - psh->params.Coords[0];
+ state.delta.y = psh->params.Coords[3] - psh->params.Coords[1];
+ gs_distance_transform(state.delta.x, state.delta.y, &ctm_only(pis),
+ &dist);
+ state.length = hypot(dist.x, dist.y); /* device space line length */
+ state.dd = dd;
+/****** DOESN'T HANDLE Extend ******/
+ return A_fill_region(&state, (t[0] - d0) / dd, (t[1] - d0) / dd);
+}
+
+/* ---------------- Radial shading ---------------- */
+
+typedef struct R_fill_state_s {
+ shading_fill_state_common;
+ const gs_shading_R_t *psh;
+ gs_rect rect;
+ gs_client_color cc[2];
+ gs_point delta;
+ double dr, width, dd;
+} R_fill_state_t;
+
+/* Note t0 and t1 vary over [0..1], not the Domain. */
+private int
+R_fill_region(R_fill_state_t * pfs, floatp t0, floatp t1)
+{
+ const gs_shading_R_t *psh = pfs->psh;
+
+ top:if (!shade_colors2_converge(pfs->cc,
+ (const shading_fill_state_t *)pfs)
+ ) {
+ /*
+ * The colors don't converge. Is the annulus less than 1 pixel wide?
+ */
+ if (pfs->width * (t1 - t0) > 1)
+ goto recur;
+ /* We could do the 1-pixel case a lot faster! */
+ }
+ /* Fill the region with the color. */
+ {
+ gx_device_color dev_color;
+ const gs_color_space *pcs = psh->params.ColorSpace;
+ gs_imager_state *pis = pfs->pis;
+ double
+ x0 = psh->params.Coords[0] + pfs->delta.x * t0, y0 = psh->params.Coords[1] + pfs->delta.y * t0,
+ r0 = psh->params.Coords[2] + pfs->dr * t0;
+ double
+ x1 = psh->params.Coords[0] + pfs->delta.x * t1, y1 = psh->params.Coords[1] + pfs->delta.y * t1,
+ r1 = psh->params.Coords[2] + pfs->dr * t1;
+ gx_path *ppath = gx_path_alloc(pis->memory, "R_fill");
+ int code;
+
+ (*pcs->type->restrict_color) (&pfs->cc[0], pcs);
+ (*pcs->type->remap_color) (&pfs->cc[0], pcs, &dev_color, pis,
+ pfs->dev, gs_color_select_texture);
+ if ((code = gs_imager_arc_add(ppath, pis, false, x0, y0, r0,
+ 0.0, 360.0, false)) >= 0 &&
+ (code = gs_imager_arc_add(ppath, pis, true, x1, y1, r1,
+ 0.0, 360.0, false)) >= 0
+ ) {
+ code = shade_fill_path((const shading_fill_state_t *)pfs,
+ ppath, &dev_color);
+ }
+ gx_path_free(ppath, "R_fill");
+ return code;
+ }
+
+ /*
+ * No luck. Subdivide the interval and recur.
+ */
+ recur:{
+ gs_client_color ccm, cc1;
+ gs_function_t *pfn = psh->params.Function;
+ float tm = (t0 + t1) * 0.5;
+ float dm = tm * pfs->dd + psh->params.Domain[0];
+
+ cc1.paint = pfs->cc[1].paint;
+ gs_function_evaluate(pfn, &dm, ccm.paint.values);
+ pfs->cc[1].paint = ccm.paint;
+ R_fill_region(pfs, t0, tm);
+ pfs->cc[0].paint = ccm.paint;
+ pfs->cc[1].paint = cc1.paint;
+ t0 = tm;
+ goto top;
+ }
+ return 0;
+}
+
+int
+gs_shading_R_fill_rectangle(const gs_shading_t * psh0, const gs_rect * rect,
+ gx_device * dev, gs_imager_state * pis)
+{
+ const gs_shading_R_t *const psh = (const gs_shading_R_t *)psh0;
+ R_fill_state_t state;
+ float d0 = psh->params.Domain[0], d1 = psh->params.Domain[1], dd = d1 - d0;
+ float t[2];
+ int i;
+
+ shade_init_fill_state((shading_fill_state_t *) & state, psh0, dev, pis);
+ state.psh = psh;
+ state.rect = *rect;
+ /* Compute the parameter range. */
+ t[0] = d0;
+ t[1] = d1;
+/****** INTERSECT Domain WITH rect ******/
+ for (i = 0; i < 2; ++i)
+ gs_function_evaluate(psh->params.Function, &t[i],
+ state.cc[i].paint.values);
+ state.delta.x = psh->params.Coords[3] - psh->params.Coords[0];
+ state.delta.y = psh->params.Coords[4] - psh->params.Coords[1];
+ state.dr = psh->params.Coords[5] - psh->params.Coords[2];
+ /*
+ * Compute the annulus width in its thickest direction. This is
+ * only used for a conservative check, so it can be pretty crude
+ * (and it is!).
+ */
+ state.width =
+ (fabs(pis->ctm.xx) + fabs(pis->ctm.xy) + fabs(pis->ctm.yx) +
+ fabs(pis->ctm.yy)) * fabs(state.dr);
+ state.dd = dd;
+/****** DOESN'T HANDLE Extend ******/
+ return R_fill_region(&state, (t[0] - d0) / dd, (t[1] - d0) / dd);
+}
diff --git a/gs/src/gxshade4.c b/gs/src/gxshade4.c
new file mode 100644
index 000000000..4e63aa37d
--- /dev/null
+++ b/gs/src/gxshade4.c
@@ -0,0 +1,289 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gxshade4.c */
+/* Rendering for Gouraud triangle shadings */
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsmatrix.h" /* for gscoord.h */
+#include "gscoord.h"
+#include "gxcspace.h"
+#include "gxdcolor.h"
+#include "gxdevcli.h"
+#include "gxistate.h"
+#include "gxpath.h"
+#include "gxshade.h"
+#include "gxshade4.h"
+
+/* ---------------- Triangle mesh filling ---------------- */
+
+/* Initialize the fill state for triangle shading. */
+void
+mesh_init_fill_state(mesh_fill_state_t * pfs, const gs_shading_mesh_t * psh,
+ const gs_rect * rect, gx_device * dev, gs_imager_state * pis)
+{
+ shade_init_fill_state((shading_fill_state_t *) pfs,
+ (const gs_shading_t *)psh, dev, pis);
+ pfs->pshm = psh;
+ shade_bbox_transform2fixed(rect, pis, &pfs->rect);
+}
+
+#define SET_MIN_MAX_3(vmin, vmax, a, b, c)\
+ if ( a < b ) vmin = a, vmax = b; else vmin = b, vmax = a;\
+ if ( c < vmin ) vmin = c; else if ( c > vmax ) vmax = c
+
+private int
+mesh_fill_region(const mesh_fill_state_t * pfs, fixed xa, fixed ya, fixed xb,
+ fixed yb, fixed xc, fixed yc, const gs_client_color cc[3], bool check)
+{
+ const gs_shading_mesh_t *psh = pfs->pshm;
+ int ci;
+
+ /*
+ * Fill the triangle with vertices at x/ya, x/yb, and x/yc
+ * with color cc[0].
+ * If check is true, check for whether the triangle is entirely
+ * inside the rectangle, entirely outside, or partly inside;
+ * if check is false, assume the triangle is entirely inside.
+ */
+ if (check) {
+ fixed xmin, ymin, xmax, ymax;
+
+ SET_MIN_MAX_3(xmin, xmax, xa, xb, xc);
+ SET_MIN_MAX_3(ymin, ymax, ya, yb, yc);
+ if (xmin >= pfs->rect.p.x && xmax <= pfs->rect.q.x &&
+ ymin >= pfs->rect.p.y && ymax <= pfs->rect.q.y
+ ) {
+ /* The triangle is entirely inside the rectangle. */
+ check = false;
+ } else if (xmin >= pfs->rect.q.x || xmax <= pfs->rect.p.x ||
+ ymin >= pfs->rect.q.y || ymax <= pfs->rect.p.y
+ ) {
+ /* The triangle is entirely outside the rectangle. */
+ return 0;
+ } else {
+/****** CLIP HERE ******/
+ }
+ }
+ /* Check whether the colors fall within the smoothness criterion. */
+ for (ci = 0; ci < pfs->num_components; ++ci) {
+ float
+ c0 = cc[0].paint.values[ci], c1 = cc[1].paint.values[ci],
+ c2 = cc[2].paint.values[ci];
+ float cmin, cmax;
+
+ SET_MIN_MAX_3(cmin, cmax, c0, c1, c2);
+ if (cmax - cmin > pfs->cc_max_error[ci])
+ goto recur;
+ }
+ /* Fill the triangle with the color. */
+ {
+ gx_device_color dev_color;
+ const gs_color_space *pcs = psh->params.ColorSpace;
+ gs_imager_state *pis = pfs->pis;
+ gx_path *ppath;
+ gs_client_color fcc;
+ int code;
+
+ fcc.paint = cc[0].paint;
+ (*pcs->type->restrict_color) (&fcc, pcs);
+ (*pcs->type->remap_color) (&fcc, pcs, &dev_color, pis,
+ pfs->dev, gs_color_select_texture);
+/****** SHOULD ADD adjust ON ANY OUTSIDE EDGES ******/
+#if 0
+ ppath = gx_path_alloc(pis->memory, "Gt_fill");
+ gx_path_add_point(ppath, xa, ya);
+ gx_path_add_line(ppath, xb, yb);
+ gx_path_add_line(ppath, xc, yc);
+ code = shade_fill_path((const shading_fill_state_t *)pfs,
+ ppath, &dev_color);
+ gx_path_free(ppath, "Gt_fill");
+#else
+ code = (*dev_proc(pfs->dev, fill_triangle))
+ (pfs->dev, xa, ya, xb - xa, yb - ya, xc - xa, yc - ya,
+ &dev_color, pis->log_op);
+#endif
+ return code;
+ }
+ /*
+ * Subdivide the triangle and recur. The only subdivision method
+ * that doesn't seem to create anomalous shapes divides the
+ * triangle in 4, using the midpoints of each side.
+ */
+ recur:{
+#define midpoint_fast(a,b)\
+ arith_rshift_1((a) + (b) + 1)
+ fixed
+ xab = midpoint_fast(xa, xb), yab = midpoint_fast(ya, yb),
+ xac = midpoint_fast(xa, xc), yac = midpoint_fast(ya, yc),
+ xbc = midpoint_fast(xb, xc), ybc = midpoint_fast(yb, yc);
+#undef midpoint_fast
+ gs_client_color rcc[5];
+ int i;
+
+ for (i = 0; i < pfs->num_components; ++i) {
+ float
+ ta = cc[0].paint.values[i], tb = cc[1].paint.values[i],
+ tc = cc[2].paint.values[i];
+
+ rcc[1].paint.values[i] = (ta + tb) * 0.5;
+ rcc[2].paint.values[i] = (ta + tc) * 0.5;
+ rcc[3].paint.values[i] = (tb + tc) * 0.5;
+ }
+ /* Do the "A" triangle. */
+ rcc[0].paint = cc[0].paint; /* rcc: a,ab,ac,bc,- */
+ mesh_fill_region(pfs, xa, ya, xab, yab, xac, yac, rcc, check);
+ /* Do the central triangle. */
+ mesh_fill_region(pfs, xab, yab, xac, yac, xbc, ybc, rcc + 1, check);
+ /* Do the "C" triangle. */
+ rcc[4].paint = cc[2].paint; /* rcc: a,ab,ac,bc,c */
+ mesh_fill_region(pfs, xac, yac, xbc, ybc, xc, yc, rcc + 2, check);
+ /* Do the "B" triangle. */
+ rcc[2].paint = cc[1].paint; /* rcc: a,ab,b,bc,c */
+ mesh_fill_region(pfs, xab, yab, xb, yb, xbc, ybc, rcc + 1, check);
+ return 0;
+ }
+}
+
+int
+mesh_fill_triangle(const mesh_fill_state_t * pfs, const gs_fixed_point * pa,
+ const float *pca, const gs_fixed_point * pb, const float *pcb,
+ const gs_fixed_point * pc, const float *pcc, bool check)
+{
+ gs_client_color cc[3];
+
+ memcpy(cc[0].paint.values, pca, sizeof(cc[0].paint.values));
+ memcpy(cc[1].paint.values, pcb, sizeof(cc[1].paint.values));
+ memcpy(cc[2].paint.values, pcc, sizeof(cc[2].paint.values));
+ return mesh_fill_region(pfs, pa->x, pa->y, pb->x, pb->y,
+ pc->x, pc->y, cc, check);
+}
+
+/* ---------------- Gouraud triangle shadings ---------------- */
+
+private int
+Gt_next_vertex(const gs_shading_mesh_t * psh, shade_coord_stream_t * cs,
+ mesh_vertex_t * vertex)
+{
+ int code = shade_next_vertex(cs, vertex);
+
+ if (code >= 0 && psh->params.Function) {
+ /* Decode the color with the function. */
+ gs_function_evaluate(psh->params.Function, vertex->cc, vertex->cc);
+ }
+ return code;
+}
+
+private int
+Gt_fill_triangle(const mesh_fill_state_t * pfs, const mesh_vertex_t * va,
+ const mesh_vertex_t * vb, const mesh_vertex_t * vc)
+{
+ return mesh_fill_triangle(pfs, &va->p, va->cc, &vb->p, vb->cc,
+ &vc->p, vc->cc, true);
+}
+
+int
+gs_shading_FfGt_fill_rectangle(const gs_shading_t * psh0, const gs_rect * rect,
+ gx_device * dev, gs_imager_state * pis)
+{
+ const gs_shading_FfGt_t *psh = (const gs_shading_FfGt_t *)psh0;
+ mesh_fill_state_t state;
+ shade_coord_stream_t cs;
+ int num_bits = psh->params.BitsPerFlag;
+ int flag;
+ mesh_vertex_t va, vb, vc;
+
+ mesh_init_fill_state(&state, (const gs_shading_mesh_t *)psh, rect,
+ dev, pis);
+ shade_next_init(&cs, (const gs_shading_mesh_params_t *)&psh->params,
+ pis);
+ while ((flag = shade_next_flag(&cs, num_bits)) >= 0) {
+ int code;
+
+ switch (flag) {
+ default:
+ return_error(gs_error_rangecheck);
+ case 0:
+ if ((code = Gt_next_vertex(state.pshm, &cs, &va)) < 0 ||
+ (code = shade_next_flag(&cs, num_bits)) < 0 ||
+ (code = Gt_next_vertex(state.pshm, &cs, &vb)) < 0 ||
+ (code = shade_next_flag(&cs, num_bits)) < 0
+ )
+ return code;
+ goto v2;
+ case 1:
+ va = vb;
+ case 2:
+ vb = vc;
+ v2:if ((code = Gt_next_vertex(state.pshm, &cs, &vc)) < 0)
+ return code;
+ code = Gt_fill_triangle(&state, &va, &vb, &vc);
+ if (code < 0)
+ return code;
+ }
+ }
+ return 0;
+}
+
+int
+gs_shading_LfGt_fill_rectangle(const gs_shading_t * psh0, const gs_rect * rect,
+ gx_device * dev, gs_imager_state * pis)
+{
+ const gs_shading_LfGt_t *psh = (const gs_shading_LfGt_t *)psh0;
+ mesh_fill_state_t state;
+ shade_coord_stream_t cs;
+ mesh_vertex_t *vertex;
+ mesh_vertex_t next;
+ int per_row = psh->params.VerticesPerRow;
+ int i, code;
+
+ mesh_init_fill_state(&state, (const gs_shading_mesh_t *)psh, rect,
+ dev, pis);
+ shade_next_init(&cs, (const gs_shading_mesh_params_t *)&psh->params,
+ pis);
+ vertex = (mesh_vertex_t *)
+ gs_alloc_byte_array(pis->memory, per_row, sizeof(*vertex),
+ "gs_shading_LfGt_render");
+ if (vertex == 0)
+ return_error(gs_error_VMerror);
+ for (i = 0; i < per_row; ++i)
+ if ((code = Gt_next_vertex(state.pshm, &cs, &vertex[i])) < 0)
+ goto out;
+ while (!seofp(cs.s)) {
+ code = Gt_next_vertex(state.pshm, &cs, &next);
+ if (code < 0)
+ goto out;
+ for (i = 1; i < per_row; ++i) {
+ code = Gt_fill_triangle(&state, &vertex[i - 1], &vertex[i], &next);
+ if (code < 0)
+ goto out;
+ vertex[i - 1] = next;
+ code = Gt_next_vertex(state.pshm, &cs, &next);
+ if (code < 0)
+ goto out;
+ code = Gt_fill_triangle(&state, &vertex[i], &vertex[i - 1], &next);
+ if (code < 0)
+ goto out;
+ }
+ vertex[per_row - 1] = next;
+ }
+ out:
+ gs_free_object(pis->memory, vertex, "gs_shading_LfGt_render");
+ return code;
+}
diff --git a/gs/src/gxshade4.h b/gs/src/gxshade4.h
new file mode 100644
index 000000000..bf1b471c3
--- /dev/null
+++ b/gs/src/gxshade4.h
@@ -0,0 +1,53 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gxshade4.h */
+/* Internal definitions for triangle shading rendering */
+
+#ifndef gxshade4_INCLUDED
+# define gxshade4_INCLUDED
+
+/*
+ * Define the fill state structure for triangle shadings. This is used
+ * both for the Gouraud triangle shading types and for the Coons and
+ * tensor patch types.
+ *
+ * The shading pointer is named pshm rather than psh in case subclasses
+ * also want to store a pointer of a more specific type.
+ */
+#define mesh_fill_state_common\
+ shading_fill_state_common;\
+ const gs_shading_mesh_t *pshm;\
+ gs_fixed_rect rect
+typedef struct mesh_fill_state_s {
+ mesh_fill_state_common;
+} mesh_fill_state_t;
+
+/* Initialize the fill state for triangle shading. */
+void mesh_init_fill_state(P5(mesh_fill_state_t * pfs,
+ const gs_shading_mesh_t * psh, const gs_rect * rect,
+ gx_device * dev, gs_imager_state * pis));
+
+/* Fill one triangle in a mesh. */
+int mesh_fill_triangle(P8(const mesh_fill_state_t * pfs,
+ const gs_fixed_point * pa, const float *pca,
+ const gs_fixed_point * pb, const float *pcb,
+ const gs_fixed_point * pc, const float *pcc,
+ bool check_clipping));
+
+#endif /* gxshade4_INCLUDED */
diff --git a/gs/src/gxshade6.c b/gs/src/gxshade6.c
new file mode 100644
index 000000000..b52bb4d2a
--- /dev/null
+++ b/gs/src/gxshade6.c
@@ -0,0 +1,552 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gxshade6.c */
+/* Rendering for Coons and tensor patch shadings */
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsmatrix.h" /* for gscoord.h */
+#include "gscoord.h"
+#include "gxcspace.h"
+#include "gxdcolor.h"
+#include "gxistate.h"
+#include "gxshade.h"
+#include "gxshade4.h"
+#include "gzpath.h"
+
+/* ================ Utilities ================ */
+
+/* Define one segment (vertex and next control points) of a curve. */
+typedef struct patch_curve_s {
+ mesh_vertex_t vertex;
+ gs_fixed_point control[2];
+} patch_curve_t;
+
+/* Get colors for patch vertices. */
+private int
+shade_next_colors(shade_coord_stream_t * cs, patch_curve_t * curves,
+ int num_vertices)
+{
+ int i, code = 0;
+
+ for (i = 0; i < num_vertices && code >= 0; ++i)
+ code = shade_next_color(cs, curves[i].vertex.cc);
+ return code;
+}
+
+/* Get a Bezier or tensor patch element. */
+private int
+shade_next_curve(shade_coord_stream_t * cs, patch_curve_t * curve)
+{
+ int code = shade_next_coords(cs, &curve->vertex.p, 1);
+
+ if (code >= 0)
+ code = shade_next_coords(cs, curve->control,
+ countof(curve->control));
+ return code;
+}
+
+/* Define a color to be used in curve rendering. */
+/* This may be a real client color, or a parametric function argument. */
+typedef struct patch_color_s {
+ float t; /* parametric value */
+ gs_client_color cc;
+} patch_color_t;
+
+/*
+ * Parse the next patch out of the input stream. Return 1 if done,
+ * 0 if patch, <0 on error.
+ */
+private int
+shade_next_patch(shade_coord_stream_t * cs, int BitsPerFlag,
+patch_curve_t curve[4], gs_fixed_point interior[4] /* 0 for Coons patch */ )
+{
+ int flag = shade_next_flag(cs, BitsPerFlag);
+ int num_colors, code;
+
+ if (flag < 0)
+ return 1; /* no more data */
+ switch (flag & 3) {
+ default:
+ return_error(gs_error_rangecheck); /* not possible */
+ case 0:
+ if ((code = shade_next_curve(cs, &curve[0])) < 0 ||
+ (code = shade_next_coords(cs, &curve[1].vertex.p, 1)) < 0
+ )
+ return code;
+ num_colors = 4;
+ goto vx;
+ case 1:
+ curve[0] = curve[1], curve[1].vertex = curve[2].vertex;
+ goto v3;
+ case 2:
+ curve[0] = curve[2], curve[1].vertex = curve[3].vertex;
+ goto v3;
+ case 3:
+ curve[1].vertex = curve[0].vertex, curve[0] = curve[3];
+ v3:num_colors = 2;
+ vx:if ((code = shade_next_coords(cs, curve[1].control, 2)) < 0 ||
+ (code = shade_next_curve(cs, &curve[2])) < 0 ||
+ (code = shade_next_curve(cs, &curve[3])) < 0 ||
+ (interior != 0 &&
+ (code = shade_next_coords(cs, interior, 4)) < 0) ||
+ (code = shade_next_colors(cs, &curve[4 - num_colors],
+ num_colors)) < 0
+ )
+ return code;
+ }
+ return 0;
+}
+
+/* Define the common state for rendering Coons and tensor patches. */
+typedef struct patch_fill_state_s {
+ mesh_fill_state_common;
+ const gs_function_t *Function;
+} patch_fill_state_t;
+
+/* Calculate the interpolated color at a given point. */
+/* Note that we must do this twice for bilinear interpolation. */
+private void
+patch_interpolate_color(patch_color_t * ppc, const patch_color_t * ppc0,
+ const patch_color_t * ppc1, const patch_fill_state_t * pfs, floatp t)
+{
+ if (pfs->Function)
+ ppc->t = ppc0->t + t * (ppc1->t - ppc0->t);
+ else {
+ int ci;
+
+ for (ci = pfs->num_components - 1; ci >= 0; --ci)
+ ppc->cc.paint.values[ci] =
+ ppc0->cc.paint.values[ci] +
+ t * (ppc1->cc.paint.values[ci] - ppc0->cc.paint.values[ci]);
+ }
+}
+
+/* Resolve a patch color using the Function if necessary. */
+private void
+patch_resolve_color(patch_color_t * ppc, const patch_fill_state_t * pfs)
+{
+ if (pfs->Function)
+ gs_function_evaluate(pfs->Function, &ppc->t, ppc->cc.paint.values);
+}
+
+/* ================ Specific shadings ================ */
+
+/*
+ * The curves are stored in a clockwise or counter-clockwise order that maps
+ * to the patch definition in a non-intuitive way:
+ */
+/* The starting points of the curves: */
+#define C1START 0
+#define D1START 0
+#define C2START 3
+#define D2START 1
+/* The control points of the curves (x means reversed order): */
+#define C1CTRL 0
+#define D1XCTRL 3
+#define C2XCTRL 2
+#define D2CTRL 1
+/* The end points of the curves: */
+#define C1END 1
+#define D1END 3
+#define C2END 2
+#define D2END 2
+
+/* ---------------- Common code ---------------- */
+
+/* Evaluate a curve at a given point. */
+private void
+curve_eval(gs_fixed_point * pt, const gs_fixed_point * p0,
+ const gs_fixed_point * p1, const gs_fixed_point * p2,
+ const gs_fixed_point * p3, floatp t)
+{
+ fixed a, b, c, d;
+ fixed t01, t12;
+
+ d = p0->x;
+ curve_points_to_coefficients(d, p1->x, p2->x, p3->x,
+ a, b, c, t01, t12);
+ pt->x = (fixed) (((a * t + b) * t + c) * t + d);
+ d = p0->y;
+ curve_points_to_coefficients(d, p1->y, p2->y, p3->y,
+ a, b, c, t01, t12);
+ pt->y = (fixed) (((a * t + b) * t + c) * t + d);
+ if_debug3('2', "[2]t=%g => (%g,%g)\n", t, fixed2float(pt->x),
+ fixed2float(pt->y));
+}
+
+/*
+ * Merge two arrays of splits, sorted in increasing order.
+ * Return the number of entries in the result, which might be less than
+ * n1 + n2 (if an a1 entry is equal to an a2 entry).
+ * a1 or a2 may overlap out as long as a1 - out >= n2 or a2 - out >= n1
+ * respectively.
+ */
+private int
+merge_splits(double *out, const double *a1, int n1, const double *a2, int n2)
+{
+ double *p = out;
+ int i1 = 0, i2 = 0;
+
+ /*
+ * We would like to write the body of the loop as an assignement
+ * with a conditional expression on the right, but gcc 2.7.2.3
+ * generates incorrect code if we do this.
+ */
+ while (i1 < n1 || i2 < n2)
+ if (i1 == n1)
+ *p++ = a2[i2++];
+ else if (i2 == n2 || a1[i1] < a2[i2])
+ *p++ = a1[i1++];
+ else if (a1[i1] > a2[i2])
+ *p++ = a2[i2++];
+ else
+ i1++, *p++ = a2[i2++];
+ return p - out;
+}
+
+/* Split a curve in both X and Y. Return the number of split points. */
+private int
+split_xy(double out[4], const patch_curve_t * curve, const gs_fixed_point * p3)
+{
+ double tx[2], ty[2];
+
+ return merge_splits(out, tx,
+ gx_curve_monotonic_points(curve->vertex.p.x,
+ curve->control[0].x,
+ curve->control[1].x,
+ p3->x, tx),
+ ty,
+ gx_curve_monotonic_points(curve->vertex.p.y,
+ curve->control[0].y,
+ curve->control[1].y,
+ p3->y, ty));
+}
+
+/*
+ * Compute the joint split points of 2 curves.
+ * Return the number of split points.
+ */
+private int
+split2_xy(double out[8], const patch_curve_t * curve1,
+ const gs_fixed_point * p31, const patch_curve_t * curve2,
+ const gs_fixed_point * p32)
+{
+ double t1[4], t2[4];
+
+ return merge_splits(out, t1, split_xy(t1, curve1, p31),
+ t2, split_xy(t2, curve2, p32));
+}
+
+private int
+patch_fill(const patch_fill_state_t * pfs, const patch_curve_t curve[4],
+ const gs_fixed_point interior[4],
+ void (*transform) (P5(gs_fixed_point *, const patch_curve_t[4],
+ const gs_fixed_point[4], floatp, floatp)))
+{ /*
+ * The specification says the output must appear to be produced in
+ * order of increasing values of v, and for equal v, in order of
+ * increasing u. However, all we actually have to do is follow this
+ * order with respect to sub-patches that might overlap, which can
+ * only occur as a result of non-monotonic curves; we can render
+ * each monotonic sub-patch in any order we want. Therefore, we
+ * begin by breaking up the patch into pieces that are monotonic
+ * with respect to all 4 edges. Since each edge has no more than
+ * 2 X and 2 Y split points (for a total of 4), taking both edges
+ * together we have a maximum of 8 split points for each axis.
+ *
+ * The current documentation doesn't say how the 4 curves
+ * correspond to the 'u' or 'v' edges. Pending clarification from
+ * Adobe, we assume the 1st and 3rd are the 'u' edges and the
+ * 2nd and 4th are the 'v' edges.
+ */
+ double u[9], v[9];
+ int nu = split2_xy(u, &curve[0], &curve[1].vertex.p,
+ &curve[2], &curve[3].vertex.p);
+ int nv = split2_xy(v, &curve[1], &curve[2].vertex.p,
+ &curve[3], &curve[0].vertex.p);
+ int iu, iv, ju, jv, ku, kv;
+ double dku, dkv;
+
+ /*
+ * At some future time, we should set check = false if the curves
+ * fall entirely within the bounding rectangle. (Only a small
+ * performance optimization, to avoid making this check for each
+ * triangle.)
+ */
+ bool check = true;
+
+#ifdef DEBUG
+ if (gs_debug_c('2')) {
+ int k;
+
+ dlputs("[2]patch curves:\n");
+ for (k = 0; k < 4; ++k)
+ dprintf6(" (%g,%g) (%g,%g)(%g,%g)\n",
+ fixed2float(curve[k].vertex.p.x),
+ fixed2float(curve[k].vertex.p.y),
+ fixed2float(curve[k].control[0].x),
+ fixed2float(curve[k].control[0].y),
+ fixed2float(curve[k].control[1].x),
+ fixed2float(curve[k].control[1].y));
+ }
+#endif
+ /* Add boundary values to simplify the iteration. */
+ u[nu] = 1;
+ v[nv] = 1;
+
+ /*
+ * We're going to fill the curves by flatting them and then filling
+ * the resulting triangles. Start by computing the number of
+ * segments required for flattening each side of the patch.
+ */
+ {
+ fixed flatness = float2fixed(pfs->pis->flatness);
+ int i;
+ int log2_k[4];
+
+ for (i = 0; i < 4; ++i) {
+ curve_segment cseg;
+
+ cseg.p1 = curve[i].control[0];
+ cseg.p2 = curve[i].control[1];
+ cseg.pt = curve[(i + 1) & 3].vertex.p;
+ log2_k[i] =
+ gx_curve_log2_samples(curve[i].vertex.p.x, curve[i].vertex.p.y,
+ &cseg, flatness);
+ }
+ ku = 1 << max(log2_k[0], log2_k[2]);
+ kv = 1 << max(log2_k[1], log2_k[3]);
+ }
+ dku = (double)ku;
+ dkv = (double)kv;
+
+ /* Now iterate over the sub-patches. */
+ for (iv = 0, jv = 0; jv < kv;) {
+ double v0 = jv / dkv, v1 = (jv + 1) / dkv;
+ patch_color_t c0, c1, cv[4];
+
+ /* Subdivide the interval if it cross a split point. */
+
+#define CHECK_SPLIT(ix, jx, x1, ax)\
+ if ( x1 < ax[ix] ) jx++;\
+ else if ( x1 == ax[ix] ) jx++, ix++;\
+ else x1 = ax[ix++]
+
+ CHECK_SPLIT(iv, jv, v1, v);
+
+#define PATCH_SET_COLOR(c, v)\
+ if ( pfs->Function ) c.t = v.cc[0];\
+ else memcpy(c.cc.paint.values, v.cc, sizeof(c.cc.paint.values))
+
+ PATCH_SET_COLOR(c0, curve[0].vertex);
+ PATCH_SET_COLOR(c1, curve[3].vertex);
+ patch_interpolate_color(&cv[0], &c0, &c1,
+ (const patch_fill_state_t *)pfs, v0);
+ patch_interpolate_color(&cv[1], &c0, &c1,
+ (const patch_fill_state_t *)pfs, v1);
+ PATCH_SET_COLOR(c0, curve[1].vertex);
+ PATCH_SET_COLOR(c1, curve[2].vertex);
+ patch_interpolate_color(&cv[2], &c0, &c1,
+ (const patch_fill_state_t *)pfs, v0);
+ patch_interpolate_color(&cv[3], &c0, &c1,
+ (const patch_fill_state_t *)pfs, v1);
+
+#undef PATCH_SET_COLOR
+
+ for (iu = 0, ju = 0; ju < ku;) {
+ double u0 = ju / dku, u1 = (ju + 1) / dku;
+ patch_color_t cu[4];
+ int code;
+
+ CHECK_SPLIT(iu, ju, u1, u);
+ patch_interpolate_color(&cu[0], &cv[0], &cv[2],
+ (const patch_fill_state_t *)pfs, u0);
+ patch_resolve_color(&cu[0], (const patch_fill_state_t *)pfs);
+ patch_interpolate_color(&cu[1], &cv[0], &cv[2],
+ (const patch_fill_state_t *)pfs, u1);
+ patch_resolve_color(&cu[1], (const patch_fill_state_t *)pfs);
+ patch_interpolate_color(&cu[2], &cv[1], &cv[3],
+ (const patch_fill_state_t *)pfs, u1);
+ patch_resolve_color(&cu[2], (const patch_fill_state_t *)pfs);
+ patch_interpolate_color(&cu[3], &cv[1], &cv[3],
+ (const patch_fill_state_t *)pfs, u0);
+ patch_resolve_color(&cu[3], (const patch_fill_state_t *)pfs);
+ if_debug6('2', "[2]u[%d]=(%g,%g), v[%d]=(%g,%g)\n",
+ iu, u0, u1, iv, v0, v1);
+
+ /* Fill the sub-patch given by ((u0,v0),(u1,v1)). */
+ {
+ gs_fixed_point pts[4];
+
+ (*transform) (&pts[0], curve, interior, u0, v0);
+ (*transform) (&pts[1], curve, interior, u1, v0);
+ (*transform) (&pts[2], curve, interior, u1, v1);
+ (*transform) (&pts[3], curve, interior, u0, v1);
+ code = mesh_fill_triangle((const mesh_fill_state_t *)pfs,
+ &pts[0], cu[0].cc.paint.values,
+ &pts[1], cu[1].cc.paint.values,
+ &pts[2], cu[2].cc.paint.values, check);
+ if (code < 0)
+ return code;
+ code = mesh_fill_triangle((const mesh_fill_state_t *)pfs,
+ &pts[2], cu[2].cc.paint.values,
+ &pts[3], cu[3].cc.paint.values,
+ &pts[0], cu[0].cc.paint.values, check);
+ if (code < 0)
+ return code;
+ }
+ }
+
+#undef CHECK_SPLIT
+
+ }
+ return 0;
+}
+
+/* ---------------- Coons patch shading ---------------- */
+
+/* Calculate the device-space coordinate corresponding to (u,v). */
+private void
+Cp_transform(gs_fixed_point * pt, const patch_curve_t curve[4],
+ const gs_fixed_point ignore_interior[4], floatp u, floatp v)
+{
+ double co_u = 1.0 - u, co_v = 1.0 - v;
+ gs_fixed_point c1u, d1v, c2u, d2v;
+
+ curve_eval(&c1u, &curve[C1START].vertex.p,
+ &curve[C1CTRL].control[0], &curve[C1CTRL].control[1],
+ &curve[C1END].vertex.p, u);
+ curve_eval(&d1v, &curve[D1START].vertex.p,
+ &curve[D1XCTRL].control[1], &curve[D1XCTRL].control[0],
+ &curve[D1END].vertex.p, v);
+ curve_eval(&c2u, &curve[C2START].vertex.p,
+ &curve[C2XCTRL].control[1], &curve[C2XCTRL].control[0],
+ &curve[C2END].vertex.p, u);
+ curve_eval(&d2v, &curve[D2START].vertex.p,
+ &curve[D2CTRL].control[0], &curve[D2CTRL].control[1],
+ &curve[D2END].vertex.p, v);
+#define COMPUTE_COORD(xy)\
+ pt->xy = (fixed)\
+ ((co_v * c1u.xy + v * c2u.xy) + (co_u * d1v.xy + u * d2v.xy) -\
+ (co_v * (co_u * curve[C1START].vertex.p.xy +\
+ u * curve[C1END].vertex.p.xy) +\
+ v * (co_u * curve[C2START].vertex.p.xy +\
+ u * curve[C2END].vertex.p.xy)))
+ COMPUTE_COORD(x);
+ COMPUTE_COORD(y);
+#undef COMPUTE_COORD
+ if_debug4('2', "[2](u=%g,v=%g) => (%g,%g)\n",
+ u, v, fixed2float(pt->x), fixed2float(pt->y));
+}
+
+int
+gs_shading_Cp_fill_rectangle(const gs_shading_t * psh0, const gs_rect * rect,
+ gx_device * dev, gs_imager_state * pis)
+{
+ const gs_shading_Cp_t *psh = (const gs_shading_Cp_t *)psh0;
+ patch_fill_state_t state;
+ shade_coord_stream_t cs;
+ patch_curve_t curve[4];
+ int code;
+
+ mesh_init_fill_state((mesh_fill_state_t *) & state,
+ (const gs_shading_mesh_t *)psh0, rect, dev, pis);
+ state.Function = psh->params.Function;
+ shade_next_init(&cs, (const gs_shading_mesh_params_t *)&psh->params,
+ pis);
+ while ((code = shade_next_patch(&cs, psh->params.BitsPerFlag,
+ curve, NULL)) == 0 &&
+ (code = patch_fill(&state, curve, NULL, Cp_transform)) >= 0
+ )
+ DO_NOTHING;
+ return min(code, 0);
+}
+
+/* ---------------- Tensor product patch shading ---------------- */
+
+/* Calculate the device-space coordinate corresponding to (u,v). */
+private void
+Tpp_transform(gs_fixed_point * pt, const patch_curve_t curve[4],
+ const gs_fixed_point interior[4], floatp u, floatp v)
+{
+ double u2 = u * u, co_u = 1.0 - u, co_u2 = co_u * co_u;
+ double v2 = v * v, co_v = 1.0 - v, co_v2 = co_v * co_v;
+ double Bu[4], Bv[4];
+ gs_fixed_point pts[4][4];
+ int i, j;
+ fixed x = 0, y = 0;
+
+ /* Compute the Bernstein polynomials of u and v. */
+ Bu[0] = co_u * co_u2, Bu[1] = 3 * u * co_u2,
+ Bu[2] = 3 * u2 * co_u, Bu[3] = u * u2;
+ Bv[0] = co_v * co_v2, Bv[1] = 3 * v * co_v2,
+ Bv[2] = 3 * v2 * co_v, Bv[3] = v * v2;
+
+ /* Arrange the points into an indexable order. */
+ pts[0][0] = curve[0].vertex.p;
+ pts[1][0] = curve[0].control[0];
+ pts[2][0] = curve[0].control[1];
+ pts[3][0] = curve[1].vertex.p;
+ pts[3][1] = curve[1].control[0];
+ pts[3][2] = curve[1].control[1];
+ pts[3][3] = curve[2].vertex.p;
+ pts[2][3] = curve[2].control[0];
+ pts[1][3] = curve[2].control[1];
+ pts[0][3] = curve[3].vertex.p;
+ pts[0][2] = curve[3].control[0];
+ pts[0][1] = curve[3].control[1];
+ pts[1][1] = interior[0];
+ pts[2][1] = interior[1];
+ pts[2][2] = interior[2];
+ pts[1][2] = interior[3];
+
+ /* Now compute the actual point. */
+ for (i = 0; i < 4; ++i)
+ for (j = 0; j < 4; ++j) {
+ double coeff = Bu[i] * Bv[j];
+
+ x += pts[i][j].x * coeff, y += pts[i][j].y * coeff;
+ }
+ pt->x = x, pt->y = y;
+}
+
+int
+gs_shading_Tpp_fill_rectangle(const gs_shading_t * psh0, const gs_rect * rect,
+ gx_device * dev, gs_imager_state * pis)
+{
+ const gs_shading_Tpp_t *psh = (const gs_shading_Tpp_t *)psh0;
+ patch_fill_state_t state;
+ shade_coord_stream_t cs;
+ patch_curve_t curve[4];
+ gs_fixed_point interior[4];
+ int code;
+
+ mesh_init_fill_state((mesh_fill_state_t *) & state,
+ (const gs_shading_mesh_t *)psh0, rect, dev, pis);
+ state.Function = psh->params.Function;
+ shade_next_init(&cs, (const gs_shading_mesh_params_t *)&psh->params,
+ pis);
+ while ((code = shade_next_patch(&cs, psh->params.BitsPerFlag,
+ curve, interior)) == 0 &&
+ (code = patch_fill(&state, curve, interior, Tpp_transform)) >= 0
+ )
+ DO_NOTHING;
+ return min(code, 0);
+}
diff --git a/gs/src/gxtext.h b/gs/src/gxtext.h
new file mode 100644
index 000000000..4ed5fbaae
--- /dev/null
+++ b/gs/src/gxtext.h
@@ -0,0 +1,115 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: gstext.h */
+/* Driver text interface implementation support */
+
+#ifndef gxtext_INCLUDED
+# define gxtext_INCLUDED
+
+#include "gstext.h"
+
+/* EVERYTHING IN THIS FILE IS SUBJECT TO CHANGE WITHOUT NOTICE. */
+
+/*
+ * Define the control parameter for setting text metrics.
+ */
+typedef enum {
+ TEXT_SET_CHAR_WIDTH,
+ TEXT_SET_CACHE_DEVICE,
+ TEXT_SET_CACHE_DEVICE2
+} gs_text_cache_control_t;
+
+/*
+ * Define the procedures associated with text display.
+ */
+struct gs_text_enum_procs_s {
+
+ /*
+ * Process the text. Then client should call this repeatedly until
+ * it returns <= 0. (> 0 means the client must intervene.)
+ */
+
+#define text_enum_proc_process(proc)\
+ int proc(P1(gs_text_enum_t *penum))
+
+ text_enum_proc_process((*process));
+
+ /*
+ * Set the character width and optionally bounding box,
+ * and enable caching.
+ */
+
+#define text_enum_proc_set_cache(proc)\
+ int proc(P3(gs_text_enum_t *penum, const double *values,\
+ gs_text_cache_control_t control))
+
+ text_enum_proc_set_cache((*set_cache));
+
+};
+
+/* Abstract types */
+#ifndef gs_imager_state_DEFINED
+# define gs_imager_state_DEFINED
+typedef struct gs_imager_state_s gs_imager_state;
+
+#endif
+#ifndef gx_device_color_DEFINED
+# define gx_device_color_DEFINED
+typedef struct gx_device_color_s gx_device_color;
+
+#endif
+#ifndef gs_font_DEFINED
+# define gs_font_DEFINED
+typedef struct gs_font_s gs_font;
+
+#endif
+#ifndef gx_path_DEFINED
+# define gx_path_DEFINED
+typedef struct gx_path_s gx_path;
+
+#endif
+#ifndef gx_clip_path_DEFINED
+# define gx_clip_path_DEFINED
+typedef struct gx_clip_path_s gx_clip_path;
+
+#endif
+
+/*
+ * Define the driver procedure for text.
+ */
+#define dev_t_proc_text_begin(proc, dev_t)\
+ int proc(P9(dev_t *dev,\
+ gs_imager_state *pis,\
+ const gs_text_params_t *text,\
+ const gs_font *font,\
+ gx_path *path, /* unless DO_NONE & !RETURN_WIDTH */\
+ const gx_device_color *pdcolor, /* DO_DRAW */\
+ const gx_clip_path *pcpath, /* DO_DRAW */\
+ gs_memory_t *memory,\
+ gs_text_enum_t **ppenum))
+#define dev_proc_text_begin(proc)\
+ dev_t_proc_text_begin(proc, gx_device)
+
+/*
+ * Begin processing text. This calls the device procedure, and also
+ * initializes the common parts of the enumerator.
+ */
+dev_proc_text_begin(gx_device_text_begin);
+
+#endif /* gxtext_INCLUDED */
diff --git a/gs/src/icstate.h b/gs/src/icstate.h
new file mode 100644
index 000000000..59a2f8abf
--- /dev/null
+++ b/gs/src/icstate.h
@@ -0,0 +1,70 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: icstate.h */
+/* Externally visible context state */
+/* Requires iref.h */
+
+#ifndef icstate_INCLUDED
+# define icstate_INCLUDED
+
+#include "imemory.h"
+
+/*
+ * Define the externally visible state of an interpreter context.
+ * If we aren't supporting Display PostScript features, there is only
+ * a single context.
+ */
+#ifndef gs_context_state_t_DEFINED
+# define gs_context_state_t_DEFINED
+typedef struct gs_context_state_s gs_context_state_t;
+
+#endif
+#ifndef ref_stack_DEFINED
+# define ref_stack_DEFINED
+typedef struct ref_stack_s ref_stack;
+
+#endif
+struct gs_context_state_s {
+ ref_stack *dstack;
+ ref_stack *estack;
+ ref_stack *ostack;
+ gs_state *pgs;
+ gs_dual_memory_t memory;
+ ref array_packing; /* t_boolean */
+ ref binary_object_format; /* t_integer */
+ long rand_state; /* (not in Red Book) */
+ long usertime_total; /* total accumulated usertime, */
+ /* not counting current time if running */
+ bool keep_usertime; /* true if context ever executed usertime */
+ /* View clipping is handled in the graphics state. */
+ ref userparams; /* t_dictionary */
+ ref stdio[2]; /* t_file */
+};
+
+/*
+ * We make st_context_state public because interp.c must allocate one,
+ * and zcontext.c must subclass it.
+ */
+ /*extern_st(st_context_state); *//* in icontext.h */
+#define public_st_context_state() /* in icontext.c */\
+ gs_public_st_complex_only(st_context_state, gs_context_state_t,\
+ "gs_context_state_t", context_state_clear_marks,\
+ context_state_enum_ptrs, context_state_reloc_ptrs, 0)
+
+#endif /* icstate_INCLUDED */
diff --git a/gs/src/idictdef.h b/gs/src/idictdef.h
new file mode 100644
index 000000000..a5d21e556
--- /dev/null
+++ b/gs/src/idictdef.h
@@ -0,0 +1,122 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: idictdef.h */
+/* Internals of dictionary implementation */
+
+#ifndef idictdef_INCLUDED
+# define idictdef_INCLUDED
+
+/*
+ * A dictionary of capacity M is a structure containing the following
+ * elements (refs):
+ *
+ * keys - a t_shortarray or t_array of M+1 elements, containing
+ * the keys.
+ *
+ * values - a t_array of M+1 elements, containing the values.
+ *
+ * count - a t_integer whose value tells how many entries are
+ * occupied (N).
+ *
+ * maxlength - a t_integer whose value gives the client's view of
+ * the capacity (C). C may be less than M (see below).
+ *
+ * memory - a foreign t_struct referencing the allocator used to
+ * create this dictionary, which will also be used to expand or
+ * unpack it if necessary.
+ *
+ * C < M is possible because on large-memory systems, we usually round up M
+ * so that M is a power of 2 (see idict.h for details); this allows us to
+ * use masking rather than division for computing the initial hash probe.
+ * However, C is always the maxlength specified by the client, so clients
+ * get a consistent story.
+ *
+ * As noted above, the keys may be either in packed or unpacked form.
+ * The markers for unused and deleted entries are different in the two forms.
+ * In the packed form:
+ * unused entries contain packed_key_empty;
+ * deleted entries contain packed_key_deleted.
+ * In the unpacked form:
+ * unused entries contain a literal null;
+ * deleted entries contain an executable null.
+ *
+ * The first entry is always marked deleted, to reduce the cost of the
+ * wrap-around check.
+ *
+ * Note that if the keys slot in the dictionary is new,
+ * all the key slots are new (more recent than the last save).
+ * We use this fact to avoid saving stores into packed keys
+ * for newly created dictionaries.
+ *
+ * Note that name keys with indices above packed_name_max_index require using
+ * the unpacked form. */
+#define dict_is_packed(dct) r_has_type(&(dct)->keys, t_shortarray)
+#define packed_key_empty (pt_tag(pt_integer) + 0)
+#define packed_key_deleted (pt_tag(pt_integer) + 1)
+#define packed_key_impossible pt_tag(pt_full_ref) /* never matches */
+#define packed_name_key(nidx)\
+ ((nidx) <= packed_name_max_index ? pt_tag(pt_literal_name) + (nidx) :\
+ packed_key_impossible)
+/*
+ * Using a special mark for deleted entries causes lookup time to degrade
+ * as entries are inserted and deleted. This is not a problem, because
+ * entries are almost never deleted.
+ */
+#define d_maxlength(dct) ((uint)((dct)->maxlength.value.intval))
+#define d_set_maxlength(dct,siz) ((dct)->maxlength.value.intval = (siz))
+#define nslots(dct) r_size(&(dct)->values)
+#define npairs(dct) (nslots(dct) - 1)
+#define d_length(dct) ((uint)((dct)->count.value.intval))
+
+/*
+ * Define macros for searching a packed dictionary. Free variables:
+ * ref_packed kpack - holds the packed key.
+ * uint hash - holds the hash of the name.
+ * dict *pdict - points to the dictionary.
+ * uint size - holds npairs(pdict).
+ * Note that the macro is *not* enclosed in {}, so that we can access
+ * the values of kbot and kp after leaving the loop.
+ *
+ * We break the macro into two to avoid overflowing some preprocessors.
+ */
+/* packed_search_body also uses kp and kbot as free variables. */
+#define packed_search_value_pointer (pdict->values.value.refs + (kp - kbot))
+#define packed_search_body(found1,found2,del,miss)\
+ { if_debug2('D', "[D]probe 0x%lx: 0x%x\n", (ulong)kp, *kp);\
+ if ( *kp == kpack )\
+ { found1;\
+ found2;\
+ }\
+ else if ( !r_packed_is_name(kp) )\
+ { /* Empty, deleted, or wraparound. Figure out which. */\
+ if ( *kp == packed_key_empty ) miss;\
+ if ( kp == kbot ) break; /* wrap */\
+ else { del; }\
+ }\
+ }
+#define packed_search_1(found1,found2,del,miss)\
+ const ref_packed *kbot = pdict->keys.value.packed;\
+ register const ref_packed *kp;\
+ for ( kp = kbot + dict_hash_mod(hash, size) + 1; ; kp-- )\
+ packed_search_body(found1,found2,del,miss)
+#define packed_search_2(found1,found2,del,miss)\
+ for ( kp += size; ; kp-- )\
+ packed_search_body(found1,found2,del,miss)
+
+#endif /* idictdef_INCLUDED */
diff --git a/gs/src/idstack.c b/gs/src/idstack.c
new file mode 100644
index 000000000..5cc0d457d
--- /dev/null
+++ b/gs/src/idstack.c
@@ -0,0 +1,243 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: idstack.c */
+/* Implementation of dictionary stacks */
+#include "ghost.h"
+#include "idict.h"
+#include "idictdef.h"
+#include "idstack.h"
+#include "inamedef.h"
+#include "iname.h"
+#include "ipacked.h"
+#include "iutil.h"
+#include "ivmspace.h"
+
+/* Debugging statistics */
+#ifdef DEBUG
+#include "idebug.h"
+long ds_lookups; /* total lookups */
+long ds_1probe; /* successful lookups on only 1 probe */
+long ds_2probe; /* successful lookups on 2 probes */
+
+/* Wrapper for dstack_find_name_by_index */
+ref *real_dstack_find_name_by_index(P2(dict_stack_t * pds, uint nidx));
+ref *
+dstack_find_name_by_index(dict_stack_t * pds, uint nidx)
+{
+ ref *pvalue = real_dstack_find_name_by_index(pds, nidx);
+ dict *pdict = pds->stack.p->value.pdict;
+
+ ds_lookups++;
+ if (dict_is_packed(pdict)) {
+ uint hash =
+ dict_hash_mod(dict_name_index_hash(nidx), npairs(pdict)) + 1;
+
+ if (pdict->keys.value.packed[hash] ==
+ pt_tag(pt_literal_name) + nidx
+ )
+ ds_1probe++;
+ else if (pdict->keys.value.packed[hash - 1] ==
+ pt_tag(pt_literal_name) + nidx
+ )
+ ds_2probe++;
+ }
+ /* Do the cheap flag test before the expensive remainder test. */
+ if (gs_debug_c('d') && !(ds_lookups % 1000))
+ dlprintf3("[d]lookups=%ld 1probe=%ld 2probe=%ld\n",
+ ds_lookups, ds_1probe, ds_2probe);
+ return pvalue;
+}
+#define dstack_find_name_by_index real_dstack_find_name_by_index
+#endif
+
+/* Check whether a dictionary is one of the permanent ones on the d-stack. */
+bool
+dstack_dict_is_permanent(const dict_stack_t * pds, const ref * pdref)
+{
+ dict *pdict = pdref->value.pdict;
+ int i;
+
+ if (pds->stack.extension_size == 0) { /* Only one block of d-stack. */
+ for (i = 0; i < pds->min_size; ++i)
+ if (pds->stack.bot[i].value.pdict == pdict)
+ return true;
+ } else { /* More than one block of d-stack. */
+ uint count = ref_stack_count(&pds->stack);
+
+ for (i = count - pds->min_size; i < count; ++i)
+ if (ref_stack_index(&pds->stack, i)->value.pdict == pdict)
+ return true;
+ }
+ return false;
+}
+
+/*
+ * Look up a name on the dictionary stack.
+ * Return the pointer to the value if found, 0 if not.
+ */
+ref *
+dstack_find_name_by_index(dict_stack_t * pds, uint nidx)
+{
+ ds_ptr pdref = pds->stack.p;
+
+/* Since we know the hash function is the identity function, */
+/* there's no point in allocating a separate variable for it. */
+#define hash dict_name_index_hash(nidx)
+ ref_packed kpack = packed_name_key(nidx);
+
+ do {
+ dict *pdict = pdref->value.pdict;
+ uint size = npairs(pdict);
+
+#ifdef DEBUG
+ if (gs_debug_c('D')) {
+ ref dnref;
+
+ name_index_ref(nidx, &dnref);
+ dlputs("[D]lookup ");
+ debug_print_name(&dnref);
+ dprintf3(" in 0x%lx(%u/%u)\n",
+ (ulong) pdict, dict_length(pdref),
+ dict_maxlength(pdref));
+ }
+#endif
+ if (dict_is_packed(pdict)) {
+ packed_search_1(DO_NOTHING,
+ return packed_search_value_pointer,
+ DO_NOTHING, goto miss);
+ packed_search_2(DO_NOTHING,
+ return packed_search_value_pointer,
+ DO_NOTHING, break);
+ miss:;
+ } else {
+ ref *kbot = pdict->keys.value.refs;
+ register ref *kp;
+ int wrap = 0;
+
+ /* Search the dictionary */
+ for (kp = kbot + dict_hash_mod(hash, size) + 2;;) {
+ --kp;
+ if (r_has_type(kp, t_name)) {
+ if (name_index(kp) == nidx)
+ return pdict->values.value.refs +
+ (kp - kbot);
+ } else if (r_has_type(kp, t_null)) { /* Empty, deleted, or wraparound. */
+ /* Figure out which. */
+ if (!r_has_attr(kp, a_executable))
+ break;
+ if (kp == kbot) { /* wrap */
+ if (wrap++)
+ break; /* 2 wraps */
+ kp += size + 1;
+ }
+ }
+ }
+ }
+ }
+ while (pdref-- > pds->stack.bot);
+ /* The name isn't in the top dictionary block. */
+ /* If there are other blocks, search them now (more slowly). */
+ if (!pds->stack.extension_size) /* no more blocks */
+ return (ref *) 0;
+ { /* We could use the STACK_LOOP macros, but for now, */
+ /* we'll do things the simplest way. */
+ ref key;
+ uint i = pds->stack.p + 1 - pds->stack.bot;
+ uint size = ref_stack_count(&pds->stack);
+ ref *pvalue;
+
+ name_index_ref(nidx, &key);
+ for (; i < size; i++) {
+ if (dict_find(ref_stack_index(&pds->stack, i),
+ &key, &pvalue) > 0
+ )
+ return pvalue;
+ }
+ }
+ return (ref *) 0;
+#undef hash
+}
+
+/* Set the cached values computed from the top entry on the dstack. */
+/* See idstack.h for details. */
+private const ref_packed no_packed_keys[2] =
+{packed_key_deleted, packed_key_empty};
+void
+dstack_set_top(dict_stack_t * pds)
+{
+ ds_ptr dsp = pds->stack.p;
+ dict *pdict = dsp->value.pdict;
+
+ if_debug3('d', "[d]dsp = 0x%lx -> 0x%lx, key array type = %d\n",
+ (ulong) dsp, (ulong) pdict, r_type(&pdict->keys));
+ if (dict_is_packed(pdict) &&
+ r_has_attr(dict_access_ref(dsp), a_read)
+ ) {
+ pds->top_keys = pdict->keys.value.packed;
+ pds->top_npairs = npairs(pdict);
+ pds->top_values = pdict->values.value.refs;
+ } else {
+ pds->top_keys = no_packed_keys;
+ pds->top_npairs = 1;
+ }
+ if (!r_has_attr(dict_access_ref(dsp), a_write))
+ pds->def_space = -1;
+ else
+ pds->def_space = r_space(dsp);
+}
+
+/* After a garbage collection, scan the permanent dictionaries and */
+/* update the cached value pointers in names. */
+void
+dstack_gc_cleanup(dict_stack_t * pds)
+{
+ uint count = ref_stack_count(&pds->stack);
+ uint dsi;
+
+ for (dsi = pds->min_size; dsi > 0; --dsi) {
+ const dict *pdict =
+ ref_stack_index(&pds->stack, count - dsi)->value.pdict;
+ uint size = nslots(pdict);
+ ref *pvalue = pdict->values.value.refs;
+ uint i;
+
+ for (i = 0; i < size; ++i, ++pvalue) {
+ ref key;
+ ref *old_pvalue;
+
+ array_get(&pdict->keys, (long)i, &key);
+ if (r_has_type(&key, t_name) &&
+ pv_valid(old_pvalue = key.value.pname->pvalue)
+ ) { /*
+ * The name only has a single definition,
+ * so it must be this one. Check to see if
+ * no relocation is actually needed; if so,
+ * we can skip the entire dictionary.
+ */
+ if (old_pvalue == pvalue) {
+ if_debug1('d', "[d]skipping dstack entry %d\n",
+ dsi - 1);
+ break;
+ }
+ /* Update the value pointer. */
+ key.value.pname->pvalue = pvalue;
+ }
+ }
+ }
+}
diff --git a/gs/src/idstack.h b/gs/src/idstack.h
new file mode 100644
index 000000000..62cedf6bb
--- /dev/null
+++ b/gs/src/idstack.h
@@ -0,0 +1,119 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: idstack.h */
+/* Generic dictionary stack API */
+
+#ifndef idstack_INCLUDED
+# define idstack_INCLUDED
+
+#include "istack.h"
+
+/* Define the dictionary stack structure. */
+typedef struct dict_stack_s {
+
+ ref_stack stack; /* the actual stack of dictionaries */
+
+/*
+ * Switching between Level 1 and Level 2 involves inserting and removing
+ * globaldict on the dictionary stack. Instead of truly inserting and
+ * removing entries, we replace globaldict by a copy of systemdict in
+ * Level 1 mode. min_dstack_size, the minimum number of entries, does not
+ * change depending on language level; the countdictstack and dictstack
+ * operators must take this into account.
+ */
+ uint min_size; /* size of stack after clearing */
+
+ int userdict_index; /* index of userdict on stack */
+
+/*
+ * Cache a value for fast checking of def operations.
+ * If the top entry on the dictionary stack is a writable dictionary,
+ * dsspace is the space of the dictionary; if it is a non-writable
+ * dictionary, dsspace = -1. Then def is legal precisely if
+ * r_space(pvalue) <= dsspace. Note that in order for this trick to work,
+ * the result of r_space must be a signed integer; some compilers treat
+ * enums as unsigned, probably in violation of the ANSI standard.
+ */
+ int def_space;
+
+/*
+ * Cache values for fast name lookup. If the top entry on the dictionary
+ * stack is a readable dictionary with packed keys, dtop_keys, dtop_npairs,
+ * and dtop_values are keys.value.packed, npairs, and values.value.refs
+ * for that dictionary; otherwise, these variables point to a dummy
+ * empty dictionary.
+ */
+ const ref_packed *top_keys;
+ uint top_npairs;
+ ref *top_values;
+
+/*
+ * Cache a copy of the bottom entry on the stack, which is never deleted.
+ */
+ ref system_dict;
+
+} dict_stack_t;
+
+/*
+ * Reset the cached top values. Every routine that alters the
+ * dictionary stack (including changing the protection or size of the
+ * top dictionary on the stack) must call this.
+ */
+void dstack_set_top(P1(dict_stack_t *));
+
+/* Check whether a dictionary is one of the permanent ones on the d-stack. */
+bool dstack_dict_is_permanent(P2(const dict_stack_t *, const ref *));
+
+/* Define the type of pointers into the dictionary stack. */
+typedef s_ptr ds_ptr;
+typedef const_s_ptr const_ds_ptr;
+
+/* Clean up a dictionary stack after a garbage collection. */
+void dstack_gc_cleanup(P1(dict_stack_t *));
+
+/*
+ * Define a special fast entry for name lookup on a dictionary stack.
+ * The key is known to be a name; search the entire dict stack.
+ * Return the pointer to the value slot.
+ * If the name isn't found, just return 0.
+ */
+ref *dstack_find_name_by_index(P2(dict_stack_t *, uint));
+
+/*
+ * Define an extra-fast macro for name lookup, optimized for
+ * a single-probe lookup in the top dictionary on the stack.
+ * Amazingly enough, this seems to hit over 90% of the time
+ * (aside from operators, of course, which are handled either with
+ * the special cache pointer or with 'bind').
+ */
+#define dstack_find_name_by_index_inline(pds,nidx,htemp)\
+ ((pds)->top_keys[htemp = dict_hash_mod_inline(dict_name_index_hash(nidx),\
+ (pds)->top_npairs) + 1] == pt_tag(pt_literal_name) + (nidx) ?\
+ (pds)->top_values + htemp : dstack_find_name_by_index(pds, nidx))
+/*
+ * Define a similar macro that only checks the top dictionary on the stack.
+ */
+#define if_dstack_find_name_by_index_top(pds,nidx,htemp,pvslot)\
+ if ( (((pds)->top_keys[htemp = dict_hash_mod_inline(dict_name_index_hash(nidx),\
+ (pds)->top_npairs) + 1] == pt_tag(pt_literal_name) + (nidx)) ?\
+ ((pvslot) = (pds)->top_values + (htemp), 1) :\
+ 0)\
+ )
+
+#endif /* idstack_INCLUDED */
diff --git a/gs/src/iestack.h b/gs/src/iestack.h
new file mode 100644
index 000000000..71bf7a295
--- /dev/null
+++ b/gs/src/iestack.h
@@ -0,0 +1,50 @@
+/* Copyright (C) 1989, 1992, 1993, 1994, 1996, 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: iestack.h */
+/* Generic execution stack API */
+
+#ifndef iestack_INCLUDED
+# define iestack_INCLUDED
+
+#include "istack.h"
+
+/* Define the execution stack structure. */
+typedef struct exec_stack_s {
+
+ ref_stack stack; /* the actual execution stack */
+
+/*
+ * To improve performance, we cache the currentfile pointer
+ * (i.e., `shallow-bind' it in Lisp terminology). The invariant is as
+ * follows: either esfile points to the currentfile slot on the estack
+ * (i.e., the topmost slot with an executable file), or it is 0.
+ * To maintain the invariant, it is sufficient that whenever a routine
+ * pushes or pops anything on the estack, if the object *might* be
+ * an executable file, invoke esfile_clear_cache(); alternatively,
+ * immediately after pushing an object, invoke esfile_check_cache().
+ */
+ ref *current_file;
+
+} exec_stack_t;
+
+/* Define pointers into the execution stack. */
+typedef s_ptr es_ptr;
+typedef const_s_ptr const_es_ptr;
+
+#endif /* iestack_INCLUDED */
diff --git a/gs/src/iimage2.h b/gs/src/iimage2.h
new file mode 100644
index 000000000..45cbdc71b
--- /dev/null
+++ b/gs/src/iimage2.h
@@ -0,0 +1,44 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: iimage2.h */
+/* Requires gsiparam.h */
+
+#ifndef iimage2_INCLUDED
+# define iimage2_INCLUDED
+
+/* These procedures are exported by zimage2.c for other modules. */
+
+/*
+ * Define a structure for image parameters other than those defined
+ * in the gs_*image*_t structure.
+ */
+typedef struct image_params_s {
+ bool MultipleDataSources;
+ ref DataSource[gs_image_max_components];
+ const float *pDecode;
+} image_params;
+
+/* Extract and check parameters for an image. */
+int data_image_params(P6(const ref * op, gs_data_image_t * pim,
+ image_params * pip, bool require_DataSource,
+ int num_components, int max_bits_per_component));
+int pixel_image_params(P4(const ref * op, gs_pixel_image_t * pim,
+ image_params * pip, int max_bits_per_component));
+
+#endif /* iimage2_INCLUDED */
diff --git a/gs/src/inames.h b/gs/src/inames.h
new file mode 100644
index 000000000..ca7aa60ab
--- /dev/null
+++ b/gs/src/inames.h
@@ -0,0 +1,108 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: inames.h */
+/* Name table interface */
+
+#ifndef inames_INCLUDED
+# define inames_INCLUDED
+
+/*
+ * This file defines those parts of the name table API that depend neither
+ * on the implementation nor on the existence of a single distinguished
+ * instance. Procedures in this file begin with names_.
+ */
+
+/* ---------------- Interface types ---------------- */
+
+#ifndef name_table_DEFINED
+# define name_table_DEFINED
+typedef struct name_table_s name_table;
+
+#endif
+
+typedef uint name_index_t;
+
+/* ---------------- Constant values ---------------- */
+
+extern const uint name_max_string;
+
+/* ---------------- Procedural interface ---------------- */
+
+/* Allocate and initialize a name table. */
+name_table *names_init(P2(ulong size, gs_memory_t * mem));
+
+/* Get the allocator for a name table. */
+gs_memory_t *names_memory(P1(const name_table * nt));
+
+/*
+ * Look up and/or enter a name in the name table.
+ * The values of enterflag are:
+ * -1 -- don't enter (return an error) if missing;
+ * 0 -- enter if missing, don't copy the string, which was allocated
+ * statically;
+ * 1 -- enter if missing, copy the string;
+ * 2 -- enter if missing, don't copy the string, which was already
+ * allocated dynamically (using the names_memory allocator).
+ * Possible errors: VMerror, limitcheck (if string is too long or if
+ * we have assigned all possible name indices).
+ */
+int names_ref(P5(name_table * nt, const byte * ptr, uint size, ref * pnref,
+ int enterflag));
+void names_string_ref(P3(const name_table * nt, const ref * pnref, ref * psref));
+
+/*
+ * names_enter_string calls names_ref with a (permanent) C string.
+ */
+int names_enter_string(P3(name_table * nt, const char *str, ref * pnref));
+
+/*
+ * names_from_string essentially implements cvn.
+ * It always enters the name, and copies the executable attribute.
+ */
+int names_from_string(P3(name_table * nt, const ref * psref, ref * pnref));
+
+/* Compare two names for equality. */
+#define names_eq(pnref1, pnref2)\
+ ((pnref1)->value.pname == (pnref2)->value.pname)
+
+/* Invalidate the value cache for a name. */
+void names_invalidate_value_cache(P2(name_table * nt, const ref * pnref));
+
+/* Convert between names and indices. */
+name_index_t names_index(P2(const name_table * nt, const ref * pnref)); /* ref => index */
+name *names_index_ptr(P2(const name_table * nt, name_index_t nidx)); /* index => name */
+void names_index_ref(P3(const name_table * nt, name_index_t nidx, ref * pnref)); /* index => ref */
+
+/* Get the index of the next valid name. */
+/* The argument is 0 or a valid index. */
+/* Return 0 if there are no more. */
+name_index_t names_next_valid_index(P2(name_table * nt, name_index_t nidx));
+
+/* Mark a name for the garbage collector. */
+/* Return true if this is a new mark. */
+bool names_mark_index(P2(name_table * nt, name_index_t nidx));
+
+/* Get the object (sub-table) containing a name. */
+/* The garbage collector needs this so it can relocate pointers to names. */
+void /*obj_header_t */ *
+ names_ref_sub_table(P2(name_table * nt, const ref * pnref));
+void /*obj_header_t */ *
+ names_index_ptr_sub_table(P3(name_table * nt, name_index_t nidx, name * pname));
+
+#endif /* inames_INCLUDED */
diff --git a/gs/src/inouparm.c b/gs/src/inouparm.c
new file mode 100644
index 000000000..3239809e5
--- /dev/null
+++ b/gs/src/inouparm.c
@@ -0,0 +1,28 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: inouparm.c */
+/* Dummy set_user_params for Level 1 systems */
+#include "ghost.h"
+#include "icontext.h" /* for set_user_params prototype */
+
+int
+set_user_params(const ref * op)
+{
+ return 0;
+}
diff --git a/gs/src/iostack.h b/gs/src/iostack.h
new file mode 100644
index 000000000..342914a23
--- /dev/null
+++ b/gs/src/iostack.h
@@ -0,0 +1,39 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: iostack.h */
+/* Generic operand stack API */
+
+#ifndef iostack_INCLUDED
+# define iostack_INCLUDED
+
+#include "istack.h"
+
+/* Define pointers into the operand stack. */
+typedef s_ptr os_ptr;
+typedef const_s_ptr const_os_ptr;
+
+/* Define the operand stack structure. */
+/* Currently this is just a generic ref stack. */
+typedef struct op_stack_s {
+
+ ref_stack stack; /* the actual operand stack */
+
+} op_stack_t;
+
+#endif /* iostack_INCLUDED */
diff --git a/gs/src/pcwin.mak b/gs/src/pcwin.mak
new file mode 100644
index 000000000..1bbf5fcec
--- /dev/null
+++ b/gs/src/pcwin.mak
@@ -0,0 +1,100 @@
+# Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# Id: pcwin.mak
+# makefile for PC window system (MS Windows and OS/2) -specific device
+# drivers.
+
+# Define the name of this makefile.
+PCWIN_MAK=$(GLSRC)pcwin.mak
+
+# We have to isolate these in their own file because the MS Windows code
+# requires special compilation switches, different from all other files
+# and platforms.
+
+### -------------------- The MS-Windows 3.n DLL ------------------------- ###
+
+gp_mswin_h=$(GLSRC)gp_mswin.h
+gsdll_h=$(GLSRC)gsdll.h
+
+gdevmswn_h=$(GLSRC)gdevmswn.h $(GDEVH)\
+ $(dos__h) $(memory__h) $(string__h) $(windows__h)\
+ $(gp_mswin_h)
+
+$(GLOBJ)gdevmswn.$(OBJ): $(GLSRC)gdevmswn.c $(gdevmswn_h) $(gp_h) $(gpcheck_h)\
+ $(gsdll_h) $(gsparam_h) $(gdevpccm_h)
+ $(GLCCWIN) $(GLO_)gdevmswn.$(OBJ) $(C_) $(GLSRC)gdevmswn.c
+
+$(GLOBJ)gdevmsxf.$(OBJ): $(GLSRC)gdevmsxf.c $(ctype__h) $(math__h) $(memory__h) $(string__h)\
+ $(gdevmswn_h) $(gsstruct_h) $(gsutil_h) $(gxxfont_h)
+ $(GLCCWIN) $(GLO_)gdevmsxf.$(OBJ) $(C_) $(GLSRC)gdevmsxf.c
+
+# An implementation using a DIB filled by an image device.
+$(GLOBJ)gdevwdib.$(OBJ): $(GLSRC)gdevwdib.c $(gdevmswn_h) $(gsdll_h) $(gxdevmem_h)
+ $(GLCCWIN) $(GLO_)gdevwdib.$(OBJ) $(C_) $(GLSRC)gdevwdib.c
+
+mswindll1_=$(GLOBJ)gdevmswn.$(OBJ) $(GLOBJ)gdevmsxf.$(OBJ) $(GLOBJ)gdevwdib.$(OBJ)
+mswindll2_=$(GLOBJ)gdevemap.$(OBJ) $(GLOBJ)gdevpccm.$(OBJ)
+mswindll_=$(mswindll1_) $(mswindll2_)
+mswindll.dev: $(mswindll_)
+ $(SETDEV) mswindll $(mswindll1_)
+ $(ADDMOD) mswindll $(mswindll2_)
+
+### -------------------- The MS-Windows DDB 3.n printer ----------------- ###
+
+mswinprn_=$(GLOBJ)gdevwprn.$(OBJ) $(GLOBJ)gdevmsxf.$(OBJ)
+mswinprn.dev: $(mswinprn_)
+ $(SETDEV) mswinprn $(mswinprn_)
+
+$(GLOBJ)gdevwprn.$(OBJ): $(GLSRC)gdevwprn.c $(gdevmswn_h) $(gp_h)
+ $(GLCCWIN) $(GLO_)gdevwprn.$(OBJ) $(C_) $(GLSRC)gdevwprn.c
+
+### -------------------- The MS-Windows DIB 3.n printer ----------------- ###
+
+mswinpr2_=$(GLOBJ)gdevwpr2.$(OBJ)
+mswinpr2.dev: $(mswinpr2_) page.dev
+ $(SETPDEV) mswinpr2 $(mswinpr2_)
+
+$(GLOBJ)gdevwpr2.$(OBJ): $(GLSRC)gdevwpr2.c $(PDEVH) $(windows__h)\
+ $(gdevpccm_h) $(gp_h) $(gp_mswin_h)
+ $(GLCCWIN) $(GLO_)gdevwpr2.$(OBJ) $(C_) $(GLSRC)gdevwpr2.c
+
+### ------------------ OS/2 Presentation Manager device ----------------- ###
+
+os2pm_=$(GLOBJ)gdevpm.$(OBJ) $(GLOBJ)gdevpccm.$(OBJ)
+os2pm.dev: $(os2pm_)
+ $(SETDEV) os2pm $(os2pm_)
+
+os2dll_=$(GLOBJ)gdevpm.$(OBJ) $(GLOBJ)gdevpccm.$(OBJ)
+os2dll.dev: $(os2dll_)
+ $(SETDEV) os2dll $(os2dll_)
+
+$(GLOBJ)gdevpm.$(OBJ): $(GLSRC)gdevpm.c $(string__h)\
+ $(gp_h) $(gpcheck_h)\
+ $(gsdll_h) $(gserrors_h) $(gsexit_h) $(gsparam_h)\
+ $(gx_h) $(gxdevice_h) $(gxdevmem_h)\
+ $(gdevpccm_h) $(GLSRC)gdevpm.h
+ $(GLCC) $(GLO_)gdevpm.$(OBJ) $(C_) $(GLSRC)gdevpm.c
+
+### --------------------------- The OS/2 printer ------------------------ ###
+
+os2prn_=$(GLOBJ)gdevos2p.$(OBJ)
+os2prn.dev: $(os2prn_) page.dev
+ $(SETPDEV) os2prn $(os2prn_)
+
+$(GLOBJ)gdevos2p.$(OBJ): gdevos2p.c $(gp_h) $(gdevpccm_h) $(gdevprn_h) $(gscdefs_h)
+ $(GLCC) $(GLO_)gdevos2p.$(OBJ) $(C_) $(GLSRC)gdevos2p.c
diff --git a/gs/src/pipe_.h b/gs/src/pipe_.h
new file mode 100644
index 000000000..758a82627
--- /dev/null
+++ b/gs/src/pipe_.h
@@ -0,0 +1,36 @@
+/* Copyright (C) 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: pipe_.h */
+/* Declaration of popen and pclose */
+
+#ifndef pipe__INCLUDED
+# define pipe__INCLUDED
+
+#include "stdio_.h"
+
+/*
+ * popen isn't POSIX-standard, so we declare it here.
+ * Because of inconsistent (and sometimes incorrect) header files,
+ * we must omit the argument list. Unfortunately, this sometimes causes
+ * more trouble than it cures.
+ */
+extern FILE *popen( /* P2(const char *, const char *) */ );
+extern int pclose(P1(FILE *));
+
+#endif /* pipe__INCLUDED */
diff --git a/gs/src/scfparam.c b/gs/src/scfparam.c
new file mode 100644
index 000000000..233fc6861
--- /dev/null
+++ b/gs/src/scfparam.c
@@ -0,0 +1,93 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: scfparam.c */
+/* CCITTFax filter parameter setting and reading */
+#include "std.h"
+#include "gserror.h"
+#include "gserrors.h"
+#include "gstypes.h"
+#include "gsmemory.h"
+#include "gsparam.h"
+#include "scommon.h"
+#include "scf.h" /* for cfe_max_width */
+#include "scfx.h"
+
+/* Define the CCITTFax parameters. */
+private const gs_param_item_t s_CF_param_items[] =
+{
+#define cfp(key, type, memb) { key, type, offset_of(stream_CF_state, memb) }
+ cfp("Uncompressed", gs_param_type_bool, Uncompressed),
+ cfp("K", gs_param_type_int, K),
+ cfp("EndOfLine", gs_param_type_bool, EndOfLine),
+ cfp("EncodedByteAlign", gs_param_type_bool, EncodedByteAlign),
+ cfp("Columns", gs_param_type_int, Columns),
+ cfp("Rows", gs_param_type_int, Rows),
+ cfp("EndOfBlock", gs_param_type_bool, EndOfBlock),
+ cfp("BlackIs1", gs_param_type_bool, BlackIs1),
+ cfp("DamagedRowsBeforeError", gs_param_type_int, DamagedRowsBeforeError),
+ cfp("FirstBitLowOrder", gs_param_type_bool, FirstBitLowOrder),
+ cfp("DecodedByteAlign", gs_param_type_int, DecodedByteAlign),
+#undef cfp
+ gs_param_item_end
+};
+
+/* Define a limit on the Rows parameter, close to max_int. */
+#define cf_max_height 32000
+
+/* Get non-default CCITTFax filter parameters. */
+stream_state_proc_get_params(s_CF_get_params, stream_CF_state); /* check */
+int
+s_CF_get_params(gs_param_list * plist, const stream_CF_state * ss, bool all)
+{
+ stream_CF_state cfs_defaults;
+ const stream_CF_state *defaults;
+
+ if (all)
+ defaults = 0;
+ else {
+ s_CF_set_defaults_inline(&cfs_defaults);
+ defaults = &cfs_defaults;
+ }
+ return gs_param_write_items(plist, ss, defaults, s_CF_param_items);
+}
+
+/* Put CCITTFax filter parameters. */
+stream_state_proc_put_params(s_CF_put_params, stream_CF_state); /* check */
+int
+s_CF_put_params(gs_param_list * plist, stream_CF_state * ss)
+{
+ stream_CF_state state;
+ int code;
+
+ state = *ss;
+ code = gs_param_read_items(plist, (void *)&state, s_CF_param_items);
+ if (code >= 0 &&
+ (state.K < -cf_max_height || state.K > cf_max_height ||
+ state.Columns < 0 || state.Columns > cfe_max_width ||
+ state.Rows < 0 || state.Rows > cf_max_height ||
+ state.DamagedRowsBeforeError < 0 ||
+ state.DamagedRowsBeforeError > cf_max_height ||
+ state.DecodedByteAlign < 1 || state.DecodedByteAlign > 16 ||
+ (state.DecodedByteAlign & (state.DecodedByteAlign - 1)) != 0)
+ )
+ code = gs_note_error(gs_error_rangecheck);
+ if (code >= 0)
+ *ss = state;
+ return code;
+}
diff --git a/gs/src/sdcparam.c b/gs/src/sdcparam.c
new file mode 100644
index 000000000..183e0a59e
--- /dev/null
+++ b/gs/src/sdcparam.c
@@ -0,0 +1,619 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: sdcparam.c */
+/* DCT filter parameter setting and reading */
+#include "memory_.h"
+#include "jpeglib.h"
+#include "gserror.h"
+#include "gserrors.h"
+#include "gstypes.h"
+#include "gsmemory.h"
+#include "gsparam.h"
+#include "strimpl.h" /* sdct.h requires this */
+#include "sdct.h"
+#include "sdcparam.h"
+#include "sjpeg.h"
+
+/* Define the DCT parameters. */
+#define dctp(key, type, stype, memb) { key, type, offset_of(stype, memb) }
+private const gs_param_item_t s_DCT_param_items[] =
+{
+dctp("ColorTransform", gs_param_type_int, stream_DCT_state, ColorTransform),
+ dctp("QFactor", gs_param_type_float, stream_DCT_state, QFactor),
+ gs_param_item_end
+};
+private const gs_param_item_t jsd_param_items[] =
+{
+ dctp("Picky", gs_param_type_int, jpeg_stream_data, Picky),
+ dctp("Relax", gs_param_type_int, jpeg_stream_data, Relax),
+ gs_param_item_end
+};
+
+#undef dctp
+
+/*
+ * Adobe specifies the values to be supplied in zigzag order.
+ * For IJG versions newer than v6, we need to convert this order
+ * to natural array order. Older IJG versions want zigzag order.
+ */
+#if JPEG_LIB_VERSION >= 61
+ /* natural array position of n'th element of JPEG zigzag order */
+static const byte natural_order[DCTSIZE2] =
+{
+ 0, 1, 8, 16, 9, 2, 3, 10,
+ 17, 24, 32, 25, 18, 11, 4, 5,
+ 12, 19, 26, 33, 40, 48, 41, 34,
+ 27, 20, 13, 6, 7, 14, 21, 28,
+ 35, 42, 49, 56, 57, 50, 43, 36,
+ 29, 22, 15, 23, 30, 37, 44, 51,
+ 58, 59, 52, 45, 38, 31, 39, 46,
+ 53, 60, 61, 54, 47, 55, 62, 63
+};
+
+#define jpeg_order(x) natural_order[x]
+ /* invert natural_order for getting parameters */
+static const byte inverse_natural_order[DCTSIZE2] =
+{
+ 0, 1, 5, 6, 14, 15, 27, 28,
+ 2, 4, 7, 13, 16, 26, 29, 42,
+ 3, 8, 12, 17, 25, 30, 41, 43,
+ 9, 11, 18, 24, 31, 40, 44, 53,
+ 10, 19, 23, 32, 39, 45, 52, 54,
+ 20, 22, 33, 38, 46, 51, 55, 60,
+ 21, 34, 37, 47, 50, 56, 59, 61,
+ 35, 36, 48, 49, 57, 58, 62, 63
+};
+
+#define jpeg_inverse_order(x) inverse_natural_order[x]
+#else
+#define jpeg_order(x) (x)
+#define jpeg_inverse_order(x) (x)
+#endif
+
+/* ================ Get parameters ================ */
+
+private int
+quant_param_string(gs_param_string * pstr, int count, const UINT16 * pvals,
+ floatp QFactor, gs_memory_t * mem)
+{
+ byte *data;
+ int code = 0;
+ int i;
+
+ data = gs_alloc_string(mem, count, "quant_param_string");
+ if (data == 0)
+ return_error(gs_error_VMerror);
+ for (i = 0; i < count; ++i) {
+ floatp val = pvals[jpeg_inverse_order(i)] / QFactor;
+
+ data[i] =
+ (val < 1 ? (code = 1) : val > 255 ? (code = 255) : (byte) val);
+ }
+ pstr->data = data;
+ pstr->size = count;
+ pstr->persistent = true;
+ return code & 1;
+}
+
+private int
+quant_param_array(gs_param_float_array * pfa, int count, const UINT16 * pvals,
+ floatp QFactor, gs_memory_t * mem)
+{
+ float *data;
+ int i;
+
+ data = (float *)gs_alloc_byte_array(mem, count, sizeof(float),
+ "quant_param_array");
+
+ if (data == 0)
+ return_error(gs_error_VMerror);
+ for (i = 0; i < count; ++i)
+ data[i] = pvals[jpeg_inverse_order(i)] / QFactor;
+ pfa->data = data;
+ pfa->size = count;
+ pfa->persistent = true;
+ return 0;
+}
+
+int
+s_DCT_get_quantization_tables(gs_param_list * plist,
+ const stream_DCT_state * pdct, const stream_DCT_state * defaults,
+ bool is_encode)
+{
+ gs_memory_t *mem = pdct->memory;
+ jpeg_component_info d_comp_info[4];
+ int num_in_tables;
+ const jpeg_component_info *comp_info;
+ const jpeg_component_info *default_comp_info;
+ JQUANT_TBL **table_ptrs;
+ JQUANT_TBL **default_table_ptrs;
+ gs_param_array quant_tables;
+ floatp QFactor = pdct->QFactor;
+ int i;
+ int code;
+
+ if (is_encode) {
+ num_in_tables = pdct->data.compress->cinfo.num_components;
+ comp_info = pdct->data.compress->cinfo.comp_info;
+ table_ptrs = pdct->data.compress->cinfo.quant_tbl_ptrs;
+ if (defaults) {
+ default_comp_info = defaults->data.compress->cinfo.comp_info;
+ default_table_ptrs = defaults->data.compress->cinfo.quant_tbl_ptrs;
+ }
+ } else {
+ num_in_tables = quant_tables.size;
+ for (i = 0; i < num_in_tables; ++i)
+ d_comp_info[i].quant_tbl_no = i;
+ comp_info = d_comp_info;
+ table_ptrs = pdct->data.decompress->dinfo.quant_tbl_ptrs;
+ if (defaults) {
+ default_comp_info = d_comp_info;
+ default_table_ptrs =
+ defaults->data.decompress->dinfo.quant_tbl_ptrs;
+ }
+ }
+
+ /* Check whether all tables match defaults. */
+ if (defaults) {
+ bool match = true;
+
+ for (i = 0; i < num_in_tables; ++i) {
+ JQUANT_TBL *tbl = table_ptrs[comp_info[i].quant_tbl_no];
+ JQUANT_TBL *default_tbl =
+ (default_comp_info == 0 || default_table_ptrs == 0 ? 0 :
+ default_table_ptrs[default_comp_info[i].quant_tbl_no]);
+
+ if (tbl == default_tbl)
+ continue;
+ if (tbl == 0 || default_tbl == 0 ||
+ memcmp(tbl->quantval, default_tbl->quantval,
+ DCTSIZE2 * sizeof(UINT16))
+ ) {
+ match = false;
+ break;
+ }
+ }
+ if (match)
+ return 0;
+ }
+ quant_tables.size = num_in_tables;
+ code = param_begin_write_collection(plist, "QuantTables",
+ &quant_tables,
+ gs_param_collection_array);
+ if (code < 0)
+ return code;
+ for (i = 0; i < num_in_tables; ++i) {
+ char key[3];
+ gs_param_string str;
+ gs_param_float_array fa;
+
+ sprintf(key, "%d", i);
+ if (QFactor == 1.0) {
+ code = quant_param_string(&str, DCTSIZE2,
+ table_ptrs[comp_info[i].quant_tbl_no]->quantval,
+ QFactor, mem);
+ switch (code) {
+ case 0:
+ code = param_write_string(quant_tables.list, key, &str);
+ if (code < 0)
+ return code; /* should dealloc */
+ continue;
+ default:
+ return code; /* should dealloc */
+ case 1:
+ break;
+ }
+ /* break const to free the string */
+ gs_free_string(mem, (byte *) str.data, str.size,
+ "quant_param_string");
+ }
+ code = quant_param_array(&fa, DCTSIZE2,
+ table_ptrs[comp_info[i].quant_tbl_no]->quantval,
+ QFactor, mem);
+ if (code < 0)
+ return code; /* should dealloc */
+ code = param_write_float_array(quant_tables.list, key, &fa);
+ if (code < 0)
+ return code; /* should dealloc */
+ }
+ return param_end_write_dict(plist, "QuantTables", &quant_tables);
+}
+
+private int
+pack_huff_table(gs_param_string * pstr, const JHUFF_TBL * table,
+ gs_memory_t * mem)
+{
+ int total;
+ int i;
+ byte *data;
+
+ for (i = 1, total = 0; i <= 16; ++i)
+ total += table->bits[i];
+ data = gs_alloc_string(mem, 16 + total, "pack_huff_table");
+ if (data == 0)
+ return_error(gs_error_VMerror);
+ memcpy(data, table->bits + 1, 16);
+ memcpy(data + 16, table->huffval, total);
+ pstr->data = data;
+ pstr->size = 16 + total;
+ pstr->persistent = true;
+ return 0;
+}
+
+int
+s_DCT_get_huffman_tables(gs_param_list * plist,
+ const stream_DCT_state * pdct, const stream_DCT_state * defaults,
+ bool is_encode)
+{
+ gs_memory_t *mem = pdct->memory;
+ gs_param_string *huff_data;
+ gs_param_string_array hta;
+ int num_in_tables;
+ jpeg_component_info *comp_info;
+ JHUFF_TBL **dc_table_ptrs;
+ JHUFF_TBL **ac_table_ptrs;
+ int i;
+ int code = 0;
+
+ if (is_encode) {
+ dc_table_ptrs = pdct->data.compress->cinfo.dc_huff_tbl_ptrs;
+ ac_table_ptrs = pdct->data.compress->cinfo.ac_huff_tbl_ptrs;
+ num_in_tables = pdct->data.compress->cinfo.input_components * 2;
+ comp_info = pdct->data.compress->cinfo.comp_info;
+ } else {
+ dc_table_ptrs = pdct->data.decompress->dinfo.dc_huff_tbl_ptrs;
+ ac_table_ptrs = pdct->data.decompress->dinfo.ac_huff_tbl_ptrs;
+ for (i = 2; i > 0; --i)
+ if (dc_table_ptrs[i - 1] || ac_table_ptrs[i - 1])
+ break;
+ num_in_tables = i * 2;
+ comp_info = NULL; /* do not set for decompress case */
+ }
+/****** byte_array IS WRONG ******/
+ huff_data = (gs_param_string *)
+ gs_alloc_byte_array(mem, num_in_tables, sizeof(gs_param_string),
+ "get huffman tables");
+ if (huff_data == 0)
+ return_error(gs_error_VMerror);
+ for (i = 0; i < num_in_tables; i += 2) {
+ if ((code = pack_huff_table(huff_data + i, ac_table_ptrs[i >> 1], mem)) < 0 ||
+ (code = pack_huff_table(huff_data + i + 1, dc_table_ptrs[i >> 1], mem))
+ )
+ break;
+ }
+ if (code < 0)
+ return code;
+ hta.data = huff_data;
+ hta.size = num_in_tables;
+ hta.persistent = true;
+ return param_write_string_array(plist, "HuffTables", &hta);
+}
+
+int
+s_DCT_get_params(gs_param_list * plist, const stream_DCT_state * ss,
+ const stream_DCT_state * defaults)
+{
+ int code =
+ gs_param_write_items(plist, ss, defaults, s_DCT_param_items);
+
+ if (code >= 0)
+ code = gs_param_write_items(plist, ss->data.common,
+ (defaults ? defaults->data.common :
+ NULL),
+ jsd_param_items);
+ return code;
+}
+
+/* ================ Put parameters ================ */
+
+stream_state_proc_put_params(s_DCT_put_params, stream_DCT_state); /* check */
+
+/* ---------------- Utilities ---------------- */
+
+/*
+ * Get N byte-size values from an array or a string.
+ * Used for HuffTables, HSamples, VSamples.
+ */
+int
+s_DCT_byte_params(gs_param_list * plist, gs_param_name key, int start,
+ int count, UINT8 * pvals)
+{
+ int i;
+ gs_param_string bytes;
+ gs_param_float_array floats;
+ int code = param_read_string(plist, key, &bytes);
+
+ switch (code) {
+ case 0:
+ if (bytes.size < start + count) {
+ code = gs_note_error(gs_error_rangecheck);
+ break;
+ }
+ for (i = 0; i < count; ++i)
+ pvals[i] = (UINT8) bytes.data[start + i];
+ return 0;
+ default: /* might be a float array */
+ code = param_read_float_array(plist, key, &floats);
+ if (!code) {
+ if (floats.size < start + count) {
+ code = gs_note_error(gs_error_rangecheck);
+ break;
+ }
+ for (i = 0; i < count; ++i) {
+ float v = floats.data[start + i];
+
+ if (v < 0 || v > 255) {
+ code = gs_note_error(gs_error_rangecheck);
+ break;
+ }
+ pvals[i] = (UINT8) (v + 0.5);
+ }
+ }
+ }
+ if (code < 0)
+ param_signal_error(plist, key, code);
+ return code;
+}
+
+/* Get N quantization values from an array or a string. */
+private int
+quant_params(gs_param_list * plist, gs_param_name key, int count,
+ UINT16 * pvals, floatp QFactor)
+{
+ int i;
+ gs_param_string bytes;
+ gs_param_float_array floats;
+ int code = param_read_string(plist, key, &bytes);
+
+ switch (code) {
+ case 0:
+ if (bytes.size != count) {
+ code = gs_note_error(gs_error_rangecheck);
+ break;
+ }
+ for (i = 0; i < count; ++i) {
+ double v = bytes.data[i] * QFactor;
+
+ pvals[jpeg_order(i)] =
+ (UINT16) (v < 1 ? 1 : v > 255 ? 255 : v + 0.5);
+ }
+ return 0;
+ default: /* might be a float array */
+ code = param_read_float_array(plist, key, &floats);
+ if (!code) {
+ if (floats.size != count) {
+ code = gs_note_error(gs_error_rangecheck);
+ break;
+ }
+ for (i = 0; i < count; ++i) {
+ double v = floats.data[i] * QFactor;
+
+ pvals[jpeg_order(i)] =
+ (UINT16) (v < 1 ? 1 : v > 255 ? 255 : v + 0.5);
+ }
+ }
+ }
+ if (code < 0)
+ param_signal_error(plist, key, code);
+ return code;
+#undef jpeg_order
+}
+
+/* ---------------- Main procedures ---------------- */
+
+/* Put common scalars. */
+int
+s_DCT_put_params(gs_param_list * plist, stream_DCT_state * pdct)
+{
+ int code =
+ gs_param_read_items(plist, pdct, s_DCT_param_items);
+
+ if (code < 0)
+ return code;
+ code = gs_param_read_items(plist, pdct->data.common, jsd_param_items);
+ if (code < 0)
+ return code;
+ if (pdct->data.common->Picky < 0 || pdct->data.common->Picky > 1 ||
+ pdct->data.common->Relax < 0 || pdct->data.common->Relax > 1 ||
+ pdct->ColorTransform < -1 || pdct->ColorTransform > 2 ||
+ pdct->QFactor < 0.0 || pdct->QFactor > 1000000.0
+ )
+ return_error(gs_error_rangecheck);
+ return 0;
+}
+
+/* Put quantization tables. */
+int
+s_DCT_put_quantization_tables(gs_param_list * plist, stream_DCT_state * pdct,
+ bool is_encode)
+{
+ int code;
+ int i, j;
+ gs_param_array quant_tables; /* array of strings/arrays */
+ int num_in_tables;
+ int num_out_tables;
+ jpeg_component_info *comp_info;
+ JQUANT_TBL **table_ptrs;
+ JQUANT_TBL *this_table;
+
+ switch ((code = param_begin_read_dict(plist, "QuantTables",
+ &quant_tables, true))
+ ) {
+ case 1:
+ return 0;
+ default:
+ return param_signal_error(plist, "QuantTables", code);
+ case 0:
+ ;
+ }
+ if (is_encode) {
+ num_in_tables = pdct->data.compress->cinfo.num_components;
+ if (quant_tables.size < num_in_tables)
+ return_error(gs_error_rangecheck);
+ comp_info = pdct->data.compress->cinfo.comp_info;
+ table_ptrs = pdct->data.compress->cinfo.quant_tbl_ptrs;
+ } else {
+ num_in_tables = quant_tables.size;
+ comp_info = NULL; /* do not set for decompress case */
+ table_ptrs = pdct->data.decompress->dinfo.quant_tbl_ptrs;
+ }
+ num_out_tables = 0;
+ for (i = 0; i < num_in_tables; ++i) {
+ char istr[5]; /* i converted to string key */
+ UINT16 values[DCTSIZE2];
+
+ sprintf(istr, "%d", i);
+ code = quant_params(quant_tables.list, istr, DCTSIZE2, values,
+ pdct->QFactor);
+ if (code < 0)
+ return code;
+ /* Check for duplicate tables. */
+ for (j = 0; j < num_out_tables; j++) {
+ if (!memcmp(table_ptrs[j]->quantval, values, sizeof(values)))
+ break;
+ }
+ if (comp_info != NULL)
+ comp_info[i].quant_tbl_no = j;
+ if (j < num_out_tables) /* found a duplicate */
+ continue;
+ if (++num_out_tables > NUM_QUANT_TBLS)
+ return_error(gs_error_rangecheck);
+ this_table = table_ptrs[j];
+ if (this_table == NULL) {
+ this_table = gs_jpeg_alloc_quant_table(pdct);
+ if (this_table == NULL)
+ return_error(gs_error_VMerror);
+ table_ptrs[j] = this_table;
+ }
+ memcpy(this_table->quantval, values, sizeof(values));
+ }
+ return 0;
+}
+
+/* Put Huffman tables. */
+private int
+find_huff_values(JHUFF_TBL ** table_ptrs, int num_tables,
+ const UINT8 counts[16], const UINT8 * values, int codes_size)
+{
+ int j;
+
+ for (j = 0; j < num_tables; ++j)
+ if (!memcmp(table_ptrs[j]->bits, counts, sizeof(counts)) &&
+ !memcmp(table_ptrs[j]->huffval, values,
+ codes_size * sizeof(values[0])))
+ break;
+ return j;
+}
+int
+s_DCT_put_huffman_tables(gs_param_list * plist, stream_DCT_state * pdct,
+ bool is_encode)
+{
+ int code;
+ int i, j;
+ gs_param_array huff_tables;
+ int num_in_tables;
+ int ndc, nac;
+ int codes_size;
+ jpeg_component_info *comp_info;
+ JHUFF_TBL **dc_table_ptrs;
+ JHUFF_TBL **ac_table_ptrs;
+ JHUFF_TBL **this_table_ptr;
+ JHUFF_TBL *this_table;
+ int max_tables = 2; /* baseline limit */
+
+ switch ((code = param_begin_read_dict(plist, "HuffTables",
+ &huff_tables, true))
+ ) {
+ case 1:
+ return 0;
+ default:
+ return param_signal_error(plist, "HuffTables", code);
+ case 0:
+ ;
+ }
+ if (is_encode) {
+ num_in_tables = pdct->data.compress->cinfo.input_components * 2;
+ if (huff_tables.size < num_in_tables)
+ return_error(gs_error_rangecheck);
+ comp_info = pdct->data.compress->cinfo.comp_info;
+ dc_table_ptrs = pdct->data.compress->cinfo.dc_huff_tbl_ptrs;
+ ac_table_ptrs = pdct->data.compress->cinfo.ac_huff_tbl_ptrs;
+ if (pdct->data.common->Relax)
+ max_tables = max(pdct->data.compress->cinfo.input_components, 2);
+ } else {
+ num_in_tables = huff_tables.size;
+ comp_info = NULL; /* do not set for decompress case */
+ dc_table_ptrs = pdct->data.decompress->dinfo.dc_huff_tbl_ptrs;
+ ac_table_ptrs = pdct->data.decompress->dinfo.ac_huff_tbl_ptrs;
+ if (pdct->data.common->Relax)
+ max_tables = NUM_HUFF_TBLS;
+ }
+ ndc = nac = 0;
+ for (i = 0; i < num_in_tables; ++i) {
+ char istr[5]; /* i converted to string key */
+ UINT8 counts[16], values[256];
+
+ /* Collect the Huffman parameters. */
+ sprintf(istr, "%d", i);
+ code = s_DCT_byte_params(huff_tables.list, istr, 0, 16, counts);
+ if (code < 0)
+ return code;
+ for (codes_size = 0, j = 0; j < 16; j++)
+ codes_size += counts[j];
+ if (codes_size > 256 /*|| r_size(pa) != codes_size+16 */ )
+ return_error(gs_error_rangecheck);
+ code = s_DCT_byte_params(huff_tables.list, istr, 16, codes_size,
+ values);
+ if (code < 0)
+ return code;
+ if (i & 1) {
+ j = find_huff_values(ac_table_ptrs, nac, counts, values,
+ codes_size);
+ if (comp_info != NULL)
+ comp_info[i >> 1].ac_tbl_no = j;
+ if (j < nac)
+ continue;
+ if (++nac > NUM_HUFF_TBLS)
+ return_error(gs_error_rangecheck);
+ this_table_ptr = ac_table_ptrs + j;
+ } else {
+ j = find_huff_values(dc_table_ptrs, ndc, counts, values,
+ codes_size);
+ if (comp_info != NULL)
+ comp_info[i >> 1].dc_tbl_no = j;
+ if (j < ndc)
+ continue;
+ if (++ndc > NUM_HUFF_TBLS)
+ return_error(gs_error_rangecheck);
+ this_table_ptr = dc_table_ptrs + j;
+ }
+ this_table = *this_table_ptr;
+ if (this_table == NULL) {
+ this_table = gs_jpeg_alloc_huff_table(pdct);
+ if (this_table == NULL)
+ return_error(gs_error_VMerror);
+ *this_table_ptr = this_table;
+ }
+ memcpy(this_table->bits, counts, sizeof(counts));
+ memcpy(this_table->huffval, values, codes_size * sizeof(values[0]));
+ }
+ if (nac > max_tables || ndc > max_tables)
+ return_error(gs_error_rangecheck);
+ return 0;
+}
diff --git a/gs/src/sdcparam.h b/gs/src/sdcparam.h
new file mode 100644
index 000000000..aa5501dfb
--- /dev/null
+++ b/gs/src/sdcparam.h
@@ -0,0 +1,51 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: sdcparam.h */
+/* DCT filter parameter setting and reading interface */
+
+#ifndef sdcparam_INCLUDED
+# define sdcparam_INCLUDED
+
+/*
+ * All of these procedures are defined in sdcparam.c and are only for
+ * internal use (by sddparam.c and sdeparam.c), so they are not
+ * documented here.
+ */
+
+int s_DCT_get_params(P3(gs_param_list * plist, const stream_DCT_state * ss,
+ const stream_DCT_state * defaults));
+int s_DCT_get_quantization_tables(P4(gs_param_list * plist,
+ const stream_DCT_state * pdct,
+ const stream_DCT_state * defaults,
+ bool is_encode));
+int s_DCT_get_huffman_tables(P4(gs_param_list * plist,
+ const stream_DCT_state * pdct,
+ const stream_DCT_state * defaults,
+ bool is_encode));
+
+int s_DCT_byte_params(P5(gs_param_list * plist, gs_param_name key, int start,
+ int count, UINT8 * pvals));
+int s_DCT_put_params(P2(gs_param_list * plist, stream_DCT_state * pdct));
+int s_DCT_put_quantization_tables(P3(gs_param_list * plist,
+ stream_DCT_state * pdct,
+ bool is_encode));
+int s_DCT_put_huffman_tables(P3(gs_param_list * plist, stream_DCT_state * pdct,
+ bool is_encode));
+
+#endif /* sdcparam_INCLUDED */
diff --git a/gs/src/sddparam.c b/gs/src/sddparam.c
new file mode 100644
index 000000000..0d7ccf294
--- /dev/null
+++ b/gs/src/sddparam.c
@@ -0,0 +1,72 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: sddparam.c */
+/* DCTDecode filter parameter setting and reading */
+#include "std.h"
+#include "jpeglib.h"
+#include "gserror.h"
+#include "gserrors.h"
+#include "gstypes.h"
+#include "gsmemory.h"
+#include "gsparam.h"
+#include "strimpl.h" /* sdct.h requires this */
+#include "sdct.h"
+#include "sdcparam.h"
+#include "sjpeg.h"
+
+/* ================ Get parameters ================ */
+
+stream_state_proc_get_params(s_DCTD_get_params, stream_DCT_state); /* check */
+
+int
+s_DCTD_get_params(gs_param_list * plist, const stream_DCT_state * ss, bool all)
+{
+ stream_DCT_state dcts_defaults;
+ const stream_DCT_state *defaults;
+
+ if (all)
+ defaults = 0;
+ else {
+ (*s_DCTE_template.set_defaults) ((stream_state *) & dcts_defaults);
+ defaults = &dcts_defaults;
+ }
+/****** NYI ******/
+ return s_DCT_get_params(plist, ss, defaults);
+}
+
+/* ================ Put parameters ================ */
+
+stream_state_proc_put_params(s_DCTD_put_params, stream_DCT_state); /* check */
+
+int
+s_DCTD_put_params(gs_param_list * plist, stream_DCT_state * pdct)
+{
+ int code;
+
+ if ((code = s_DCT_put_params(plist, pdct)) < 0 ||
+ /*
+ * DCTDecode accepts quantization and huffman tables
+ * in case these tables have been omitted from the datastream.
+ */
+ (code = s_DCT_put_huffman_tables(plist, pdct, false)) < 0 ||
+ (code = s_DCT_put_quantization_tables(plist, pdct, false)) < 0
+ )
+ DO_NOTHING;
+ return code;
+}
diff --git a/gs/src/sdeparam.c b/gs/src/sdeparam.c
new file mode 100644
index 000000000..fae6b1610
--- /dev/null
+++ b/gs/src/sdeparam.c
@@ -0,0 +1,317 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: sdeparam.c */
+/* DCTEncode filter parameter setting and reading */
+#include "memory_.h"
+#include "jpeglib.h"
+#include "gserror.h"
+#include "gserrors.h"
+#include "gstypes.h"
+#include "gsmemory.h"
+#include "gsparam.h"
+#include "strimpl.h" /* sdct.h requires this */
+#include "sdct.h"
+#include "sdcparam.h"
+#include "sjpeg.h"
+
+/* Define a structure for the DCTEncode scalar parameters. */
+typedef struct dcte_scalars_s {
+ int Columns;
+ int Rows;
+ int Colors;
+ gs_param_string Markers;
+ bool NoMarker;
+ int Resync;
+ int Blend;
+} dcte_scalars_t;
+private const dcte_scalars_t dcte_scalars_default =
+{
+ 0, 0, -1,
+ {0, 0}, 0 /*false */ , 0, 0
+};
+private const gs_param_item_t s_DCTE_param_items[] =
+{
+#define dctp(key, type, memb) { key, type, offset_of(dcte_scalars_t, memb) }
+ dctp("Columns", gs_param_type_int, Columns),
+ dctp("Rows", gs_param_type_int, Rows),
+ dctp("Colors", gs_param_type_int, Colors),
+ dctp("Marker", gs_param_type_string, Markers),
+ dctp("NoMarker", gs_param_type_bool, NoMarker),
+ dctp("Resync", gs_param_type_int, Resync),
+ dctp("Blend", gs_param_type_int, Blend),
+#undef dctp
+ gs_param_item_end
+};
+
+/* ================ Get parameters ================ */
+
+stream_state_proc_get_params(s_DCTE_get_params, stream_DCT_state); /* check */
+
+/* Get a set of sampling values. */
+private int
+dcte_get_samples(gs_param_list * plist, gs_param_name key, int num_colors,
+ const jpeg_compress_data * jcdp, gs_memory_t * mem, bool is_vert, bool all)
+{
+ const jpeg_component_info *comp_info = jcdp->cinfo.comp_info;
+ int samples[4];
+ bool write = all;
+ int i;
+
+ for (i = 0; i < num_colors; ++i)
+ write |= (samples[i] = (is_vert ? comp_info[i].v_samp_factor :
+ comp_info[i].h_samp_factor)) != 1;
+ if (write) {
+ int *data = (int *)gs_alloc_byte_array(mem, num_colors, sizeof(int),
+ "dcte_get_samples");
+ gs_param_int_array sa;
+
+ if (data == 0)
+ return_error(gs_error_VMerror);
+ sa.data = data;
+ sa.size = num_colors;
+ sa.persistent = true;
+ memcpy(data, samples, num_colors * sizeof(samples[0]));
+ return param_write_int_array(plist, key, &sa);
+ }
+ return 0;
+}
+
+int
+s_DCTE_get_params(gs_param_list * plist, const stream_DCT_state * ss, bool all)
+{
+ gs_memory_t *mem = ss->memory;
+ stream_DCT_state dcts_defaults;
+ const stream_DCT_state *defaults = 0;
+ dcte_scalars_t params;
+ const jpeg_compress_data *jcdp = ss->data.compress;
+ int code;
+
+ if (!all) {
+ jpeg_compress_data *jcdp_default =
+ (jpeg_compress_data *)
+ gs_alloc_bytes_immovable(mem, sizeof(*jcdp), "s_DCTE_get_params");
+
+ if (jcdp_default == 0)
+ return_error(gs_error_VMerror);
+ defaults = &dcts_defaults;
+ (*s_DCTE_template.set_defaults) ((stream_state *) & dcts_defaults);
+ dcts_defaults.data.compress = jcdp_default;
+ jcdp_default->memory = dcts_defaults.jpeg_memory = mem;
+ if ((code = gs_jpeg_create_compress(&dcts_defaults)) < 0)
+ goto fail; /* correct to do jpeg_destroy here */
+/****** SET DEFAULTS HERE ******/
+ dcts_defaults.data.common->Picky = 0;
+ dcts_defaults.data.common->Relax = 0;
+ }
+ params.Columns = jcdp->cinfo.image_width;
+ params.Rows = jcdp->cinfo.image_height;
+ params.Colors = jcdp->cinfo.input_components;
+ params.Markers.data = ss->Markers.data;
+ params.Markers.size = ss->Markers.size;
+ params.Markers.persistent = false;
+ params.NoMarker = ss->NoMarker;
+ params.Resync = jcdp->cinfo.restart_interval;
+ /* What about Blend?? */
+ if ((code = s_DCT_get_params(plist, ss, defaults)) < 0 ||
+ (code = gs_param_write_items(plist, &params,
+ &dcte_scalars_default,
+ s_DCTE_param_items)) < 0 ||
+ (code = dcte_get_samples(plist, "HSamples", params.Colors,
+ jcdp, mem, false, all)) < 0 ||
+ (code = dcte_get_samples(plist, "VSamples", params.Colors,
+ jcdp, mem, true, all)) < 0 ||
+ (code = s_DCT_get_quantization_tables(plist, ss, defaults, true)) < 0 ||
+ (code = s_DCT_get_huffman_tables(plist, ss, defaults, true)) < 0
+ )
+ DO_NOTHING;
+/****** NYI ******/
+ fail:if (defaults) {
+ gs_jpeg_destroy(&dcts_defaults);
+ gs_free_object(mem, dcts_defaults.data.compress,
+ "s_DCTE_get_params");
+ }
+ return code;
+}
+
+/* ================ Put parameters ================ */
+
+stream_state_proc_put_params(s_DCTE_put_params, stream_DCT_state); /* check */
+
+/* Put a set of sampling values. */
+private int
+dcte_put_samples(gs_param_list * plist, gs_param_name key, int num_colors,
+ jpeg_compress_data * jcdp, bool is_vert)
+{
+ int code;
+ int i;
+ jpeg_component_info *comp_info = jcdp->cinfo.comp_info;
+ UINT8 samples[4];
+
+ /*
+ * Adobe default is all sampling factors = 1,
+ * which is NOT the IJG default, so we must always assign values.
+ */
+ switch ((code = s_DCT_byte_params(plist, key, 0, num_colors,
+ samples))
+ ) {
+ default: /* error */
+ return code;
+ case 0:
+ break;
+ case 1:
+ samples[0] = samples[1] = samples[2] = samples[3] = 1;
+ }
+ for (i = 0; i < num_colors; i++) {
+ if (samples[i] < 1 || samples[i] > 4)
+ return_error(gs_error_rangecheck);
+ if (is_vert)
+ comp_info[i].v_samp_factor = samples[i];
+ else
+ comp_info[i].h_samp_factor = samples[i];
+ }
+ return 0;
+}
+
+/* Main procedure */
+int
+s_DCTE_put_params(gs_param_list * plist, stream_DCT_state * pdct)
+{
+ jpeg_compress_data *jcdp = pdct->data.compress;
+ dcte_scalars_t params;
+ int i;
+ int code;
+
+ params = dcte_scalars_default;
+ /*
+ * Required parameters for DCTEncode.
+ * (DCTDecode gets the equivalent info from the SOF marker.)
+ */
+ code = gs_param_read_items(plist, &params, s_DCTE_param_items);
+ if (code < 0)
+ return code;
+ if (params.Columns <= 0 || params.Columns > 0xffff ||
+ params.Rows <= 0 || params.Rows > 0xffff ||
+ params.Colors <= 0 || params.Colors == 2 || params.Colors > 4 ||
+ params.Resync < 0 || params.Resync > 0xffff ||
+ params.Blend < 0 || params.Blend > 1
+ )
+ return_error(gs_error_rangecheck);
+/****** HACK: SET DEFAULTS HERE ******/
+ jcdp->Picky = 0;
+ jcdp->Relax = 0;
+ if ((code = s_DCT_put_params(plist, pdct)) < 0 ||
+ (code = s_DCT_put_huffman_tables(plist, pdct, false)) < 0
+ )
+ return code;
+ switch ((code = s_DCT_put_quantization_tables(plist, pdct, false))) {
+ case 0:
+ break;
+ default:
+ return code;
+ case 1:
+ /* No QuantTables, but maybe a QFactor to apply to default. */
+ if (pdct->QFactor != 1.0) {
+ code = gs_jpeg_set_linear_quality(pdct,
+ (int)(min(pdct->QFactor, 100.0)
+ * 100.0 + 0.5),
+ TRUE);
+ if (code < 0)
+ return code;
+ }
+ }
+ /* Set up minimal image description & call set_defaults */
+ jcdp->cinfo.image_width = params.Columns;
+ jcdp->cinfo.image_height = params.Rows;
+ jcdp->cinfo.input_components = params.Colors;
+ switch (params.Colors) {
+ case 1:
+ jcdp->cinfo.in_color_space = JCS_GRAYSCALE;
+ break;
+ case 3:
+ jcdp->cinfo.in_color_space = JCS_RGB;
+ break;
+ case 4:
+ jcdp->cinfo.in_color_space = JCS_CMYK;
+ break;
+ default:
+ jcdp->cinfo.in_color_space = JCS_UNKNOWN;
+ }
+ if ((code = gs_jpeg_set_defaults(pdct)) < 0)
+ return code;
+ /* Change IJG colorspace defaults as needed;
+ * set ColorTransform to what will go in the Adobe marker.
+ */
+ switch (params.Colors) {
+ case 3:
+ if (pdct->ColorTransform < 0)
+ pdct->ColorTransform = 1; /* default */
+ if (pdct->ColorTransform == 0) {
+ if ((code = gs_jpeg_set_colorspace(pdct, JCS_RGB)) < 0)
+ return code;
+ } else
+ pdct->ColorTransform = 1; /* flag YCC xform */
+ break;
+ case 4:
+ if (pdct->ColorTransform < 0)
+ pdct->ColorTransform = 0; /* default */
+ if (pdct->ColorTransform != 0) {
+ if ((code = gs_jpeg_set_colorspace(pdct, JCS_YCCK)) < 0)
+ return code;
+ pdct->ColorTransform = 2; /* flag YCCK xform */
+ } else {
+ if ((code = gs_jpeg_set_colorspace(pdct, JCS_CMYK)) < 0)
+ return code;
+ }
+ break;
+ default:
+ pdct->ColorTransform = 0; /* no transform otherwise */
+ break;
+ }
+ /* Optional encoding-only parameters */
+ pdct->Markers.data = params.Markers.data;
+ pdct->Markers.size = params.Markers.size;
+ pdct->NoMarker = params.NoMarker;
+ if ((code = dcte_put_samples(plist, "HSamples", params.Colors,
+ jcdp, false)) < 0 ||
+ (code = dcte_put_samples(plist, "VSamples", params.Colors,
+ jcdp, true)) < 0
+ )
+ return code;
+ jcdp->cinfo.write_JFIF_header = FALSE;
+ jcdp->cinfo.write_Adobe_marker = FALSE; /* must do it myself */
+ jcdp->cinfo.restart_interval = params.Resync;
+ /* What to do with Blend ??? */
+ if (pdct->data.common->Relax == 0) {
+ jpeg_component_info *comp_info = jcdp->cinfo.comp_info;
+ int num_samples;
+
+ for (i = 0, num_samples = 0; i < params.Colors; i++)
+ num_samples += comp_info[i].h_samp_factor *
+ comp_info[i].v_samp_factor;
+ if (num_samples > 10)
+ return_error(gs_error_rangecheck);
+ /*
+ * Note: by default the IJG software does not allow
+ * num_samples to exceed 10, Relax or no. For full
+ * compatibility with Adobe's non-JPEG-compliant
+ * software, set MAX_BLOCKS_IN_MCU to 64 in jpeglib.h.
+ */
+ }
+ return 0;
+}
diff --git a/gs/src/unixinst.mak b/gs/src/unixinst.mak
new file mode 100644
index 000000000..2ba26d1e7
--- /dev/null
+++ b/gs/src/unixinst.mak
@@ -0,0 +1,102 @@
+# Copyright (C) 1997, 1998 Aladdin Enterprises. All rights reserved.
+#
+# This file is part of Aladdin Ghostscript.
+#
+# Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+# or distributor accepts any responsibility for the consequences of using it,
+# or for whether it serves any particular purpose or works at all, unless he
+# or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+# License (the "License") for full details.
+#
+# Every copy of Aladdin Ghostscript must include a copy of the License,
+# normally in a plain ASCII text file named PUBLIC. The License grants you
+# the right to copy, modify and redistribute Aladdin Ghostscript, but only
+# under certain conditions described in the License. Among other things, the
+# License requires that the copyright notice and this notice be preserved on
+# all copies.
+
+# Id: unixinst.mak
+# Partial makefile common to all Unix and Desqview/X configurations,
+# containing the `install' targets.
+# This is the very last part of the makefile for these configurations.
+
+install: install-exec install-scripts install-data
+
+# The sh -c in the rules below is required because Ultrix's implementation
+# of sh -e terminates execution of a command if any error occurs, even if
+# the command traps the error with ||.
+
+# We include mkdirs for datadir, gsdir, and gsdatadir in all 3 install
+# rules, just in case bindir or scriptdir is a subdirectory of any of these.
+
+install-exec: $(GS_XE)
+ -mkdir $(datadir)
+ -mkdir $(gsdir)
+ -mkdir $(gsdatadir)
+ -mkdir $(bindir)
+ $(INSTALL_PROGRAM) $(GS_XE) $(bindir)/$(GS)
+
+install-scripts: gsnd
+ -mkdir $(datadir)
+ -mkdir $(gsdir)
+ -mkdir $(gsdatadir)
+ -mkdir $(scriptdir)
+ sh -c 'for f in \
+gsbj gsdj gsdj500 gslj gslp gsnd \
+bdftops dvipdf font2c \
+pdf2dsc pdf2ps pf2afm printafm ps2ascii ps2epsi ps2pdf ps2ps wftopfa ;\
+ do if ( test -f $$f ); then $(INSTALL_PROGRAM) $$f $(scriptdir)/$$f; fi;\
+ done'
+
+MAN1_PAGES=gs pdf2dsc pdf2ps ps2ascii ps2epsi ps2pdf ps2ps
+install-data: gs.1
+ -mkdir $(mandir)
+ -mkdir $(man1dir)
+ sh -c 'for f in $(MAN1_PAGES) ;\
+ do if ( test -f $$f.1 ); then $(INSTALL_DATA) $$f.1 $(man1dir)/$$f.$(man1ext); fi;\
+ done'
+ -mkdir $(datadir)
+ -mkdir $(gsdir)
+ -mkdir $(gsdatadir)
+ sh -c 'for f in \
+Fontmap \
+cbjc600.ppd cbjc800.ppd *.upp \
+gs_init.ps gs_btokn.ps gs_ccfnt.ps gs_cff.ps gs_cidfn.ps gs_cmap.ps \
+gs_diskf.ps gs_dpnxt.ps gs_dps.ps gs_dps1.ps gs_dps2.ps gs_epsf.ps \
+gs_fonts.ps gs_kanji.ps gs_lev2.ps gs_ll3.ps \
+gs_pfile.ps gs_res.ps gs_setpd.ps gs_statd.ps \
+gs_ttf.ps gs_typ32.ps gs_typ42.ps gs_type1.ps \
+gs_dbt_e.ps gs_iso_e.ps gs_ksb_e.ps gs_std_e.ps gs_sym_e.ps \
+acctest.ps align.ps bdftops.ps caption.ps decrypt.ps docie.ps \
+font2c.ps font2pcl.ps gslp.ps impath.ps landscap.ps level1.ps lines.ps \
+markhint.ps markpath.ps \
+packfile.ps pcharstr.ps pf2afm.ps ppath.ps prfont.ps printafm.ps \
+ps2ai.ps ps2ascii.ps ps2epsi.ps ps2image.ps \
+quit.ps showchar.ps showpage.ps stcinfo.ps stcolor.ps \
+traceimg.ps traceop.ps type1enc.ps type1ops.ps uninfo.ps unprot.ps \
+viewcmyk.ps viewgif.ps viewjpeg.ps viewpcx.ps viewpbm.ps viewps2a.ps \
+winmaps.ps wftopfa.ps wrfont.ps zeroline.ps \
+gs_l2img.ps \
+pdf2dsc.ps \
+pdf_base.ps pdf_draw.ps pdf_font.ps pdf_main.ps pdf_ops.ps pdf_sec.ps \
+gs_mex_e.ps gs_mro_e.ps gs_pdf_e.ps gs_wan_e.ps \
+gs_pdfwr.ps ;\
+ do if ( test -f $$f ); then $(INSTALL_DATA) $$f $(gsdatadir)/$$f; fi;\
+ done'
+ -mkdir $(docdir)
+ sh -c 'for f in \
+COPYING NEWS PUBLIC README \
+bug-form.txt c-style.txt current.txt devices.txt drivers.txt fonts.txt \
+helpers.txt hershey.txt history1.txt history2.txt history3.txt humor.txt \
+install.txt language.txt lib.txt make.txt new-user.txt \
+ps2epsi.txt ps2pdf.txt psfiles.txt public.txt \
+unix-lpr.txt use.txt xfonts.txt ;\
+ do if ( test -f $$f ); then $(INSTALL_DATA) $$f $(docdir)/$$f; fi;\
+ done'
+ -mkdir $(exdir)
+ for f in \
+alphabet.ps chess.ps cheq.ps colorcir.ps escher.ps golfer.ps \
+grayalph.ps snowflak.ps tiger.ps vasarely.ps waterfal.ps \
+ridt91.eps ;\
+ do $(INSTALL_DATA) $$f $(exdir)/$$f ;\
+ done
diff --git a/gs/src/zcfont.c b/gs/src/zcfont.c
new file mode 100644
index 000000000..1ccbca488
--- /dev/null
+++ b/gs/src/zcfont.c
@@ -0,0 +1,158 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: zcfont.c */
+/* Composite font-related character operators */
+#include "ghost.h"
+#include "oper.h"
+#include "gschar.h"
+#include "gsmatrix.h" /* for gxfont.h */
+#include "gxfixed.h" /* for gxfont.h */
+#include "gxfont.h"
+#include "gxchar.h"
+#include "estack.h"
+#include "ichar.h"
+#include "ifont.h"
+#include "igstate.h"
+#include "store.h"
+
+/* Forward references */
+private int cshow_continue(P1(os_ptr));
+private int cshow_restore_font(P1(os_ptr));
+
+/* <proc> <string> cshow - */
+private int
+zcshow(os_ptr op)
+{
+ os_ptr proc_op = op - 1;
+ os_ptr str_op = op;
+ gs_show_enum *penum;
+ int code;
+
+ /*
+ * Even though this is not documented anywhere by Adobe,
+ * the Adobe interpreters apparently allow the string and
+ * the procedure to be provided in either order!
+ */
+ if (r_is_proc(proc_op))
+ ;
+ else if (r_is_proc(op)) { /* operands reversed */
+ proc_op = op;
+ str_op = op - 1;
+ } else {
+ check_op(2);
+ return_error(e_typecheck);
+ }
+ if ((code = op_show_setup(str_op, &penum)) != 0)
+ return code;
+ if ((code = gs_cshow_n_init(penum, igs, (char *)str_op->value.bytes,
+ r_size(str_op))) < 0
+ ) {
+ ifree_object(penum, "op_show_enum_setup");
+ return code;
+ }
+ op_show_finish_setup(penum, 2, NULL);
+ sslot = *proc_op; /* save kerning proc */
+ return cshow_continue(op - 2);
+}
+private int
+cshow_continue(os_ptr op)
+{
+ gs_show_enum *penum = senum;
+ int code;
+
+ check_estack(4); /* in case we call the procedure */
+ code = gs_show_next(penum);
+ if (code != gs_show_move) {
+ code = op_show_continue_dispatch(op, code);
+ if (code == o_push_estack) /* must be gs_show_render */
+ make_op_estack(esp - 1, cshow_continue);
+ return code;
+ }
+ /* Push the character code and width, and call the procedure. */
+ {
+ ref *pslot = &sslot;
+ gs_point wpt;
+ gs_font *font = gs_show_current_font(penum);
+ gs_font *scaled_font;
+
+ gs_show_current_width(penum, &wpt);
+#if 0
+ /****************
+ * The following code is logically correct (or at least,
+ * probably more correct than the code it replaces),
+ * but because of the issues about creating the scaled
+ * font in the correct VM space that make_font (in zfont.c)
+ * has to deal with, it creates references pointing to
+ * the wrong spaces. Therefore, we've removed it.
+ *****************/
+ {
+ int fdepth = penum->fstack.depth;
+
+ if (fdepth <= 0)
+ scaled_font = font; /* not composite */
+ else {
+ code = gs_makefont(font->dir, font,
+ &penum->fstack.items[fdepth - 1].font->
+ FontMatrix, &scaled_font);
+ if (code < 0)
+ return code;
+ }
+ }
+#else
+ scaled_font = font;
+#endif
+ push(3);
+ make_int(op - 2, gs_show_current_char(penum));
+ make_real(op - 1, wpt.x);
+ make_real(op, wpt.y);
+ push_op_estack(cshow_continue);
+ if (scaled_font != gs_rootfont(igs))
+ push_op_estack(cshow_restore_font);
+ /* cshow does not change rootfont for user procedure */
+ gs_set_currentfont(igs, scaled_font);
+ *++esp = *pslot; /* user procedure */
+ }
+ return o_push_estack;
+}
+private int
+cshow_restore_font(os_ptr op)
+{ /* We have 1 more entry on the e-stack (cshow_continue). */
+ return gs_show_restore_font(esenum(esp - 1));
+}
+
+/* - rootfont <font> */
+private int
+zrootfont(os_ptr op)
+{
+ push(1);
+ *op = *pfont_dict(gs_rootfont(igs));
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zcfont_op_defs[] =
+{
+ {"2cshow", zcshow},
+ {"0rootfont", zrootfont},
+ /* Internal operators */
+ {"0%cshow_continue", cshow_continue},
+ {"0%cshow_restore_font", cshow_restore_font},
+ op_def_end(0)
+};
diff --git a/gs/src/zchar32.c b/gs/src/zchar32.c
new file mode 100644
index 000000000..39b310914
--- /dev/null
+++ b/gs/src/zchar32.c
@@ -0,0 +1,190 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: zchar32.c */
+/* Type 32 font glyph operators */
+#include "ghost.h"
+#include "oper.h"
+#include "gsccode.h" /* for gxfont.h */
+#include "gscoord.h"
+#include "gsutil.h"
+#include "gxdevice.h"
+#include "gxdevmem.h"
+#include "gxchar.h"
+#include "gxfont.h"
+#include "gxfcache.h"
+#include "ifont.h"
+#include "igstate.h"
+
+/* ([wx wy llx lly urx ury] | [w0x w0y llx lly urx ury w1x w1y vx vy]) */
+/* <bitmap> <cid> <type32font> addglyph - */
+private floatp
+coeff_sign(floatp v)
+{
+ return (v < 0 ? -1.0 : v > 0 ? 1.0 : 0.0);
+}
+private int
+zaddglyph(os_ptr op)
+{
+ int num_wmodes = 1;
+ int int_mask = 0x3c; /* bits for llx .. ury */
+ uint msize;
+ double metrics[10];
+ int llx, lly, urx, ury;
+ int width, height, raster;
+ gs_font *pfont;
+ gs_matrix save_mat;
+ cached_fm_pair *pair;
+ int wmode;
+ int code;
+
+ check_array(op[-3]);
+ msize = r_size(op - 3);
+ switch (msize) {
+ case 10:
+ num_wmodes = 2;
+ int_mask = 0x33c; /* add bits for vx, vy */
+ case 6:
+ break;
+ default:
+ return_error(e_rangecheck);
+ }
+ code = num_params(op[-3].value.refs + msize - 1, msize, metrics);
+ if (code < 0)
+ return code;
+ if (~code & int_mask) /* check llx .. ury for integers */
+ return_error(e_typecheck);
+ check_read_type(op[-2], t_string);
+ llx = (int)metrics[2];
+ lly = (int)metrics[3];
+ urx = (int)metrics[4];
+ ury = (int)metrics[5];
+ width = urx - llx;
+ height = ury - lly;
+ raster = (width + 7) >> 3;
+ if (width < 0 || height < 0 || r_size(op - 2) != raster * height)
+ return_error(e_rangecheck);
+ check_int_leu(op[-1], 65535);
+ code = font_param(op, &pfont);
+ if (code < 0)
+ return code;
+ if (pfont->FontType != ft_bitmap)
+ return_error(e_invalidfont);
+ /* Set the CTM to the (properly oriented) identity. */
+ gs_currentmatrix(igs, &save_mat);
+ {
+ gs_matrix init_mat, font_mat;
+
+ gs_defaultmatrix(igs, &init_mat);
+ font_mat.xx = coeff_sign(init_mat.xx);
+ font_mat.xy = coeff_sign(init_mat.xy);
+ font_mat.yx = coeff_sign(init_mat.yx);
+ font_mat.yy = coeff_sign(init_mat.yy);
+ font_mat.tx = font_mat.ty = 0;
+ gs_setmatrix(igs, &font_mat);
+ }
+ pair = gx_lookup_fm_pair(pfont, igs);
+ if (pair == 0) {
+ gs_setmatrix(igs, &save_mat);
+ return_error(e_VMerror);
+ }
+ /* The APIs for adding characters to the cache are not ideal.... */
+ for (wmode = 0; wmode < num_wmodes; ++wmode) {
+ gx_device_memory mdev;
+ static const gs_log2_scale_point no_scale =
+ {0, 0};
+ cached_char *cc;
+ gx_bitmap_id id = gs_next_ids(1);
+
+ mdev.memory = 0;
+ mdev.target = 0;
+ cc = gx_alloc_char_bits(pfont->dir, &mdev, NULL, width, height,
+ &no_scale, 1);
+ if (cc == 0) {
+ code = gs_note_error(e_limitcheck);
+ break;
+ }
+ cc->wxy.x = float2fixed(metrics[0]);
+ cc->wxy.y = float2fixed(metrics[1]);
+ cc->offset.x = -llx;
+ cc->offset.y = -lly;
+ gx_copy_mono_unaligned((gx_device *) & mdev,
+ op[-2].value.const_bytes, 0, raster, id,
+ 0, 0, width, height,
+ (gx_color_index) 0, (gx_color_index) 1);
+ gx_add_cached_char(pfont->dir, &mdev, cc, pair, &no_scale);
+ cc->code = gs_min_cid_glyph + op[-1].value.intval;
+ cc->wmode = wmode;
+ gx_add_char_bits(pfont->dir, cc, &no_scale);
+ /* Adjust for WMode = 1. */
+ if (num_wmodes > wmode + 1) {
+ metrics[0] = metrics[6];
+ metrics[1] = metrics[7];
+ llx -= (int)metrics[8];
+ lly -= (int)metrics[9];
+ }
+ }
+ gs_setmatrix(igs, &save_mat);
+ if (code >= 0)
+ pop(4);
+ return code;
+}
+
+/* <cid_min> <cid_max> <type32font> removeglyphs - */
+typedef struct {
+ gs_glyph cid_min, cid_max;
+ gs_font *font;
+} font_cid_range_t;
+private bool
+select_cid_range(cached_char * cc, void *range_ptr)
+{
+ const font_cid_range_t *range = range_ptr;
+
+ return (cc->code >= range->cid_min &&
+ cc->code <= range->cid_max &&
+ cc->pair->font == range->font);
+}
+private int
+zremoveglyphs(os_ptr op)
+{
+ int code;
+ font_cid_range_t range;
+
+ check_int_leu(op[-2], 65535);
+ check_int_leu(op[-1], 65535);
+ code = font_param(op, &range.font);
+ if (code < 0)
+ return code;
+ if (range.font->FontType != ft_bitmap)
+ return_error(e_invalidfont);
+ range.cid_min = gs_min_cid_glyph + op[-2].value.intval;
+ range.cid_max = gs_min_cid_glyph + op[-1].value.intval;
+ gx_purge_selected_cached_chars(range.font->dir, select_cid_range,
+ &range);
+ pop(3);
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zchar32_op_defs[] =
+{
+ {"4addglyph", zaddglyph},
+ {"3removeglyphs", zremoveglyphs},
+ op_def_end(0)
+};
diff --git a/gs/src/zcsdevn.c b/gs/src/zcsdevn.c
new file mode 100644
index 000000000..92c406bd2
--- /dev/null
+++ b/gs/src/zcsdevn.c
@@ -0,0 +1,113 @@
+/* Copyright (C) 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: zcsdevn.c */
+/* DeviceN color space support */
+#include "ghost.h"
+#include "oper.h"
+#include "gxcspace.h" /* must precede gscolor2.h */
+#include "gscolor2.h"
+#include "igstate.h"
+#include "ialloc.h"
+#include "iname.h"
+
+/* Imported from gscdevn.c */
+extern const gs_color_space_type gs_color_space_type_DeviceN;
+
+/* <array> .setdevicepixelspace - */
+/* The current color space is the alternate space for the DeviceN space. */
+private int
+zsetdevicenspace(register os_ptr op)
+{
+ const ref *pcsa;
+ gs_separation_name *names;
+ uint num_components;
+ gs_color_space cs;
+ ref_colorspace cspace_old;
+ int code;
+
+ check_read_type(*op, t_array);
+ if (r_size(op) != 4)
+ return_error(e_rangecheck);
+ pcsa = op->value.const_refs + 1;
+ if (!r_is_array(pcsa))
+ return_error(e_typecheck);
+ num_components = r_size(pcsa);
+ if (num_components == 0)
+ return_error(e_rangecheck);
+ check_proc(pcsa[2]);
+ cs = *gs_currentcolorspace(igs);
+ if (!cs.type->can_be_alt_space)
+ return_error(e_rangecheck);
+ names = (gs_separation_name *)
+ ialloc_byte_array(num_components, sizeof(gs_separation_name),
+ ".setdevicenspace");
+ if (names == 0)
+ return_error(e_VMerror);
+ {
+ uint i;
+ ref sname;
+
+ for (i = 0; i < num_components; ++i) {
+ array_get(pcsa, (long)i, &sname);
+ switch (r_type(&sname)) {
+ case t_string:
+ code = name_from_string(&sname, &sname);
+ if (code < 0) {
+ ifree_object(names, ".setdevicenspace");
+ return code;
+ }
+ /* falls through */
+ case t_name:
+ names[i] = name_index(&sname);
+ break;
+ default:
+ ifree_object(names, ".setdevicenspace");
+ return_error(e_typecheck);
+ }
+ }
+ }
+ cs.params.device_n.alt_space = *(gs_base_color_space *) & cs;
+ cspace_old = istate->colorspace;
+ istate->colorspace.procs.special.device_n.layer_names = pcsa[0];
+ istate->colorspace.procs.special.device_n.tint_transform = pcsa[2];
+ cs.type = &gs_color_space_type_DeviceN;
+ cs.params.device_n.names = names;
+ cs.params.device_n.num_components = num_components;
+ cs.params.device_n.tint_transform = 0;
+/****** ? ******/
+ cs.params.device_n.tint_transform_data = 0;
+/****** ? ******/
+ code = gs_setcolorspace(igs, &cs);
+ if (code < 0) {
+ istate->colorspace = cspace_old;
+ ifree_object(names, ".setdevicenspace");
+ return code;
+ }
+ pop(1);
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zcsdevn_op_defs[] =
+{
+ op_def_begin_ll3(),
+ {"1.setdevicenspace", zsetdevicenspace},
+ op_def_end(0)
+};
diff --git a/gs/src/zcspixel.c b/gs/src/zcspixel.c
new file mode 100644
index 000000000..39ed38fd6
--- /dev/null
+++ b/gs/src/zcspixel.c
@@ -0,0 +1,67 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: zcspixel.c */
+/* DevicePixel color space support */
+#include "ghost.h"
+#include "oper.h"
+#include "igstate.h"
+#include "gscspace.h"
+#include "gsmatrix.h" /* for gscolor2.h */
+#include "gscolor2.h"
+#include "gscpixel.h"
+
+/* <array> .setdevicepixelspace - */
+private int
+zsetdevicepixelspace(register os_ptr op)
+{
+ ref depth;
+ gs_color_space cs;
+ int code;
+
+ check_read_type(*op, t_array);
+ if (r_size(op) != 2)
+ return_error(e_rangecheck);
+ array_get(op, 1L, &depth);
+ check_type_only(depth, t_integer);
+ switch (depth.value.intval) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ case 16:
+ case 24:
+ case 32:
+ break;
+ default:
+ return_error(e_rangecheck);
+ }
+ gs_cs_init_DevicePixel(&cs, (int)depth.value.intval);
+ code = gs_setcolorspace(igs, &cs);
+ if (code >= 0)
+ pop(1);
+ return code;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zcspixel_op_defs[] =
+{
+ {"1.setdevicepixelspace", zsetdevicepixelspace},
+ op_def_end(0)
+};
diff --git a/gs/src/zfont32.c b/gs/src/zfont32.c
new file mode 100644
index 000000000..6185597d3
--- /dev/null
+++ b/gs/src/zfont32.c
@@ -0,0 +1,73 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: zfont32.c */
+/* Type 32 font operators */
+#include "ghost.h"
+#include "oper.h"
+#include "gsccode.h" /* for gxfont.h */
+#include "gsmatrix.h"
+#include "gsutil.h"
+#include "gxfixed.h" /* for gxchar.h */
+#include "gxchar.h"
+#include "gxfont.h"
+#include "bfont.h"
+#include "store.h"
+
+/* The encode_char procedure of a Type 32 font should never be called. */
+private gs_glyph
+zfont_no_encode_char(gs_show_enum * penum, gs_font * pfont, gs_char * pchr)
+{
+ return gs_no_glyph;
+}
+
+/* <string|name> <font_dict> .buildfont32 <string|name> <font> */
+/* Build a type 32 (bitmap) font. */
+private int
+zbuildfont32(os_ptr op)
+{
+ int code;
+ build_proc_refs build;
+ gs_font_base *pfont;
+
+ check_type(*op, t_dictionary);
+ make_null(&build.BuildChar);
+ make_null(&build.BuildGlyph);
+ code = build_gs_simple_font(op, &pfont, ft_bitmap,
+ &st_gs_font_base, &build,
+ bf_Encoding_optional);
+ if (code < 0)
+ return code;
+ /* Always transform cached bitmaps. */
+ pfont->BitmapWidths = true;
+ pfont->ExactSize = fbit_transform_bitmaps;
+ pfont->InBetweenSize = fbit_transform_bitmaps;
+ pfont->TransformedChar = fbit_transform_bitmaps;
+ /* The encode_char procedure of a Type 32 font */
+ /* should never be called. */
+ pfont->procs.encode_char = zfont_no_encode_char;
+ return define_gs_font((gs_font *) pfont);
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zfont32_op_defs[] =
+{
+ {"2.buildfont32", zbuildfont32},
+ op_def_end(0)
+};
diff --git a/gs/src/zfreuse.c b/gs/src/zfreuse.c
new file mode 100644
index 000000000..041f15ae3
--- /dev/null
+++ b/gs/src/zfreuse.c
@@ -0,0 +1,200 @@
+/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: zfreuse.c */
+/* ReusableStreamDecode filter support */
+#include "memory_.h"
+#include "ghost.h"
+#include "oper.h"
+#include "stream.h"
+#include "strimpl.h"
+#include "sfilter.h" /* for SubFileDecode */
+#include "files.h"
+#include "idict.h"
+#include "idparam.h"
+#include "iname.h"
+#include "store.h"
+
+/*
+ * The actual work of constructing the filter is done in PostScript code.
+ * The operators in this file are internal ones that handle the dirty work.
+ */
+
+/* <dict|null> .rsdparams <filters> <decodeparms|null> */
+/* filters is always an array, and decodeparms is always either an array */
+/* of the same length as filters, or null. */
+private int
+zrsdparams(os_ptr op)
+{
+ ref *pFilter;
+ ref *pDecodeParms;
+ int Intent;
+ bool AsyncRead;
+ ref empty_array, filter1_array, parms1_array;
+ uint i;
+ int code;
+
+ make_empty_array(&empty_array, a_readonly);
+ if (dict_find_string(op, "Filter", &pFilter) > 0) {
+ if (!r_is_array(pFilter)) {
+ if (!r_has_type(pFilter, t_name))
+ return_error(e_typecheck);
+ make_array(&filter1_array, a_readonly, 1, pFilter);
+ pFilter = &filter1_array;
+ }
+ } else
+ pFilter = &empty_array;
+ /* If Filter is undefined, ignore DecodeParms. */
+ if (pFilter != &empty_array &&
+ dict_find_string(op, "DecodeParms", &pDecodeParms) > 0
+ ) {
+ if (pFilter == &filter1_array) {
+ make_array(&parms1_array, a_readonly, 1, pDecodeParms);
+ pDecodeParms = &parms1_array;
+ } else if (!r_is_array(pDecodeParms))
+ return_error(e_typecheck);
+ else if (r_size(pFilter) != r_size(pDecodeParms))
+ return_error(e_rangecheck);
+ } else
+ pDecodeParms = 0;
+ for (i = 0; i < r_size(pFilter); ++i) {
+ ref f, fname, dp;
+
+ array_get(pFilter, (long)i, &f);
+ if (!r_has_type(&f, t_name))
+ return_error(e_typecheck);
+ name_string_ref(&f, &fname);
+ if (r_size(&fname) < 6 ||
+ !memcmp(fname.value.bytes + r_size(&fname) - 6, "Decode", 6)
+ )
+ return_error(e_rangecheck);
+ if (pDecodeParms) {
+ array_get(pDecodeParms, (long)i, &dp);
+ if (!(r_has_type(&dp, t_dictionary) || r_has_type(&dp, t_null)))
+ return_error(e_typecheck);
+ }
+ }
+ if ((code = dict_int_param(op, "Intent", 0, 3, 0, &Intent)) < 0 ||
+ (code = dict_bool_param(op, "AsyncRead", false, &AsyncRead)) < 0
+ )
+ return code;
+ push(1);
+ op[-1] = *pFilter;
+ if (pDecodeParms)
+ *op = *pDecodeParms;
+ else
+ make_null(op);
+ return 0;
+}
+
+/* <file|string> <length|null> <CloseSource> .reusablestream <filter> */
+/*
+ * The file|string operand must be a "reusable source", either:
+ * - A string;
+ * - A readable, positionable file stream;
+ * - A SubFileDecode filter with an empty EODString and a reusable
+ * source;
+ * - A reusable stream.
+ */
+private int make_rss(P6(os_ptr op, const byte * data, uint size, long offset,
+ long length, bool close_source));
+private int
+zreusablestream(os_ptr op)
+{
+ os_ptr source_op = op - 2;
+ os_ptr length_op = op - 1;
+ long length;
+ bool close_source;
+ int code;
+
+ if (r_has_type(length_op, t_integer)) {
+ length = length_op->value.intval;
+ if (length < 0)
+ return_error(e_rangecheck);
+ } else
+ length = -1;
+ check_type(*op, t_boolean);
+ close_source = op->value.boolval;
+ if (r_has_type(source_op, t_string)) {
+ check_read(*source_op);
+ code = make_rss(source_op, source_op->value.const_bytes,
+ r_size(source_op), 0L, length, close_source);
+ } else {
+ long offset = 0;
+ stream *source;
+
+ check_read_file(source, source_op);
+rs:
+ if (source->cbuf_string.data != 0) {
+ /* The data source is a string. */
+ long avail;
+
+ offset += stell(source);
+ savailable(source, &avail);
+ if (avail < 0)
+ avail = 0;
+ if (avail > length)
+ avail = length;
+ code = make_rss(source_op, source->cbuf_string.data,
+ source->cbuf_string.size, offset, avail,
+ close_source);
+ } else if (source->file != 0) {
+ /* The data source is a file. */
+/****** NYI ******/
+ } else if (source->state->template == &s_SFD_template) {
+ /* The data source is a SubFileDecode filter. */
+ const stream_SFD_state *const sfd_state =
+ (const stream_SFD_state *)source->state;
+
+ if (sfd_state->eod.size != 0)
+ return_error(e_rangecheck);
+ if (sfd_state->count != 0) {
+ long left = sfd_state->count + sbufavailable(source);
+
+ if (left < length)
+ length = left;
+ }
+ source = source->strm;
+ goto rs;
+ }
+/****** REUSABLE CASE IS NYI ******/
+ else
+ return_error(e_rangecheck);
+ }
+ if (code >= 0)
+ pop(2);
+ return code;
+}
+
+/* Make a reusable string stream. */
+private int
+make_rss(os_ptr op, const byte * data, uint size, long offset,
+ long length, bool close_source)
+{
+/****** NYI ******/
+ return_error(e_rangecheck);
+}
+
+/* ---------------- Initialization procedure ---------------- */
+
+const op_def zfreuse_op_defs[] =
+{
+ {"2.rsdparams", zrsdparams},
+ {"2.reusablestream", zreusablestream},
+ op_def_end(0)
+};
diff --git a/gs/src/zfunc3.c b/gs/src/zfunc3.c
new file mode 100644
index 000000000..383f5fa1d
--- /dev/null
+++ b/gs/src/zfunc3.c
@@ -0,0 +1,130 @@
+/* Copyright (C) 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: zfunc3.c */
+/* PostScript language interface to LL3 Functions */
+#include "memory_.h"
+#include "ghost.h"
+#include "oper.h"
+#include "gsfunc3.h"
+#include "gsstruct.h"
+#include "stream.h" /* for files.h */
+#include "files.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "idparam.h"
+#include "ifunc.h"
+#include "store.h"
+
+/* Initialization */
+private build_function_proc(build_function_2);
+private build_function_proc(build_function_3);
+int
+zfunc3_init(gs_memory_t * mem)
+{
+ build_function_procs[2] = build_function_2;
+ build_function_procs[3] = build_function_3;
+ return 0;
+}
+
+const op_def zfunc3_op_defs[] =
+{
+ op_def_end(zfunc3_init)
+};
+
+/* Define the available Function types. */
+
+/* Finish building a FunctionType 2 (ExponentialInterpolation) function. */
+private int
+build_function_2(const_os_ptr op, const gs_function_params_t * mnDR, int depth,
+ gs_function_t ** ppfn)
+{
+ gs_function_ElIn_params_t params;
+ int code, n0, n1;
+
+ *(gs_function_params_t *)&params = *mnDR;
+ params.C0 = 0;
+ params.C1 = 0;
+ if ((code = dict_float_param(op, "N", 0.0, &params.N)) != 0 ||
+ (code = n0 = fn_build_float_array(op, "C0", false, false, &params.C0)) < 0 ||
+ (code = n1 = fn_build_float_array(op, "C1", false, false, &params.C1)) < 0
+ )
+ goto fail;
+ if (params.C0 == 0)
+ n0 = 1; /* C0 defaulted */
+ if (params.C1 == 0)
+ n1 = 1; /* C1 defaulted */
+ if (params.Range == 0)
+ params.n = n0; /* either one will do */
+ if (n0 != n1 || n0 != params.n)
+ goto fail;
+ code = gs_function_ElIn_init(ppfn, &params, imemory);
+ if (code >= 0)
+ return 0;
+fail:
+ gs_function_ElIn_free_params(&params, imemory);
+ return (code < 0 ? code : gs_note_error(e_rangecheck));
+}
+
+/* Finish building a FunctionType 3 (1-Input Stitching) function. */
+private int
+build_function_3(const_os_ptr op, const gs_function_params_t * mnDR, int depth,
+ gs_function_t ** ppfn)
+{
+ gs_function_1ItSg_params_t params;
+ int code;
+
+ *(gs_function_params_t *) & params = *mnDR;
+ params.Functions = 0;
+ params.Bounds = 0;
+ params.Encode = 0;
+ {
+ ref *pFunctions;
+ gs_function_t **ptr;
+ int i;
+
+ if ((code = dict_find_string(op, "Functions", &pFunctions)) <= 0)
+ return (code < 0 ? code : gs_note_error(e_rangecheck));
+ check_array_only(*pFunctions);
+ params.k = r_size(pFunctions);
+ code = ialloc_function_array(params.k, &ptr);
+ if (code < 0)
+ return code;
+ params.Functions = (const gs_function_t * const *)ptr;
+ for (i = 0; i < params.k; ++i) {
+ ref subfn;
+
+ array_get(pFunctions, (long)i, &subfn);
+ code = fn_build_sub_function(&subfn, &ptr[i], depth);
+ if (code < 0)
+ goto fail;
+ }
+ }
+ if ((code = fn_build_float_array(op, "Bounds", true, false, &params.Bounds)) != params.k - 1 ||
+ (code = fn_build_float_array(op, "Encode", true, true, &params.Encode)) != 2 * params.k
+ )
+ goto fail;
+ if (params.Range == 0)
+ params.n = params.Functions[0]->params.n;
+ code = gs_function_1ItSg_init(ppfn, &params, imemory);
+ if (code >= 0)
+ return 0;
+fail:
+ gs_function_1ItSg_free_params(&params, imemory);
+ return (code < 0 ? code : gs_note_error(e_rangecheck));
+}
diff --git a/gs/src/zimage3.c b/gs/src/zimage3.c
new file mode 100644
index 000000000..e9ae20a0d
--- /dev/null
+++ b/gs/src/zimage3.c
@@ -0,0 +1,119 @@
+/* Copyright (C) 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: zimage3.c */
+/* LanguageLevel 3 ImageTypes (3 & 4 - masked images) */
+#include "memory_.h"
+#include "ghost.h"
+#include "oper.h"
+#include "gscspace.h" /* for gscolor2.h */
+#include "gscolor2.h"
+#include "gsiparm3.h"
+#include "gsiparm4.h"
+#include "gxiparam.h" /* for image enumerator */
+#include "idict.h"
+#include "idparam.h"
+#include "igstate.h"
+#include "iimage.h"
+#include "iimage2.h"
+
+/* <dict> .image3 - */
+private int
+zimage3(register os_ptr op)
+{
+ gs_image3_t image;
+ int interleave_type;
+ ref *pDataDict;
+ ref *pMaskDict;
+ image_params ip_data, ip_mask;
+ int ignored;
+ int code, mcode;
+
+ check_type(*op, t_dictionary);
+ check_dict_read(*op);
+ if ((code = dict_int_param(op, "InterleaveType", 1, 3, -1,
+ &interleave_type)) < 0
+ )
+ return code;
+ gs_image3_t_init(&image, NULL, interleave_type);
+ if (dict_find_string(op, "DataDict", &pDataDict) <= 0 ||
+ dict_find_string(op, "MaskDict", &pMaskDict) <= 0
+ )
+ return_error(e_rangecheck);
+ if ((code = pixel_image_params(pDataDict, (gs_pixel_image_t *)&image,
+ &ip_data, 12)) < 0 ||
+ (mcode = code = data_image_params(pMaskDict, &image.MaskDict, &ip_mask, false, 1, 12)) < 0 ||
+ (code = dict_int_param(pDataDict, "ImageType", 1, 1, 0, &ignored)) < 0 ||
+ (code = dict_int_param(pMaskDict, "ImageType", 1, 1, 0, &ignored)) < 0
+ )
+ return code;
+ /*
+ * MaskDict must have a DataSource iff InterleaveType == 3.
+ */
+ if ((ip_data.MultipleDataSources && interleave_type != 3) ||
+ ip_mask.MultipleDataSources ||
+ mcode != (image.InterleaveType != 3)
+ )
+ return_error(e_rangecheck);
+ if (!mcode) {
+ /* Insert the mask DataSource before the data DataSources. */
+ memmove(&ip_data.DataSource[1], &ip_data.DataSource[0],
+ (countof(ip_data.DataSource) - 1) *
+ sizeof(ip_data.DataSource[0]));
+ ip_data.DataSource[0] = ip_mask.DataSource[0];
+ }
+ return zimage_setup((gs_pixel_image_t *)&image,
+ &ip_data.DataSource[0],
+ image.CombineWithColor, 1);
+}
+
+/* <dict> .image4 - */
+private int
+zimage4(register os_ptr op)
+{
+ gs_image4_t image;
+ image_params ip;
+ int num_components =
+ gs_color_space_num_components(gs_currentcolorspace(igs));
+ int code;
+
+ gs_image4_t_init(&image, NULL);
+ code = pixel_image_params(op, (gs_pixel_image_t *)&image, &ip, 12);
+ if (code < 0)
+ return code;
+ code = dict_int_array_param(op, "MaskColor", num_components * 2,
+ image.MaskColor);
+ if (code == num_components)
+ image.MaskColor_is_range = false;
+ else if (code == num_components * 2)
+ image.MaskColor_is_range = true;
+ else
+ return_error(code < 0 ? code : gs_note_error(e_rangecheck));
+ return zimage_setup((gs_pixel_image_t *)&image, &ip.DataSource[0],
+ image.CombineWithColor, 1);
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zimage3_op_defs[] =
+{
+ op_def_begin_ll3(),
+ {"1.image3", zimage3},
+ {"1.image4", zimage4},
+ op_def_end(0)
+};
diff --git a/gs/src/zmisc3.c b/gs/src/zmisc3.c
new file mode 100644
index 000000000..68e1420a4
--- /dev/null
+++ b/gs/src/zmisc3.c
@@ -0,0 +1,105 @@
+/* Copyright (C) 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: zmisc3.c */
+/* Miscellaneous LanguageLevel 3 operators */
+#include "ghost.h"
+#include "oper.h"
+#include "store.h"
+
+/* <proc1> <proc2> .eqproc <bool> */
+/*
+ * Test whether two procedures are equal to depth 10.
+ * This is the equality test used by idiom recognition in 'bind'.
+ */
+#define MAX_DEPTH 10 /* depth is per Adobe specification */
+typedef struct ref2_s {
+ ref proc1, proc2;
+} ref2_t;
+private int
+zeqproc(register os_ptr op)
+{
+ ref2_t stack[MAX_DEPTH + 1];
+ ref2_t *top = stack;
+
+ make_array(&stack[0].proc1, 0, 1, op - 1);
+ make_array(&stack[0].proc2, 0, 1, op);
+ for (;;) {
+ long i;
+
+ if (r_size(&top->proc1) == 0) {
+ /* Finished these arrays, go up to next level. */
+ if (top == stack) {
+ /* We're done matching: it succeeded. */
+ make_true(op - 1);
+ pop(1);
+ return 0;
+ }
+ --top;
+ continue;
+ }
+ /* Look at the next elements of the arrays. */
+ r_dec_size(&top->proc1, 1);
+ i = r_size(&top->proc1);
+ array_get(&top->proc1, i, &top[1].proc1);
+ array_get(&top->proc2, i, &top[1].proc2);
+ ++top;
+ /*
+ * Amazingly enough, the objects' executable attributes are not
+ * required to match. This means { x load } will match { /x load },
+ * even though this is clearly wrong.
+ */
+#if 0
+ if (r_has_attr(&top->proc1, a_executable) !=
+ r_has_attr(&top->proc2, a_executable)
+ )
+ break;
+#endif
+ if (obj_eq(&top->proc1, &top->proc2)) {
+ /* Names don't match strings. */
+ if (r_type(&top->proc1) != r_type(&top->proc2) &&
+ (r_type(&top->proc1) == t_name ||
+ r_type(&top->proc2) == t_name)
+ )
+ break;
+ --top; /* no recursion */
+ continue;
+ }
+ if (r_is_array(&top->proc1) && r_is_array(&top->proc2) &&
+ r_size(&top->proc1) == r_size(&top->proc2) &&
+ top < stack + (MAX_DEPTH - 1)
+ ) {
+ /* Descend into the arrays. */
+ continue;
+ }
+ break;
+ }
+ /* An exit from the loop indicates that matching failed. */
+ make_false(op - 1);
+ pop(1);
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zmisc3_op_defs[] =
+{
+ op_def_begin_ll3(),
+ {"2.eqproc", zeqproc},
+ op_def_end(0)
+};
diff --git a/gs/src/zshade.c b/gs/src/zshade.c
new file mode 100644
index 000000000..d096e7404
--- /dev/null
+++ b/gs/src/zshade.c
@@ -0,0 +1,593 @@
+/* Copyright (C) 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: zshade.c */
+/* PostScript language interface to shading */
+#include "memory_.h"
+#include "ghost.h"
+#include "oper.h"
+#include "gscolor3.h"
+#include "gscspace.h"
+#include "gscolor2.h" /* requires gscspace.h */
+#include "gsfunc3.h"
+#include "gsstruct.h" /* must precede gsshade.h */
+#include "gsshade.h"
+#include "gsuid.h"
+#include "stream.h" /* for files.h */
+#include "files.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "idparam.h"
+#include "ifunc.h"
+#include "igstate.h"
+#include "store.h"
+
+/* Forward references */
+private int shading_param(P2(const_os_ptr op, const gs_shading_t ** ppsh));
+
+/* ---------------- Standard operators ---------------- */
+
+/* - currentsmoothness <smoothness> */
+private int
+zcurrentsmoothness(register os_ptr op)
+{
+ push(1);
+ make_real(op, gs_currentsmoothness(igs));
+ return 0;
+}
+
+/* <smoothness> setsmoothness - */
+private int
+zsetsmoothness(register os_ptr op)
+{
+ double smoothness;
+ int code;
+
+ if (real_param(op, &smoothness) < 0)
+ return_op_typecheck(op);
+ if ((code = gs_setsmoothness(igs, smoothness)) < 0)
+ return code;
+ pop(1);
+ return 0;
+}
+
+/* <shading> .shfill - */
+private int
+zshfill(register os_ptr op)
+{
+ const gs_shading_t *psh;
+ int code = shading_param(op, &psh);
+
+ if (code < 0 || (code = gs_shfill(igs, psh)) < 0)
+ return code;
+ pop(1);
+ return 0;
+}
+
+/* ------ Non-standard operators ------ */
+
+/* <pattern> <matrix> <shading> .buildshadingpattern <pattern> <instance> */
+private int
+zbuildshadingpattern(os_ptr op)
+{
+ os_ptr op2 = op - 2;
+ const gs_shading_t *psh;
+ gs_matrix mat;
+ struct {
+ gs_uid uid;
+ } template; /****** WRONG ******/
+ int code;
+
+ check_type(*op2, t_dictionary);
+ check_dict_read(*op2);
+
+ if ((code = shading_param(op, &psh)) < 0 ||
+ (code = read_matrix(op - 1, &mat)) < 0 ||
+ (code = dict_uid_param(op2, &template.uid, 1, imemory)) != 1
+ )
+ return_error((code < 0 ? code : e_rangecheck));
+ /****** NYI ******/
+ return_error(e_undefined);
+}
+
+/* ------ Internal procedures ------ */
+
+/* Get a shading parameter. */
+private int
+shading_param(const_os_ptr op, const gs_shading_t ** ppsh)
+{ /*
+ * Since shadings form a subclass hierarchy, we currently have
+ * no way to check whether a structure is actually a shading.
+ */
+ if (!r_is_struct(op) ||
+ r_has_masked_attrs(op, a_executable | a_execute, a_all)
+ )
+ return_error(e_typecheck);
+ *ppsh = (gs_shading_t *) op->value.pstruct;
+ return 0;
+}
+
+/* ---------------- Shading dictionaries ---------------- */
+
+/* ------ Common code ------ */
+
+extern_st(st_color_space);
+
+typedef int (*build_shading_proc_t)(P3(const ref *op,
+ const gs_shading_params_t *params,
+ gs_shading_t **ppsh));
+
+/* Operators */
+
+/* Common framework for building shadings. */
+private int
+build_shading(ref * op, build_shading_proc_t proc)
+{
+ int code;
+ float box[4];
+ gs_shading_params_t params;
+ gs_shading_t *psh;
+ ref *pvalue;
+
+ check_type(*op, t_dictionary);
+ params.ColorSpace = 0;
+ params.Background = 0;
+ /* Collect parameters common to all shading types. */
+ {
+ const gs_color_space *pcs_orig = gs_currentcolorspace(igs);
+ int num_comp = gs_color_space_num_components(pcs_orig);
+ gs_color_space *pcs;
+
+ if (num_comp < 0) /* Pattern color space */
+ return_error(e_rangecheck);
+ pcs = ialloc_struct(gs_color_space, &st_color_space,
+ "build_shading");
+ if (pcs == 0)
+ return_error(e_VMerror);
+ gs_cspace_init_from(pcs, pcs_orig);
+ params.ColorSpace = pcs;
+ if (dict_find_string(op, "Background", &pvalue) > 0) {
+ gs_client_color *pcc =
+ ialloc_struct(gs_client_color, &st_client_color,
+ "build_shading");
+
+ if (pcc == 0) {
+ code = gs_note_error(e_VMerror);
+ goto fail;
+ }
+ pcc->pattern = 0;
+ params.Background = pcc;
+ code = dict_float_array_param(op, "Background",
+ countof(pcc->paint.values),
+ pcc->paint.values, NULL);
+ if (code != gs_color_space_num_components(pcs))
+ goto fail;
+ }
+ }
+ if (dict_find_string(op, "BBox", &pvalue) <= 0)
+ params.have_BBox = false;
+ else if ((code = dict_float_array_param(op, "BBox", 4, box, NULL)) == 4) {
+ params.BBox.p.x = box[0];
+ params.BBox.p.y = box[1];
+ params.BBox.q.x = box[2];
+ params.BBox.q.y = box[3];
+ params.have_BBox = true;
+ } else
+ goto fail;
+ code = dict_bool_param(op, "AntiAlias", false, &params.AntiAlias);
+ if (code < 0)
+ goto fail;
+ /* Finish building the shading. */
+ code = (*proc) (op, &params, &psh);
+ if (code < 0)
+ goto fail;
+ make_istruct_new(op, 0, psh);
+ return code;
+fail:
+ ifree_object(params.Background, "Background");
+ if (params.ColorSpace) {
+ gs_cspace_release(params.ColorSpace);
+ ifree_object(params.ColorSpace, "ColorSpace");
+ }
+ return (code < 0 ? code : gs_note_error(e_rangecheck));
+}
+
+/* Collect a Function value. */
+private int
+build_shading_function(const ref * op, gs_function_t ** ppfn, int num_inputs)
+{
+ ref *pFunction;
+
+ *ppfn = 0;
+ if (dict_find_string(op, "Function", &pFunction) <= 0)
+ return 0;
+ if (r_is_array(pFunction)) {
+ uint size = r_size(pFunction);
+ gs_function_t **Functions;
+ uint i;
+ gs_function_AdOt_params_t params;
+ int code;
+
+ check_read(*pFunction);
+ if (size == 0)
+ return_error(e_rangecheck);
+ code = ialloc_function_array(size, &Functions);
+ if (code < 0)
+ return code;
+ for (i = 0; i < size; ++i) {
+ ref rsubfn;
+
+ array_get(op, (long)i, &rsubfn);
+ code = fn_build_function(&rsubfn, &Functions[i]);
+ if (code < 0)
+ break;
+ }
+ params.m = 1;
+ params.Domain = 0;
+ params.n = size;
+ params.Range = 0;
+ params.Functions = (const gs_function_t * const *)Functions;
+ if (code >= 0)
+ code = gs_function_AdOt_init(ppfn, &params, imemory);
+ if (code < 0)
+ gs_function_AdOt_free_params(&params, imemory);
+ return code;
+ } else
+ return fn_build_function(pFunction, ppfn);
+}
+
+/* ------ Build shadings ------ */
+
+/* Build a ShadingType 1 (Function-based) shading. */
+private int
+build_shading_1(const ref * op, const gs_shading_params_t * pcommon,
+ gs_shading_t ** ppsh)
+{
+ gs_shading_Fb_params_t params;
+ int code;
+ static const float default_Domain[4] = {0, 1, 0, 1};
+
+ *(gs_shading_params_t *)&params = *pcommon;
+ gs_make_identity(&params.Matrix);
+ params.Function = 0;
+ if ((code = dict_float_array_param(op, "Domain", 4, params.Domain,
+ default_Domain)) != 4 ||
+ (code = dict_matrix_param(op, "Matrix", &params.Matrix)) < 0 ||
+ (code = build_shading_function(op, &params.Function, 2)) < 0 ||
+ (code = gs_shading_Fb_init(ppsh, &params, imemory)) < 0
+ ) {
+ ifree_object(params.Function, "Function");
+ return (code < 0 ? code : gs_note_error(e_rangecheck));
+ }
+ return 0;
+}
+/* <dict> .buildshading1 <shading_struct> */
+private int
+zbuildshading1(os_ptr op)
+{
+ return build_shading(op, build_shading_1);
+}
+
+/* Collect parameters for an Axial or Radial shading. */
+private int
+build_directional_shading(const ref * op, float *Coords, int num_Coords,
+ float Domain[2], gs_function_t ** pFunction, bool Extend[2])
+{
+ int code =
+ dict_float_array_param(op, "Coords", num_Coords, Coords, NULL);
+ static const float default_Domain[2] = {0, 1};
+ ref *pExtend;
+
+ *pFunction = 0;
+ if (code != num_Coords ||
+ (code = dict_float_array_param(op, "Domain", 2, Domain,
+ default_Domain)) != 2 ||
+ (code = build_shading_function(op, pFunction, 1)) < 0
+ )
+ return (code < 0 ? code : gs_note_error(e_rangecheck));
+ if (dict_find_string(op, "Extend", &pExtend) <= 0)
+ Extend[0] = Extend[1] = false;
+ else {
+ ref E0, E1;
+
+ if (!r_is_array(pExtend))
+ return_error(e_typecheck);
+ else if (r_size(pExtend) != 2)
+ return_error(e_rangecheck);
+ else if ((array_get(pExtend, 0L, &E0), !r_has_type(&E0, t_boolean)) ||
+ (array_get(pExtend, 1L, &E1), !r_has_type(&E1, t_boolean))
+ )
+ return_error(e_typecheck);
+ Extend[0] = E0.value.boolval, Extend[1] = E1.value.boolval;
+ }
+ return 0;
+}
+
+/* Build a ShadingType 2 (Axial) shading. */
+private int
+build_shading_2(const ref * op, const gs_shading_params_t * pcommon,
+ gs_shading_t ** ppsh)
+{
+ gs_shading_A_params_t params;
+ int code;
+
+ *(gs_shading_params_t *)&params = *pcommon;
+ if ((code = build_directional_shading(op, params.Coords, 4,
+ params.Domain, &params.Function,
+ params.Extend)) < 0 ||
+ (code = gs_shading_A_init(ppsh, &params, imemory)) < 0
+ ) {
+ ifree_object(params.Function, "Function");
+ }
+ return code;
+}
+/* <dict> .buildshading2 <shading_struct> */
+private int
+zbuildshading2(os_ptr op)
+{
+ return build_shading(op, build_shading_2);
+}
+
+/* Build a ShadingType 3 (Radial) shading. */
+private int
+build_shading_3(const ref * op, const gs_shading_params_t * pcommon,
+ gs_shading_t ** ppsh)
+{
+ gs_shading_R_params_t params;
+ int code;
+
+ *(gs_shading_params_t *)&params = *pcommon;
+ if ((code = build_directional_shading(op, params.Coords, 6,
+ params.Domain, &params.Function,
+ params.Extend)) < 0 ||
+ (code = gs_shading_R_init(ppsh, &params, imemory)) < 0
+ ) {
+ ifree_object(params.Function, "Function");
+ }
+ return code;
+}
+/* <dict> .buildshading3 <shading_struct> */
+private int
+zbuildshading3(os_ptr op)
+{
+ return build_shading(op, build_shading_3);
+}
+
+/* Collect parameters for a mesh shading. */
+private int
+build_mesh_shading(const ref * op, gs_shading_mesh_params_t * params,
+ float **pDecode, gs_function_t ** pFunction)
+{
+ int code;
+ ref *pDataSource;
+
+ *pDecode = 0;
+ *pFunction = 0;
+ if (dict_find_string(op, "DataSource", &pDataSource) <= 0)
+ return_error(e_rangecheck);
+ if (r_is_array(pDataSource)) {
+ uint size = r_size(pDataSource);
+ float *data =
+ (float *)ialloc_byte_array(size, sizeof(float),
+ "build_mesh_shading");
+ int code;
+
+ if (data == 0)
+ return_error(e_VMerror);
+ code = float_params(pDataSource->value.refs + size - 1, size, data);
+ if (code < 0) {
+ ifree_object(data, "build_mesh_shading");
+ return code;
+ }
+ data_source_init_floats(&params->DataSource, data, size);
+ } else
+ switch (r_type(pDataSource)) {
+ case t_file: {
+ stream *s;
+
+ check_read_file(s, pDataSource);
+ data_source_init_stream(&params->DataSource, s);
+ break;
+ }
+ case t_string:
+ check_read(*pDataSource);
+ data_source_init_string2(&params->DataSource,
+ pDataSource->value.bytes,
+ r_size(pDataSource));
+ break;
+ default:
+ return_error(e_typecheck);
+ }
+ if (data_source_is_array(params->DataSource)) {
+ params->BitsPerCoordinate = 0;
+ params->BitsPerComponent = 0;
+ } else {
+ int num_decode =
+ 4 + gs_color_space_num_components(params->ColorSpace) * 2;
+
+/****** FREE FLOAT ARRAY DATA ON ERROR ******/
+ if ((code = dict_int_param(op, "BitsPerCoordinate", 1, 32, 0,
+ &params->BitsPerCoordinate)) < 0 ||
+ (code = dict_int_param(op, "BitsPerComponent", 1, 16, 0,
+ &params->BitsPerComponent)) < 0
+ )
+ return code;
+ *pDecode = (float *)ialloc_byte_array(num_decode, sizeof(float),
+ "build_mesh_shading");
+
+ if (*pDecode == 0)
+ return_error(e_VMerror);
+ code = dict_float_array_param(op, "Decode", num_decode, *pDecode,
+ NULL);
+ if (code != num_decode) {
+ ifree_object(*pDecode, "build_mesh_shading");
+ *pDecode = 0;
+ return (code < 0 ? code : gs_note_error(e_rangecheck));
+ }
+ }
+ code = build_shading_function(op, pFunction, 1);
+ if (code < 0) {
+ ifree_object(*pDecode, "build_mesh_shading");
+ *pDecode = 0;
+ }
+ return code;
+}
+
+/* Collect the BitsPerFlag parameter, if relevant. */
+private int
+flag_bits_param(const ref * op, const gs_shading_mesh_params_t * params,
+ int *pBitsPerFlag)
+{
+ if (data_source_is_array(params->DataSource)) {
+ *pBitsPerFlag = 0;
+ return 0;
+ } else {
+ return dict_int_param(op, "BitsPerFlag", 2, 8, 0, pBitsPerFlag);
+ }
+}
+
+/* Build a ShadingType 4 (Free-form Gouraud triangle mesh) shading. */
+private int
+build_shading_4(const ref * op, const gs_shading_params_t * pcommon,
+ gs_shading_t ** ppsh)
+{
+ gs_shading_FfGt_params_t params;
+ int code;
+
+ *(gs_shading_params_t *)&params = *pcommon;
+ if ((code =
+ build_mesh_shading(op, (gs_shading_mesh_params_t *)&params,
+ &params.Decode, &params.Function)) < 0 ||
+ (code = flag_bits_param(op, (gs_shading_mesh_params_t *)&params,
+ &params.BitsPerFlag)) < 0 ||
+ (code = gs_shading_FfGt_init(ppsh, &params, imemory)) < 0
+ ) {
+ ifree_object(params.Function, "Function");
+ ifree_object(params.Decode, "Decode");
+ }
+ return code;
+}
+/* <dict> .buildshading4 <shading_struct> */
+private int
+zbuildshading4(os_ptr op)
+{
+ return build_shading(op, build_shading_4);
+}
+
+/* Build a ShadingType 5 (Lattice-form Gouraud triangle mesh) shading. */
+private int
+build_shading_5(const ref * op, const gs_shading_params_t * pcommon,
+ gs_shading_t ** ppsh)
+{
+ gs_shading_LfGt_params_t params;
+ int code;
+
+ *(gs_shading_params_t *)&params = *pcommon;
+ if ((code =
+ build_mesh_shading(op, (gs_shading_mesh_params_t *)&params,
+ &params.Decode, &params.Function)) < 0 ||
+ (code = dict_int_param(op, "VerticesPerRow", 2, max_int, 0,
+ &params.VerticesPerRow)) < 0 ||
+ (code = gs_shading_LfGt_init(ppsh, &params, imemory)) < 0
+ ) {
+ ifree_object(params.Function, "Function");
+ ifree_object(params.Decode, "Decode");
+ }
+ return code;
+}
+/* <dict> .buildshading5 <shading_struct> */
+private int
+zbuildshading5(os_ptr op)
+{
+ return build_shading(op, build_shading_5);
+}
+
+/* Build a ShadingType 6 (Coons patch mesh) shading. */
+private int
+build_shading_6(const ref * op, const gs_shading_params_t * pcommon,
+ gs_shading_t ** ppsh)
+{
+ gs_shading_Cp_params_t params;
+ int code;
+
+ *(gs_shading_params_t *)&params = *pcommon;
+ if ((code =
+ build_mesh_shading(op, (gs_shading_mesh_params_t *)&params,
+ &params.Decode, &params.Function)) < 0 ||
+ (code = flag_bits_param(op, (gs_shading_mesh_params_t *)&params,
+ &params.BitsPerFlag)) < 0 ||
+ (code = gs_shading_Cp_init(ppsh, &params, imemory)) < 0
+ ) {
+ ifree_object(params.Function, "Function");
+ ifree_object(params.Decode, "Decode");
+ }
+ return code;
+}
+/* <dict> .buildshading6 <shading_struct> */
+private int
+zbuildshading6(os_ptr op)
+{
+ return build_shading(op, build_shading_6);
+}
+
+/* Build a ShadingType 7 (Tensor product patch mesh) shading. */
+private int
+build_shading_7(const ref * op, const gs_shading_params_t * pcommon,
+ gs_shading_t ** ppsh)
+{
+ gs_shading_Tpp_params_t params;
+ int code;
+
+ *(gs_shading_params_t *)&params = *pcommon;
+ if ((code =
+ build_mesh_shading(op, (gs_shading_mesh_params_t *)&params,
+ &params.Decode, &params.Function)) < 0 ||
+ (code = flag_bits_param(op, (gs_shading_mesh_params_t *)&params,
+ &params.BitsPerFlag)) < 0 ||
+ (code = gs_shading_Tpp_init(ppsh, &params, imemory)) < 0
+ ) {
+ ifree_object(params.Function, "Function");
+ ifree_object(params.Decode, "Decode");
+ }
+ return code;
+}
+/* <dict> .buildshading7 <shading_struct> */
+private int
+zbuildshading7(os_ptr op)
+{
+ return build_shading(op, build_shading_7);
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zshade_op_defs[] =
+{
+ op_def_begin_ll3(),
+ {"0currentsmoothness", zcurrentsmoothness},
+ {"1setsmoothness", zsetsmoothness},
+ {"1.shfill", zshfill},
+ {"1.buildshading1", zbuildshading1},
+ {"1.buildshading2", zbuildshading2},
+ {"1.buildshading3", zbuildshading3},
+ {"1.buildshading4", zbuildshading4},
+ {"1.buildshading5", zbuildshading5},
+ {"1.buildshading6", zbuildshading6},
+ {"1.buildshading7", zbuildshading7},
+ {"3.buildshadingpattern", zbuildshadingpattern},
+ op_def_end(0)
+};
diff --git a/gs/src/ztrap.c b/gs/src/ztrap.c
new file mode 100644
index 000000000..3270e56c9
--- /dev/null
+++ b/gs/src/ztrap.c
@@ -0,0 +1,66 @@
+/* Copyright (C) 1997, 1998 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+ */
+
+/*Id: ztrap.c */
+/* Operators for setting trapping parameters and zones */
+#include "ghost.h"
+#include "oper.h"
+#include "ialloc.h"
+#include "iparam.h"
+#include "gstrap.h"
+
+/* Define the current trap parameters. */
+/****** THIS IS BOGUS ******/
+gs_trap_params_t i_trap_params;
+
+/* <dict> .settrapparams - */
+private int
+zsettrapparams(os_ptr op)
+{
+ dict_param_list list;
+ int code;
+
+ cheak_type(*op, t_dictionary);
+ code = dict_param_list_read(&list, op, NULL, false);
+ if (code < 0)
+ return code;
+ code = gs_settrapparams(&i_trap_params, (gs_param_list *) & list);
+ iparam_list_release(&list);
+ if (code < 0)
+ return code;
+ pop(1);
+ return 0;
+}
+
+/* - settrapzone - */
+private int
+zsettrapzone(os_ptr op)
+{
+/****** NYI ******/
+ return_error(e_undefined);
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def ztrap_op_defs[] =
+{
+ op_def_begin_ll3(),
+ {"1.settrapparams", zsettrapparams},
+ {"0settrapzone", zsettrapzone},
+ op_def_end(0)
+};