13ff48bf5SDavid du Colombier /* Copyright (C) 1997, 2000 Aladdin Enterprises. All rights reserved.
27dd7cddfSDavid du Colombier
3*593dc095SDavid du Colombier This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier implied.
57dd7cddfSDavid du Colombier
6*593dc095SDavid du Colombier This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier of the license contained in the file LICENSE in this distribution.
97dd7cddfSDavid du Colombier
10*593dc095SDavid du Colombier For more information about licensing, please refer to
11*593dc095SDavid du Colombier http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier San Rafael, CA 94903, U.S.A., +1(415)492-9861.
157dd7cddfSDavid du Colombier */
167dd7cddfSDavid du Colombier
17*593dc095SDavid du Colombier /* $Id: gsfunc.c,v 1.12 2005/04/19 14:35:12 igor Exp $ */
187dd7cddfSDavid du Colombier /* Generic Function support */
19*593dc095SDavid du Colombier #include "memory_.h"
207dd7cddfSDavid du Colombier #include "gx.h"
217dd7cddfSDavid du Colombier #include "gserrors.h"
223ff48bf5SDavid du Colombier #include "gsparam.h"
237dd7cddfSDavid du Colombier #include "gxfunc.h"
24*593dc095SDavid du Colombier #include "stream.h"
257dd7cddfSDavid du Colombier
267dd7cddfSDavid du Colombier /* GC descriptors */
277dd7cddfSDavid du Colombier public_st_function();
28*593dc095SDavid du Colombier gs_private_st_ptr(st_function_ptr, gs_function_t *, "gs_function_t *",
29*593dc095SDavid du Colombier function_ptr_enum_ptrs, function_ptr_reloc_ptrs);
30*593dc095SDavid du Colombier gs_private_st_element(st_function_ptr_element, gs_function_t *,
31*593dc095SDavid du Colombier "gs_function_t *[]", function_ptr_element_enum_ptrs,
32*593dc095SDavid du Colombier function_ptr_element_reloc_ptrs, st_function_ptr);
33*593dc095SDavid du Colombier
34*593dc095SDavid du Colombier /* Allocate an array of function pointers. */
35*593dc095SDavid du Colombier int
alloc_function_array(uint count,gs_function_t *** pFunctions,gs_memory_t * mem)36*593dc095SDavid du Colombier alloc_function_array(uint count, gs_function_t *** pFunctions,
37*593dc095SDavid du Colombier gs_memory_t *mem)
38*593dc095SDavid du Colombier {
39*593dc095SDavid du Colombier gs_function_t **ptr;
40*593dc095SDavid du Colombier
41*593dc095SDavid du Colombier if (count == 0)
42*593dc095SDavid du Colombier return_error(gs_error_rangecheck);
43*593dc095SDavid du Colombier ptr = gs_alloc_struct_array(mem, count, gs_function_t *,
44*593dc095SDavid du Colombier &st_function_ptr_element, "Functions");
45*593dc095SDavid du Colombier if (ptr == 0)
46*593dc095SDavid du Colombier return_error(gs_error_VMerror);
47*593dc095SDavid du Colombier memset(ptr, 0, sizeof(*ptr) * count);
48*593dc095SDavid du Colombier *pFunctions = ptr;
49*593dc095SDavid du Colombier return 0;
50*593dc095SDavid du Colombier }
517dd7cddfSDavid du Colombier
527dd7cddfSDavid du Colombier /* Generic free_params implementation. */
537dd7cddfSDavid du Colombier void
fn_common_free_params(gs_function_params_t * params,gs_memory_t * mem)547dd7cddfSDavid du Colombier fn_common_free_params(gs_function_params_t * params, gs_memory_t * mem)
557dd7cddfSDavid du Colombier {
567dd7cddfSDavid du Colombier gs_free_const_object(mem, params->Range, "Range");
577dd7cddfSDavid du Colombier gs_free_const_object(mem, params->Domain, "Domain");
587dd7cddfSDavid du Colombier }
597dd7cddfSDavid du Colombier
607dd7cddfSDavid du Colombier /* Generic free implementation. */
617dd7cddfSDavid du Colombier void
fn_common_free(gs_function_t * pfn,bool free_params,gs_memory_t * mem)627dd7cddfSDavid du Colombier fn_common_free(gs_function_t * pfn, bool free_params, gs_memory_t * mem)
637dd7cddfSDavid du Colombier {
647dd7cddfSDavid du Colombier if (free_params)
657dd7cddfSDavid du Colombier gs_function_free_params(pfn, mem);
667dd7cddfSDavid du Colombier gs_free_object(mem, pfn, "fn_common_free");
677dd7cddfSDavid du Colombier }
687dd7cddfSDavid du Colombier
697dd7cddfSDavid du Colombier /* Check the values of m, n, Domain, and (if supplied) Range. */
707dd7cddfSDavid du Colombier int
fn_check_mnDR(const gs_function_params_t * params,int m,int n)717dd7cddfSDavid du Colombier fn_check_mnDR(const gs_function_params_t * params, int m, int n)
727dd7cddfSDavid du Colombier {
737dd7cddfSDavid du Colombier int i;
747dd7cddfSDavid du Colombier
757dd7cddfSDavid du Colombier if (m <= 0 || n <= 0)
767dd7cddfSDavid du Colombier return_error(gs_error_rangecheck);
777dd7cddfSDavid du Colombier for (i = 0; i < m; ++i)
787dd7cddfSDavid du Colombier if (params->Domain[2 * i] > params->Domain[2 * i + 1])
797dd7cddfSDavid du Colombier return_error(gs_error_rangecheck);
807dd7cddfSDavid du Colombier if (params->Range != 0)
817dd7cddfSDavid du Colombier for (i = 0; i < n; ++i)
827dd7cddfSDavid du Colombier if (params->Range[2 * i] > params->Range[2 * i + 1])
837dd7cddfSDavid du Colombier return_error(gs_error_rangecheck);
847dd7cddfSDavid du Colombier return 0;
857dd7cddfSDavid du Colombier }
867dd7cddfSDavid du Colombier
873ff48bf5SDavid du Colombier /* Return default function information. */
889a747e4fSDavid du Colombier void
gs_function_get_info_default(const gs_function_t * pfn,gs_function_info_t * pfi)893ff48bf5SDavid du Colombier gs_function_get_info_default(const gs_function_t *pfn, gs_function_info_t *pfi)
907dd7cddfSDavid du Colombier {
913ff48bf5SDavid du Colombier pfi->DataSource = 0;
923ff48bf5SDavid du Colombier pfi->Functions = 0;
939a747e4fSDavid du Colombier }
949a747e4fSDavid du Colombier
95*593dc095SDavid du Colombier /*
96*593dc095SDavid du Colombier * Write generic parameters (FunctionType, Domain, Range) on a parameter list.
97*593dc095SDavid du Colombier */
989a747e4fSDavid du Colombier int
fn_common_get_params(const gs_function_t * pfn,gs_param_list * plist)993ff48bf5SDavid du Colombier fn_common_get_params(const gs_function_t *pfn, gs_param_list *plist)
1009a747e4fSDavid du Colombier {
1013ff48bf5SDavid du Colombier int ecode = param_write_int(plist, "FunctionType", &FunctionType(pfn));
1027dd7cddfSDavid du Colombier int code;
1037dd7cddfSDavid du Colombier
1043ff48bf5SDavid du Colombier if (pfn->params.Domain) {
1053ff48bf5SDavid du Colombier code = param_write_float_values(plist, "Domain", pfn->params.Domain,
1063ff48bf5SDavid du Colombier 2 * pfn->params.m, false);
1077dd7cddfSDavid du Colombier if (code < 0)
1083ff48bf5SDavid du Colombier ecode = code;
1097dd7cddfSDavid du Colombier }
1103ff48bf5SDavid du Colombier if (pfn->params.Range) {
1113ff48bf5SDavid du Colombier code = param_write_float_values(plist, "Range", pfn->params.Range,
1123ff48bf5SDavid du Colombier 2 * pfn->params.n, false);
1133ff48bf5SDavid du Colombier if (code < 0)
1143ff48bf5SDavid du Colombier ecode = code;
1153ff48bf5SDavid du Colombier }
1163ff48bf5SDavid du Colombier return ecode;
1177dd7cddfSDavid du Colombier }
118*593dc095SDavid du Colombier
119*593dc095SDavid du Colombier /*
120*593dc095SDavid du Colombier * Copy an array of numeric values when scaling a function.
121*593dc095SDavid du Colombier */
122*593dc095SDavid du Colombier void *
fn_copy_values(const void * pvalues,int count,int size,gs_memory_t * mem)123*593dc095SDavid du Colombier fn_copy_values(const void *pvalues, int count, int size, gs_memory_t *mem)
124*593dc095SDavid du Colombier {
125*593dc095SDavid du Colombier if (pvalues) {
126*593dc095SDavid du Colombier void *values = gs_alloc_byte_array(mem, count, size, "fn_copy_values");
127*593dc095SDavid du Colombier
128*593dc095SDavid du Colombier if (values)
129*593dc095SDavid du Colombier memcpy(values, pvalues, count * size);
130*593dc095SDavid du Colombier return values;
131*593dc095SDavid du Colombier } else
132*593dc095SDavid du Colombier return 0; /* caller must check */
133*593dc095SDavid du Colombier }
134*593dc095SDavid du Colombier
135*593dc095SDavid du Colombier /*
136*593dc095SDavid du Colombier * If necessary, scale the Range or Decode array for fn_make_scaled.
137*593dc095SDavid du Colombier * Note that we must always allocate a new array.
138*593dc095SDavid du Colombier */
139*593dc095SDavid du Colombier int
fn_scale_pairs(const float ** ppvalues,const float * pvalues,int npairs,const gs_range_t * pranges,gs_memory_t * mem)140*593dc095SDavid du Colombier fn_scale_pairs(const float **ppvalues, const float *pvalues, int npairs,
141*593dc095SDavid du Colombier const gs_range_t *pranges, gs_memory_t *mem)
142*593dc095SDavid du Colombier {
143*593dc095SDavid du Colombier if (pvalues == 0)
144*593dc095SDavid du Colombier *ppvalues = 0;
145*593dc095SDavid du Colombier else {
146*593dc095SDavid du Colombier float *out = (float *)
147*593dc095SDavid du Colombier gs_alloc_byte_array(mem, 2 * npairs, sizeof(*pvalues),
148*593dc095SDavid du Colombier "fn_scale_pairs");
149*593dc095SDavid du Colombier
150*593dc095SDavid du Colombier *ppvalues = out;
151*593dc095SDavid du Colombier if (out == 0)
152*593dc095SDavid du Colombier return_error(gs_error_VMerror);
153*593dc095SDavid du Colombier if (pranges) {
154*593dc095SDavid du Colombier /* Allocate and compute scaled ranges. */
155*593dc095SDavid du Colombier int i;
156*593dc095SDavid du Colombier for (i = 0; i < npairs; ++i) {
157*593dc095SDavid du Colombier double base = pranges[i].rmin, factor = pranges[i].rmax - base;
158*593dc095SDavid du Colombier
159*593dc095SDavid du Colombier out[2 * i] = pvalues[2 * i] * factor + base;
160*593dc095SDavid du Colombier out[2 * i + 1] = pvalues[2 * i + 1] * factor + base;
161*593dc095SDavid du Colombier }
162*593dc095SDavid du Colombier } else
163*593dc095SDavid du Colombier memcpy(out, pvalues, 2 * sizeof(*pvalues) * npairs);
164*593dc095SDavid du Colombier }
165*593dc095SDavid du Colombier return 0;
166*593dc095SDavid du Colombier }
167*593dc095SDavid du Colombier
168*593dc095SDavid du Colombier /*
169*593dc095SDavid du Colombier * Scale the generic part of a function (Domain and Range).
170*593dc095SDavid du Colombier * The client must have copied the parameters already.
171*593dc095SDavid du Colombier */
172*593dc095SDavid du Colombier int
fn_common_scale(gs_function_t * psfn,const gs_function_t * pfn,const gs_range_t * pranges,gs_memory_t * mem)173*593dc095SDavid du Colombier fn_common_scale(gs_function_t *psfn, const gs_function_t *pfn,
174*593dc095SDavid du Colombier const gs_range_t *pranges, gs_memory_t *mem)
175*593dc095SDavid du Colombier {
176*593dc095SDavid du Colombier int code;
177*593dc095SDavid du Colombier
178*593dc095SDavid du Colombier psfn->head = pfn->head;
179*593dc095SDavid du Colombier psfn->params.Domain = 0; /* in case of failure */
180*593dc095SDavid du Colombier psfn->params.Range = 0;
181*593dc095SDavid du Colombier if ((code = fn_scale_pairs(&psfn->params.Domain, pfn->params.Domain,
182*593dc095SDavid du Colombier pfn->params.m, NULL, mem)) < 0 ||
183*593dc095SDavid du Colombier (code = fn_scale_pairs(&psfn->params.Range, pfn->params.Range,
184*593dc095SDavid du Colombier pfn->params.n, pranges, mem)) < 0)
185*593dc095SDavid du Colombier return code;
186*593dc095SDavid du Colombier return 0;
187*593dc095SDavid du Colombier }
188*593dc095SDavid du Colombier
189*593dc095SDavid du Colombier /* Serialize. */
190*593dc095SDavid du Colombier int
fn_common_serialize(const gs_function_t * pfn,stream * s)191*593dc095SDavid du Colombier fn_common_serialize(const gs_function_t * pfn, stream *s)
192*593dc095SDavid du Colombier {
193*593dc095SDavid du Colombier uint n;
194*593dc095SDavid du Colombier const gs_function_params_t * p = &pfn->params;
195*593dc095SDavid du Colombier int code = sputs(s, (const byte *)&pfn->head.type, sizeof(pfn->head.type), &n);
196*593dc095SDavid du Colombier const float dummy[8] = {0, 0, 0, 0, 0, 0, 0, 0};
197*593dc095SDavid du Colombier
198*593dc095SDavid du Colombier if (code < 0)
199*593dc095SDavid du Colombier return code;
200*593dc095SDavid du Colombier code = sputs(s, (const byte *)&p->m, sizeof(p->m), &n);
201*593dc095SDavid du Colombier if (code < 0)
202*593dc095SDavid du Colombier return code;
203*593dc095SDavid du Colombier code = sputs(s, (const byte *)&p->Domain[0], sizeof(p->Domain[0]) * p->m * 2, &n);
204*593dc095SDavid du Colombier if (code < 0)
205*593dc095SDavid du Colombier return code;
206*593dc095SDavid du Colombier code = sputs(s, (const byte *)&p->n, sizeof(p->n), &n);
207*593dc095SDavid du Colombier if (code < 0)
208*593dc095SDavid du Colombier return code;
209*593dc095SDavid du Colombier if (p->Range == NULL && p->n * 2 > count_of(dummy))
210*593dc095SDavid du Colombier return_error(gs_error_unregistered); /* Unimplemented. */
211*593dc095SDavid du Colombier return sputs(s, (const byte *)(p->Range != NULL ? &p->Range[0] : dummy),
212*593dc095SDavid du Colombier sizeof(p->Range[0]) * p->n * 2, &n);
213*593dc095SDavid du Colombier }
214*593dc095SDavid du Colombier
215