summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'base/gsfunc.c')
-rw-r--r--base/gsfunc.c214
1 files changed, 214 insertions, 0 deletions
diff --git a/base/gsfunc.c b/base/gsfunc.c
new file mode 100644
index 00000000..9844b8d7
--- /dev/null
+++ b/base/gsfunc.c
@@ -0,0 +1,214 @@
+/* Copyright (C) 2001-2019 Artifex Software, Inc.
+ All Rights Reserved.
+
+ This software is provided AS-IS with no warranty, either express or
+ implied.
+
+ This software is distributed under license and may not be copied,
+ modified or distributed except as expressly authorized under the terms
+ of the license contained in the file LICENSE in this distribution.
+
+ Refer to licensing information at http://www.artifex.com or contact
+ Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato,
+ CA 94945, U.S.A., +1(415)492-9861, for further information.
+*/
+
+
+/* Generic Function support */
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsparam.h"
+#include "gxfunc.h"
+#include "stream.h"
+
+/* GC descriptors */
+public_st_function();
+gs_private_st_ptr(st_function_ptr, gs_function_t *, "gs_function_t *",
+ function_ptr_enum_ptrs, function_ptr_reloc_ptrs);
+gs_private_st_element(st_function_ptr_element, gs_function_t *,
+ "gs_function_t *[]", function_ptr_element_enum_ptrs,
+ function_ptr_element_reloc_ptrs, st_function_ptr);
+
+/* Allocate an array of function pointers. */
+int
+alloc_function_array(uint count, gs_function_t *** pFunctions,
+ gs_memory_t *mem)
+{
+ gs_function_t **ptr;
+
+ if (count == 0)
+ return_error(gs_error_rangecheck);
+ ptr = gs_alloc_struct_array(mem, count, gs_function_t *,
+ &st_function_ptr_element, "Functions");
+ if (ptr == 0)
+ return_error(gs_error_VMerror);
+ memset(ptr, 0, sizeof(*ptr) * count);
+ *pFunctions = ptr;
+ return 0;
+}
+
+/* Generic free_params implementation. */
+void
+fn_common_free_params(gs_function_params_t * params, gs_memory_t * mem)
+{
+ gs_free_const_object(mem, params->Range, "Range");
+ params->Range = NULL;
+ gs_free_const_object(mem, params->Domain, "Domain");
+ params->Domain = NULL;
+}
+
+/* Generic free implementation. */
+void
+fn_common_free(gs_function_t * pfn, bool free_params, gs_memory_t * mem)
+{
+ if (free_params)
+ gs_function_free_params(pfn, mem);
+ gs_free_object(mem, pfn, "fn_common_free");
+}
+
+/* Check the values of m, n, Domain, and (if supplied) Range. */
+int
+fn_check_mnDR(const gs_function_params_t * params, int m, int n)
+{
+ int i;
+
+ if (m <= 0 || n <= 0)
+ return_error(gs_error_rangecheck);
+ for (i = 0; i < m; ++i)
+ if (params->Domain[2 * i] > params->Domain[2 * i + 1])
+ return_error(gs_error_rangecheck);
+ if (params->Range != 0)
+ for (i = 0; i < n; ++i)
+ if (params->Range[2 * i] > params->Range[2 * i + 1])
+ return_error(gs_error_rangecheck);
+ return 0;
+}
+
+/* Return default function information. */
+void
+gs_function_get_info_default(const gs_function_t *pfn, gs_function_info_t *pfi)
+{
+ pfi->DataSource = 0;
+ pfi->Functions = 0;
+}
+
+/*
+ * Write generic parameters (FunctionType, Domain, Range) on a parameter list.
+ */
+int
+fn_common_get_params(const gs_function_t *pfn, gs_param_list *plist)
+{
+ int ecode = param_write_int(plist, "FunctionType", &FunctionType(pfn));
+ int code;
+
+ if (pfn->params.Domain) {
+ code = param_write_float_values(plist, "Domain", pfn->params.Domain,
+ 2 * pfn->params.m, false);
+ if (code < 0)
+ ecode = code;
+ }
+ if (pfn->params.Range) {
+ code = param_write_float_values(plist, "Range", pfn->params.Range,
+ 2 * pfn->params.n, false);
+ if (code < 0)
+ ecode = code;
+ }
+ return ecode;
+}
+
+/*
+ * Copy an array of numeric values when scaling a function.
+ */
+void *
+fn_copy_values(const void *pvalues, int count, int size, gs_memory_t *mem)
+{
+ if (pvalues) {
+ void *values = gs_alloc_byte_array(mem, count, size, "fn_copy_values");
+
+ if (values)
+ memcpy(values, pvalues, count * size);
+ return values;
+ } else
+ return 0; /* caller must check */
+}
+
+/*
+ * If necessary, scale the Range or Decode array for fn_make_scaled.
+ * Note that we must always allocate a new array.
+ */
+int
+fn_scale_pairs(const float **ppvalues, const float *pvalues, int npairs,
+ const gs_range_t *pranges, gs_memory_t *mem)
+{
+ if (pvalues == 0)
+ *ppvalues = 0;
+ else {
+ float *out = (float *)
+ gs_alloc_byte_array(mem, 2 * npairs, sizeof(*pvalues),
+ "fn_scale_pairs");
+
+ *ppvalues = out;
+ if (out == 0)
+ return_error(gs_error_VMerror);
+ if (pranges) {
+ /* Allocate and compute scaled ranges. */
+ int i;
+ for (i = 0; i < npairs; ++i) {
+ double base = pranges[i].rmin, factor = pranges[i].rmax - base;
+
+ out[2 * i] = pvalues[2 * i] * factor + base;
+ out[2 * i + 1] = pvalues[2 * i + 1] * factor + base;
+ }
+ } else
+ memcpy(out, pvalues, 2 * sizeof(*pvalues) * npairs);
+ }
+ return 0;
+}
+
+/*
+ * Scale the generic part of a function (Domain and Range).
+ * The client must have copied the parameters already.
+ */
+int
+fn_common_scale(gs_function_t *psfn, const gs_function_t *pfn,
+ const gs_range_t *pranges, gs_memory_t *mem)
+{
+ int code;
+
+ psfn->head = pfn->head;
+ psfn->params.Domain = 0; /* in case of failure */
+ psfn->params.Range = 0;
+ if ((code = fn_scale_pairs(&psfn->params.Domain, pfn->params.Domain,
+ pfn->params.m, NULL, mem)) < 0 ||
+ (code = fn_scale_pairs(&psfn->params.Range, pfn->params.Range,
+ pfn->params.n, pranges, mem)) < 0)
+ return code;
+ return 0;
+}
+
+/* Serialize. */
+int
+fn_common_serialize(const gs_function_t * pfn, stream *s)
+{
+ uint n;
+ const gs_function_params_t * p = &pfn->params;
+ int code = sputs(s, (const byte *)&pfn->head.type, sizeof(pfn->head.type), &n);
+ const float dummy[8] = {0, 0, 0, 0, 0, 0, 0, 0};
+
+ if (code < 0)
+ return code;
+ code = sputs(s, (const byte *)&p->m, sizeof(p->m), &n);
+ if (code < 0)
+ return code;
+ code = sputs(s, (const byte *)&p->Domain[0], sizeof(p->Domain[0]) * p->m * 2, &n);
+ if (code < 0)
+ return code;
+ code = sputs(s, (const byte *)&p->n, sizeof(p->n), &n);
+ if (code < 0)
+ return code;
+ if (p->Range == NULL && p->n * 2 > count_of(dummy))
+ return_error(gs_error_unregistered); /* Unimplemented. */
+ return sputs(s, (const byte *)(p->Range != NULL ? &p->Range[0] : dummy),
+ sizeof(p->Range[0]) * p->n * 2, &n);
+}