~ubuntu-branches/ubuntu/jaunty/ghostscript/jaunty-updates

« back to all changes in this revision

Viewing changes to base/gsfunc3.c

  • Committer: Bazaar Package Importer
  • Author(s): Till Kamppeter
  • Date: 2009-01-20 16:40:45 UTC
  • mfrom: (1.1.10 upstream)
  • Revision ID: james.westby@ubuntu.com-20090120164045-lnfhi0n30o5lwhwa
Tags: 8.64.dfsg.1~svn9377-0ubuntu1
* New upstream release (SVN rev 9377)
   o Fixes many bugs concerning PDF rendering, to make the PDF printing
     workflow correctly working.
   o Fixes long-standing bugs in many drivers, like input paper tray and
     duplex options not working for the built-in PCL 4, 5, 5c, 5e, and
     6/XL drivers, PDF input not working for bjc600, bjc800, and cups
     output devices, several options not working and uninitialized
     memory with cups output device.
   o Merged nearly all patches of the Ubuntu and Debian packages upstream.
   o Fixes LP: #317810, LP: #314439, LP: #314018.
* debian/patches/03_libpaper_support.dpatch,
  debian/patches/11_gs-cjk_font_glyph_handling_fix.dpatch,
  debian/patches/12_gs-cjk_vertical_writing_metrics_fix.dpatch,
  debian/patches/13_gs-cjk_cjkps_examples.dpatch,
  debian/patches/20_bbox_segv_fix.dpatch,
  debian/patches/21_brother_7x0_gdi_fix.dpatch,
  debian/patches/22_epsn_margin_workaround.dpatch,
  debian/patches/24_gs_man_fix.dpatch,
  debian/patches/25_toolbin_insecure_tmp_usage_fix.dpatch,
  debian/patches/26_assorted_script_fixes.dpatch,
  debian/patches/29_gs_css_fix.dpatch,
  debian/patches/30_ps2pdf_man_improvement.dpatch,
  debian/patches/31_fix-gc-sigbus.dpatch,
  debian/patches/34_ftbfs-on-hurd-fix.dpatch,
  debian/patches/35_disable_libcairo.dpatch,
  debian/patches/38_pxl-duplex.dpatch,
  debian/patches/39_pxl-resolution.dpatch,
  debian/patches/42_gs-init-ps-delaybind-fix.dpatch,
  debian/patches/45_bjc600-bjc800-pdf-input.dpatch,
  debian/patches/48_cups-output-device-pdf-duplex-uninitialized-memory-fix.dpatch,
  debian/patches/50_lips4-floating-point-exception.dpatch,
  debian/patches/52_cups-device-logging.dpatch,
  debian/patches/55_pcl-input-slot-fix.dpatch,
  debian/patches/57_pxl-input-slot-fix.dpatch,
  debian/patches/60_pxl-cups-driver-pdf.dpatch,
  debian/patches/62_onebitcmyk-pdf.dpatch,
  debian/patches/65_too-big-temp-files-1.dpatch,
  debian/patches/67_too-big-temp-files-2.dpatch,
  debian/patches/70_take-into-account-data-in-stream-buffer-before-refill.dpatch:
  Removed, applied upstream.
* debian/patches/01_docdir_fix_for_debian.dpatch,
  debian/patches/02_gs_man_fix_debian.dpatch,
  debian/patches/01_docdir-fix-for-debian.dpatch,
  debian/patches/02_docdir-fix-for-debian.dpatch: Renamed patches to
  make merging with Debian easier.
* debian/patches/32_improve-handling-of-media-size-changes-from-gv.dpatch, 
  debian/patches/33_bad-params-to-xinitimage-on-large-bitmaps.dpatch:
  regenerated for new source directory structure.
* debian/rules: Corrected paths to remove cidfmap (it is in Resource/Init/
  in GS 8.64) and to install headers (source paths are psi/ and base/ now).
* debian/rules: Remove all fontmaps, as DeFoMa replaces them.
* debian/local/pdftoraster/pdftoraster.c,
  debian/local/pdftoraster/pdftoraster.convs, debian/rules: Removed
  added pdftoraster filter and use the one which comes with Ghostscript.
* debian/ghostscript.links: s/8.63/8.64/

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2001-2006 Artifex Software, Inc.
 
2
   All Rights Reserved.
 
3
  
 
4
   This software is provided AS-IS with no warranty, either express or
 
5
   implied.
 
6
 
 
7
   This software is distributed under license and may not be copied, modified
 
8
   or distributed except as expressly authorized under the terms of that
 
9
   license.  Refer to licensing information at http://www.artifex.com/
 
10
   or contact Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134,
 
11
   San Rafael, CA  94903, U.S.A., +1(415)492-9861, for further information.
 
12
*/
 
13
 
 
14
/* $Id: gsfunc3.c 8250 2007-09-25 13:31:24Z giles $ */
 
15
/* Implementation of LL3 Functions */
 
16
#include "math_.h"
 
17
#include "memory_.h"
 
18
#include "gx.h"
 
19
#include "gserrors.h"
 
20
#include "gsfunc3.h"
 
21
#include "gsparam.h"
 
22
#include "gxfunc.h"
 
23
#include "gxarith.h"
 
24
#include "stream.h"
 
25
 
 
26
/* ---------------- Utilities ---------------- */
 
27
 
 
28
#define MASK1 ((uint)(~0) / 3)
 
29
 
 
30
/*
 
31
 * Free an array of subsidiary Functions.  Note that this may be called
 
32
 * before the Functions array has been fully initialized.  Note also that
 
33
 * its argument conforms to the Functions array in the parameter structure,
 
34
 * but it (necessarily) deconstifies it.
 
35
 */
 
36
static void
 
37
fn_free_functions(const gs_function_t *const * Functions, int count,
 
38
                  gs_memory_t * mem)
 
39
{
 
40
    int i;
 
41
 
 
42
    for (i = count; --i >= 0;)
 
43
        if (Functions[i])
 
44
            gs_function_free((gs_function_t *)Functions[i], true, mem);
 
45
    gs_free_const_object(mem, Functions, "Functions");
 
46
}
 
47
 
 
48
/*
 
49
 * Scale an array of subsidiary functions.  Note that the scale may either
 
50
 * be propagated unchanged (step_ranges = false) or divided among the
 
51
 * (1-output) subfunctions (step_ranges = true).
 
52
 */
 
53
static int
 
54
fn_scale_functions(gs_function_t ***ppsfns, const gs_function_t *const *pfns,
 
55
                   int count, const gs_range_t *pranges, bool step_ranges,
 
56
                   gs_memory_t *mem)
 
57
{
 
58
    gs_function_t **psfns;
 
59
    int code = alloc_function_array(count, &psfns, mem);
 
60
    const gs_range_t *ranges = pranges;
 
61
    int i;
 
62
    
 
63
    if (code < 0)
 
64
        return code;
 
65
    for (i = 0; i < count; ++i) {
 
66
        int code = gs_function_make_scaled(pfns[i], &psfns[i], ranges, mem);
 
67
 
 
68
        if (code < 0) {
 
69
            fn_free_functions((const gs_function_t *const *)psfns, count, mem);
 
70
            return code;
 
71
        }
 
72
        if (step_ranges)
 
73
            ++ranges;
 
74
    }
 
75
    *ppsfns = psfns;
 
76
    return 0;
 
77
}
 
78
 
 
79
/* ---------------- Exponential Interpolation functions ---------------- */
 
80
 
 
81
typedef struct gs_function_ElIn_s {
 
82
    gs_function_head_t head;
 
83
    gs_function_ElIn_params_t params;
 
84
} gs_function_ElIn_t;
 
85
 
 
86
private_st_function_ElIn();
 
87
 
 
88
/* Evaluate an Exponential Interpolation function. */
 
89
static int
 
90
fn_ElIn_evaluate(const gs_function_t * pfn_common, const float *in, float *out)
 
91
{
 
92
    const gs_function_ElIn_t *const pfn =
 
93
        (const gs_function_ElIn_t *)pfn_common;
 
94
    double arg = in[0], raised;
 
95
    int i;
 
96
 
 
97
    if (arg < pfn->params.Domain[0])
 
98
        arg = pfn->params.Domain[0];
 
99
    else if (arg > pfn->params.Domain[1])
 
100
        arg = pfn->params.Domain[1];
 
101
    raised = pow(arg, pfn->params.N);
 
102
    for (i = 0; i < pfn->params.n; ++i) {
 
103
        float v0 = (pfn->params.C0 == 0 ? 0.0 : pfn->params.C0[i]);
 
104
        float v1 = (pfn->params.C1 == 0 ? 1.0 : pfn->params.C1[i]);
 
105
        double value = v0 + raised * (v1 - v0);
 
106
 
 
107
        if (pfn->params.Range) {
 
108
            float r0 = pfn->params.Range[2 * i],
 
109
                r1 = pfn->params.Range[2 * i + 1];
 
110
 
 
111
            if (value < r0)
 
112
                value = r0;
 
113
            else if (value > r1)
 
114
                value = r1;
 
115
        }
 
116
        out[i] = value;
 
117
        if_debug3('~', "[~]ElIn %g => [%d]%g\n", arg, i, out[i]);
 
118
    }
 
119
    return 0;
 
120
}
 
121
 
 
122
/* Test whether an Exponential function is monotonic.  (They always are.) */
 
123
static int
 
124
fn_ElIn_is_monotonic(const gs_function_t * pfn_common,
 
125
                     const float *lower, const float *upper, uint *mask)
 
126
{
 
127
    const gs_function_ElIn_t *const pfn =
 
128
        (const gs_function_ElIn_t *)pfn_common;
 
129
 
 
130
    if (lower[0] > pfn->params.Domain[1] ||
 
131
        upper[0] < pfn->params.Domain[0]
 
132
        )
 
133
        return_error(gs_error_rangecheck);
 
134
    *mask = 0;
 
135
    return 1;
 
136
}
 
137
 
 
138
/* Write Exponential Interpolation function parameters on a parameter list. */
 
139
static int
 
140
fn_ElIn_get_params(const gs_function_t *pfn_common, gs_param_list *plist)
 
141
{
 
142
    const gs_function_ElIn_t *const pfn =
 
143
        (const gs_function_ElIn_t *)pfn_common;
 
144
    int ecode = fn_common_get_params(pfn_common, plist);
 
145
    int code;
 
146
 
 
147
    if (pfn->params.C0) {
 
148
        if ((code = param_write_float_values(plist, "C0", pfn->params.C0,
 
149
                                             pfn->params.n, false)) < 0)
 
150
            ecode = code;
 
151
    }
 
152
    if (pfn->params.C1) {
 
153
        if ((code = param_write_float_values(plist, "C1", pfn->params.C1,
 
154
                                             pfn->params.n, false)) < 0)
 
155
            ecode = code;
 
156
    }
 
157
    if ((code = param_write_float(plist, "N", &pfn->params.N)) < 0)
 
158
        ecode = code;
 
159
    return ecode;
 
160
}
 
161
 
 
162
/* Make a scaled copy of an Exponential Interpolation function. */
 
163
static int
 
164
fn_ElIn_make_scaled(const gs_function_ElIn_t *pfn,
 
165
                     gs_function_ElIn_t **ppsfn,
 
166
                     const gs_range_t *pranges, gs_memory_t *mem)
 
167
{
 
168
    gs_function_ElIn_t *psfn =
 
169
        gs_alloc_struct(mem, gs_function_ElIn_t, &st_function_ElIn,
 
170
                        "fn_ElIn_make_scaled");
 
171
    float *c0;
 
172
    float *c1;
 
173
    int code, i;
 
174
 
 
175
    if (psfn == 0)
 
176
        return_error(gs_error_VMerror);
 
177
    psfn->params = pfn->params;
 
178
    psfn->params.C0 = c0 =
 
179
        fn_copy_values(pfn->params.C0, pfn->params.n, sizeof(float), mem);
 
180
    psfn->params.C1 = c1 =
 
181
        fn_copy_values(pfn->params.C1, pfn->params.n, sizeof(float), mem);
 
182
    if ((code = ((c0 == 0 && pfn->params.C0 != 0) ||
 
183
                 (c1 == 0 && pfn->params.C1 != 0) ?
 
184
                 gs_note_error(gs_error_VMerror) : 0)) < 0 ||
 
185
        (code = fn_common_scale((gs_function_t *)psfn,
 
186
                                (const gs_function_t *)pfn,
 
187
                                pranges, mem)) < 0) {
 
188
        gs_function_free((gs_function_t *)psfn, true, mem);
 
189
        return code;
 
190
    }
 
191
    for (i = 0; i < pfn->params.n; ++i) {
 
192
        double base = pranges[i].rmin, factor = pranges[i].rmax - base;
 
193
 
 
194
        c1[i] = c1[i] * factor + base;
 
195
        c0[i] = c0[i] * factor + base;
 
196
    }
 
197
    *ppsfn = psfn;
 
198
    return 0;
 
199
}
 
200
 
 
201
/* Free the parameters of an Exponential Interpolation function. */
 
202
void
 
203
gs_function_ElIn_free_params(gs_function_ElIn_params_t * params,
 
204
                             gs_memory_t * mem)
 
205
{
 
206
    gs_free_const_object(mem, params->C1, "C1");
 
207
    gs_free_const_object(mem, params->C0, "C0");
 
208
    fn_common_free_params((gs_function_params_t *) params, mem);
 
209
}
 
210
 
 
211
/* Serialize. */
 
212
static int
 
213
gs_function_ElIn_serialize(const gs_function_t * pfn, stream *s)
 
214
{
 
215
    uint n;
 
216
    const gs_function_ElIn_params_t * p = (const gs_function_ElIn_params_t *)&pfn->params;
 
217
    int code = fn_common_serialize(pfn, s);
 
218
 
 
219
    if (code < 0)
 
220
        return code;
 
221
    code = sputs(s, (const byte *)&p->C0[0], sizeof(p->C0[0]) * p->n, &n);
 
222
    if (code < 0)
 
223
        return code;
 
224
    code = sputs(s, (const byte *)&p->C1[0], sizeof(p->C1[0]) * p->n, &n);
 
225
    if (code < 0)
 
226
        return code;
 
227
    return sputs(s, (const byte *)&p->N, sizeof(p->N), &n);
 
228
}
 
229
 
 
230
/* Allocate and initialize an Exponential Interpolation function. */
 
231
int
 
232
gs_function_ElIn_init(gs_function_t ** ppfn,
 
233
                      const gs_function_ElIn_params_t * params,
 
234
                      gs_memory_t * mem)
 
235
{
 
236
    static const gs_function_head_t function_ElIn_head = {
 
237
        function_type_ExponentialInterpolation,
 
238
        {
 
239
            (fn_evaluate_proc_t) fn_ElIn_evaluate,
 
240
            (fn_is_monotonic_proc_t) fn_ElIn_is_monotonic,
 
241
            gs_function_get_info_default,
 
242
            (fn_get_params_proc_t) fn_ElIn_get_params,
 
243
            (fn_make_scaled_proc_t) fn_ElIn_make_scaled,
 
244
            (fn_free_params_proc_t) gs_function_ElIn_free_params,
 
245
            fn_common_free,
 
246
            (fn_serialize_proc_t) gs_function_ElIn_serialize,
 
247
        }
 
248
    };
 
249
    int code;
 
250
 
 
251
    *ppfn = 0;                  /* in case of error */
 
252
    code = fn_check_mnDR((const gs_function_params_t *)params, 1, params->n);
 
253
    if (code < 0)
 
254
        return code;
 
255
    if ((params->C0 == 0 || params->C1 == 0) && params->n != 1)
 
256
        return_error(gs_error_rangecheck);
 
257
    if (params->N != floor(params->N)) {
 
258
        /* Non-integral exponent, all inputs must be non-negative. */
 
259
        if (params->Domain[0] < 0)
 
260
            return_error(gs_error_rangecheck);
 
261
    }
 
262
    if (params->N < 0) {
 
263
        /* Negative exponent, input must not be zero. */
 
264
        if (params->Domain[0] <= 0 && params->Domain[1] >= 0)
 
265
            return_error(gs_error_rangecheck);
 
266
    } {
 
267
        gs_function_ElIn_t *pfn =
 
268
            gs_alloc_struct(mem, gs_function_ElIn_t, &st_function_ElIn,
 
269
                            "gs_function_ElIn_init");
 
270
 
 
271
        if (pfn == 0)
 
272
            return_error(gs_error_VMerror);
 
273
        pfn->params = *params;
 
274
        pfn->params.m = 1;
 
275
        pfn->head = function_ElIn_head;
 
276
        *ppfn = (gs_function_t *) pfn;
 
277
    }
 
278
    return 0;
 
279
}
 
280
 
 
281
/* ---------------- 1-Input Stitching functions ---------------- */
 
282
 
 
283
typedef struct gs_function_1ItSg_s {
 
284
    gs_function_head_t head;
 
285
    gs_function_1ItSg_params_t params;
 
286
} gs_function_1ItSg_t;
 
287
 
 
288
private_st_function_1ItSg();
 
289
 
 
290
/* Evaluate a 1-Input Stitching function. */
 
291
static int
 
292
fn_1ItSg_evaluate(const gs_function_t * pfn_common, const float *in, float *out)
 
293
{
 
294
    const gs_function_1ItSg_t *const pfn =
 
295
        (const gs_function_1ItSg_t *)pfn_common;
 
296
    float arg = in[0], b0, b1, e0, encoded;
 
297
    int k = pfn->params.k;
 
298
    int i;
 
299
 
 
300
    if (arg < pfn->params.Domain[0]) {
 
301
        arg = pfn->params.Domain[0];
 
302
        i = 0;
 
303
    } else if (arg > pfn->params.Domain[1]) {
 
304
        arg = pfn->params.Domain[1];
 
305
        i = k - 1;
 
306
    } else {
 
307
        for (i = 0; i < k - 1; ++i)
 
308
            if (arg <= pfn->params.Bounds[i])
 
309
                break;
 
310
    }
 
311
    b0 = (i == 0 ? pfn->params.Domain[0] : pfn->params.Bounds[i - 1]);
 
312
    b1 = (i == k - 1 ? pfn->params.Domain[1] : pfn->params.Bounds[i]);
 
313
    e0 = pfn->params.Encode[2 * i];
 
314
    if (b1 == b0)
 
315
        encoded = e0;
 
316
    else
 
317
        encoded =
 
318
            (arg - b0) * (pfn->params.Encode[2 * i + 1] - e0) / (b1 - b0) + e0;
 
319
    if_debug3('~', "[~]1ItSg %g in %d => %g\n", arg, i, encoded);
 
320
    return gs_function_evaluate(pfn->params.Functions[i], &encoded, out);
 
321
}
 
322
 
 
323
/* Test whether a 1-Input Stitching function is monotonic. */
 
324
static int
 
325
fn_1ItSg_is_monotonic(const gs_function_t * pfn_common,
 
326
                      const float *lower, const float *upper, uint *mask)
 
327
{
 
328
    const gs_function_1ItSg_t *const pfn =
 
329
        (const gs_function_1ItSg_t *)pfn_common;
 
330
    float v0 = lower[0], v1 = upper[0];
 
331
    float d0 = pfn->params.Domain[0], d1 = pfn->params.Domain[1];
 
332
    int k = pfn->params.k;
 
333
    int i;
 
334
 
 
335
    *mask = 0;
 
336
    if (v0 > v1) {
 
337
        v0 = v1; v1 = lower[0];
 
338
    }
 
339
    if (v0 > d1 || v1 < d0)
 
340
        return_error(gs_error_rangecheck);
 
341
    if (v0 < d0)
 
342
        v0 = d0;
 
343
    if (v1 > d1)
 
344
        v1 = d1;
 
345
    for (i = 0; i < pfn->params.k; ++i) {
 
346
        float b0 = (i == 0 ? d0 : pfn->params.Bounds[i - 1]);
 
347
        float b1 = (i == k - 1 ? d1 : pfn->params.Bounds[i]);
 
348
        const float bsmall = (float)1e-6 * (b1 - b0);
 
349
        float esmall;
 
350
        float e0, e1;
 
351
        float w0, w1;
 
352
        float vv0, vv1;
 
353
        double vb0, vb1;
 
354
 
 
355
        if (v0 >= b1)
 
356
            continue;
 
357
        if (v0 >= b1 - bsmall)
 
358
            continue; /* Ignore a small noise */
 
359
        vv0 = max(b0, v0);
 
360
        vv1 = v1;
 
361
        if (vv1 > b1 && v1 < b1 + bsmall)
 
362
            vv1 = b1; /* Ignore a small noise */
 
363
        if (vv0 == vv1)
 
364
            return 1;
 
365
        if (vv0 < b1 && vv1 > b1) {
 
366
            *mask = 1;
 
367
            return 0; /* Consider stitches as monotonity breaks. */
 
368
        }
 
369
        e0 = pfn->params.Encode[2 * i];
 
370
        e1 = pfn->params.Encode[2 * i + 1];
 
371
        esmall = (float)1e-6 * any_abs(e1 - e0);
 
372
        vb0 = max(vv0, b0);
 
373
        vb1 = min(vv1, b1);
 
374
        w0 = (float)(vb0 - b0) * (e1 - e0) / (b1 - b0) + e0;
 
375
        w1 = (float)(vb1 - b0) * (e1 - e0) / (b1 - b0) + e0;
 
376
        /* Note that w0 > w1 is now possible if e0 > e1. */
 
377
        if (e0 > e1) {
 
378
            if (w0 > e0 && w0 - esmall <= e0)
 
379
                w0 = e0; /* Suppress a small noise */
 
380
            if (w1 < e1 && w1 + esmall >= e1)
 
381
                w1 = e1; /* Suppress a small noise */
 
382
        } else {
 
383
            if (w0 < e0 && w0 + esmall >= e0)
 
384
                w0 = e0; /* Suppress a small noise */
 
385
            if (w1 > e1 && w1 - esmall <= e1)
 
386
                w1 = e1; /* Suppress a small noise */
 
387
        }
 
388
        if (w0 > w1)
 
389
            return gs_function_is_monotonic(pfn->params.Functions[i],
 
390
                                            &w1, &w0, mask);
 
391
        else
 
392
            return gs_function_is_monotonic(pfn->params.Functions[i],
 
393
                                            &w0, &w1, mask);
 
394
    }
 
395
    /* v0 is equal to the range end. */
 
396
    *mask = 0;
 
397
    return 1; 
 
398
}
 
399
 
 
400
/* Return 1-Input Stitching function information. */
 
401
static void
 
402
fn_1ItSg_get_info(const gs_function_t *pfn_common, gs_function_info_t *pfi)
 
403
{
 
404
    const gs_function_1ItSg_t *const pfn =
 
405
        (const gs_function_1ItSg_t *)pfn_common;
 
406
 
 
407
    gs_function_get_info_default(pfn_common, pfi);
 
408
    pfi->Functions = pfn->params.Functions;
 
409
    pfi->num_Functions = pfn->params.k;
 
410
}
 
411
 
 
412
/* Write 1-Input Stitching function parameters on a parameter list. */
 
413
static int
 
414
fn_1ItSg_get_params(const gs_function_t *pfn_common, gs_param_list *plist)
 
415
{
 
416
    const gs_function_1ItSg_t *const pfn =
 
417
        (const gs_function_1ItSg_t *)pfn_common;
 
418
    int ecode = fn_common_get_params(pfn_common, plist);
 
419
    int code;
 
420
 
 
421
    if ((code = param_write_float_values(plist, "Bounds", pfn->params.Bounds,
 
422
                                         pfn->params.k - 1, false)) < 0)
 
423
        ecode = code;
 
424
    if ((code = param_write_float_values(plist, "Encode", pfn->params.Encode,
 
425
                                         2 * pfn->params.k, false)) < 0)
 
426
        ecode = code;
 
427
    return ecode;
 
428
}
 
429
 
 
430
/* Make a scaled copy of a 1-Input Stitching function. */
 
431
static int
 
432
fn_1ItSg_make_scaled(const gs_function_1ItSg_t *pfn,
 
433
                     gs_function_1ItSg_t **ppsfn,
 
434
                     const gs_range_t *pranges, gs_memory_t *mem)
 
435
{
 
436
    gs_function_1ItSg_t *psfn =
 
437
        gs_alloc_struct(mem, gs_function_1ItSg_t, &st_function_1ItSg,
 
438
                        "fn_1ItSg_make_scaled");
 
439
    int code;
 
440
 
 
441
    if (psfn == 0)
 
442
        return_error(gs_error_VMerror);
 
443
    psfn->params = pfn->params;
 
444
    psfn->params.Functions = 0; /* in case of failure */
 
445
    psfn->params.Bounds =
 
446
        fn_copy_values(pfn->params.Bounds, pfn->params.k - 1, sizeof(float),
 
447
                       mem);
 
448
    psfn->params.Encode =
 
449
        fn_copy_values(pfn->params.Encode, 2 * pfn->params.k, sizeof(float),
 
450
                       mem);
 
451
    if ((code = (psfn->params.Bounds == 0 || psfn->params.Encode == 0 ?
 
452
                 gs_note_error(gs_error_VMerror) : 0)) < 0 ||
 
453
        (code = fn_common_scale((gs_function_t *)psfn,
 
454
                                (const gs_function_t *)pfn,
 
455
                                pranges, mem)) < 0 ||
 
456
        (code = fn_scale_functions((gs_function_t ***)&psfn->params.Functions,
 
457
                                   pfn->params.Functions,
 
458
                                   pfn->params.n, pranges, false, mem)) < 0) {
 
459
        gs_function_free((gs_function_t *)psfn, true, mem);
 
460
        return code;
 
461
    }
 
462
    *ppsfn = psfn;
 
463
    return 0;
 
464
}
 
465
 
 
466
/* Free the parameters of a 1-Input Stitching function. */
 
467
void
 
468
gs_function_1ItSg_free_params(gs_function_1ItSg_params_t * params,
 
469
                              gs_memory_t * mem)
 
470
{
 
471
    gs_free_const_object(mem, params->Encode, "Encode");
 
472
    gs_free_const_object(mem, params->Bounds, "Bounds");
 
473
    fn_free_functions(params->Functions, params->k, mem);
 
474
    fn_common_free_params((gs_function_params_t *) params, mem);
 
475
}
 
476
 
 
477
/* Serialize. */
 
478
static int
 
479
gs_function_1ItSg_serialize(const gs_function_t * pfn, stream *s)
 
480
{
 
481
    uint n;
 
482
    const gs_function_1ItSg_params_t * p = (const gs_function_1ItSg_params_t *)&pfn->params;
 
483
    int code = fn_common_serialize(pfn, s);
 
484
    int k;
 
485
 
 
486
    if (code < 0)
 
487
        return code;
 
488
    code = sputs(s, (const byte *)&p->k, sizeof(p->k), &n);
 
489
    if (code < 0)
 
490
        return code;
 
491
 
 
492
    for (k = 0; k < p->k && code >= 0; k++) 
 
493
        code = gs_function_serialize(p->Functions[k], s);
 
494
    if (code < 0)
 
495
        return code;
 
496
    code = sputs(s, (const byte *)&p->Bounds[0], sizeof(p->Bounds[0]) * (p->k - 1), &n);
 
497
    if (code < 0)
 
498
        return code;
 
499
    return sputs(s, (const byte *)&p->Encode[0], sizeof(p->Encode[0]) * (p->k * 2), &n);
 
500
}
 
501
 
 
502
/* Allocate and initialize a 1-Input Stitching function. */
 
503
int
 
504
gs_function_1ItSg_init(gs_function_t ** ppfn,
 
505
               const gs_function_1ItSg_params_t * params, gs_memory_t * mem)
 
506
{
 
507
    static const gs_function_head_t function_1ItSg_head = {
 
508
        function_type_1InputStitching,
 
509
        {
 
510
            (fn_evaluate_proc_t) fn_1ItSg_evaluate,
 
511
            (fn_is_monotonic_proc_t) fn_1ItSg_is_monotonic,
 
512
            (fn_get_info_proc_t) fn_1ItSg_get_info,
 
513
            (fn_get_params_proc_t) fn_1ItSg_get_params,
 
514
            (fn_make_scaled_proc_t) fn_1ItSg_make_scaled,
 
515
            (fn_free_params_proc_t) gs_function_1ItSg_free_params,
 
516
            fn_common_free,
 
517
            (fn_serialize_proc_t) gs_function_1ItSg_serialize,
 
518
        }
 
519
    };
 
520
    int n = (params->Range == 0 ? 0 : params->n);
 
521
    float prev = params->Domain[0];
 
522
    int i;
 
523
 
 
524
    *ppfn = 0;                  /* in case of error */
 
525
    for (i = 0; i < params->k; ++i) {
 
526
        const gs_function_t *psubfn = params->Functions[i];
 
527
 
 
528
        if (psubfn->params.m != 1)
 
529
            return_error(gs_error_rangecheck);
 
530
        if (n == 0)
 
531
            n = psubfn->params.n;
 
532
        else if (psubfn->params.n != n)
 
533
            return_error(gs_error_rangecheck);
 
534
        /* There are only k - 1 Bounds, not k. */
 
535
        if (i < params->k - 1) {
 
536
            if (params->Bounds[i] < prev)
 
537
                return_error(gs_error_rangecheck);
 
538
            prev = params->Bounds[i];
 
539
        }
 
540
    }
 
541
    if (params->Domain[1] < prev)
 
542
        return_error(gs_error_rangecheck);
 
543
    fn_check_mnDR((const gs_function_params_t *)params, 1, n);
 
544
    {
 
545
        gs_function_1ItSg_t *pfn =
 
546
            gs_alloc_struct(mem, gs_function_1ItSg_t, &st_function_1ItSg,
 
547
                            "gs_function_1ItSg_init");
 
548
 
 
549
        if (pfn == 0)
 
550
            return_error(gs_error_VMerror);
 
551
        pfn->params = *params;
 
552
        pfn->params.m = 1;
 
553
        pfn->params.n = n;
 
554
        pfn->head = function_1ItSg_head;
 
555
        *ppfn = (gs_function_t *) pfn;
 
556
    }
 
557
    return 0;
 
558
}
 
559
 
 
560
/* ---------------- Arrayed Output functions ---------------- */
 
561
 
 
562
typedef struct gs_function_AdOt_s {
 
563
    gs_function_head_t head;
 
564
    gs_function_AdOt_params_t params;
 
565
} gs_function_AdOt_t;
 
566
 
 
567
private_st_function_AdOt();
 
568
 
 
569
/* Evaluate an Arrayed Output function. */
 
570
static int
 
571
fn_AdOt_evaluate(const gs_function_t *pfn_common, const float *in0, float *out)
 
572
{
 
573
    const gs_function_AdOt_t *const pfn =
 
574
        (const gs_function_AdOt_t *)pfn_common;
 
575
    const float *in = in0;
 
576
#define MAX_ADOT_IN 16
 
577
    float in_buf[MAX_ADOT_IN];
 
578
    int i;
 
579
 
 
580
    /*
 
581
     * We have to take special care to handle the case where in and out
 
582
     * overlap.  For the moment, handle it only for a limited number of
 
583
     * input values.
 
584
     */
 
585
    if (in <= out + (pfn->params.n - 1) && out <= in + (pfn->params.m - 1)) {
 
586
        if (pfn->params.m > MAX_ADOT_IN)
 
587
            return_error(gs_error_rangecheck);
 
588
        memcpy(in_buf, in, pfn->params.m * sizeof(*in));
 
589
        in = in_buf;
 
590
    }
 
591
    for (i = 0; i < pfn->params.n; ++i) {
 
592
        int code =
 
593
            gs_function_evaluate(pfn->params.Functions[i], in, out + i);
 
594
 
 
595
        if (code < 0)
 
596
            return code;
 
597
    }
 
598
    return 0;
 
599
#undef MAX_ADOT_IN
 
600
}
 
601
 
 
602
/* Test whether an Arrayed Output function is monotonic. */
 
603
static int
 
604
fn_AdOt_is_monotonic(const gs_function_t * pfn_common,
 
605
                     const float *lower, const float *upper, uint *mask)
 
606
{
 
607
    const gs_function_AdOt_t *const pfn =
 
608
        (const gs_function_AdOt_t *)pfn_common;
 
609
    int i;
 
610
 
 
611
    for (i = 0; i < pfn->params.n; ++i) {
 
612
        int code =
 
613
            gs_function_is_monotonic(pfn->params.Functions[i], lower, upper, mask);
 
614
 
 
615
        if (code <= 0)
 
616
            return code;
 
617
    }
 
618
    return 1;
 
619
}
 
620
 
 
621
/* Return Arrayed Output function information. */
 
622
static void
 
623
fn_AdOt_get_info(const gs_function_t *pfn_common, gs_function_info_t *pfi)
 
624
{
 
625
    const gs_function_AdOt_t *const pfn =
 
626
        (const gs_function_AdOt_t *)pfn_common;
 
627
 
 
628
    gs_function_get_info_default(pfn_common, pfi);
 
629
    pfi->Functions = pfn->params.Functions;
 
630
    pfi->num_Functions = pfn->params.n;
 
631
}
 
632
 
 
633
/* Make a scaled copy of an Arrayed Output function. */
 
634
static int
 
635
fn_AdOt_make_scaled(const gs_function_AdOt_t *pfn, gs_function_AdOt_t **ppsfn,
 
636
                    const gs_range_t *pranges, gs_memory_t *mem)
 
637
{
 
638
    gs_function_AdOt_t *psfn =
 
639
        gs_alloc_struct(mem, gs_function_AdOt_t, &st_function_AdOt,
 
640
                        "fn_AdOt_make_scaled");
 
641
    int code;
 
642
 
 
643
    if (psfn == 0)
 
644
        return_error(gs_error_VMerror);
 
645
    psfn->params = pfn->params;
 
646
    psfn->params.Functions = 0; /* in case of failure */
 
647
    if ((code = fn_common_scale((gs_function_t *)psfn,
 
648
                                (const gs_function_t *)pfn,
 
649
                                pranges, mem)) < 0 ||
 
650
        (code = fn_scale_functions((gs_function_t ***)&psfn->params.Functions,
 
651
                                   pfn->params.Functions,
 
652
                                   pfn->params.n, pranges, true, mem)) < 0) {
 
653
        gs_function_free((gs_function_t *)psfn, true, mem);
 
654
        return code;
 
655
    }
 
656
    *ppsfn = psfn;
 
657
    return 0;
 
658
}
 
659
 
 
660
/* Free the parameters of an Arrayed Output function. */
 
661
void
 
662
gs_function_AdOt_free_params(gs_function_AdOt_params_t * params,
 
663
                             gs_memory_t * mem)
 
664
{
 
665
    fn_free_functions(params->Functions, params->n, mem);
 
666
    fn_common_free_params((gs_function_params_t *) params, mem);
 
667
}
 
668
 
 
669
/* Serialize. */
 
670
static int
 
671
gs_function_AdOt_serialize(const gs_function_t * pfn, stream *s)
 
672
{
 
673
    const gs_function_AdOt_params_t * p = (const gs_function_AdOt_params_t *)&pfn->params;
 
674
    int code = fn_common_serialize(pfn, s);
 
675
    int k;
 
676
 
 
677
    if (code < 0)
 
678
        return code;
 
679
    for (k = 0; k < p->n && code >= 0; k++) 
 
680
        code = gs_function_serialize(p->Functions[k], s);
 
681
    return code;
 
682
}
 
683
 
 
684
/* Allocate and initialize an Arrayed Output function. */
 
685
int
 
686
gs_function_AdOt_init(gs_function_t ** ppfn,
 
687
                const gs_function_AdOt_params_t * params, gs_memory_t * mem)
 
688
{
 
689
    static const gs_function_head_t function_AdOt_head = {
 
690
        function_type_ArrayedOutput,
 
691
        {
 
692
            (fn_evaluate_proc_t) fn_AdOt_evaluate,
 
693
            (fn_is_monotonic_proc_t) fn_AdOt_is_monotonic,
 
694
            (fn_get_info_proc_t) fn_AdOt_get_info,
 
695
            fn_common_get_params,       /****** WHAT TO DO ABOUT THIS? ******/
 
696
            (fn_make_scaled_proc_t) fn_AdOt_make_scaled,
 
697
            (fn_free_params_proc_t) gs_function_AdOt_free_params,
 
698
            fn_common_free,
 
699
            (fn_serialize_proc_t) gs_function_AdOt_serialize,
 
700
        }
 
701
    };
 
702
    int m = params->m, n = params->n;
 
703
 
 
704
    *ppfn = 0;                  /* in case of error */
 
705
    if (m <= 0 || n <= 0)
 
706
        return_error(gs_error_rangecheck);
 
707
    {
 
708
        gs_function_AdOt_t *pfn =
 
709
            gs_alloc_struct(mem, gs_function_AdOt_t, &st_function_AdOt,
 
710
                            "gs_function_AdOt_init");
 
711
        float *domain = (float *)
 
712
            gs_alloc_byte_array(mem, 2 * m, sizeof(float),
 
713
                                "gs_function_AdOt_init(Domain)");
 
714
        int i, j;
 
715
 
 
716
        if (pfn == 0)
 
717
            return_error(gs_error_VMerror);
 
718
        pfn->params = *params;
 
719
        pfn->params.Domain = domain;
 
720
        pfn->params.Range = 0;
 
721
        pfn->head = function_AdOt_head;
 
722
        if (domain == 0) {
 
723
            gs_function_free((gs_function_t *)pfn, true, mem);
 
724
            return_error(gs_error_VMerror);
 
725
        }
 
726
        /*
 
727
         * We compute the Domain as the intersection of the Domains of
 
728
         * the individual subfunctions.  This isn't quite right: some
 
729
         * subfunction might actually make use of a larger domain of
 
730
         * input values.  However, the only place that Arrayed Output
 
731
         * functions are used is in Shading and similar dictionaries,
 
732
         * where the input values are clamped to the intersection of
 
733
         * the individual Domains anyway.
 
734
         */
 
735
        memcpy(domain, params->Functions[0]->params.Domain,
 
736
               2 * sizeof(float) * m);
 
737
        for (i = 1; i < n; ++i) {
 
738
            const float *dom = params->Functions[i]->params.Domain;
 
739
 
 
740
            for (j = 0; j < 2 * m; j += 2, dom += 2) {
 
741
                domain[j] = max(domain[j], dom[0]);
 
742
                domain[j + 1] = min(domain[j + 1], dom[1]);
 
743
            }
 
744
        }
 
745
        *ppfn = (gs_function_t *) pfn;
 
746
    }
 
747
    return 0;
 
748
}