xref: /plan9/sys/src/cmd/gs/src/gsfunc.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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