~ubuntu-branches/ubuntu/oneiric/ghostscript/oneiric

« back to all changes in this revision

Viewing changes to .pc/020110411~4509a49.patch/psi/zcolor.c

  • Committer: Bazaar Package Importer
  • Author(s): Till Kamppeter
  • Date: 2011-07-15 16:49:55 UTC
  • mfrom: (1.1.23 upstream)
  • Revision ID: james.westby@ubuntu.com-20110715164955-uga6qibao6kez05c
Tags: 9.04~dfsg~20110715-0ubuntu1
* New upstream release
   - GIT snapshot from Jult, 12 2011.
* debian/patches/020110406~a54df2d.patch,
  debian/patches/020110408~0791cc8.patch,
  debian/patches/020110408~507cbee.patch,
  debian/patches/020110411~4509a49.patch,
  debian/patches/020110412~78bb9a6.patch,
  debian/patches/020110418~a05ab8a.patch,
  debian/patches/020110420~20b6c78.patch,
  debian/patches/020110420~4ddefa2.patch: Removed upstream patches.
* debian/rules: Generate ABI version number (variable "abi") correctly,
  cutting off repackaging and pre-release parts.
* debian/rules: Added ./lcms2/ directory to DEB_UPSTREAM_REPACKAGE_EXCLUDES.
* debian/copyright: Added lcms2/* to the list of excluded files.
* debian/symbols.common: Updated for new upstream source. Applied patch
  which dpkg-gensymbols generated for debian/libgs9.symbols to this file.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (C) 2001-2008 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: zcolor.c 12140 2011-02-10 10:43:26Z ken $ */
15
 
/* Color operators */
16
 
#include "memory_.h"
17
 
#include "math_.h"
18
 
#include "ghost.h"
19
 
#include "oper.h"
20
 
#include "dstack.h"     /* for systemdict */
21
 
#include "estack.h"
22
 
#include "ialloc.h"
23
 
#include "igstate.h"
24
 
#include "iutil.h"
25
 
#include "store.h"
26
 
#include "gscolor.h"    /* for gs_setgray and gs_setrgbcolor */
27
 
#include "gscsepr.h"    /* For declarartion of Separation functions */
28
 
#include "gscdevn.h"    /* For declarartion of DeviceN functions */
29
 
#include "gscpixel.h"   /* For declarartion of DevicePixel functions */
30
 
#include "gxfixed.h"
31
 
#include "gxmatrix.h"
32
 
#include "gzstate.h"
33
 
#include "gxdcolor.h"           /* for gxpcolor.h */
34
 
#include "gxdevice.h"
35
 
#include "gxdevmem.h"           /* for gxpcolor.h */
36
 
#include "gxcmap.h"
37
 
#include "gxcspace.h"
38
 
#include "gxcolor2.h"
39
 
#include "gxpcolor.h"
40
 
#include "idict.h"
41
 
#include "icolor.h"
42
 
#include "idparam.h"
43
 
#include "iname.h"
44
 
#include "iutil.h"
45
 
#include "ifunc.h"      /* For declaration of buildfunction */
46
 
#include "icsmap.h"
47
 
#include "ifunc.h"
48
 
#include "zht2.h"
49
 
#include "zcolor.h"     /* For the PS_colour_space_t structure */
50
 
#include "zcie.h"       /* For CIE space function declarations */
51
 
#include "zicc.h"       /* For declaration of seticc */
52
 
#include "gscspace.h"   /* Needed for checking if current pgs colorspace is CIE */
53
 
#include "iddict.h"     /* for idict_put_string */
54
 
#include "zfrsd.h"      /* for make_rss() */
55
 
 
56
 
/* imported from gsht.c */
57
 
extern  void    gx_set_effective_transfer(gs_state *);
58
 
 
59
 
/* Essential forward declarations */
60
 
static int validate_spaces(i_ctx_t *i_ctx_p, ref *arr, int *depth);
61
 
static int setcolorspace_cont(i_ctx_t *i_ctx_p);
62
 
static int setcolor_cont(i_ctx_t *i_ctx_p);
63
 
 
64
 
/* define the number of stack slots needed for zcolor_remap_one */
65
 
const int   zcolor_remap_one_ostack = 4;
66
 
const int   zcolor_remap_one_estack = 3;
67
 
 
68
 
 
69
 
/* utility to test whether a Pattern instance uses a base space */
70
 
static inline bool
71
 
pattern_instance_uses_base_space(const gs_pattern_instance_t * pinst)
72
 
{
73
 
    return pinst->type->procs.uses_base_space(
74
 
                   pinst->type->procs.get_pattern(pinst) );
75
 
}
76
 
 
77
 
/*
78
 
 *  -   currentcolor   <param1>  ...  <paramN>
79
 
 *
80
 
 * Return the current color. <paramN> may be a dictionary or a null
81
 
 * object, if the current color space is a pattern color space. The
82
 
 * other parameters will be numeric.
83
 
 *
84
 
 * Note that the results of this operator differ slightly from those of
85
 
 * most currentcolor implementations. If a color component value is
86
 
 * integral (e.g.: 0, 1), it will be pushed on the stack as an integer.
87
 
 * Most currentcolor implementations, including the earlier
88
 
 * implementation in Ghostscript, would push real objects for all
89
 
 * color spaces except indexed color space. The approach taken here is
90
 
 * equally legitimate, and avoids special handling of indexed color
91
 
 * spaces.
92
 
 */
93
 
static int
94
 
zcurrentcolor(i_ctx_t * i_ctx_p)
95
 
{
96
 
    os_ptr                  op = osp;
97
 
    const gs_color_space *  pcs = gs_currentcolorspace(igs);
98
 
    const gs_client_color * pcc = gs_currentcolor(igs);
99
 
    int                     i, n = cs_num_components(pcs);
100
 
    bool                    push_pattern = n < 0;
101
 
 
102
 
    /* check for pattern */
103
 
    if (push_pattern) {
104
 
        gs_pattern_instance_t * pinst = pcc->pattern;
105
 
 
106
 
        if (pinst == 0 || !pattern_instance_uses_base_space(pinst))
107
 
            n = 1;
108
 
        else
109
 
            n = -n;
110
 
    }
111
 
 
112
 
    /* check for sufficient space on the stack */
113
 
    push(n);
114
 
    op -= n - 1;
115
 
 
116
 
    /* push the numeric operands, if any */
117
 
    if (push_pattern)
118
 
        --n;
119
 
    for (i = 0; i < n; i++, op++) {
120
 
        float   rval = pcc->paint.values[i];
121
 
        int     ival = (int)rval;
122
 
 
123
 
        /* the following handles indexed color spaces */
124
 
        if (rval == ival && pcs->type->index == gs_color_space_index_Indexed)
125
 
            make_int(op, ival);
126
 
        else
127
 
            make_real(op, rval);
128
 
    }
129
 
 
130
 
    /* push the pattern dictionary or null object, if appropriate */
131
 
    if (push_pattern)
132
 
        *op = istate->pattern[0];
133
 
 
134
 
    return 0;
135
 
}
136
 
 
137
 
/*
138
 
 *  -   .currentcolorspace   <array>
139
 
 *
140
 
 * Return the current color space. Unlike the prior implementation, the
141
 
 * istate->color_space.array field will now always have a legitimate
142
 
 * (array) value.
143
 
 */
144
 
static int
145
 
zcurrentcolorspace(i_ctx_t * i_ctx_p)
146
 
{
147
 
    os_ptr  op = osp;   /* required by "push" macro */
148
 
    int code;
149
 
    ref namestr,stref;
150
 
    byte *body;
151
 
 
152
 
    /* Adobe applications expect that the Device spaces (DeviceGray
153
 
     * DeviceRGB and DeviceCMYK) will always return the same array.
154
 
     * Not merely the same content but the same actual array. To do
155
 
     * this we define the arrays at startup (see gs_cspace.ps), and
156
 
     * recover them here by executing PostScript.
157
 
     */
158
 
    if (r_has_type(&istate->colorspace[0].array, t_name)) {
159
 
        name_string_ref(imemory, &istate->colorspace[0].array, &namestr);
160
 
        if (r_size(&namestr) == 10 && !memcmp(namestr.value.bytes, "DeviceGray", 10)) {
161
 
            body = ialloc_string(32, "string");
162
 
            if (body == 0)
163
 
                return_error(e_VMerror);
164
 
            memcpy(body, "systemdict /DeviceGray_array get", 32);
165
 
            make_string(&stref, a_all | icurrent_space, 32, body);
166
 
        } else {
167
 
            if (r_size(&namestr) == 9 && !memcmp(namestr.value.bytes, "DeviceRGB", 9)) {
168
 
                body = ialloc_string(31, "string");
169
 
                if (body == 0)
170
 
                    return_error(e_VMerror);
171
 
                memcpy(body, "systemdict /DeviceRGB_array get", 31);
172
 
                make_string(&stref, a_all | icurrent_space, 31, body);
173
 
            } else {
174
 
                if (r_size(&namestr) == 10 && !memcmp(namestr.value.bytes, "DeviceCMYK", 10)) {
175
 
                    body = ialloc_string(32, "string");
176
 
                    if (body == 0)
177
 
                        return_error(e_VMerror);
178
 
                    memcpy(body, "systemdict /DeviceCMYK_array get", 32);
179
 
                    make_string(&stref, a_all | icurrent_space, 32, body);
180
 
                } else {
181
 
                    /* Not one of the Device spaces, but still just a name. Give
182
 
                     * up and return the name on the stack.
183
 
                     */
184
 
                    push(1);
185
 
                    code = ialloc_ref_array(op, a_all, 1, "currentcolorspace");
186
 
                    if (code < 0)
187
 
                        return code;
188
 
                    refset_null(op->value.refs, 1);
189
 
                    ref_assign_old(op, op->value.refs,
190
 
                                   &istate->colorspace[0].array,
191
 
                                   "currentcolorspace");
192
 
                    return 0;
193
 
                }
194
 
            }
195
 
        }
196
 
        r_set_attrs(&stref, a_executable);
197
 
        esp++;
198
 
        ref_assign(esp, &stref);
199
 
        return o_push_estack;
200
 
    } else {
201
 
        /* If the space isn't a simple name, then we don't need any special
202
 
         * action and can simply use it.
203
 
         */
204
 
        push(1);
205
 
        *op = istate->colorspace[0].array;
206
 
    }
207
 
    return 0;
208
 
}
209
 
 
210
 
/*
211
 
 *  -   .getuseciecolor   <bool>
212
 
 *
213
 
 * Return the current setting of the use_cie_color graphic state parameter,
214
 
 * which tracks the UseCIEColor page device parameter. This parameter may be
215
 
 * read (via this operator) at all language leves, but may only be set (via
216
 
 * the .setuseciecolor operator; see zcolor3.c) only in language level 3.
217
 
 *
218
 
 * We handle this parameter separately from the page device primarily for
219
 
 * performance reasons (the parameter may be queried frequently), but as a
220
 
 * side effect achieve proper behavior relative to the language level. The
221
 
 * interpreter is always initialized with this parameter set to false, and
222
 
 * it can only be updated (via setpagedevice) in language level 3.
223
 
 */
224
 
static int
225
 
zgetuseciecolor(i_ctx_t * i_ctx_p)
226
 
{
227
 
    os_ptr  op = osp;
228
 
 
229
 
    push(1);
230
 
    *op = istate->use_cie_color;
231
 
    return 0;
232
 
}
233
 
 
234
 
/*
235
 
 *  <param1>  ...  <paramN>   setcolor   -
236
 
 *
237
 
 * Set the current color. All of the parameters except the topmost (paramN) are
238
 
 * numbers; the topmost (and possibly only) entry may be pattern dictionary or
239
 
 * a null object.
240
 
 *
241
 
 * The use of one operator to set both patterns and "normal" colors is
242
 
 * consistent with Adobe's documentation, but primarily reflects the use of
243
 
 * gs_setcolor for both purposes in the graphic library. An alternate
244
 
 * implementation would use a .setpattern operator, which would interface with
245
 
 * gs_setpattern.
246
 
 *
247
 
 * This operator is hidden by a pseudo-operator of the same name, so it will
248
 
 * only be invoked under controlled situations. Hence, it does no operand
249
 
 * checking.
250
 
 */
251
 
static int
252
 
zsetcolor(i_ctx_t * i_ctx_p)
253
 
{
254
 
    os_ptr                  op = osp;
255
 
    es_ptr ep = esp;
256
 
    const gs_color_space *  pcs = gs_currentcolorspace(igs);
257
 
    gs_client_color         cc;
258
 
    int                     n_comps, n_numeric_comps, num_offset = 0, code, depth;
259
 
    bool                    is_ptype2 = 0;
260
 
    PS_colour_space_t *space;
261
 
 
262
 
    /* initialize the client color pattern pointer for GC */
263
 
    cc.pattern = 0;
264
 
 
265
 
    /* check for a pattern color space */
266
 
    if ((n_comps = cs_num_components(pcs)) < 0) {
267
 
        n_comps = -n_comps;
268
 
        if (r_has_type(op, t_dictionary)) {
269
 
            ref     *pImpl, pPatInst;
270
 
            int     ptype;
271
 
 
272
 
            code = dict_find_string(op, "Implementation", &pImpl);
273
 
            if (code < 0)
274
 
                return code;
275
 
            code = array_get(imemory, pImpl, 0, &pPatInst);
276
 
            if (code < 0)
277
 
                return code;
278
 
            cc.pattern = r_ptr(&pPatInst, gs_pattern_instance_t);
279
 
            n_numeric_comps = ( pattern_instance_uses_base_space(cc.pattern)
280
 
                                  ? n_comps - 1
281
 
                                  : 0 );
282
 
            (void)dict_int_param(op, "PatternType", 1, 2, 1, &ptype);
283
 
            is_ptype2 = ptype == 2;
284
 
        } else
285
 
            n_numeric_comps = 0;
286
 
        num_offset = 1;
287
 
    } else
288
 
        n_numeric_comps = n_comps;
289
 
 
290
 
    /* gather the numeric operands */
291
 
    code = float_params(op - num_offset, n_numeric_comps, cc.paint.values);
292
 
    if (code < 0)
293
 
        return code;
294
 
 
295
 
    code = get_space_object(i_ctx_p, &istate->colorspace[0].array, &space);
296
 
    if (code < 0)
297
 
        return code;
298
 
    if (space->validatecomponents) {
299
 
        code = space->validatecomponents(i_ctx_p,
300
 
                                         &istate->colorspace[0].array,
301
 
                                         cc.paint.values, n_numeric_comps);
302
 
        if (code < 0)
303
 
            return code;
304
 
    }
305
 
 
306
 
    /* pass the color to the graphic library */
307
 
    if ((code = gs_setcolor(igs, &cc)) >= 0) {
308
 
 
309
 
        if (n_comps > n_numeric_comps) {
310
 
            istate->pattern[0] = *op;      /* save pattern dict or null */
311
 
            n_comps = n_numeric_comps + 1;
312
 
        }
313
 
    }
314
 
 
315
 
    /* Check the color spaces, to see if we need to run any tint transform
316
 
     * procedures. Some Adobe applications *eg Photoshop) expect that the
317
 
     * tint transform will be run and use this to set up duotone DeviceN
318
 
     * spaces.
319
 
     */
320
 
    code = validate_spaces(i_ctx_p, &istate->colorspace[0].array, &depth);
321
 
    if (code < 0)
322
 
        return code;
323
 
    /* Set up for the continuation procedure which will do the work */
324
 
    /* Make sure the exec stack has enough space */
325
 
    check_estack(5);
326
 
    /* A place holder for data potentially used by transform functions */
327
 
    ep = esp += 1;
328
 
    make_int(ep, 0);
329
 
    /* Store the 'depth' of the space returned during checking above */
330
 
    ep = esp += 1;
331
 
    make_int(ep, 0);
332
 
    /* Store the 'stage' of processing (initially 0) */
333
 
    ep = esp += 1;
334
 
    make_int(ep, 0);
335
 
    /* Store a pointer to the color space stored on the operand stack
336
 
     * as the stack may grow unpredictably making further access
337
 
     * to the space difficult
338
 
     */
339
 
    ep = esp += 1;
340
 
    *ep = istate->colorspace[0].array;
341
 
    /* Finally, the actual continuation routine */
342
 
    push_op_estack(setcolor_cont);
343
 
    return o_push_estack;
344
 
}
345
 
 
346
 
/* This is used to detect color space changes due
347
 
   to the changing of UseCIEColor during transparency
348
 
   soft mask processing */
349
 
 
350
 
static bool name_is_device_color( char *cs_name )
351
 
{
352
 
 
353
 
    return( strcmp(cs_name, "DeviceGray") == 0 ||
354
 
            strcmp(cs_name, "DeviceRGB")  == 0 ||
355
 
            strcmp(cs_name, "DeviceCMYK") == 0);
356
 
 
357
 
}
358
 
 
359
 
 
360
 
/*
361
 
 * Given two color space arrays, attempts to determine if they are the
362
 
 * same space by comparing their contents recursively. For some spaces,
363
 
 * especially CIE based color spaces, it can significantly improve
364
 
 * performance if the same space is frequently re-used.
365
 
 */
366
 
static int is_same_colorspace(i_ctx_t * i_ctx_p, ref *space1, ref *space2, bool isCIE)
367
 
{
368
 
    PS_colour_space_t *oldcspace = 0, *newcspace = 0;
369
 
    ref oldspace, *poldspace = &oldspace, newspace, *pnewspace = &newspace;
370
 
    int code, CIESubst;
371
 
 
372
 
    /* Silence compiler warnings */
373
 
    oldspace.tas.type_attrs = 0;
374
 
    oldspace.tas.type_attrs = 0;
375
 
 
376
 
    ref_assign(pnewspace, space1);
377
 
    ref_assign(poldspace, space2);
378
 
 
379
 
    do {
380
 
        if (r_type(poldspace) != r_type(pnewspace))
381
 
            return 0;
382
 
 
383
 
        code = get_space_object(i_ctx_p, poldspace, &oldcspace);
384
 
        if (code < 0)
385
 
            return 0;
386
 
 
387
 
        code = get_space_object(i_ctx_p, pnewspace, &newcspace);
388
 
        if (code < 0)
389
 
            return 0;
390
 
 
391
 
        /* Check the two color space types are the same
392
 
         * (Indexed, Separation, DeviceCMYK etc).
393
 
         */
394
 
        if (strcmp(oldcspace->name, newcspace->name) != 0)
395
 
            return 0;
396
 
 
397
 
        /* Call the space-specific comparison routine */
398
 
        if (!oldcspace->compareproc(i_ctx_p, poldspace, pnewspace))
399
 
            return 0;
400
 
 
401
 
        /* See if current space is CIE based (which could happen
402
 
           if UseCIE had been true previously), but UseCIE is false
403
 
           and incoming space is device based.  This can occur
404
 
           when we are now processing a soft mask, which should not
405
 
           use the UseCIEColor option.
406
 
 
407
 
           Need to detect this case at both transitions
408
 
 
409
 
            Device Color UseCIEColor true
410
 
            Soft mask
411
 
                    Device color UseCIEColor false
412
 
            Soft mask
413
 
            Device color UseCIEColor true
414
 
            */
415
 
 
416
 
        if ( name_is_device_color(newcspace->name) ){
417
 
            if ( gs_color_space_is_CIE(gs_currentcolorspace_inline(i_ctx_p->pgs)) ){
418
 
                if ( !isCIE ) return 0; /*  The color spaces will be different */
419
 
            } else {
420
 
                if ( isCIE ) return 0; /*  The color spaces will be different */
421
 
            }
422
 
        }
423
 
 
424
 
        /* The current space is OK, if there is no alternate, then that's
425
 
         * good enough.
426
 
         */
427
 
        if (!oldcspace->alternateproc)
428
 
            break;
429
 
 
430
 
        /* Otherwise, retrieve the alternate space for each, and continue
431
 
         * round the loop, checking those.
432
 
         */
433
 
        code = oldcspace->alternateproc(i_ctx_p, poldspace, &poldspace, &CIESubst);
434
 
        if (code < 0)
435
 
            return 0;
436
 
 
437
 
        code = newcspace->alternateproc(i_ctx_p, pnewspace, &pnewspace, &CIESubst);
438
 
        if (code < 0)
439
 
            return 0;
440
 
    }
441
 
    while(1);
442
 
 
443
 
    return 1;
444
 
}
445
 
 
446
 
 
447
 
 
448
 
/*
449
 
 *  <array>   setcolorspace   -
450
 
 *
451
 
 * Set the nominal color space. This color space will be pushd by the
452
 
 * currentcolorspace operator, but is not directly used to pass color
453
 
 * space information to the graphic library.
454
 
 *
455
 
 */
456
 
static int
457
 
zsetcolorspace(i_ctx_t * i_ctx_p)
458
 
{
459
 
    os_ptr  op = osp;
460
 
    es_ptr ep = esp;
461
 
    int code, depth;
462
 
    bool is_CIE;
463
 
 
464
 
    /* Make sure we have an operand... */
465
 
    check_op(1);
466
 
    /* Check its either a name (base space) or an array */
467
 
    if (!r_has_type(op, t_name))
468
 
        if (!r_is_array(op))
469
 
            return_error(e_typecheck);
470
 
 
471
 
    code = validate_spaces(i_ctx_p, op, &depth);
472
 
    if (code < 0)
473
 
        return code;
474
 
 
475
 
    is_CIE = istate->use_cie_color.value.boolval;
476
 
 
477
 
    /* See if its the same as the current space */
478
 
    if (is_same_colorspace(i_ctx_p, op, &istate->colorspace[0].array, is_CIE)) {
479
 
        PS_colour_space_t *cspace;
480
 
 
481
 
        /* Even if its the same space, we still need to set the correct
482
 
         * initial color value.
483
 
         */
484
 
        code = get_space_object(i_ctx_p, &istate->colorspace[0].array, &cspace);
485
 
        if (code < 0)
486
 
            return 0;
487
 
        if (cspace->initialcolorproc) {
488
 
            cspace->initialcolorproc(i_ctx_p, &istate->colorspace[0].array);
489
 
        }
490
 
        /* Pop the space off the stack */
491
 
        pop(1);
492
 
        return 0;
493
 
    }
494
 
    /* Set up for the continuation procedure which will do the work */
495
 
    /* Make sure the exec stack has enough space */
496
 
    check_estack(5);
497
 
    /* Store the initial value of CIE substitution (not substituting) */
498
 
    ep = esp += 1;
499
 
    make_int(ep, 0);
500
 
    /* Store the 'depth' of the space returned during checking above */
501
 
    ep = esp += 1;
502
 
    make_int(ep, depth);
503
 
    /* Store the 'stage' of processing (initially 0) */
504
 
    ep = esp += 1;
505
 
    make_int(ep, 0);
506
 
    /* Store a pointer to the color space stored on the operand stack
507
 
     * as the stack may grow unpredictably making further access
508
 
     * to the space difficult
509
 
     */
510
 
    ep = esp += 1;
511
 
    *ep = *op;
512
 
    /* Finally, the actual continuation routine */
513
 
    push_op_estack(setcolorspace_cont);
514
 
    return o_push_estack;
515
 
}
516
 
 
517
 
/*
518
 
 * A special version of the setcolorspace operation above. This sets the
519
 
 * CIE substitution flag to true before starting, which prevents any further
520
 
 * CIE substitution taking place.
521
 
 */
522
 
static int
523
 
setcolorspace_nosubst(i_ctx_t * i_ctx_p)
524
 
{
525
 
    os_ptr  op = osp;
526
 
    es_ptr ep = esp;
527
 
    int code, depth;
528
 
 
529
 
    /* Make sure we have an operand... */
530
 
    check_op(1);
531
 
    /* Check its either a name (base space) or an array */
532
 
    if (!r_has_type(op, t_name))
533
 
        if (!r_is_array(op))
534
 
            return_error(e_typecheck);
535
 
 
536
 
    code = validate_spaces(i_ctx_p, op, &depth);
537
 
    if (code < 0)
538
 
        return code;
539
 
 
540
 
    /* Set up for the continuation procedure which will do the work */
541
 
    /* Make sure the exec stack has enough space */
542
 
    check_estack(5);
543
 
    /* Store the initial value of CIE substitution (substituting) */
544
 
    ep = esp += 1;
545
 
    make_int(ep, 1);
546
 
    /* Store the 'depth' of the space returned during checking above */
547
 
    ep = esp += 1;
548
 
    make_int(ep, depth);
549
 
    /* Store the 'stage' of processing (initially 0) */
550
 
    ep = esp += 1;
551
 
    make_int(ep, 0);
552
 
    /* Store a pointer to the color space stored on the operand stack
553
 
     * as the stack may grow unpredictably making further access
554
 
     * to the space difficult
555
 
     */
556
 
    ep = esp += 1;
557
 
    *ep = *op;
558
 
    /* Finally, the actual continuation routine */
559
 
    push_op_estack(setcolorspace_cont);
560
 
    return o_push_estack;
561
 
}
562
 
 
563
 
/*
564
 
 *  <name> .includecolorspace -
565
 
 *
566
 
 * See the comment for gs_includecolorspace in gscolor2.c .
567
 
 */
568
 
static int
569
 
zincludecolorspace(i_ctx_t * i_ctx_p)
570
 
{
571
 
    os_ptr  op = osp;
572
 
    ref nsref;
573
 
    int code;
574
 
 
575
 
    check_type(*op, t_name);
576
 
    name_string_ref(imemory, op, &nsref);
577
 
    code =  gs_includecolorspace(igs, nsref.value.const_bytes, r_size(&nsref));
578
 
    if (!code)
579
 
        pop(1);
580
 
    return code;
581
 
}
582
 
 
583
 
/*  -   currenttransfer   <proc> */
584
 
static int
585
 
zcurrenttransfer(i_ctx_t *i_ctx_p)
586
 
{
587
 
    os_ptr  op = osp;
588
 
 
589
 
    push(1);
590
 
    *op = istate->transfer_procs.gray;
591
 
    return 0;
592
 
}
593
 
 
594
 
/*
595
 
 *  -   processcolors   <int>  -
596
 
 *
597
 
 * Note: this is an undocumented operator that is not supported
598
 
 * in Level 2.
599
 
 */
600
 
static int
601
 
zprocesscolors(i_ctx_t * i_ctx_p)
602
 
{
603
 
    os_ptr  op = osp;
604
 
 
605
 
    push(1);
606
 
    make_int(op, gs_currentdevice(igs)->color_info.num_components);
607
 
    return 0;
608
 
}
609
 
 
610
 
/* <proc> settransfer - */
611
 
static int
612
 
zsettransfer(i_ctx_t * i_ctx_p)
613
 
{
614
 
    os_ptr  op = osp;
615
 
    int     code;
616
 
 
617
 
    check_proc(*op);
618
 
    check_ostack(zcolor_remap_one_ostack - 1);
619
 
    check_estack(1 + zcolor_remap_one_estack);
620
 
    istate->transfer_procs.red =
621
 
        istate->transfer_procs.green =
622
 
        istate->transfer_procs.blue =
623
 
        istate->transfer_procs.gray = *op;
624
 
    if ((code = gs_settransfer_remap(igs, gs_mapped_transfer, false)) < 0)
625
 
        return code;
626
 
    push_op_estack(zcolor_reset_transfer);
627
 
    pop(1);
628
 
    return zcolor_remap_one( i_ctx_p,
629
 
                             &istate->transfer_procs.gray,
630
 
                             igs->set_transfer.gray,
631
 
                             igs,
632
 
                             zcolor_remap_one_finish );
633
 
}
634
 
 
635
 
 
636
 
/*
637
 
 * Internal routines
638
 
 */
639
 
 
640
 
/*
641
 
 * Prepare to remap one color component (also used for black generation
642
 
 * and undercolor removal). Use the 'for' operator to gather the values.
643
 
 * The caller must have done the necessary check_ostack and check_estack.
644
 
 */
645
 
int
646
 
zcolor_remap_one(
647
 
    i_ctx_t *           i_ctx_p,
648
 
    const ref *         pproc,
649
 
    gx_transfer_map *   pmap,
650
 
    const gs_state *    pgs,
651
 
    op_proc_t           finish_proc )
652
 
{
653
 
    os_ptr              op;
654
 
 
655
 
    /*
656
 
     * Detect the identity function, which is a common value for one or
657
 
     * more of these functions.
658
 
     */
659
 
    if (r_size(pproc) == 0) {
660
 
        gx_set_identity_transfer(pmap);
661
 
        /*
662
 
         * Even though we don't actually push anything on the e-stack, all
663
 
         * clients do, so we return o_push_estack in this case.  This is
664
 
         * needed so that clients' finishing procedures will get run.
665
 
         */
666
 
        return o_push_estack;
667
 
    }
668
 
    op = osp += 4;
669
 
    make_real(op - 3, 0);
670
 
    make_int(op - 2, transfer_map_size - 1);
671
 
    make_real(op - 1, 1);
672
 
    *op = *pproc;
673
 
    ++esp;
674
 
    make_struct(esp, imemory_space((gs_ref_memory_t *) pgs->memory),
675
 
                pmap);
676
 
    push_op_estack(finish_proc);
677
 
    push_op_estack(zfor_samples);
678
 
    return o_push_estack;
679
 
}
680
 
 
681
 
/* Store the result of remapping a component. */
682
 
static int
683
 
zcolor_remap_one_store(i_ctx_t *i_ctx_p, floatp min_value)
684
 
{
685
 
    int i;
686
 
    gx_transfer_map *pmap = r_ptr(esp, gx_transfer_map);
687
 
 
688
 
    if (ref_stack_count(&o_stack) < transfer_map_size)
689
 
        return_error(e_stackunderflow);
690
 
    for (i = 0; i < transfer_map_size; i++) {
691
 
        double v;
692
 
        int code =
693
 
            real_param(ref_stack_index(&o_stack, transfer_map_size - 1 - i),
694
 
                       &v);
695
 
 
696
 
        if (code < 0)
697
 
            return code;
698
 
        pmap->values[i] =
699
 
            (v < min_value ? float2frac(min_value) :
700
 
             v >= 1.0 ? frac_1 :
701
 
             float2frac(v));
702
 
    }
703
 
    ref_stack_pop(&o_stack, transfer_map_size);
704
 
    esp--;                      /* pop pointer to transfer map */
705
 
    return o_pop_estack;
706
 
}
707
 
int
708
 
zcolor_remap_one_finish(i_ctx_t *i_ctx_p)
709
 
{
710
 
    return zcolor_remap_one_store(i_ctx_p, 0.0);
711
 
}
712
 
int
713
 
zcolor_remap_one_signed_finish(i_ctx_t *i_ctx_p)
714
 
{
715
 
    return zcolor_remap_one_store(i_ctx_p, -1.0);
716
 
}
717
 
 
718
 
/* Finally, reset the effective transfer functions and */
719
 
/* invalidate the current color. */
720
 
int
721
 
zcolor_reset_transfer(i_ctx_t *i_ctx_p)
722
 
{
723
 
    gx_set_effective_transfer(igs);
724
 
    return zcolor_remap_color(i_ctx_p);
725
 
}
726
 
int
727
 
zcolor_remap_color(i_ctx_t *i_ctx_p)
728
 
{
729
 
    /* Remap both colors. This should never hurt. */
730
 
    gs_swapcolors(igs);
731
 
    gx_unset_dev_color(igs);
732
 
    gs_swapcolors(igs);
733
 
    gx_unset_dev_color(igs);
734
 
    return 0;
735
 
}
736
 
 
737
 
/*
738
 
 * <param1> ... <paramN> .color_test <param1> ... <paramN>
739
 
 *
740
 
 * encode and decode color to allow mapping to be tested.
741
 
 */
742
 
static int
743
 
zcolor_test(i_ctx_t *i_ctx_p)
744
 
{
745
 
    gx_color_value cv[GX_DEVICE_COLOR_MAX_COMPONENTS];
746
 
    gx_device *dev = gs_currentdevice(igs);
747
 
    int ncomp = dev->color_info.num_components;
748
 
    gx_color_index color;
749
 
    os_ptr op = osp - (ncomp-1);
750
 
    int i;
751
 
    if (ref_stack_count(&o_stack) < ncomp)
752
 
        return_error(e_stackunderflow);
753
 
    for (i = 0; i < ncomp; i++) {
754
 
        if (r_has_type(op+i, t_real))
755
 
            cv[i] = (gx_color_value)
756
 
                (op[i].value.realval * gx_max_color_value);
757
 
        else if (r_has_type(op+i, t_integer))
758
 
            cv[i] = (gx_color_value)
759
 
                (op[i].value.intval * gx_max_color_value);
760
 
        else
761
 
            return_error(e_typecheck);
762
 
    }
763
 
    color = (*dev_proc(dev, encode_color)) (dev, cv);
764
 
    (*dev_proc(dev, decode_color)) (dev, color, cv);
765
 
    for (i = 0; i < ncomp; i++)
766
 
        make_real(op+i, (float)cv[i] / (float)gx_max_color_value);
767
 
    return 0;
768
 
}
769
 
 
770
 
/*
771
 
 * <levels> .color_test_all <value0> ... <valueN>
772
 
 *
773
 
 * Test encode/decode color procedures for a range of values.
774
 
 * Return value with the worst error in a single component.
775
 
 */
776
 
static int
777
 
zcolor_test_all(i_ctx_t *i_ctx_p)
778
 
{
779
 
    os_ptr                  op = osp;
780
 
    gx_color_value cv[GX_DEVICE_COLOR_MAX_COMPONENTS];
781
 
    gx_color_value cvout[GX_DEVICE_COLOR_MAX_COMPONENTS];
782
 
    gx_color_value cvbad[GX_DEVICE_COLOR_MAX_COMPONENTS];
783
 
    int counter[GX_DEVICE_COLOR_MAX_COMPONENTS];
784
 
    gx_device *dev = gs_currentdevice(igs);
785
 
    int ncomp = dev->color_info.num_components;
786
 
    int steps;
787
 
    int maxerror = 0;
788
 
    int err;
789
 
    int acceptable_error;
790
 
    int linsep = dev->color_info.separable_and_linear == GX_CINFO_SEP_LIN;
791
 
    int linsepfailed = 0;
792
 
    int lsmaxerror = 0;
793
 
    gx_color_index color, lscolor;
794
 
    int i, j, k;
795
 
    int finished = 0;
796
 
 
797
 
    if (ncomp == 1)
798
 
        acceptable_error = gx_max_color_value / dev->color_info.max_gray + 1;
799
 
    else
800
 
        acceptable_error = gx_max_color_value / dev->color_info.max_color + 1;
801
 
 
802
 
    if (ref_stack_count(&o_stack) < 1)
803
 
        return_error(e_stackunderflow);
804
 
    if (!r_has_type(&osp[0], t_integer))
805
 
        return_error(e_typecheck);
806
 
    steps = osp[0].value.intval;
807
 
    for (i = 0; i < ncomp; i++) {
808
 
        counter[i] = 0;
809
 
        cvbad[i] = 0;
810
 
    }
811
 
 
812
 
    dprintf1("Number of components = %d\n", ncomp);
813
 
    dprintf1("Depth = %d\n", dev->color_info.depth);
814
 
    dprintf2("max_gray = %d   dither_grays = %d\n",
815
 
        dev->color_info.max_gray, dev->color_info.dither_grays);
816
 
    dprintf2("max_color = %d   dither_colors = %d\n",
817
 
        dev->color_info.max_color, dev->color_info.dither_colors);
818
 
    dprintf1("polarity = %s\n",
819
 
      dev->color_info.polarity == GX_CINFO_POLARITY_ADDITIVE ? "Additive" :
820
 
      dev->color_info.polarity == GX_CINFO_POLARITY_SUBTRACTIVE ?"Subtractive":
821
 
      "Unknown");
822
 
    /* Indicate color index value with all colorants = zero */
823
 
    for (i = 0; i < ncomp; i++)
824
 
        cv[i] = 0;
825
 
    color = (*dev_proc(dev, encode_color)) (dev, cv);
826
 
    if (sizeof(color) <= sizeof(ulong))
827
 
        dprintf1("Zero color index:  %8lx\n", (ulong)color);
828
 
    else
829
 
        dprintf2("Zero color index:  %8lx%08lx\n",
830
 
            (ulong)(color >> 8*(sizeof(color) - sizeof(ulong))), (ulong)color);
831
 
 
832
 
    dprintf1("separable_and_linear = %s\n",
833
 
      linsep == GX_CINFO_SEP_LIN_NONE ? "No" :
834
 
      linsep == GX_CINFO_SEP_LIN ? "Yes" :
835
 
      "Unknown");
836
 
    if (dev->color_info.gray_index == GX_CINFO_COMP_INDEX_UNKNOWN)
837
 
        dprintf("gray_index is unknown\n");
838
 
    else
839
 
        dprintf1("gray_index = %d\n", dev->color_info.gray_index);
840
 
    if (linsep) {
841
 
        dprintf(" Shift     Mask  Bits\n");
842
 
        for (i = 0; i < ncomp; i++) {
843
 
            dprintf3(" %5d %8x  %4d\n",
844
 
                (int)(dev->color_info.comp_shift[i]),
845
 
                (int)(dev->color_info.comp_mask[i]),
846
 
                (int)(dev->color_info.comp_bits[i]));
847
 
        }
848
 
    }
849
 
 
850
 
    while (!finished) {
851
 
        for (j = 0; j <= steps; j++) {
852
 
            for (i = 0; i < ncomp; i++)
853
 
                cv[i] = counter[i] * gx_max_color_value / steps;
854
 
            color = (*dev_proc(dev, encode_color)) (dev, cv);
855
 
            if (linsep) {
856
 
                /* Derive it the other way */
857
 
                lscolor = gx_default_encode_color(dev, cv);
858
 
                if ((color != lscolor) && (linsepfailed < 5)) {
859
 
                    linsepfailed++;
860
 
                    dprintf("Failed separable_and_linear for");
861
 
                    for (i = 0; i < ncomp; i++)
862
 
                        dprintf1(" %d", cv[i]);
863
 
                    dprintf("\n");
864
 
                    dprintf2("encode_color=%x  gx_default_encode_color=%x\n",
865
 
                        (int)color, (int)lscolor);
866
 
                }
867
 
            }
868
 
            (*dev_proc(dev, decode_color)) (dev, color, cvout);
869
 
            for (i = 0; i < ncomp; i++) {
870
 
                err = (int)cvout[i] - (int)cv[i];
871
 
                if (err < 0)
872
 
                    err = -err;
873
 
                if (err > maxerror) {
874
 
                    maxerror = err;
875
 
                    for (k=0; k < ncomp; k++)
876
 
                        cvbad[k] = cv[k];
877
 
                }
878
 
            }
879
 
            if (linsep) {
880
 
                gx_default_decode_color(dev, color, cvout);
881
 
                for (i = 0; i < ncomp; i++) {
882
 
                    err = (int)cvout[i] - (int)cv[i];
883
 
                    if (err < 0)
884
 
                        err = -err;
885
 
                    if (err > lsmaxerror) {
886
 
                        lsmaxerror = err;
887
 
                    }
888
 
                }
889
 
            }
890
 
            counter[0] += 1;
891
 
        }
892
 
        counter[0] = 0;
893
 
        i = 1;
894
 
        while (i < ncomp) {
895
 
            counter[i] += 1;
896
 
            if (counter[i] > steps) {
897
 
                counter[i] = 0;
898
 
                i++;
899
 
            }
900
 
            else
901
 
                break;
902
 
        }
903
 
        if (i >= ncomp)
904
 
            finished = 1;
905
 
    }
906
 
 
907
 
    dprintf2("Maximum error %g %s\n",
908
 
        (float)maxerror / (float)gx_max_color_value,
909
 
        maxerror <= acceptable_error ? "is Ok" :
910
 
        maxerror <= 3*acceptable_error/2 ? "is POOR" : "FAILED");
911
 
 
912
 
    if (linsep)
913
 
      dprintf2("Maximum linear_and_separable error %g %s\n",
914
 
        (float)lsmaxerror / (float)gx_max_color_value,
915
 
        lsmaxerror <= acceptable_error ? "is Ok" :
916
 
        lsmaxerror <= 3*acceptable_error/2 ? "is POOR" : "FAILED");
917
 
 
918
 
    /* push worst value */
919
 
    push(ncomp-1);
920
 
    op -= ncomp - 1;
921
 
    for (i = 0; i < ncomp; i++)
922
 
        make_real(op+i, (float)cvbad[i] / (float)gx_max_color_value);
923
 
 
924
 
    return 0;
925
 
}
926
 
 
927
 
/* Convert between RGB and HSB colors, using the hexcone approach (see
928
 
 * Rogers, David, "Procedureal Elements For Computer Graphics",
929
 
 * (McGraw-Hill, 1985), pp. 402 - 3).
930
 
 *
931
 
 * The rgb ==> hsb calculation is:
932
 
 *
933
 
 *   br = max(r, g, b)
934
 
 *
935
 
 *   if (br == 0)
936
 
 *       h = 0, s = 0;
937
 
 *   else {
938
 
 *       v = min(r, g, b)
939
 
 *       diff = br - v;
940
 
 *       sat = diff / br;
941
 
 *       if (r == br)
942
 
 *           h = (g - b) / (6 * diff) + (b > g ? 1 : 0);
943
 
 *       else if (g == br)
944
 
 *           h = 1/3 + (b - r) / (6 * diff);
945
 
 *       else
946
 
 *           h = 2/3 + (r - g) / (6 * diff);
947
 
 *   }
948
 
 */
949
 
static int rgb2hsb(float *RGB)
950
 
{
951
 
    float HSB[3], v, diff;
952
 
    int i, j=0;
953
 
 
954
 
    v = 1.0;
955
 
    for (i=0;i<3;i++)
956
 
        HSB[i] = 0.0;
957
 
    for (i=0;i<3;i++) {
958
 
        if (RGB[i] > HSB[2]) {
959
 
            HSB[2] = RGB[i];
960
 
            j = i;
961
 
        }
962
 
        if (RGB[i] < v)
963
 
            v = RGB[i];
964
 
    }
965
 
    if (HSB[2] != 0) {
966
 
        diff = HSB[2] - v;
967
 
        HSB[1] = diff / HSB[2];
968
 
        switch (j) {
969
 
            case 0 : /* R == Brightness */
970
 
                /* diff can only be zero if r == br, so we need to make sure here we
971
 
                 * don't divide by zero
972
 
                 */
973
 
                if (diff)
974
 
                    HSB[0] = ((RGB[1] - RGB[2]) / (6.0 * diff)) + (RGB[2] > RGB[1] ? 1.0 : 0.0);
975
 
                else
976
 
                    HSB[0] = (RGB[1] - RGB[2]) + (RGB[2] > RGB[1] ? 1.0 : 0.0);
977
 
                break;
978
 
            case 1 : /* G == Brightness */
979
 
                HSB[0] = (1.0 / 3.0) + (RGB[2] - RGB[0]) / (6.0 * diff);
980
 
                break;
981
 
            case 2 : /* B == Brightness */
982
 
                HSB[0] = (2.0 / 3.0) + (RGB[0] - RGB[1]) / (6.0 * diff);
983
 
                break;
984
 
        }
985
 
    }
986
 
    for (i=0;i<3;i++) {
987
 
        if (HSB[i] < 0)
988
 
            HSB[i] = 0;
989
 
        if (RGB[i] > 1)
990
 
            HSB[i] = 1;
991
 
        RGB[i] = HSB[i];
992
 
    }
993
 
    return 0;
994
 
}
995
 
/* The hsb ==> rgb conversion is:
996
 
 *
997
 
 *    mn = (1 - s) * br, md = 6 * s * br;
998
 
 *
999
 
 *    switch ((int)floor(6 * h)) {
1000
 
 *      case 0:   %% r >= g >= b
1001
 
 *        r = br;
1002
 
 *        g = mn + h * md;
1003
 
 *        b = mn;
1004
 
 *        break;
1005
 
 *
1006
 
 *      case 1:  %% g >= r >= b
1007
 
 *        r = mn + md * (1/3 - h);
1008
 
 *        g = br;
1009
 
 *        b = mn;
1010
 
 *        break;
1011
 
 *
1012
 
 *      case 2:  %% g >= b >= r
1013
 
 *        r = mn;
1014
 
 *        g = br;
1015
 
 *        b = mn + (h - 1/3) * md;
1016
 
 *        break;
1017
 
 *
1018
 
 *      case 3:  %% b >= g >= r
1019
 
 *        r = mn;
1020
 
 *        g = mn + (2/3 - h) * md;
1021
 
 *        b = br;
1022
 
 *        break;
1023
 
 *
1024
 
 *      case 4:  %% b >= r >= g
1025
 
 *        r = mn + (h - 2/3) * md;
1026
 
 *        g = mn;
1027
 
 *        b = br;
1028
 
 *        break;
1029
 
 *
1030
 
 *      case 5:  %% r >= b >= g
1031
 
 *        r = br;
1032
 
 *        g = mn;
1033
 
 *        b = mn + (1 - h) * md;
1034
 
 *        break;
1035
 
 *
1036
 
 *      case 6:  %% We have wrapped around the hexcone.  Thus this case is
1037
 
 *                         the same as case 0 with h = 0
1038
 
 *        h = 0;
1039
 
 *        r = br;
1040
 
 *        g = mn + h * md = mn;
1041
 
 *        b = mn;
1042
 
 *        break;
1043
 
 *    }
1044
 
 */
1045
 
static int hsb2rgb(float *HSB)
1046
 
{
1047
 
    float RGB[3], mn, md;
1048
 
    int i;
1049
 
 
1050
 
    mn = (1.0 - HSB[1]) * HSB[2];
1051
 
    md = 6.0 * HSB[1] * HSB[2];
1052
 
 
1053
 
    switch ((int)floor(6.0 * HSB[0])) {
1054
 
        case 6:
1055
 
            HSB[0] = (float)0;
1056
 
        default: /* Shuts up compiler warning about RGB being uninited */
1057
 
        case 0:
1058
 
            RGB[0] = HSB[2];
1059
 
            RGB[1] = mn + (HSB[0] * md);
1060
 
            RGB[2] = mn;
1061
 
            break;
1062
 
        case 1:
1063
 
            RGB[0] = mn + (md * ((1.0 / 3.0) - HSB[0]));
1064
 
            RGB[1] = HSB[2];
1065
 
            RGB[2] = mn;
1066
 
            break;
1067
 
        case 2:
1068
 
            RGB[0] = mn;
1069
 
            RGB[1] = HSB[2];
1070
 
            RGB[2] = mn + ((HSB[0] - (1.0 / 3.0)) * md);
1071
 
            break;
1072
 
        case 3:
1073
 
            RGB[0] = mn;
1074
 
            RGB[1] = mn + (((2.0 / 3.0f) - HSB[0]) * md);
1075
 
            RGB[2] = HSB[2];
1076
 
            break;
1077
 
        case 4:
1078
 
            RGB[0] = mn + ((HSB[0] - (2.0 / 3.0)) * md);
1079
 
            RGB[1] = mn;
1080
 
            RGB[2] = HSB[2];
1081
 
            break;
1082
 
        case 5:
1083
 
            RGB[0] = HSB[2];
1084
 
            RGB[1] = mn;
1085
 
            RGB[2] = mn + ((1.0 - HSB[0]) * md);
1086
 
            break;
1087
 
    }
1088
 
    for (i=0;i<3;i++) {
1089
 
        if (RGB[i] < 0)
1090
 
            RGB[i] = 0;
1091
 
        if (RGB[i] > 1)
1092
 
            RGB[i] = 1;
1093
 
        HSB[i] = RGB[i];
1094
 
    }
1095
 
    return 0;
1096
 
}
1097
 
 
1098
 
/* The routines for handling colors and color spaces, moved from
1099
 
 * PostScript to C, start here.
1100
 
 */
1101
 
 
1102
 
/* DeviceGray */
1103
 
static int setgrayspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
1104
 
{
1105
 
    os_ptr op = osp;
1106
 
    gs_color_space  *pcs;
1107
 
    int code=0;
1108
 
    ref stref;
1109
 
 
1110
 
    do {
1111
 
        switch (*stage) {
1112
 
            case 0:
1113
 
                if (istate->use_cie_color.value.boolval && !CIESubst) {
1114
 
                    byte *body;
1115
 
                    ref *nosubst;
1116
 
 
1117
 
                    code = dict_find_string(systemdict, "NOSUBSTDEVICECOLORS", &nosubst);
1118
 
                    if (code < 0)
1119
 
                        return code;
1120
 
                    if (!r_has_type(nosubst, t_boolean))
1121
 
                        return_error(e_typecheck);
1122
 
                    if (nosubst->value.boolval) {
1123
 
                        *stage = 4;
1124
 
                        *cont = 1;
1125
 
                        body = ialloc_string(32, "string");
1126
 
                        if (body == 0)
1127
 
                            return_error(e_VMerror);
1128
 
                        memcpy(body, "/DefaultGray ..nosubstdevicetest",32);
1129
 
                        make_string(&stref, a_all | icurrent_space, 32, body);
1130
 
                        r_set_attrs(&stref, a_executable);
1131
 
                        esp++;
1132
 
                        ref_assign(esp, &stref);
1133
 
                        return o_push_estack;
1134
 
                    } else {
1135
 
                        *stage = 2;
1136
 
                        *cont = 1;
1137
 
                        body = ialloc_string(47, "string");
1138
 
                        if (body == 0)
1139
 
                            return_error(e_VMerror);
1140
 
                        memcpy(body, "{/DefaultGray /ColorSpace findresource} stopped",47);
1141
 
                        make_string(&stref, a_all | icurrent_space, 47, body);
1142
 
                        r_set_attrs(&stref, a_executable);
1143
 
                        esp++;
1144
 
                        ref_assign(esp, &stref);
1145
 
                        return o_push_estack;
1146
 
                    }
1147
 
                    break;
1148
 
                }
1149
 
                /* fall through */
1150
 
            case 1:
1151
 
                pcs = gs_cspace_new_DeviceGray(imemory);
1152
 
                if (pcs == NULL)
1153
 
                    return_error(e_VMerror);
1154
 
                code = gs_setcolorspace(igs, pcs);
1155
 
                if (code >= 0) {
1156
 
                    gs_client_color *pcc = gs_currentcolor_inline(igs);
1157
 
 
1158
 
                    cs_adjust_color_count(igs, -1); /* not strictly necessary */
1159
 
                    pcc->paint.values[0] = (0);
1160
 
                    pcc->pattern = 0;           /* for GC */
1161
 
                    gx_unset_dev_color(igs);
1162
 
                }
1163
 
                rc_decrement_only_cs(pcs, "zsetdevcspace");
1164
 
                *cont = 0;
1165
 
                *stage = 0;
1166
 
                break;
1167
 
            case 2:
1168
 
                if (!r_has_type(op, t_boolean))
1169
 
                    return_error(e_typecheck);
1170
 
                if (op->value.boolval) {
1171
 
                    /* Failed to find the /DefaultGray CSA, so give up and
1172
 
                     * just use DeviceGray
1173
 
                     */
1174
 
                    pop(1);
1175
 
                    *stage = 1;
1176
 
                    break;
1177
 
                }
1178
 
                pop(1);
1179
 
                *cont = 1;
1180
 
                *stage = 3;
1181
 
                code = setcolorspace_nosubst(i_ctx_p);
1182
 
                if (code != 0)
1183
 
                    return code;
1184
 
                break;
1185
 
            case 3:
1186
 
                /* We end up here after setting the DefaultGray space
1187
 
                 * We've finished setting the gray color space, so we
1188
 
                 * just exit now
1189
 
                 */
1190
 
                *cont = 0;
1191
 
                *stage = 0;
1192
 
                break;
1193
 
            case 4:
1194
 
                /* We come here if /UseCIEColor is true, and NOSUBSTDEVICECOLORS
1195
 
                 * is also true. We will have a boolean on the stack, if its true
1196
 
                 * then we need to set the space (also on the stack), invoke
1197
 
                 * .includecolorspace, and set /DeviceGray, otherwise we just need
1198
 
                 * to set DeviceGray. See gs_cspace.ps.
1199
 
                 */
1200
 
                if (!r_has_type(op, t_boolean))
1201
 
                    return_error(e_typecheck);
1202
 
                pop(1);
1203
 
                *stage = 1;
1204
 
                *cont = 1;
1205
 
                if (op->value.boolval) {
1206
 
                    *stage = 5;
1207
 
                    code = setcolorspace_nosubst(i_ctx_p);
1208
 
                    if (code != 0)
1209
 
                        return code;
1210
 
                }
1211
 
                break;
1212
 
            case 5:
1213
 
                /* After stage 4 above, if we had to set a color space, we come
1214
 
                 * here. Now we need to use .includecolorspace to register the space
1215
 
                 * with any high-level devices which want it.
1216
 
                 */
1217
 
                *stage = 1;
1218
 
                *cont = 1;
1219
 
                code = zincludecolorspace(i_ctx_p);
1220
 
                if (code != 0)
1221
 
                    return code;
1222
 
                break;
1223
 
        }
1224
 
    } while (*stage);
1225
 
    return code;
1226
 
}
1227
 
static int graydomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
1228
 
{
1229
 
    ptr[0] = 0;
1230
 
    ptr[1] = 1;
1231
 
    return 0;
1232
 
}
1233
 
static int grayrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
1234
 
{
1235
 
    ptr[0] = 0;
1236
 
    ptr[1] = 1;
1237
 
    return 0;
1238
 
}
1239
 
/* This routine converts a Gray value into its equivalent in a different
1240
 
 * device space, required by currentgray, currentrgb, currenthsb and
1241
 
 * currentcmyk. The actual color value will have been processed through
1242
 
 * the tint transform(s) of the parent space(s) until it reaches a device
1243
 
 * space. This converts that final value into the requested space.
1244
 
 */
1245
 
static int graybasecolor(i_ctx_t * i_ctx_p, ref *space, int base, int *stage, int *cont, int *stack_depth)
1246
 
{
1247
 
    os_ptr op = osp;
1248
 
    float Gray, RGB[3];
1249
 
 
1250
 
    *cont = 0;
1251
 
    *stage = 0;
1252
 
    check_op(1);
1253
 
    if (!r_has_type(op, t_integer)) {
1254
 
        if (r_has_type(op, t_real)) {
1255
 
            Gray = op->value.realval;
1256
 
        } else
1257
 
            return_error(e_typecheck);
1258
 
    } else
1259
 
        Gray = (float)op->value.intval;
1260
 
 
1261
 
    if (Gray < 0 || Gray > 1)
1262
 
        return_error(e_rangecheck);
1263
 
 
1264
 
    switch (base) {
1265
 
        case 0:
1266
 
            /* Requested space is DeviceGray, just use the value */
1267
 
            make_real(op, Gray);
1268
 
            break;
1269
 
        case 1:
1270
 
            /* Requested space is HSB */
1271
 
        case 2:
1272
 
            /* Requested space is RGB, set all the components
1273
 
             * to the gray value
1274
 
             */
1275
 
            push(2);
1276
 
            RGB[0] = RGB[1] = RGB[2] = Gray;
1277
 
            if (base == 1)
1278
 
                /* If the requested space is HSB, convert the RGB to HSB */
1279
 
                rgb2hsb((float *)&RGB);
1280
 
            make_real(&op[-2], RGB[0]);
1281
 
            make_real(&op[-1], RGB[1]);
1282
 
            make_real(op, RGB[2]);
1283
 
            break;
1284
 
        case 3:
1285
 
            /* Requested space is CMYK, use the gray value to set the
1286
 
             * black channel.
1287
 
             */
1288
 
            push(3);
1289
 
            make_real(&op[-3], (float)0);
1290
 
            make_real(&op[-2], (float)0);
1291
 
            make_real(&op[-1], (float)0);
1292
 
            make_real(op, (float)1.0 - Gray);
1293
 
            break;
1294
 
        default:
1295
 
            return_error(e_undefined);
1296
 
    }
1297
 
    return 0;
1298
 
}
1299
 
static int grayvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
1300
 
{
1301
 
    os_ptr op = osp;
1302
 
 
1303
 
    if (!r_has_type(op, t_integer) && !r_has_type(op, t_real))
1304
 
        return_error(e_typecheck);
1305
 
 
1306
 
    if (num_comps < 1)
1307
 
        return_error(e_stackunderflow);
1308
 
 
1309
 
    if (*values > 1.0)
1310
 
        *values = 1.0;
1311
 
 
1312
 
    if ( *values < 0.0)
1313
 
        *values = 0.0;
1314
 
 
1315
 
    return 0;
1316
 
}
1317
 
static int grayinitialproc(i_ctx_t *i_ctx_p, ref *space)
1318
 
{
1319
 
    gs_client_color cc;
1320
 
 
1321
 
    cc.pattern = 0x00;
1322
 
    cc.paint.values[0] = 0;
1323
 
    return gs_setcolor(igs, &cc);
1324
 
}
1325
 
 
1326
 
/* DeviceRGB */
1327
 
static int setrgbspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
1328
 
{
1329
 
    os_ptr op = osp;
1330
 
    gs_color_space  *pcs;
1331
 
    int code=0;
1332
 
    ref stref;
1333
 
 
1334
 
    do {
1335
 
        switch (*stage) {
1336
 
            case 0:
1337
 
                if (istate->use_cie_color.value.boolval && !CIESubst) {
1338
 
                    byte *body;
1339
 
                    ref *nosubst;
1340
 
 
1341
 
                    code = dict_find_string(systemdict, "NOSUBSTDEVICECOLORS", &nosubst);
1342
 
                    if (code < 0)
1343
 
                        return code;
1344
 
                    if (!r_has_type(nosubst, t_boolean))
1345
 
                        return_error(e_typecheck);
1346
 
                    if (nosubst->value.boolval) {
1347
 
                        *stage = 4;
1348
 
                        *cont = 1;
1349
 
                        body = ialloc_string(31, "string");
1350
 
                        if (body == 0)
1351
 
                            return_error(e_VMerror);
1352
 
                        memcpy(body, "/DefaultRGB ..nosubstdevicetest",31);
1353
 
                        make_string(&stref, a_all | icurrent_space, 31, body);
1354
 
                        r_set_attrs(&stref, a_executable);
1355
 
                        esp++;
1356
 
                        ref_assign(esp, &stref);
1357
 
                        return o_push_estack;
1358
 
                    } else {
1359
 
                        *stage = 2;
1360
 
                        *cont = 1;
1361
 
                        body = ialloc_string(46, "string");
1362
 
                        if (body == 0)
1363
 
                            return_error(e_VMerror);
1364
 
                        memcpy(body, "{/DefaultRGB /ColorSpace findresource} stopped", 46);
1365
 
                        make_string(&stref, a_all | icurrent_space, 46, body);
1366
 
                        r_set_attrs(&stref, a_executable);
1367
 
                        esp++;
1368
 
                        ref_assign(esp, &stref);
1369
 
                        return o_push_estack;
1370
 
                    }
1371
 
                }
1372
 
                /* fall through */
1373
 
            case 1:
1374
 
                pcs = gs_cspace_new_DeviceRGB(imemory);
1375
 
                if (pcs == NULL)
1376
 
                    return_error(e_VMerror);
1377
 
                code = gs_setcolorspace(igs, pcs);
1378
 
                if (code >= 0) {
1379
 
                    gs_client_color *pcc = gs_currentcolor_inline(igs);
1380
 
 
1381
 
                    cs_adjust_color_count(igs, -1); /* not strictly necessary */
1382
 
                    pcc->paint.values[0] = 0;
1383
 
                    pcc->paint.values[1] = 0;
1384
 
                    pcc->paint.values[2] = 0;
1385
 
                    pcc->pattern = 0;           /* for GC */
1386
 
                    gx_unset_dev_color(igs);
1387
 
                }
1388
 
                rc_decrement_only_cs(pcs, "zsetdevcspace");
1389
 
                *cont = 0;
1390
 
                *stage = 0;
1391
 
                break;
1392
 
            case 2:
1393
 
                if (!r_has_type(op, t_boolean))
1394
 
                    return_error(e_typecheck);
1395
 
                if (op->value.boolval) {
1396
 
                    /* Failed to find the /DefaultRGB CSA, so give up and
1397
 
                     * just use DeviceRGB
1398
 
                     */
1399
 
                    pop(1);
1400
 
                    *stage = 1;
1401
 
                    break;
1402
 
                }
1403
 
                pop(1);
1404
 
                *stage = 3;
1405
 
                code = setcolorspace_nosubst(i_ctx_p);
1406
 
                if (code != 0)
1407
 
                    return code;
1408
 
                break;
1409
 
            case 3:
1410
 
                /* We end up here after setting the DefaultGray CIE space
1411
 
                 * We've finished setting the gray color space, so we
1412
 
                 * just exit now
1413
 
                 */
1414
 
                *cont = 0;
1415
 
                *stage = 0;
1416
 
                break;
1417
 
            case 4:
1418
 
                /* We come here if /UseCIEColor is true, and NOSUBSTDEVICECOLORS
1419
 
                 * is also true. We will have a boolean on the stack, if its true
1420
 
                 * then we need to set the space (also on the stack), invoke
1421
 
                 * .includecolorspace, and set /DeviceGray, otherwise we just need
1422
 
                 * to set DeviceGray. See gs-cspace.ps.
1423
 
                 */
1424
 
                if (!r_has_type(op, t_boolean))
1425
 
                    return_error(e_typecheck);
1426
 
                pop(1);
1427
 
                *stage = 1;
1428
 
                *cont = 1;
1429
 
                if (op->value.boolval) {
1430
 
                    *stage = 5;
1431
 
                    code = setcolorspace_nosubst(i_ctx_p);
1432
 
                    if (code != 0)
1433
 
                        return code;
1434
 
                }
1435
 
                break;
1436
 
            case 5:
1437
 
                /* After stage 4 above, if we had to set a color space, we come
1438
 
                 * here. Now we need to use .includecolorspace to register the space
1439
 
                 * with any high-level devices which want it.
1440
 
                 */
1441
 
                *stage = 1;
1442
 
                *cont = 1;
1443
 
                code = zincludecolorspace(i_ctx_p);
1444
 
                if (code != 0)
1445
 
                    return code;
1446
 
                break;
1447
 
        }
1448
 
    } while (*stage);
1449
 
    return code;
1450
 
}
1451
 
static int rgbdomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
1452
 
{
1453
 
    int i;
1454
 
 
1455
 
    for (i = 0;i < 6;i+=2) {
1456
 
        ptr[i] = 0;
1457
 
        ptr[i+1] = 1;
1458
 
    }
1459
 
    return 0;
1460
 
}
1461
 
static int rgbrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
1462
 
{
1463
 
    int i;
1464
 
 
1465
 
    for (i = 0;i < 6;i+=2) {
1466
 
        ptr[i] = 0;
1467
 
        ptr[i+1] = 1;
1468
 
    }
1469
 
    return 0;
1470
 
}
1471
 
/* This routine converts an RGB value into its equivalent in a different
1472
 
 * device space, required by currentgray, currentrgb, currenthsb and
1473
 
 * currentcmyk. The actual color value will have been processed through
1474
 
 * the tint transform(s) of the parent space(s) until it reaches a device
1475
 
 * space. This converts that final value into the requested space.
1476
 
 */
1477
 
static int rgbbasecolor(i_ctx_t * i_ctx_p, ref *space, int base, int *stage, int *cont, int *stack_depth)
1478
 
{
1479
 
    os_ptr op = osp;
1480
 
    float RGB[3], CMYK[4], Gray, UCR, BG;
1481
 
    int i;
1482
 
 
1483
 
    switch (*stage) {
1484
 
        case 0:
1485
 
            *cont = 0;
1486
 
            check_op(3);
1487
 
            op -= 2;
1488
 
            for (i=0;i<3;i++) {
1489
 
                if (!r_has_type(op, t_integer)) {
1490
 
                    if (r_has_type(op, t_real)) {
1491
 
                        RGB[i] = op->value.realval;
1492
 
                    } else
1493
 
                        return_error(e_typecheck);
1494
 
                } else
1495
 
                    RGB[i] = (float)op->value.intval;
1496
 
                if (RGB[i] < 0 || RGB[i] > 1)
1497
 
                    return_error(e_rangecheck);
1498
 
                op++;
1499
 
            }
1500
 
            op = osp;
1501
 
 
1502
 
            switch (base) {
1503
 
                case 0:
1504
 
                    pop(2);
1505
 
                    op = osp;
1506
 
                    /* If R == G == B, then this is gray, so just use it. Avoids
1507
 
                     * rounding errors.
1508
 
                     */
1509
 
                    if (RGB[0] == RGB[1] && RGB[1] == RGB[2])
1510
 
                        Gray = RGB[0];
1511
 
                    else
1512
 
                        Gray = (0.3 * RGB[0]) + (0.59 * RGB[1]) + (0.11 * RGB[2]);
1513
 
                    make_real(op, Gray);
1514
 
                    return 0;
1515
 
                    break;
1516
 
                case 1:
1517
 
                    rgb2hsb((float *)&RGB);
1518
 
                    make_real(&op[-2], RGB[0]);
1519
 
                    make_real(&op[-1], RGB[1]);
1520
 
                    make_real(op, RGB[2]);
1521
 
                    return 0;
1522
 
                    break;
1523
 
                case 2:
1524
 
                    make_real(&op[-2], RGB[0]);
1525
 
                    make_real(&op[-1], RGB[1]);
1526
 
                    make_real(op, RGB[2]);
1527
 
                    return 0;
1528
 
                    break;
1529
 
                case 3:
1530
 
                    *stage = 1;
1531
 
                    *cont = 1;
1532
 
                    for (i=0;i<3;i++)
1533
 
                        CMYK[i] = 1 - RGB[i];
1534
 
                    if (CMYK[0] < CMYK[1]) {
1535
 
                        if (CMYK[0] < CMYK[2])
1536
 
                            CMYK[3] = CMYK[0];
1537
 
                        else
1538
 
                            CMYK[3] = CMYK[2];
1539
 
                    } else {
1540
 
                        if (CMYK[1] < CMYK[2])
1541
 
                            CMYK[3] = CMYK[1];
1542
 
                        else
1543
 
                            CMYK[3] = CMYK[2];
1544
 
                    }
1545
 
                    check_estack(1);
1546
 
                    push(2);
1547
 
                    op = osp - 4;
1548
 
                    for (i=0;i<4;i++) {
1549
 
                        make_real(op, CMYK[i]);
1550
 
                        op++;
1551
 
                    }
1552
 
                    make_real(op, CMYK[3]);
1553
 
                    esp++;
1554
 
                    *esp = istate->undercolor_removal;
1555
 
                    return o_push_estack;
1556
 
                    break;
1557
 
                default:
1558
 
                    return_error(e_undefined);
1559
 
                    break;
1560
 
            }
1561
 
            break;
1562
 
        case 1:
1563
 
            (*stage)++;
1564
 
            *cont = 1;
1565
 
            check_estack(1);
1566
 
            check_op(5);
1567
 
            op -= 4;
1568
 
            for (i=0;i<4;i++) {
1569
 
                if (!r_has_type(op, t_integer)) {
1570
 
                    if (r_has_type(op, t_real)) {
1571
 
                        CMYK[i] = op->value.realval;
1572
 
                    } else
1573
 
                        return_error(e_typecheck);
1574
 
                } else
1575
 
                    CMYK[i] = (float)op->value.intval;
1576
 
                op++;
1577
 
            }
1578
 
            if (!r_has_type(op, t_integer)) {
1579
 
                if (r_has_type(op, t_real)) {
1580
 
                    UCR = op->value.realval;
1581
 
                } else
1582
 
                    return_error(e_typecheck);
1583
 
            } else
1584
 
                UCR = (float)op->value.intval;
1585
 
            for (i=0;i<3;i++) {
1586
 
                CMYK[i] = CMYK[i] - UCR;
1587
 
                if (CMYK[i] < 0)
1588
 
                    CMYK[i] = 0;
1589
 
                if (CMYK[i] > 1)
1590
 
                    CMYK[i] = 1.0;
1591
 
            }
1592
 
            op -= 4;
1593
 
            for (i=0;i<4;i++) {
1594
 
                make_real(op, CMYK[i]);
1595
 
                op++;
1596
 
            }
1597
 
            make_real(op, CMYK[3]);
1598
 
            esp++;
1599
 
            *esp = istate->black_generation;
1600
 
            return o_push_estack;
1601
 
            break;
1602
 
        case 2:
1603
 
            *stage = 0;
1604
 
            *cont = 0;
1605
 
            check_op(5);
1606
 
            if (!r_has_type(op, t_integer)) {
1607
 
                if (r_has_type(op, t_real)) {
1608
 
                    BG = op->value.realval;
1609
 
                } else
1610
 
                    return_error(e_typecheck);
1611
 
            } else
1612
 
                BG = (float)op->value.intval;
1613
 
            pop(1);
1614
 
            op = osp;
1615
 
            if (BG < 0)
1616
 
                BG = 0;
1617
 
            if (BG > 1)
1618
 
                BG = 1;
1619
 
            make_real(op, BG);
1620
 
            break;
1621
 
    }
1622
 
    return 0;
1623
 
}
1624
 
static int rgbvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
1625
 
{
1626
 
    os_ptr op = osp;
1627
 
    int i;
1628
 
 
1629
 
    if (num_comps < 3)
1630
 
        return_error(e_stackunderflow);
1631
 
 
1632
 
    op -= 2;
1633
 
    for (i=0;i<3;i++) {
1634
 
        if (!r_has_type(op, t_integer) && !r_has_type(op, t_real))
1635
 
            return_error(e_typecheck);
1636
 
        op++;
1637
 
    }
1638
 
 
1639
 
    for (i=0;i < 3; i++) {
1640
 
        if (values[i] > 1.0)
1641
 
            values[i] = 1.0;
1642
 
 
1643
 
        if (values[i] < 0.0)
1644
 
            values[i] = 0.0;
1645
 
    }
1646
 
 
1647
 
    return 0;
1648
 
}
1649
 
static int rgbinitialproc(i_ctx_t *i_ctx_p, ref *space)
1650
 
{
1651
 
    gs_client_color cc;
1652
 
 
1653
 
    cc.pattern = 0x00;
1654
 
    cc.paint.values[0] = 0;
1655
 
    cc.paint.values[1] = 0;
1656
 
    cc.paint.values[2] = 0;
1657
 
    return gs_setcolor(igs, &cc);
1658
 
}
1659
 
 
1660
 
/* DeviceCMYK */
1661
 
static int setcmykspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
1662
 
{
1663
 
    os_ptr op = osp;
1664
 
    gs_color_space  *pcs;
1665
 
    int code=0;
1666
 
    ref stref;
1667
 
 
1668
 
    do {
1669
 
        switch (*stage) {
1670
 
            case 0:
1671
 
                if (istate->use_cie_color.value.boolval && !CIESubst) {
1672
 
                    byte *body;
1673
 
                    ref *nosubst;
1674
 
 
1675
 
                    code = dict_find_string(systemdict, "NOSUBSTDEVICECOLORS", &nosubst);
1676
 
                    if (code < 0)
1677
 
                        return code;
1678
 
                    if (!r_has_type(nosubst, t_boolean))
1679
 
                        return_error(e_typecheck);
1680
 
                    if (nosubst->value.boolval) {
1681
 
                        *stage = 4;
1682
 
                        *cont = 1;
1683
 
                        body = ialloc_string(32, "string");
1684
 
                        if (body == 0)
1685
 
                            return_error(e_VMerror);
1686
 
                        memcpy(body, "/DefaultCMYK ..nosubstdevicetest",32);
1687
 
                        make_string(&stref, a_all | icurrent_space, 32, body);
1688
 
                        r_set_attrs(&stref, a_executable);
1689
 
                        esp++;
1690
 
                        ref_assign(esp, &stref);
1691
 
                        return o_push_estack;
1692
 
                    } else {
1693
 
                        *stage = 2;
1694
 
                        *cont = 1;
1695
 
                        body = ialloc_string(47, "string");
1696
 
                        if (body == 0)
1697
 
                            return_error(e_VMerror);
1698
 
                        memcpy(body, "{/DefaultCMYK /ColorSpace findresource} stopped", 47);
1699
 
                        make_string(&stref, a_all | icurrent_space, 47, body);
1700
 
                        r_set_attrs(&stref, a_executable);
1701
 
                        esp++;
1702
 
                        ref_assign(esp, &stref);
1703
 
                        return o_push_estack;
1704
 
                    }
1705
 
                }
1706
 
                /* fall through */
1707
 
            case 1:
1708
 
                pcs = gs_cspace_new_DeviceCMYK(imemory);
1709
 
                if (pcs == NULL)
1710
 
                    return_error(e_VMerror);
1711
 
                code = gs_setcolorspace(igs, pcs);
1712
 
                if (code >= 0) {
1713
 
                    gs_client_color *pcc = gs_currentcolor_inline(igs);
1714
 
 
1715
 
                    cs_adjust_color_count(igs, -1); /* not strictly necessary */
1716
 
                    pcc->paint.values[0] = 0;
1717
 
                    pcc->paint.values[1] = 0;
1718
 
                    pcc->paint.values[2] = 0;
1719
 
                    pcc->paint.values[3] = 1;
1720
 
                    pcc->pattern = 0;           /* for GC */
1721
 
                    gx_unset_dev_color(igs);
1722
 
                }
1723
 
                rc_decrement_only_cs(pcs, "zsetdevcspace");
1724
 
                *cont = 0;
1725
 
                *stage = 0;
1726
 
                break;
1727
 
            case 2:
1728
 
                if (!r_has_type(op, t_boolean))
1729
 
                    return_error(e_typecheck);
1730
 
                if (op->value.boolval) {
1731
 
                    /* Failed to find the /DefaultCMYK CSA, so give up and
1732
 
                     * just use DeviceCMYK
1733
 
                     */
1734
 
                    pop(1);
1735
 
                    *stage = 1;
1736
 
                    break;
1737
 
                }
1738
 
                pop(1);
1739
 
                *stage = 3;
1740
 
                code = setcolorspace_nosubst(i_ctx_p);
1741
 
                if (code != 0)
1742
 
                    return code;
1743
 
                break;
1744
 
            case 3:
1745
 
                /* We end up here after setting the DefaultGray CIE space
1746
 
                 * We've finished setting the gray color space, so we
1747
 
                 * just exit now
1748
 
                 */
1749
 
                *cont = 0;
1750
 
                *stage = 0;
1751
 
                break;
1752
 
            case 4:
1753
 
                /* We come here if /UseCIEColor is true, and NOSUBSTDEVICECOLORS
1754
 
                 * is also true. We will have a boolean on the stack, if its true
1755
 
                 * then we need to set the space (also on the stack), invoke
1756
 
                 * .includecolorspace, and set /DeviceGray, otherwise we just need
1757
 
                 * to set DeviceGray. See gs-cspace.ps.
1758
 
                 */
1759
 
                if (!r_has_type(op, t_boolean))
1760
 
                    return_error(e_typecheck);
1761
 
                pop(1);
1762
 
                *stage = 1;
1763
 
                *cont = 1;
1764
 
                if (op->value.boolval) {
1765
 
                    *stage = 5;
1766
 
                    code = setcolorspace_nosubst(i_ctx_p);
1767
 
                    if (code != 0)
1768
 
                        return code;
1769
 
                }
1770
 
                break;
1771
 
            case 5:
1772
 
                /* After stage 4 above, if we had to set a color space, we come
1773
 
                 * here. Now we need to use .includecolorspace to register the space
1774
 
                 * with any high-level devices which want it.
1775
 
                 */
1776
 
                *stage = 1;
1777
 
                *cont = 1;
1778
 
                code = zincludecolorspace(i_ctx_p);
1779
 
                if (code != 0)
1780
 
                    return code;
1781
 
                break;
1782
 
        }
1783
 
    } while (*stage);
1784
 
    return code;
1785
 
}
1786
 
static int cmykdomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
1787
 
{
1788
 
    int i;
1789
 
 
1790
 
    for (i = 0;i < 8;i+=2) {
1791
 
        ptr[i] = 0;
1792
 
        ptr[i+1] = 1;
1793
 
    }
1794
 
    return 0;
1795
 
}
1796
 
static int cmykrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
1797
 
{
1798
 
    int i;
1799
 
 
1800
 
    for (i = 0;i < 8;i+=2) {
1801
 
        ptr[i] = 0;
1802
 
        ptr[i+1] = 1;
1803
 
    }
1804
 
    return 0;
1805
 
}
1806
 
/* This routine converts a CMYK value into its equivalent in a different
1807
 
 * device space, required by currentgray, currentrgb, currenthsb and
1808
 
 * currentcmyk. The actual color value will have been processed through
1809
 
 * the tint transform(s) of the parent space(s) until it reaches a device
1810
 
 * space. This converts that final value into the requested space.
1811
 
 */
1812
 
static int cmykbasecolor(i_ctx_t * i_ctx_p, ref *space, int base, int *stage, int *cont, int *stack_depth)
1813
 
{
1814
 
    os_ptr op = osp;
1815
 
    float CMYK[4], Gray, RGB[3];
1816
 
    int i;
1817
 
 
1818
 
    *cont = 0;
1819
 
    *stage = 0;
1820
 
    check_op(4);
1821
 
    op -= 3;
1822
 
    for (i=0;i<4;i++) {
1823
 
        if (!r_has_type(op, t_integer)) {
1824
 
            if (r_has_type(op, t_real)) {
1825
 
                CMYK[i] = op->value.realval;
1826
 
            } else
1827
 
                return_error(e_typecheck);
1828
 
        } else
1829
 
            CMYK[i] = (float)op->value.intval;
1830
 
        if (CMYK[i] < 0 || CMYK[i] > 1)
1831
 
            return_error(e_rangecheck);
1832
 
        op++;
1833
 
    }
1834
 
 
1835
 
    switch (base) {
1836
 
        case 0:
1837
 
            pop(3);
1838
 
            op = osp;
1839
 
            Gray = (0.3 * CMYK[0]) + (0.59 * CMYK[1]) + (0.11 * CMYK[2]) + CMYK[3];
1840
 
            if (Gray > 1.0)
1841
 
                Gray = 0;
1842
 
            else
1843
 
                Gray = 1.0 - Gray;
1844
 
            make_real(op, Gray);
1845
 
            break;
1846
 
        case 1:
1847
 
        case 2:
1848
 
            pop(1);
1849
 
            op = osp;
1850
 
            RGB[0] = 1.0 - (CMYK[0] + CMYK[3]);
1851
 
            if (RGB[0] < 0)
1852
 
                RGB[0] = 0;
1853
 
            RGB[1] = 1.0 - (CMYK[1] + CMYK[3]);
1854
 
            if (RGB[1] < 0)
1855
 
                RGB[1] = 0;
1856
 
            RGB[2] = 1.0 - (CMYK[2] + CMYK[3]);
1857
 
            if (RGB[2] < 0)
1858
 
                RGB[2] = 0;
1859
 
            if (base == 1)
1860
 
                rgb2hsb((float *)&RGB);
1861
 
            make_real(&op[-2], RGB[0]);
1862
 
            make_real(&op[-1], RGB[1]);
1863
 
            make_real(op, RGB[2]);
1864
 
            break;
1865
 
        case 3:
1866
 
            op = osp;
1867
 
            make_real(&op[-3], CMYK[0]);
1868
 
            make_real(&op[-2], CMYK[1]);
1869
 
            make_real(&op[-1], CMYK[2]);
1870
 
            make_real(op, CMYK[3]);
1871
 
            break;
1872
 
        default:
1873
 
            return_error(e_undefined);
1874
 
    }
1875
 
    return 0;
1876
 
}
1877
 
static int cmykvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
1878
 
{
1879
 
    os_ptr op = osp;
1880
 
    int i;
1881
 
 
1882
 
    if (num_comps < 4)
1883
 
        return_error(e_stackunderflow);
1884
 
 
1885
 
    op -= 3;
1886
 
    for (i=0;i < 4;i++) {
1887
 
        if (!r_has_type(op, t_integer) && !r_has_type(op, t_real))
1888
 
            return_error(e_typecheck);
1889
 
        op++;
1890
 
    }
1891
 
 
1892
 
    for (i=0;i < 4; i++) {
1893
 
        if (values[i] > 1.0)
1894
 
            values[i] = 1.0;
1895
 
 
1896
 
        if (values[i] < 0.0)
1897
 
            values[i] = 0.0;
1898
 
    }
1899
 
 
1900
 
    return 0;
1901
 
}
1902
 
static int cmykinitialproc(i_ctx_t *i_ctx_p, ref *space)
1903
 
{
1904
 
    gs_client_color cc;
1905
 
 
1906
 
    cc.pattern = 0x00;
1907
 
    cc.paint.values[0] = 0;
1908
 
    cc.paint.values[1] = 0;
1909
 
    cc.paint.values[2] = 0;
1910
 
    cc.paint.values[3] = 1;
1911
 
    return gs_setcolor(igs, &cc);
1912
 
}
1913
 
 
1914
 
/* CIEBased */
1915
 
/* A utility routine to check whether two arrays contain the same
1916
 
 * contents. Used to check whether two color spaces are the same
1917
 
 * Note that this can be recursive if the array contains arrays.
1918
 
 */
1919
 
static int comparearrays(i_ctx_t * i_ctx_p, ref *m1, ref *m2)
1920
 
{
1921
 
    int i, code;
1922
 
    ref ref1, ref2;
1923
 
 
1924
 
    if (r_size(m1) != r_size(m2))
1925
 
        return 0;
1926
 
 
1927
 
    for (i=0;i < r_size(m1);i++) {
1928
 
        code = array_get(imemory, m1, i, &ref1);
1929
 
        if (code < 0)
1930
 
            return 0;
1931
 
        code = array_get(imemory, m2, i, &ref2);
1932
 
        if (code < 0)
1933
 
            return 0;
1934
 
 
1935
 
        if (r_type(&ref1) != r_type(&ref2))
1936
 
            return 0;
1937
 
 
1938
 
        code = r_type(&ref1);
1939
 
        switch(r_type(&ref1)) {
1940
 
            case t_null:
1941
 
                break;
1942
 
            case t_boolean:
1943
 
                if (ref1.value.boolval != ref2.value.boolval)
1944
 
                    return 0;
1945
 
                break;
1946
 
            case t_integer:
1947
 
                if (ref1.value.intval != ref2.value.intval)
1948
 
                    return 0;
1949
 
                break;
1950
 
            case t_real:
1951
 
                if (ref1.value.realval != ref2.value.realval)
1952
 
                    return 0;
1953
 
                break;
1954
 
            case t_name:
1955
 
                if (!name_eq(&ref1, &ref2))
1956
 
                    return 0;
1957
 
                break;
1958
 
            case t_string:
1959
 
                if (r_size(&ref1) != r_size(&ref2))
1960
 
                    return 0;
1961
 
                if (strncmp((const char *)ref1.value.const_bytes, (const char *)ref2.value.const_bytes, r_size(&ref1)) != 0)
1962
 
                    return 0;
1963
 
                break;
1964
 
            case t_array:
1965
 
            case t_mixedarray:
1966
 
            case t_shortarray:
1967
 
                if (!comparearrays(i_ctx_p, &ref1, &ref2))
1968
 
                    return 0;
1969
 
                break;
1970
 
            case t_oparray:
1971
 
                break;
1972
 
            case t_operator:
1973
 
                if (ref1.value.opproc != ref2.value.opproc)
1974
 
                    return 0;
1975
 
                break;
1976
 
            case t__invalid:
1977
 
            case t_dictionary:
1978
 
            case t_file:
1979
 
            case t_unused_array_:
1980
 
            case t_struct:
1981
 
            case t_astruct:
1982
 
            case t_fontID:
1983
 
            case t_save:
1984
 
            case t_mark:
1985
 
            case t_device:
1986
 
                return 0;
1987
 
            default:
1988
 
                /* Some high frequency operators are defined starting at t_next_index
1989
 
                 * I think as long as the 'type' of each is the same, we are OK
1990
 
                 */
1991
 
                break;
1992
 
        }
1993
 
    }
1994
 
    return 1;
1995
 
}
1996
 
/* A utility routine to check whether two dictionaries contain the same
1997
 
 * arrays. This is a simple routine, unlike comparearrays above it is only
1998
 
 * used by the CIE comparison code and expects only to check that the
1999
 
 * dictionary contains an array, and checks the arrays.
2000
 
 */
2001
 
static int comparedictkey(i_ctx_t * i_ctx_p, ref *CIEdict1, ref *CIEdict2, char *key)
2002
 
{
2003
 
    int code, code1;
2004
 
    ref *tempref1, *tempref2;
2005
 
 
2006
 
    code = dict_find_string(CIEdict1, key, &tempref1);
2007
 
    code1 = dict_find_string(CIEdict2, key, &tempref2);
2008
 
    if (code != code1)
2009
 
        return 0;
2010
 
 
2011
 
    if (code < 0)
2012
 
        return 1;
2013
 
 
2014
 
    if (r_type(tempref1) != r_type(tempref2))
2015
 
        return 0;
2016
 
 
2017
 
    if (r_type(tempref1) == t_null)
2018
 
        return 1;
2019
 
 
2020
 
    return comparearrays(i_ctx_p, tempref1, tempref2);
2021
 
}
2022
 
 
2023
 
/* Check that the WhitePoint of a CIE space is valid */
2024
 
static int checkWhitePoint(i_ctx_t * i_ctx_p, ref *CIEdict)
2025
 
{
2026
 
    int code = 0, i;
2027
 
    float value[3];
2028
 
    ref *tempref, valref;
2029
 
 
2030
 
    code = dict_find_string(CIEdict, "WhitePoint", &tempref);
2031
 
    if (code < 0 || r_has_type(tempref, t_null))
2032
 
        return code;
2033
 
 
2034
 
    if (!r_is_array(tempref))
2035
 
        return_error(e_typecheck);
2036
 
    if (r_size(tempref) != 3)
2037
 
        return_error(e_rangecheck);
2038
 
 
2039
 
    for (i=0;i<3;i++) {
2040
 
        code = array_get(imemory, tempref, i, &valref);
2041
 
        if (code < 0)
2042
 
            return code;
2043
 
        if (r_has_type(&valref, t_integer))
2044
 
            value[i] = (float)valref.value.intval;
2045
 
        else if (r_has_type(&valref, t_real))
2046
 
            value[i] = (float)valref.value.realval;
2047
 
        else
2048
 
            return_error(e_typecheck);
2049
 
    }
2050
 
    /* Xw and Zw must be positive and Yw must be 1 (3rd edition PLRM p230) */
2051
 
    if (value[0] < 0 || value[1] != 1 || value[2] < 0 )
2052
 
            return_error(e_rangecheck);
2053
 
 
2054
 
    return 0;
2055
 
}
2056
 
/* Check that the BlackPoint of a CIE space is valid */
2057
 
static int checkBlackPoint(i_ctx_t * i_ctx_p, ref *CIEdict)
2058
 
{
2059
 
    int code = 0, i;
2060
 
    float value[3];
2061
 
    ref *tempref, valref;
2062
 
 
2063
 
    code = dict_find_string(CIEdict, "BlackPoint", &tempref);
2064
 
    if (code >= 0 && !r_has_type(tempref, t_null)) {
2065
 
        if (!r_is_array(tempref))
2066
 
            return_error(e_typecheck);
2067
 
        if (r_size(tempref) != 3)
2068
 
            return_error(e_rangecheck);
2069
 
 
2070
 
        for (i=0;i<3;i++) {
2071
 
            code = array_get(imemory, tempref, i, &valref);
2072
 
            if (code < 0)
2073
 
                return code;
2074
 
            if (r_has_type(&valref, t_integer))
2075
 
                value[i] = (float)valref.value.intval;
2076
 
            else if (r_has_type(&valref, t_real))
2077
 
                value[i] = (float)valref.value.realval;
2078
 
            else
2079
 
                return_error(e_typecheck);
2080
 
        }
2081
 
    }
2082
 
    return 0;
2083
 
}
2084
 
/* Check that the RangeLMN of a CIE space is valid */
2085
 
static int checkRangeLMN(i_ctx_t * i_ctx_p, ref *CIEdict)
2086
 
{
2087
 
    int code = 0, i;
2088
 
    float value[6];
2089
 
    ref *tempref, valref;
2090
 
 
2091
 
    code = dict_find_string(CIEdict, "RangeLMN", &tempref);
2092
 
    if (code >= 0 && !r_has_type(tempref, t_null)) {
2093
 
        if (!r_is_array(tempref))
2094
 
            return_error(e_typecheck);
2095
 
        if (r_size(tempref) != 6)
2096
 
            return_error(e_rangecheck);
2097
 
 
2098
 
        for (i=0;i<6;i++) {
2099
 
            code = array_get(imemory, tempref, i, &valref);
2100
 
            if (code < 0)
2101
 
                return code;
2102
 
            if (r_has_type(&valref, t_integer))
2103
 
                value[i] = (float)valref.value.intval;
2104
 
            else if (r_has_type(&valref, t_real))
2105
 
                value[i] = (float)valref.value.realval;
2106
 
            else
2107
 
                return_error(e_typecheck);
2108
 
        }
2109
 
        if (value[1] < value[0] || value[3] < value[2] || value[5] < value[4])
2110
 
            return_error(e_rangecheck);
2111
 
    }
2112
 
    return 0;
2113
 
}
2114
 
/* Check that the DecodeLMN of a CIE space is valid */
2115
 
static int checkDecodeLMN(i_ctx_t * i_ctx_p, ref *CIEdict)
2116
 
{
2117
 
    int code = 0, i;
2118
 
    ref *tempref, valref;
2119
 
 
2120
 
    code = dict_find_string(CIEdict, "DecodeLMN", &tempref);
2121
 
    if (code >= 0 && !r_has_type(tempref, t_null)) {
2122
 
        if (!r_is_array(tempref))
2123
 
            return_error(e_typecheck);
2124
 
        if (r_size(tempref) != 3)
2125
 
            return_error(e_rangecheck);
2126
 
 
2127
 
        for (i=0;i<3;i++) {
2128
 
            code = array_get(imemory, tempref, i, &valref);
2129
 
            if (code < 0)
2130
 
                return code;
2131
 
            check_proc(valref);
2132
 
        }
2133
 
    }
2134
 
    return 0;
2135
 
}
2136
 
/* Check that the MatrixLMN of a CIE space is valid */
2137
 
static int checkMatrixLMN(i_ctx_t * i_ctx_p, ref *CIEdict)
2138
 
{
2139
 
    int code = 0, i;
2140
 
    float value[9];
2141
 
    ref *tempref, valref;
2142
 
 
2143
 
    code = dict_find_string(CIEdict, "MatrixLMN", &tempref);
2144
 
    if (code >= 0 && !r_has_type(tempref, t_null)) {
2145
 
        if (!r_is_array(tempref))
2146
 
            return_error(e_typecheck);
2147
 
        if (r_size(tempref) != 9)
2148
 
            return_error(e_rangecheck);
2149
 
 
2150
 
        for (i=0;i<9;i++) {
2151
 
            code = array_get(imemory, tempref, i, &valref);
2152
 
            if (code < 0)
2153
 
                return code;
2154
 
            if (r_has_type(&valref, t_integer))
2155
 
                value[i] = (float)valref.value.intval;
2156
 
            else if (r_has_type(&valref, t_real))
2157
 
                value[i] = (float)valref.value.realval;
2158
 
            else
2159
 
                return_error(e_typecheck);
2160
 
        }
2161
 
    }
2162
 
    return 0;
2163
 
}
2164
 
 
2165
 
/* CIEBasedA */
2166
 
static int setcieaspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
2167
 
{
2168
 
    int code = 0;
2169
 
    ref CIEDict, *nocie;
2170
 
    ulong dictkey;
2171
 
 
2172
 
    if (i_ctx_p->language_level < 2)
2173
 
        return_error(e_undefined);
2174
 
 
2175
 
    code = dict_find_string(systemdict, "NOCIE", &nocie);
2176
 
    if (code < 0)
2177
 
        return code;
2178
 
    if (!r_has_type(nocie, t_boolean))
2179
 
        return_error(e_typecheck);
2180
 
    if (nocie->value.boolval)
2181
 
        return setgrayspace(i_ctx_p, r, stage, cont, 1);
2182
 
 
2183
 
    *cont = 0;
2184
 
    code = array_get(imemory, r, 1, &CIEDict);
2185
 
    if (code < 0)
2186
 
        return code;
2187
 
    if ((*stage) > 0) {
2188
 
        gs_client_color cc;
2189
 
 
2190
 
        cc.pattern = 0x00;
2191
 
        cc.paint.values[0] = 0;
2192
 
        code = gs_setcolor(igs, &cc);
2193
 
        *stage = 0;
2194
 
        return code;
2195
 
    }
2196
 
    dictkey = r->value.refs->value.saveid;
2197
 
    code = cieaspace(i_ctx_p, &CIEDict, dictkey);
2198
 
    (*stage)++;
2199
 
    *cont = 1;
2200
 
    return code;
2201
 
}
2202
 
static int validatecieaspace(i_ctx_t * i_ctx_p, ref **r)
2203
 
{
2204
 
    int code = 0, i;
2205
 
    float value[9];
2206
 
    ref     CIEdict, *CIEspace = *r, *tempref, valref;
2207
 
 
2208
 
    if (!r_is_array(CIEspace))
2209
 
        return_error(e_typecheck);
2210
 
    /* Validate parameters, check we have enough operands */
2211
 
    if (r_size(CIEspace) != 2)
2212
 
        return_error(e_rangecheck);
2213
 
 
2214
 
    code = array_get(imemory, CIEspace, 1, &CIEdict);
2215
 
    if (code < 0)
2216
 
        return code;
2217
 
 
2218
 
    check_read_type(CIEdict, t_dictionary);
2219
 
 
2220
 
    /* Check white point exists, and is an array of three numbers */
2221
 
    code = checkWhitePoint(i_ctx_p, &CIEdict);
2222
 
    if (code != 0)
2223
 
        return code;
2224
 
 
2225
 
    /* Remaining parameters are optional, but we must validate
2226
 
     * them if they are present
2227
 
     */
2228
 
    code = dict_find_string(&CIEdict, "RangeA", &tempref);
2229
 
    if (code >= 0 && !r_has_type(tempref, t_null)) {
2230
 
        /* Array of two numbers A0 < A1 */
2231
 
        if (!r_is_array(tempref))
2232
 
            return_error(e_typecheck);
2233
 
        if (r_size(tempref) != 2)
2234
 
            return_error(e_rangecheck);
2235
 
 
2236
 
        for (i=0;i<2;i++) {
2237
 
            code = array_get(imemory, tempref, i, &valref);
2238
 
            if (code < 0)
2239
 
                return code;
2240
 
            if (r_has_type(&valref, t_integer))
2241
 
                value[i] = (float)valref.value.intval;
2242
 
            else if (r_has_type(&valref, t_real))
2243
 
                value[i] = (float)valref.value.realval;
2244
 
            else
2245
 
                return_error(e_typecheck);
2246
 
        }
2247
 
        if (value[1] < value[0])
2248
 
            return_error(e_rangecheck);
2249
 
    }
2250
 
 
2251
 
    code = dict_find_string(&CIEdict, "DecodeA", &tempref);
2252
 
    if (code >= 0 && !r_has_type(tempref, t_null)) {
2253
 
        check_proc(*tempref);
2254
 
    }
2255
 
 
2256
 
    code = dict_find_string(&CIEdict, "MatrixA", &tempref);
2257
 
    if (code >= 0 && !r_has_type(tempref, t_null)) {
2258
 
        if (!r_is_array(tempref))
2259
 
            return_error(e_typecheck);
2260
 
        if (r_size(tempref) != 3)
2261
 
            return_error(e_rangecheck);
2262
 
 
2263
 
        for (i=0;i<3;i++) {
2264
 
            code = array_get(imemory, tempref, i, &valref);
2265
 
            if (code < 0)
2266
 
                return code;
2267
 
            if (r_has_type(&valref, t_integer))
2268
 
                value[i] = (float)valref.value.intval;
2269
 
            else if (r_has_type(&valref, t_real))
2270
 
                value[i] = (float)valref.value.realval;
2271
 
            else
2272
 
                return_error(e_typecheck);
2273
 
        }
2274
 
    }
2275
 
 
2276
 
    code = checkRangeLMN(i_ctx_p, &CIEdict);
2277
 
    if (code != 0)
2278
 
        return code;
2279
 
 
2280
 
    code = checkDecodeLMN(i_ctx_p, &CIEdict);
2281
 
    if (code != 0)
2282
 
        return code;
2283
 
 
2284
 
    code = checkMatrixLMN(i_ctx_p, &CIEdict);
2285
 
    if (code != 0)
2286
 
        return code;
2287
 
 
2288
 
    code = checkBlackPoint(i_ctx_p, &CIEdict);
2289
 
    if (code != 0)
2290
 
        return code;
2291
 
 
2292
 
    *r = 0;
2293
 
    return 0;
2294
 
}
2295
 
static int cieadomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
2296
 
{
2297
 
    int i, code;
2298
 
    ref     CIEdict, *tempref, valref;
2299
 
 
2300
 
    code = array_get(imemory, space, 1, &CIEdict);
2301
 
    if (code < 0)
2302
 
        return code;
2303
 
 
2304
 
    /* If we have a RangeA entry in the dictionary, get the
2305
 
     * values from that
2306
 
     */
2307
 
    code = dict_find_string(&CIEdict, "RangeA", &tempref);
2308
 
    if (code >= 0 && !r_has_type(tempref, t_null)) {
2309
 
        for (i=0;i<2;i++) {
2310
 
            code = array_get(imemory, tempref, i, &valref);
2311
 
            if (code < 0)
2312
 
                return code;
2313
 
            if (r_has_type(&valref, t_integer))
2314
 
                ptr[i] = (float)valref.value.intval;
2315
 
            else if (r_has_type(&valref, t_real))
2316
 
                ptr[i] = (float)valref.value.realval;
2317
 
            else
2318
 
                return_error(e_typecheck);
2319
 
        }
2320
 
    } else {
2321
 
        /* Default values for CIEBasedA */
2322
 
        ptr[0] = 0;
2323
 
        ptr[1] = 1;
2324
 
    }
2325
 
    return 0;
2326
 
}
2327
 
static int ciearange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
2328
 
{
2329
 
    int i, code;
2330
 
    ref     CIEdict, *tempref, valref;
2331
 
 
2332
 
    code = array_get(imemory, space, 1, &CIEdict);
2333
 
    if (code < 0)
2334
 
        return code;
2335
 
 
2336
 
    /* If we have a RangeA entry in the dictionary, get the
2337
 
     * values from that
2338
 
     */
2339
 
    code = dict_find_string(&CIEdict, "RangeA", &tempref);
2340
 
    if (code >= 0 && !r_has_type(tempref, t_null)) {
2341
 
        for (i=0;i<2;i++) {
2342
 
            code = array_get(imemory, tempref, i, &valref);
2343
 
            if (code < 0)
2344
 
                return code;
2345
 
            if (r_has_type(&valref, t_integer))
2346
 
                ptr[i] = (float)valref.value.intval;
2347
 
            else if (r_has_type(&valref, t_real))
2348
 
                ptr[i] = (float)valref.value.realval;
2349
 
            else
2350
 
                return_error(e_typecheck);
2351
 
        }
2352
 
    } else {
2353
 
        /* Default values for CIEBasedA */
2354
 
        ptr[0] = 0;
2355
 
        ptr[1] = 1;
2356
 
    }
2357
 
    return 0;
2358
 
}
2359
 
static int cieavalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
2360
 
{
2361
 
    os_ptr op = osp;
2362
 
 
2363
 
    if (num_comps < 1)
2364
 
        return_error(e_stackunderflow);
2365
 
 
2366
 
    if (!r_has_type(op, t_integer) && !r_has_type(op, t_real))
2367
 
        return_error(e_typecheck);
2368
 
 
2369
 
    return 0;
2370
 
}
2371
 
static int cieacompareproc(i_ctx_t *i_ctx_p, ref *space, ref *testspace)
2372
 
{
2373
 
    int code = 0;
2374
 
    ref CIEdict1, CIEdict2;
2375
 
 
2376
 
    code = array_get(imemory, space, 1, &CIEdict1);
2377
 
    if (code < 0)
2378
 
        return 0;
2379
 
    code = array_get(imemory, testspace, 1, &CIEdict2);
2380
 
    if (code < 0)
2381
 
        return 0;
2382
 
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"WhitePoint"))
2383
 
        return 0;
2384
 
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"BlackPoint"))
2385
 
        return 0;
2386
 
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeA"))
2387
 
        return 0;
2388
 
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"DecodeA"))
2389
 
        return 0;
2390
 
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"MatrixA"))
2391
 
        return 0;
2392
 
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeLMN"))
2393
 
        return 0;
2394
 
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"DecodeLMN"))
2395
 
        return 0;
2396
 
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"MatrixMN"))
2397
 
        return 0;
2398
 
    return 1;
2399
 
}
2400
 
 
2401
 
/* CIEBasedABC */
2402
 
static int setcieabcspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
2403
 
{
2404
 
    int code = 0;
2405
 
    ref CIEDict, *nocie;
2406
 
    ulong dictkey;
2407
 
 
2408
 
    if (i_ctx_p->language_level < 2)
2409
 
        return_error(e_undefined);
2410
 
 
2411
 
    code = dict_find_string(systemdict, "NOCIE", &nocie);
2412
 
    if (code < 0)
2413
 
        return code;
2414
 
    if (!r_has_type(nocie, t_boolean))
2415
 
        return_error(e_typecheck);
2416
 
    if (nocie->value.boolval)
2417
 
        return setrgbspace(i_ctx_p, r, stage, cont, 1);
2418
 
 
2419
 
    *cont = 0;
2420
 
    code = array_get(imemory, r, 1, &CIEDict);
2421
 
    if (code < 0)
2422
 
        return code;
2423
 
 
2424
 
    if ((*stage) > 0) {
2425
 
        gs_client_color cc;
2426
 
        int i;
2427
 
 
2428
 
        cc.pattern = 0x00;
2429
 
        for (i=0;i<3;i++)
2430
 
            cc.paint.values[i] = 0;
2431
 
        code = gs_setcolor(igs, &cc);
2432
 
        *stage = 0;
2433
 
        return code;
2434
 
    }
2435
 
    dictkey = r->value.refs->value.saveid;
2436
 
    code = cieabcspace(i_ctx_p, &CIEDict,dictkey);
2437
 
    *cont = 1;
2438
 
    (*stage)++;
2439
 
    return code;
2440
 
}
2441
 
static int validatecieabcspace(i_ctx_t * i_ctx_p, ref **r)
2442
 
{
2443
 
    int code = 0, i;
2444
 
    float value[9];
2445
 
    ref     CIEdict, *CIEspace = *r, *tempref, valref;
2446
 
 
2447
 
    if (!r_is_array(CIEspace))
2448
 
        return_error(e_typecheck);
2449
 
    /* Validate parameters, check we have enough operands */
2450
 
    if (r_size(CIEspace) != 2)
2451
 
        return_error(e_rangecheck);
2452
 
 
2453
 
    code = array_get(imemory, CIEspace, 1, &CIEdict);
2454
 
    if (code < 0)
2455
 
        return code;
2456
 
    check_read_type(CIEdict, t_dictionary);
2457
 
 
2458
 
    /* Check white point exists, and is an array of three numbers */
2459
 
    code = checkWhitePoint(i_ctx_p, &CIEdict);
2460
 
    if (code != 0)
2461
 
        return code;
2462
 
 
2463
 
    /* Remaining parameters are optional, but we must validate
2464
 
     * them if they are present
2465
 
     */
2466
 
    code = dict_find_string(&CIEdict, "RangeABC", &tempref);
2467
 
    if (code >= 0 && !r_has_type(tempref, t_null)) {
2468
 
        if (!r_is_array(tempref))
2469
 
            return_error(e_typecheck);
2470
 
        if (r_size(tempref) != 6)
2471
 
            return_error(e_rangecheck);
2472
 
 
2473
 
        for (i=0;i<6;i++) {
2474
 
            code = array_get(imemory, tempref, i, &valref);
2475
 
            if (code < 0)
2476
 
                return code;
2477
 
            if (r_has_type(&valref, t_integer))
2478
 
                value[i] = (float)valref.value.intval;
2479
 
            else if (r_has_type(&valref, t_real))
2480
 
                value[i] = (float)valref.value.realval;
2481
 
            else
2482
 
                return_error(e_typecheck);
2483
 
        }
2484
 
        if (value[1] < value[0] || value[3] < value[2] || value[5] < value[4])
2485
 
            return_error(e_rangecheck);
2486
 
    }
2487
 
 
2488
 
    code = dict_find_string(&CIEdict, "DecodeABC", &tempref);
2489
 
    if (code >= 0 && !r_has_type(tempref, t_null)) {
2490
 
        if (!r_is_array(tempref))
2491
 
            return_error(e_typecheck);
2492
 
        if (r_size(tempref) != 3)
2493
 
            return_error(e_rangecheck);
2494
 
 
2495
 
        for (i=0;i<3;i++) {
2496
 
            code = array_get(imemory, tempref, i, &valref);
2497
 
            if (code < 0)
2498
 
                return code;
2499
 
            check_proc(valref);
2500
 
        }
2501
 
    }
2502
 
 
2503
 
    code = dict_find_string(&CIEdict, "MatrixABC", &tempref);
2504
 
    if (code >= 0 && !r_has_type(tempref, t_null)) {
2505
 
        if (!r_is_array(tempref))
2506
 
            return_error(e_typecheck);
2507
 
        if (r_size(tempref) != 9)
2508
 
            return_error(e_rangecheck);
2509
 
 
2510
 
        for (i=0;i<9;i++) {
2511
 
            code = array_get(imemory, tempref, i, &valref);
2512
 
            if (code < 0)
2513
 
                return code;
2514
 
            if (r_has_type(&valref, t_integer))
2515
 
                value[i] = (float)valref.value.intval;
2516
 
            else if (r_has_type(&valref, t_real))
2517
 
                value[i] = (float)valref.value.realval;
2518
 
            else
2519
 
                return_error(e_typecheck);
2520
 
        }
2521
 
    }
2522
 
 
2523
 
 
2524
 
    code = checkRangeLMN(i_ctx_p, &CIEdict);
2525
 
    if (code != 0)
2526
 
        return code;
2527
 
 
2528
 
    code = checkDecodeLMN(i_ctx_p, &CIEdict);
2529
 
    if (code != 0)
2530
 
        return code;
2531
 
 
2532
 
    code = checkMatrixLMN(i_ctx_p, &CIEdict);
2533
 
    if (code != 0)
2534
 
        return code;
2535
 
 
2536
 
    code = checkBlackPoint(i_ctx_p, &CIEdict);
2537
 
    if (code != 0)
2538
 
        return code;
2539
 
 
2540
 
    *r = 0;
2541
 
    return 0;
2542
 
}
2543
 
static int cieabcdomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
2544
 
{
2545
 
    int i, code;
2546
 
    ref     CIEdict, *tempref, valref;
2547
 
 
2548
 
    code = array_get(imemory, space, 1, &CIEdict);
2549
 
    if (code < 0)
2550
 
        return code;
2551
 
 
2552
 
    /* If we have a RangeABC, get the values from that */
2553
 
    code = dict_find_string(&CIEdict, "RangeABC", &tempref);
2554
 
    if (code >= 0 && !r_has_type(tempref, t_null)) {
2555
 
        for (i=0;i<6;i++) {
2556
 
            code = array_get(imemory, tempref, i, &valref);
2557
 
            if (code < 0)
2558
 
                return code;
2559
 
            if (r_has_type(&valref, t_integer))
2560
 
                ptr[i] = (float)valref.value.intval;
2561
 
            else if (r_has_type(&valref, t_real))
2562
 
                ptr[i] = (float)valref.value.realval;
2563
 
            else
2564
 
                return_error(e_typecheck);
2565
 
        }
2566
 
    } else {
2567
 
        /* Default values for CIEBasedABC */
2568
 
        for (i=0;i<3;i++) {
2569
 
            ptr[2 * i] = 0;
2570
 
            ptr[(2 * i) + 1] = 1;
2571
 
        }
2572
 
    }
2573
 
    return 0;
2574
 
}
2575
 
static int cieabcrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
2576
 
{
2577
 
    int i, code;
2578
 
    ref     CIEdict, *tempref, valref;
2579
 
 
2580
 
    code = array_get(imemory, space, 1, &CIEdict);
2581
 
    if (code < 0)
2582
 
        return code;
2583
 
 
2584
 
    /* If we have a RangeABC, get the values from that */
2585
 
    code = dict_find_string(&CIEdict, "RangeABC", &tempref);
2586
 
    if (code >= 0 && !r_has_type(tempref, t_null)) {
2587
 
        for (i=0;i<6;i++) {
2588
 
            code = array_get(imemory, tempref, i, &valref);
2589
 
            if (code < 0)
2590
 
                return code;
2591
 
            if (r_has_type(&valref, t_integer))
2592
 
                ptr[i] = (float)valref.value.intval;
2593
 
            else if (r_has_type(&valref, t_real))
2594
 
                ptr[i] = (float)valref.value.realval;
2595
 
            else
2596
 
                return_error(e_typecheck);
2597
 
        }
2598
 
    } else {
2599
 
        /* Default values for CIEBasedABC */
2600
 
        for (i=0;i<3;i++) {
2601
 
            ptr[2 * i] = 0;
2602
 
            ptr[(2 * i) + 1] = 1;
2603
 
        }
2604
 
    }
2605
 
    return 0;
2606
 
}
2607
 
static int cieabcvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
2608
 
{
2609
 
    os_ptr op = osp;
2610
 
    int i;
2611
 
 
2612
 
    if (num_comps < 3)
2613
 
        return_error(e_stackunderflow);
2614
 
 
2615
 
    op -= 2;
2616
 
    for (i=0;i<3;i++) {
2617
 
        if (!r_has_type(op, t_integer) && !r_has_type(op, t_real))
2618
 
            return_error(e_typecheck);
2619
 
        op++;
2620
 
    }
2621
 
 
2622
 
    return 0;
2623
 
}
2624
 
static int cieabccompareproc(i_ctx_t *i_ctx_p, ref *space, ref *testspace)
2625
 
{
2626
 
    int code = 0;
2627
 
    ref CIEdict1, CIEdict2;
2628
 
 
2629
 
    code = array_get(imemory, space, 1, &CIEdict1);
2630
 
    if (code < 0)
2631
 
        return 0;
2632
 
    code = array_get(imemory, testspace, 1, &CIEdict2);
2633
 
    if (code < 0)
2634
 
        return 0;
2635
 
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"WhitePoint"))
2636
 
        return 0;
2637
 
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"BlackPoint"))
2638
 
        return 0;
2639
 
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeABC"))
2640
 
        return 0;
2641
 
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"DecodeABC"))
2642
 
        return 0;
2643
 
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"MatrixABC"))
2644
 
        return 0;
2645
 
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeLMN"))
2646
 
        return 0;
2647
 
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"DecodeLMN"))
2648
 
        return 0;
2649
 
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"MatrixMN"))
2650
 
        return 0;
2651
 
    return 1;
2652
 
}
2653
 
 
2654
 
/* CIEBasedDEF */
2655
 
static int setciedefspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
2656
 
{
2657
 
    int code = 0;
2658
 
    ref CIEDict, *nocie;
2659
 
    ulong dictkey;
2660
 
 
2661
 
    if (i_ctx_p->language_level < 3)
2662
 
        return_error(e_undefined);
2663
 
 
2664
 
    code = dict_find_string(systemdict, "NOCIE", &nocie);
2665
 
    if (code < 0)
2666
 
        return code;
2667
 
    if (!r_has_type(nocie, t_boolean))
2668
 
        return_error(e_typecheck);
2669
 
    if (nocie->value.boolval)
2670
 
        return setrgbspace(i_ctx_p, r, stage, cont, 1);
2671
 
 
2672
 
    *cont = 0;
2673
 
    code = array_get(imemory, r, 1, &CIEDict);
2674
 
    if (code < 0)
2675
 
        return code;
2676
 
    if ((*stage) > 0) {
2677
 
        gs_client_color cc;
2678
 
        int i;
2679
 
 
2680
 
        cc.pattern = 0x00;
2681
 
        for (i=0;i<3;i++)
2682
 
            cc.paint.values[i] = 0;
2683
 
        code = gs_setcolor(igs, &cc);
2684
 
        *stage = 0;
2685
 
        return code;
2686
 
    }
2687
 
    dictkey = r->value.refs->value.saveid;
2688
 
    code = ciedefspace(i_ctx_p, &CIEDict, dictkey);
2689
 
    *cont = 1;
2690
 
    (*stage)++;
2691
 
    return code;
2692
 
}
2693
 
static int validateciedefspace(i_ctx_t * i_ctx_p, ref **r)
2694
 
{
2695
 
    int code = 0, i;
2696
 
    float value[6];
2697
 
    ref     CIEdict, *pref, *CIEspace = *r, tempref, valref;
2698
 
 
2699
 
    if (!r_is_array(CIEspace))
2700
 
        return_error(e_typecheck);
2701
 
    /* Validate parameters, check we have enough operands */
2702
 
    if (r_size(CIEspace) != 2)
2703
 
        return_error(e_rangecheck);
2704
 
 
2705
 
    code = array_get(imemory, CIEspace, 1, &CIEdict);
2706
 
    if (code < 0)
2707
 
        return code;
2708
 
    check_read_type(CIEdict, t_dictionary);
2709
 
 
2710
 
    code = validatecieabcspace(i_ctx_p, r);
2711
 
    if (code != 0)
2712
 
        return code;
2713
 
 
2714
 
    pref = &tempref;
2715
 
    code = dict_find_string(&CIEdict, "Table", &pref);
2716
 
    if (code >= 0) {
2717
 
        if (!r_is_array(pref))
2718
 
            return_error(e_typecheck);
2719
 
        if (r_size(pref) != 4)
2720
 
            return_error(e_rangecheck);
2721
 
 
2722
 
        for (i=0;i<3;i++) {
2723
 
            code = array_get(imemory, pref, i, &valref);
2724
 
            if (code < 0)
2725
 
                return code;
2726
 
            if (r_has_type(&valref, t_integer))
2727
 
                value[i] = (float)valref.value.intval;
2728
 
            else
2729
 
                return_error(e_typecheck);
2730
 
        }
2731
 
        if (value[0] <= 1 || value[1] <= 1 || value[2] <= 1)
2732
 
            return_error(e_rangecheck);
2733
 
 
2734
 
        code = array_get(imemory, pref, 3, &valref);
2735
 
        if (code < 0)
2736
 
            return code;
2737
 
        if (!r_is_array(&valref))
2738
 
            return_error(e_typecheck);
2739
 
        if (r_size(&valref) != value[0])
2740
 
            return_error(e_rangecheck);
2741
 
 
2742
 
        for (i=0;i<value[0];i++) {
2743
 
            code = array_get(imemory, &valref, i, &tempref);
2744
 
            if (code < 0)
2745
 
                return code;
2746
 
            if (!r_has_type(&tempref, t_string))
2747
 
                return_error(e_typecheck);
2748
 
 
2749
 
            if (r_size(&tempref) != (3 * value[1] * value[2]))
2750
 
                return_error(e_rangecheck);
2751
 
        }
2752
 
    } else {
2753
 
        return_error(e_rangecheck);
2754
 
    }
2755
 
 
2756
 
    /* Remaining parameters are optional, but we must validate
2757
 
     * them if they are present
2758
 
     */
2759
 
    code = dict_find_string(&CIEdict, "RangeDEF", &pref);
2760
 
    if (code >= 0 && !r_has_type(&tempref, t_null)) {
2761
 
        if (!r_is_array(pref))
2762
 
            return_error(e_typecheck);
2763
 
        if (r_size(pref) != 6)
2764
 
            return_error(e_rangecheck);
2765
 
 
2766
 
        for (i=0;i<6;i++) {
2767
 
            code = array_get(imemory, pref, i, &valref);
2768
 
            if (code < 0)
2769
 
                return code;
2770
 
            if (r_has_type(&valref, t_integer))
2771
 
                value[i] = (float)valref.value.intval;
2772
 
            else if (r_has_type(&valref, t_real))
2773
 
                value[i] = (float)valref.value.realval;
2774
 
            else
2775
 
                return_error(e_typecheck);
2776
 
        }
2777
 
        if (value[1] < value[0] || value[3] < value[2] || value[5] < value[4])
2778
 
            return_error(e_rangecheck);
2779
 
    }
2780
 
 
2781
 
    code = dict_find_string(&CIEdict, "DecodeDEF", &pref);
2782
 
    if (code >= 0 && !r_has_type(pref, t_null)) {
2783
 
        if (!r_is_array(pref))
2784
 
            return_error(e_typecheck);
2785
 
        if (r_size(pref) != 3)
2786
 
            return_error(e_rangecheck);
2787
 
 
2788
 
        for (i=0;i<3;i++) {
2789
 
            code = array_get(imemory, pref, i, &valref);
2790
 
            if (code < 0)
2791
 
                return code;
2792
 
            check_proc(valref);
2793
 
        }
2794
 
    }
2795
 
 
2796
 
    code = dict_find_string(&CIEdict, "RangeHIJ", &pref);
2797
 
    if (code >= 0 && !r_has_type(pref, t_null)) {
2798
 
        if (!r_is_array(pref))
2799
 
            return_error(e_typecheck);
2800
 
        if (r_size(pref) != 6)
2801
 
            return_error(e_rangecheck);
2802
 
 
2803
 
        for (i=0;i<6;i++) {
2804
 
            code = array_get(imemory, pref, i, &valref);
2805
 
            if (code < 0)
2806
 
                return code;
2807
 
            if (r_has_type(&valref, t_integer))
2808
 
                value[i] = (float)valref.value.intval;
2809
 
            else if (r_has_type(&valref, t_real))
2810
 
                value[i] = (float)valref.value.realval;
2811
 
            else
2812
 
                return_error(e_typecheck);
2813
 
        }
2814
 
        if (value[1] < value[0] || value[3] < value[2] || value[5] < value[4])
2815
 
            return_error(e_rangecheck);
2816
 
    }
2817
 
 
2818
 
    *r = 0;
2819
 
    return 0;
2820
 
}
2821
 
static int ciedefdomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
2822
 
{
2823
 
    int i, code;
2824
 
    ref     CIEdict, *tempref, valref;
2825
 
 
2826
 
    code = array_get(imemory, space, 1, &CIEdict);
2827
 
    if (code < 0)
2828
 
        return code;
2829
 
 
2830
 
    /* If we have a RangeDEF, get the values from that */
2831
 
    code = dict_find_string(&CIEdict, "RangeDEF", &tempref);
2832
 
    if (code >= 0 && !r_has_type(tempref, t_null)) {
2833
 
        for (i=0;i<6;i++) {
2834
 
            code = array_get(imemory, tempref, i, &valref);
2835
 
            if (code < 0)
2836
 
                return code;
2837
 
            if (r_has_type(&valref, t_integer))
2838
 
                ptr[i] = (float)valref.value.intval;
2839
 
            else if (r_has_type(&valref, t_real))
2840
 
                ptr[i] = (float)valref.value.realval;
2841
 
            else
2842
 
                return_error(e_typecheck);
2843
 
        }
2844
 
    } else {
2845
 
        /* Default values for a CIEBasedDEF */
2846
 
        for (i=0;i<3;i++) {
2847
 
            ptr[2 * i] = 0;
2848
 
            ptr[(2 * i) + 1] = 1;
2849
 
        }
2850
 
    }
2851
 
    return 0;
2852
 
}
2853
 
static int ciedefrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
2854
 
{
2855
 
    int i, code;
2856
 
    ref     CIEdict, *tempref, valref;
2857
 
 
2858
 
    code = array_get(imemory, space, 1, &CIEdict);
2859
 
    if (code < 0)
2860
 
        return code;
2861
 
 
2862
 
    /* If we have a RangeDEF, get the values from that */
2863
 
    code = dict_find_string(&CIEdict, "RangeDEF", &tempref);
2864
 
    if (code >= 0 && !r_has_type(tempref, t_null)) {
2865
 
        for (i=0;i<6;i++) {
2866
 
            code = array_get(imemory, tempref, i, &valref);
2867
 
            if (code < 0)
2868
 
                return code;
2869
 
            if (r_has_type(&valref, t_integer))
2870
 
                ptr[i] = (float)valref.value.intval;
2871
 
            else if (r_has_type(&valref, t_real))
2872
 
                ptr[i] = (float)valref.value.realval;
2873
 
            else
2874
 
                return_error(e_typecheck);
2875
 
        }
2876
 
    } else {
2877
 
        /* Default values for a CIEBasedDEF */
2878
 
        for (i=0;i<3;i++) {
2879
 
            ptr[2 * i] = 0;
2880
 
            ptr[(2 * i) + 1] = 1;
2881
 
        }
2882
 
    }
2883
 
    return 0;
2884
 
}
2885
 
static int ciedefvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
2886
 
{
2887
 
    os_ptr op = osp;
2888
 
    int i;
2889
 
 
2890
 
    if (num_comps < 3)
2891
 
        return_error(e_stackunderflow);
2892
 
 
2893
 
    op -= 2;
2894
 
    for (i=0;i<3;i++) {
2895
 
        if (!r_has_type(op, t_integer) && !r_has_type(op, t_real))
2896
 
            return_error(e_typecheck);
2897
 
        op++;
2898
 
    }
2899
 
 
2900
 
    return 0;
2901
 
}
2902
 
static int ciedefcompareproc(i_ctx_t *i_ctx_p, ref *space, ref *testspace)
2903
 
{
2904
 
    int code = 0;
2905
 
    ref CIEdict1, CIEdict2;
2906
 
 
2907
 
    code = array_get(imemory, space, 1, &CIEdict1);
2908
 
    if (code < 0)
2909
 
        return 0;
2910
 
    code = array_get(imemory, testspace, 1, &CIEdict2);
2911
 
    if (code < 0)
2912
 
        return 0;
2913
 
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"WhitePoint"))
2914
 
        return 0;
2915
 
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"BlackPoint"))
2916
 
        return 0;
2917
 
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeABC"))
2918
 
        return 0;
2919
 
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"DecodeABC"))
2920
 
        return 0;
2921
 
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"MatrixABC"))
2922
 
        return 0;
2923
 
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeLMN"))
2924
 
        return 0;
2925
 
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"DecodeLMN"))
2926
 
        return 0;
2927
 
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"MatrixMN"))
2928
 
        return 0;
2929
 
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeDEF"))
2930
 
        return 0;
2931
 
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"DecodeDEF"))
2932
 
        return 0;
2933
 
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeHIJ"))
2934
 
        return 0;
2935
 
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"Table"))
2936
 
        return 0;
2937
 
    return 1;
2938
 
}
2939
 
 
2940
 
/* CIEBasedDEFG */
2941
 
static int setciedefgspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
2942
 
{
2943
 
    int code = 0;
2944
 
    ref CIEDict, *nocie;
2945
 
    ulong dictkey;
2946
 
 
2947
 
    if (i_ctx_p->language_level < 3)
2948
 
        return_error(e_undefined);
2949
 
 
2950
 
    code = dict_find_string(systemdict, "NOCIE", &nocie);
2951
 
    if (code < 0)
2952
 
        return code;
2953
 
    if (!r_has_type(nocie, t_boolean))
2954
 
        return_error(e_typecheck);
2955
 
    if (nocie->value.boolval)
2956
 
        return setcmykspace(i_ctx_p, r, stage, cont, 1);
2957
 
 
2958
 
    *cont = 0;
2959
 
    code = array_get(imemory, r, 1, &CIEDict);
2960
 
    if (code < 0)
2961
 
        return code;
2962
 
    if ((*stage) > 0) {
2963
 
        gs_client_color cc;
2964
 
        int i;
2965
 
 
2966
 
        cc.pattern = 0x00;
2967
 
        for (i=0;i<4;i++)
2968
 
            cc.paint.values[i] = 0;
2969
 
        code = gs_setcolor(igs, &cc);
2970
 
        *stage = 0;
2971
 
        return code;
2972
 
    }
2973
 
    dictkey = r->value.refs->value.saveid;
2974
 
    code = ciedefgspace(i_ctx_p, &CIEDict,dictkey);
2975
 
    *cont = 1;
2976
 
    (*stage)++;
2977
 
    return code;
2978
 
}
2979
 
static int validateciedefgspace(i_ctx_t * i_ctx_p, ref **r)
2980
 
{
2981
 
    int code = 0, i, j;
2982
 
    float value[8];
2983
 
    ref     CIEdict, *CIEspace = *r, tempref, arrayref, valref, *pref = &tempref;
2984
 
 
2985
 
    if (!r_is_array(CIEspace))
2986
 
        return_error(e_typecheck);
2987
 
    /* Validate parameters, check we have enough operands */
2988
 
    if (r_size(CIEspace) != 2)
2989
 
        return_error(e_rangecheck);
2990
 
 
2991
 
    code = array_get(imemory, CIEspace, 1, &CIEdict);
2992
 
    if (code < 0)
2993
 
        return code;
2994
 
    check_read_type(CIEdict, t_dictionary);
2995
 
 
2996
 
    code = validatecieabcspace(i_ctx_p, r);
2997
 
    if (code != 0)
2998
 
        return code;
2999
 
 
3000
 
    code = dict_find_string(&CIEdict, "Table", &pref);
3001
 
    if (code >= 0) {
3002
 
        if (!r_is_array(pref))
3003
 
            return_error(e_typecheck);
3004
 
        if (r_size(pref) != 5)
3005
 
            return_error(e_rangecheck);
3006
 
 
3007
 
        for (i=0;i<4;i++) {
3008
 
            code = array_get(imemory, pref, i, &valref);
3009
 
            if (code < 0)
3010
 
                return code;
3011
 
            if (r_has_type(&valref, t_integer))
3012
 
                value[i] = (float)valref.value.intval;
3013
 
            else
3014
 
                return_error(e_typecheck);
3015
 
        }
3016
 
        if (value[0] <= 1 || value[1] <= 1 || value[2] <= 1 || value[3] <= 1)
3017
 
            return_error(e_rangecheck);
3018
 
 
3019
 
        code = array_get(imemory, pref, 4, &arrayref);
3020
 
        if (code < 0)
3021
 
            return code;
3022
 
        if (!r_is_array(&arrayref))
3023
 
            return_error(e_typecheck);
3024
 
        if (r_size(&arrayref) != value[0])
3025
 
            return_error(e_rangecheck);
3026
 
 
3027
 
        for (i=0;i<value[0];i++) {
3028
 
            code = array_get(imemory, &arrayref, i, &tempref);
3029
 
            if (code < 0)
3030
 
                return code;
3031
 
            for (j=0;j<value[1];j++) {
3032
 
                code = array_get(imemory, &tempref, i, &valref);
3033
 
                if (code < 0)
3034
 
                    return code;
3035
 
                if (!r_has_type(&valref, t_string))
3036
 
                    return_error(e_typecheck);
3037
 
 
3038
 
                if (r_size(&valref) != (3 * value[2] * value[3]))
3039
 
                    return_error(e_rangecheck);
3040
 
            }
3041
 
        }
3042
 
    } else {
3043
 
        return_error(e_rangecheck);
3044
 
    }
3045
 
 
3046
 
    /* Remaining parameters are optional, but we must validate
3047
 
     * them if they are present
3048
 
     */
3049
 
    code = dict_find_string(&CIEdict, "RangeDEFG", &pref);
3050
 
    if (code >= 0 && !r_has_type(pref, t_null)) {
3051
 
        if (!r_is_array(pref))
3052
 
            return_error(e_typecheck);
3053
 
        if (r_size(pref) != 8)
3054
 
            return_error(e_rangecheck);
3055
 
 
3056
 
        for (i=0;i<8;i++) {
3057
 
            code = array_get(imemory, pref, i, &valref);
3058
 
            if (code < 0)
3059
 
                return code;
3060
 
            if (r_has_type(&valref, t_integer))
3061
 
                value[i] = (float)valref.value.intval;
3062
 
            else if (r_has_type(&valref, t_real))
3063
 
                value[i] = (float)valref.value.realval;
3064
 
            else
3065
 
                return_error(e_typecheck);
3066
 
        }
3067
 
        if (value[1] < value[0] || value[3] < value[2] || value[5] < value[4] || value[7] < value[6])
3068
 
            return_error(e_rangecheck);
3069
 
    }
3070
 
 
3071
 
    code = dict_find_string(&CIEdict, "DecodeDEFG", &pref);
3072
 
    if (code >= 0 && !r_has_type(pref, t_null)) {
3073
 
        if (!r_is_array(pref))
3074
 
            return_error(e_typecheck);
3075
 
        if (r_size(pref) != 4)
3076
 
            return_error(e_rangecheck);
3077
 
 
3078
 
        for (i=0;i<4;i++) {
3079
 
            code = array_get(imemory, pref, i, &valref);
3080
 
            if (code < 0)
3081
 
                return code;
3082
 
            check_proc(valref);
3083
 
        }
3084
 
    }
3085
 
 
3086
 
    code = dict_find_string(&CIEdict, "RangeHIJK", &pref);
3087
 
    if (code >= 0 && !r_has_type(pref, t_null)) {
3088
 
        if (!r_is_array(pref))
3089
 
            return_error(e_typecheck);
3090
 
        if (r_size(pref) != 8)
3091
 
            return_error(e_rangecheck);
3092
 
 
3093
 
        for (i=0;i<8;i++) {
3094
 
            code = array_get(imemory, pref, i, &valref);
3095
 
            if (code < 0)
3096
 
                return code;
3097
 
            if (r_has_type(&valref, t_integer))
3098
 
                value[i] = (float)valref.value.intval;
3099
 
            else if (r_has_type(&valref, t_real))
3100
 
                value[i] = (float)valref.value.realval;
3101
 
            else
3102
 
                return_error(e_typecheck);
3103
 
        }
3104
 
        if (value[1] < value[0] || value[3] < value[2] || value[5] < value[4] || value[7] < value[6])
3105
 
            return_error(e_rangecheck);
3106
 
    }
3107
 
 
3108
 
    *r = 0;
3109
 
    return 0;
3110
 
}
3111
 
static int ciedefgdomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
3112
 
{
3113
 
    int i, code;
3114
 
    ref     CIEdict, *tempref, valref;
3115
 
 
3116
 
    code = array_get(imemory, space, 1, &CIEdict);
3117
 
    if (code < 0)
3118
 
        return code;
3119
 
 
3120
 
    /* If we have a RangeDEFG, get the values from that */
3121
 
    code = dict_find_string(&CIEdict, "RangeDEFG", &tempref);
3122
 
    if (code >= 0 && !r_has_type(tempref, t_null)) {
3123
 
        for (i=0;i<8;i++) {
3124
 
            code = array_get(imemory, tempref, i, &valref);
3125
 
            if (code < 0)
3126
 
                return code;
3127
 
            if (r_has_type(&valref, t_integer))
3128
 
                ptr[i] = (float)valref.value.intval;
3129
 
            else if (r_has_type(&valref, t_real))
3130
 
                ptr[i] = (float)valref.value.realval;
3131
 
            else
3132
 
                return_error(e_typecheck);
3133
 
        }
3134
 
    } else {
3135
 
        /* Default values for a CIEBasedDEFG */
3136
 
        for (i=0;i<4;i++) {
3137
 
            ptr[2 * i] = 0;
3138
 
            ptr[(2 * i) + 1] = 1;
3139
 
        }
3140
 
    }
3141
 
    return 0;
3142
 
}
3143
 
static int ciedefgrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
3144
 
{
3145
 
    int i, code;
3146
 
    ref     CIEdict, *tempref, valref;
3147
 
 
3148
 
    code = array_get(imemory, space, 1, &CIEdict);
3149
 
    if (code < 0)
3150
 
        return code;
3151
 
 
3152
 
    /* If we have a RangeDEFG, get the values from that */
3153
 
    code = dict_find_string(&CIEdict, "RangeDEFG", &tempref);
3154
 
    if (code >= 0 && !r_has_type(tempref, t_null)) {
3155
 
        for (i=0;i<8;i++) {
3156
 
            code = array_get(imemory, tempref, i, &valref);
3157
 
            if (code < 0)
3158
 
                return code;
3159
 
            if (r_has_type(&valref, t_integer))
3160
 
                ptr[i] = (float)valref.value.intval;
3161
 
            else if (r_has_type(&valref, t_real))
3162
 
                ptr[i] = (float)valref.value.realval;
3163
 
            else
3164
 
                return_error(e_typecheck);
3165
 
        }
3166
 
    } else {
3167
 
        /* Default values for a CIEBasedDEFG */
3168
 
        for (i=0;i<4;i++) {
3169
 
            ptr[2 * i] = 0;
3170
 
            ptr[(2 * i) + 1] = 1;
3171
 
        }
3172
 
    }
3173
 
    return 0;
3174
 
}
3175
 
static int ciedefgvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
3176
 
{
3177
 
    os_ptr op = osp;
3178
 
    int i;
3179
 
 
3180
 
    if (num_comps < 4)
3181
 
        return_error(e_stackunderflow);
3182
 
 
3183
 
    op -= 3;
3184
 
    for (i=0;i < 4;i++) {
3185
 
        if (!r_has_type(op, t_integer) && !r_has_type(op, t_real))
3186
 
            return_error(e_typecheck);
3187
 
        op++;
3188
 
    }
3189
 
    return 0;
3190
 
}
3191
 
static int ciedefgcompareproc(i_ctx_t *i_ctx_p, ref *space, ref *testspace)
3192
 
{
3193
 
    /* If the problems mentioned above are resolved, then this code could
3194
 
     * be re-instated.
3195
 
     */
3196
 
    int code = 0;
3197
 
    ref CIEdict1, CIEdict2;
3198
 
 
3199
 
    code = array_get(imemory, space, 1, &CIEdict1);
3200
 
    if (code < 0)
3201
 
        return 0;
3202
 
    code = array_get(imemory, testspace, 1, &CIEdict2);
3203
 
    if (code < 0)
3204
 
        return 0;
3205
 
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"WhitePoint"))
3206
 
        return 0;
3207
 
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"BlackPoint"))
3208
 
        return 0;
3209
 
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeABC"))
3210
 
        return 0;
3211
 
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"DecodeABC"))
3212
 
        return 0;
3213
 
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"MatrixABC"))
3214
 
        return 0;
3215
 
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeLMN"))
3216
 
        return 0;
3217
 
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"DecodeLMN"))
3218
 
        return 0;
3219
 
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"MatrixMN"))
3220
 
        return 0;
3221
 
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeDEFG"))
3222
 
        return 0;
3223
 
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"DecodeDEFG"))
3224
 
        return 0;
3225
 
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeHIJK"))
3226
 
        return 0;
3227
 
    if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"Table"))
3228
 
        return 0;
3229
 
    return 1;
3230
 
}
3231
 
 
3232
 
static char const * const CIESpaces[] = {
3233
 
    "CIEBasedA",
3234
 
    "CIEBasedABC",
3235
 
    "CIEBasedDEF",
3236
 
    "CIEBasedDEFG"
3237
 
};
3238
 
/* This routine returns the Device space equivalents for a CIEBased space.
3239
 
 * Used by currentgray, currentrgb and currentcmyk, the PLRM says that CIE
3240
 
 * spaces return 0 for all components.
3241
 
 */
3242
 
static int ciebasecolor(i_ctx_t * i_ctx_p, ref *space, int base, int *stage, int *cont, int *stack_depth)
3243
 
{
3244
 
    os_ptr op;
3245
 
    ref *spacename, nref;
3246
 
    int i, components=1, code;
3247
 
 
3248
 
    /* If the spaece is an array, the first element is always the name */
3249
 
    if (r_is_array(space))
3250
 
        spacename = space->value.refs;
3251
 
    else
3252
 
        spacename = space;
3253
 
    /* Check that it really is a name */
3254
 
    if (!r_has_type(spacename, t_name))
3255
 
        return_error(e_typecheck);
3256
 
 
3257
 
    /* Find the relevant color space object */
3258
 
    for (i=0;i<4;i++) {
3259
 
        code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)CIESpaces[i], strlen(CIESpaces[i]), &nref, 0);
3260
 
        if (code < 0)
3261
 
            return code;
3262
 
        if (name_eq(spacename, &nref)) {
3263
 
            break;
3264
 
        }
3265
 
    }
3266
 
    /* Find out how many values are on the stack, which depends
3267
 
     * on what kind of CIEBased space this is.
3268
 
     */
3269
 
    switch(i){
3270
 
        case 0:
3271
 
            components = 1;
3272
 
            break;
3273
 
        case 1:
3274
 
        case 2:
3275
 
            components = 3;
3276
 
            break;
3277
 
        case 3:
3278
 
            components = 4;
3279
 
            break;
3280
 
    }
3281
 
    /* Remove teh requisite number of values */
3282
 
    pop(components);
3283
 
    op = osp;
3284
 
    /* Find out how many values we need to return, which
3285
 
     * depends on the requested space.
3286
 
     */
3287
 
    switch(base) {
3288
 
        case 0:
3289
 
            components = 1;
3290
 
            break;
3291
 
        case 1:
3292
 
        case 2:
3293
 
            components = 3;
3294
 
            break;
3295
 
        case 3:
3296
 
            components = 4;
3297
 
            break;
3298
 
    }
3299
 
    push(components);
3300
 
    /* The PLRM says that all the components should be returned as 0.0 */
3301
 
    op -= components-1;
3302
 
    for (i=0;i<components;i++) {
3303
 
        make_real(op, (float)0);
3304
 
        op++;
3305
 
    }
3306
 
    /* However, Adobe implementations actually return 1.0 for the black
3307
 
     * channel of CMYK...
3308
 
     */
3309
 
    if (components == 4) {
3310
 
        op--;
3311
 
        make_real(op, (float)1);
3312
 
    }
3313
 
    *stage = 0;
3314
 
    *cont = 0;
3315
 
    return 0;
3316
 
}
3317
 
 
3318
 
/* This routine used by both Separatin and DeviceN spaces to convert
3319
 
 * a PostScript tint transform into a Function, either a type 4
3320
 
 * 'PostScript calculator (see PDF reference) or a type 0 'sampled'
3321
 
 * function.
3322
 
 */
3323
 
static int convert_transform(i_ctx_t * i_ctx_p, ref *arr, ref *pproc)
3324
 
{
3325
 
    os_ptr op = osp;   /* required by "push" macro */
3326
 
    int code;
3327
 
 
3328
 
    /* buildfunction returns an operand on the stack. In fact
3329
 
     * it replaces the lowest operand, so make sure there is an
3330
 
     * empty sacrificial one present.
3331
 
     */
3332
 
    push(1);
3333
 
    /* Start by trying a type 4 function */
3334
 
    code = buildfunction(i_ctx_p, arr, pproc, 4);
3335
 
 
3336
 
    if (code < 0)
3337
 
        /* If that fails, try a type 0. We prefer a type 4
3338
 
         * because a type 0 will require us to sample the
3339
 
         * space, which is expensive
3340
 
         */
3341
 
        code = buildfunction(i_ctx_p, arr, pproc, 0);
3342
 
 
3343
 
    return code;
3344
 
}
3345
 
 
3346
 
/* Separation */
3347
 
static int setseparationspace(i_ctx_t * i_ctx_p, ref *sepspace, int *stage, int *cont, int CIESubst)
3348
 
{
3349
 
    os_ptr op = osp;   /* required by "push" macro */
3350
 
    int code = 0;
3351
 
    ref sname, proc;
3352
 
    ref name_none, name_all;
3353
 
    separation_type sep_type;
3354
 
    ref_colorspace cspace_old;
3355
 
    gs_color_space *pcs;
3356
 
    gs_color_space * pacs;
3357
 
    gs_function_t *pfn = NULL;
3358
 
    gs_client_color cc;
3359
 
 
3360
 
    if (i_ctx_p->language_level < 2)
3361
 
        return_error(e_undefined);
3362
 
 
3363
 
    *cont = 0;
3364
 
    if ((*stage) == 0) {
3365
 
        code = array_get(imemory, sepspace, 3, &proc);
3366
 
        if (code < 0)
3367
 
            return code;
3368
 
        /* Check to see if we already have a function (eg from a PDF file) */
3369
 
        pfn = ref_function(&proc);
3370
 
        if (pfn == NULL) {
3371
 
            /* Convert tint transform to a PostScript function */
3372
 
            code = convert_transform(i_ctx_p, sepspace, &proc);
3373
 
            if (code < 0)
3374
 
                return code;
3375
 
            if (code > 0) {
3376
 
                *cont = 1;
3377
 
                (*stage)++;
3378
 
                return code;
3379
 
            }
3380
 
            /* We can only get here if the transform converted to a function
3381
 
             * without requiring a continuation. Most likely this means its a
3382
 
             * type 4 function. If so then it is still on the stack.
3383
 
             */
3384
 
            op = osp;
3385
 
            pfn = ref_function(op);
3386
 
            pop (1);
3387
 
        }
3388
 
    } else {
3389
 
        /* The function is returned on the operand stack */
3390
 
        op = osp;
3391
 
        pfn = ref_function(op);
3392
 
        pop (1);
3393
 
    }
3394
 
 
3395
 
    *stage = 0;
3396
 
    if ((code = name_ref(imemory, (const byte *)"All", 3, &name_all, 0)) < 0)
3397
 
        return code;
3398
 
    if ((code = name_ref(imemory, (const byte *)"None", 4, &name_none, 0)) < 0)
3399
 
        return code;
3400
 
    /* Check separation name is a string or name object */
3401
 
    code = array_get(imemory, sepspace, 1, &sname);
3402
 
    if (code < 0)
3403
 
        return code;
3404
 
 
3405
 
    if (r_has_type(&sname, t_string)) {
3406
 
        code = name_from_string(imemory, &sname, &sname);
3407
 
        if (code < 0)
3408
 
            return code;
3409
 
    }
3410
 
    sep_type = ( name_eq(&sname, &name_all) ? SEP_ALL :
3411
 
                 name_eq(&sname, &name_none) ? SEP_NONE : SEP_OTHER);
3412
 
 
3413
 
    /* The alternate color space has been selected as the current color space */
3414
 
    pacs = gs_currentcolorspace(igs);
3415
 
 
3416
 
    cspace_old = istate->colorspace[0];
3417
 
    /* Now set the current color space as Separation */
3418
 
    code = gs_cspace_new_Separation(&pcs, pacs, imemory);
3419
 
    if (code < 0)
3420
 
        return code;
3421
 
    pcs->params.separation.sep_type = sep_type;
3422
 
    pcs->params.separation.sep_name = name_index(imemory, &sname);
3423
 
    pcs->params.separation.get_colorname_string = gs_get_colorname_string;
3424
 
    code = array_get(imemory, sepspace, 1, &proc);
3425
 
    if (code < 0)
3426
 
        return code;
3427
 
    istate->colorspace[0].procs.special.separation.layer_name = proc;
3428
 
    code = array_get(imemory, sepspace, 3, &proc);
3429
 
    if (code < 0)
3430
 
        return code;
3431
 
    istate->colorspace[0].procs.special.separation.tint_transform = proc;
3432
 
    if (code >= 0)
3433
 
        code = gs_cspace_set_sepr_function(pcs, pfn);
3434
 
    if (code >= 0)
3435
 
        code = gs_setcolorspace(igs, pcs);
3436
 
    /* release reference from construction */
3437
 
    rc_decrement_only_cs(pcs, "setseparationspace");
3438
 
    if (code < 0) {
3439
 
        istate->colorspace[0] = cspace_old;
3440
 
        return code;
3441
 
    }
3442
 
    cc.pattern = 0x00;
3443
 
    cc.paint.values[0] = 1.0;
3444
 
    code = gs_setcolor(igs, &cc);
3445
 
    return code;
3446
 
}
3447
 
static int validateseparationspace(i_ctx_t * i_ctx_p, ref **space)
3448
 
{
3449
 
    int code = 0;
3450
 
    ref *sepspace = *space;
3451
 
    ref nameref, sref, sname, altspace, tref;
3452
 
 
3453
 
    if (!r_is_array(sepspace))
3454
 
        return_error(e_typecheck);
3455
 
    /* Validate parameters, check we have enough operands */
3456
 
    if (r_size(sepspace) != 4)
3457
 
        return_error(e_rangecheck);
3458
 
 
3459
 
    /* Check separation name is a string or name object */
3460
 
    code = array_get(imemory, sepspace, 1, &sname);
3461
 
    if (code < 0)
3462
 
        return code;
3463
 
    if (!r_has_type(&sname, t_name)) {
3464
 
        if (!r_has_type(&sname, t_string))
3465
 
            return_error(e_typecheck);
3466
 
        else {
3467
 
            code = name_from_string(imemory, &sname, &sname);
3468
 
            if (code < 0)
3469
 
                return code;
3470
 
        }
3471
 
    }
3472
 
 
3473
 
    /* Check the tint transform is a procedure */
3474
 
    code = array_get(imemory, sepspace, 3, &tref);
3475
 
    if (code < 0)
3476
 
        return code;
3477
 
    check_proc(tref);
3478
 
 
3479
 
    /* Get the name of the alternate space */
3480
 
    code = array_get(imemory, sepspace, 2, &altspace);
3481
 
    if (code < 0)
3482
 
        return code;
3483
 
    if (r_has_type(&altspace, t_name))
3484
 
        ref_assign(&nameref, &altspace);
3485
 
    else {
3486
 
        /* Make sure the alternate space is an array */
3487
 
        if (!r_is_array(&altspace))
3488
 
            return_error(e_typecheck);
3489
 
        /* And has a name for its type */
3490
 
        code = array_get(imemory, &altspace, 0, &tref);
3491
 
        if (code < 0)
3492
 
            return code;
3493
 
        if (!r_has_type(&tref, t_name))
3494
 
            return_error(e_typecheck);
3495
 
        ref_assign(&nameref, &tref);
3496
 
    }
3497
 
 
3498
 
    /* Convert alternate space name to string */
3499
 
    name_string_ref(imemory, &nameref, &sref);
3500
 
    /* Check its not /Indexed or /Pattern or /DeviceN */
3501
 
    if (r_size(&sref) == 7) {
3502
 
        if (strncmp((const char *)sref.value.const_bytes, "Indexed", 7) == 0)
3503
 
            return_error(e_typecheck);
3504
 
        if (strncmp((const char *)sref.value.const_bytes, "Pattern", 7) == 0)
3505
 
            return_error(e_typecheck);
3506
 
        if (strncmp((const char *)sref.value.const_bytes, "DeviceN", 7) == 0)
3507
 
            return_error(e_typecheck);
3508
 
    }
3509
 
    /* and also not /Separation */
3510
 
    if (r_size(&sref) == 9 && strncmp((const char *)sref.value.const_bytes, "Separation", 9) == 0)
3511
 
        return_error(e_typecheck);
3512
 
 
3513
 
    ref_assign(*space, &altspace);
3514
 
    return 0;
3515
 
}
3516
 
static int separationalternatespace(i_ctx_t * i_ctx_p, ref *sepspace, ref **r, int *CIESubst)
3517
 
{
3518
 
    ref tref;
3519
 
    int code;
3520
 
 
3521
 
    code = array_get(imemory, sepspace, 2, &tref);
3522
 
    if (code < 0)
3523
 
        return code;
3524
 
    ref_assign(*r, &tref);
3525
 
    return 0;
3526
 
}
3527
 
static int sepdomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
3528
 
{
3529
 
    ptr[0] = 0;
3530
 
    ptr[1] = 1;
3531
 
    return 0;
3532
 
}
3533
 
static int seprange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
3534
 
{
3535
 
    ptr[0] = 0;
3536
 
    ptr[1] = 1;
3537
 
    return 0;
3538
 
}
3539
 
static int septransform(i_ctx_t *i_ctx_p, ref *sepspace, int *usealternate, int *stage, int *stack_depth)
3540
 
{
3541
 
    gx_device * dev = igs->device;
3542
 
    ref sname, proc;
3543
 
    int code, colorant_number;
3544
 
 
3545
 
    code = array_get(imemory, sepspace, 1, &sname);
3546
 
    if (code < 0)
3547
 
        return code;
3548
 
    if (r_has_type(&sname, t_name)) {
3549
 
        name_string_ref(imemory, &sname, &sname);
3550
 
    }
3551
 
 
3552
 
    /* Check for /All and /None, never need the alternate for these */
3553
 
    if (r_size(&sname) == 3 &&
3554
 
        strncmp("All", (const char *)sname.value.bytes, r_size(&sname)) == 0) {
3555
 
        *usealternate = 0;
3556
 
        return 0;
3557
 
    }
3558
 
    if (r_size(&sname) == 4 &&
3559
 
        strncmp("None", (const char *)sname.value.bytes, r_size(&sname)) == 0) {
3560
 
        *usealternate = 0;
3561
 
        return 0;
3562
 
    }
3563
 
    /*
3564
 
     * Compare the colorant name to the device's.  If the device's
3565
 
     * compare routine returns GX_DEVICE_COLOR_MAX_COMPONENTS then the
3566
 
     * colorant is in the SeparationNames list but not in the
3567
 
     * SeparationOrder list.
3568
 
     */
3569
 
    colorant_number = (*dev_proc(dev, get_color_comp_index))
3570
 
                (dev, (const char *)sname.value.bytes, r_size(&sname), SEPARATION_NAME);
3571
 
    if (colorant_number >= 0) {         /* If valid colorant name */
3572
 
        *usealternate = 0;
3573
 
    } else
3574
 
        *usealternate = 1;
3575
 
 
3576
 
    if (r_size(&sname) == 4 &&
3577
 
        strncmp("Gray", (const char *)sname.value.bytes, r_size(&sname)) == 0) {
3578
 
        *usealternate = 1;
3579
 
    }
3580
 
    if (r_size(&sname) == 4 &&
3581
 
        strncmp("Cyan", (const char *)sname.value.bytes, r_size(&sname)) == 0) {
3582
 
        *usealternate = 1;
3583
 
    }
3584
 
    if (r_size(&sname) == 7 &&
3585
 
        strncmp("Magenta", (const char *)sname.value.bytes, r_size(&sname)) == 0) {
3586
 
        *usealternate = 1;
3587
 
    }
3588
 
    if (r_size(&sname) == 6 &&
3589
 
        strncmp("Yellow", (const char *)sname.value.bytes, r_size(&sname)) == 0) {
3590
 
        *usealternate = 1;
3591
 
    }
3592
 
    if (r_size(&sname) == 5 &&
3593
 
        strncmp("Black", (const char *)sname.value.bytes, r_size(&sname)) == 0) {
3594
 
        *usealternate = 1;
3595
 
    }
3596
 
    if (r_size(&sname) == 3 &&
3597
 
        strncmp("Red", (const char *)sname.value.bytes, r_size(&sname)) == 0) {
3598
 
        *usealternate = 1;
3599
 
    }
3600
 
    if (r_size(&sname) == 5 &&
3601
 
        strncmp("Green", (const char *)sname.value.bytes, r_size(&sname)) == 0) {
3602
 
        *usealternate = 1;
3603
 
    }
3604
 
    if (r_size(&sname) == 4 &&
3605
 
        strncmp("Blue", (const char *)sname.value.bytes, r_size(&sname)) == 0) {
3606
 
        *usealternate = 1;
3607
 
    }
3608
 
    if (*usealternate && *stage == 0) {
3609
 
        (*stage)++;
3610
 
        esp++;
3611
 
        code = array_get(imemory, sepspace, 3, &proc);
3612
 
        if (code < 0)
3613
 
            return code;
3614
 
        *esp = proc;
3615
 
        return o_push_estack;
3616
 
    }
3617
 
    *stage = 0;
3618
 
    return 0;
3619
 
}
3620
 
static int sepbasecolor(i_ctx_t * i_ctx_p, ref *space, int base, int *stage, int *cont, int *stack_depth)
3621
 
{
3622
 
    os_ptr op = osp;   /* required by "push" macro */
3623
 
    int use, code;
3624
 
 
3625
 
        code = septransform(i_ctx_p, space, &use, stage, stack_depth);
3626
 
        if (code != 0)
3627
 
            return code;
3628
 
        if (!use) {
3629
 
            *stage = 0;
3630
 
            *cont = 0;
3631
 
            pop(1);
3632
 
            op = osp;
3633
 
            switch(base) {
3634
 
                case 0:
3635
 
                    push(1);
3636
 
                    make_real(op, 0.0);
3637
 
                    break;
3638
 
                case 1:
3639
 
                case 2:
3640
 
                    push(3);
3641
 
                    make_real(&op[-2], 0.0);
3642
 
                    make_real(&op[-1], 0.0);
3643
 
                    make_real(op, 0.0);
3644
 
                    break;
3645
 
                case 3:
3646
 
                    push(4);
3647
 
                    make_real(&op[-3], 0.0);
3648
 
                    make_real(&op[-2], 0.0);
3649
 
                    make_real(&op[-1], 0.0);
3650
 
                    make_real(op, 0.0);
3651
 
                    break;
3652
 
            }
3653
 
        } else {
3654
 
            *stage = 0;
3655
 
            *cont = 1;
3656
 
        }
3657
 
    return 0;
3658
 
}
3659
 
static int sepvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
3660
 
{
3661
 
    os_ptr op = osp;
3662
 
 
3663
 
    if (num_comps < 1)
3664
 
        return_error(e_stackunderflow);
3665
 
 
3666
 
    if (!r_has_type(op, t_integer) && !r_has_type(op, t_real))
3667
 
        return_error(e_typecheck);
3668
 
 
3669
 
    if (*values > 1.0)
3670
 
        *values = 1.0;
3671
 
 
3672
 
    if (*values < 0.0)
3673
 
        *values = 0.0;
3674
 
 
3675
 
    return 0;
3676
 
}
3677
 
static int sepcompareproc(i_ctx_t *i_ctx_p, ref *space, ref *testspace)
3678
 
{
3679
 
    ref sname1, sname2;
3680
 
    int code;
3681
 
 
3682
 
    code = array_get(imemory, space, 1, &sname1);
3683
 
    if (code < 0)
3684
 
        return 0;
3685
 
 
3686
 
    code = array_get(imemory, testspace, 1, &sname2);
3687
 
    if (code < 0)
3688
 
        return 0;
3689
 
 
3690
 
    if (r_type(&sname1) != r_type(&sname2))
3691
 
        return 0;
3692
 
 
3693
 
    switch(r_type(&sname1)) {
3694
 
        case t_name:
3695
 
            if (!name_eq(&sname1, &sname2))
3696
 
                return 0;
3697
 
            break;
3698
 
        case t_string:
3699
 
            if (r_size(&sname1) != r_size(&sname2))
3700
 
                return 0;
3701
 
            if (strncmp((const char *)sname1.value.const_bytes, (const char *)sname2.value.const_bytes, r_size(&sname1)) != 0)
3702
 
                return 0;
3703
 
            break;
3704
 
        default:
3705
 
            return 0;
3706
 
    }
3707
 
    code = array_get(imemory, testspace, 2, &sname1);
3708
 
    if (code < 0)
3709
 
        return 0;
3710
 
    code = array_get(imemory, testspace, 2, &sname2);
3711
 
    if (code < 0)
3712
 
        return 0;
3713
 
    if (r_type(&sname1) != r_type(&sname2))
3714
 
        return 0;
3715
 
 
3716
 
    if (r_is_array(&sname1)) {
3717
 
        if (!comparearrays(i_ctx_p, &sname1, &sname2))
3718
 
            return 0;
3719
 
    } else {
3720
 
        if (!r_has_type(&sname1, t_name))
3721
 
            return 0;
3722
 
        if (!name_eq(&sname1, &sname2))
3723
 
            return 0;
3724
 
    }
3725
 
    code = array_get(imemory, space, 3, &sname1);
3726
 
    if (code < 0)
3727
 
        return 0;
3728
 
    code = array_get(imemory, testspace, 3, &sname2);
3729
 
    if (code < 0)
3730
 
        return 0;
3731
 
    return(comparearrays(i_ctx_p, &sname1, &sname2));
3732
 
}
3733
 
static int sepinitialproc(i_ctx_t *i_ctx_p, ref *space)
3734
 
{
3735
 
    gs_client_color cc;
3736
 
 
3737
 
    cc.pattern = 0x00;
3738
 
    cc.paint.values[0] = 1.0;
3739
 
    return gs_setcolor(igs, &cc);
3740
 
}
3741
 
 
3742
 
/* DeviceN */
3743
 
static int devicencolorants_cont(i_ctx_t *i_ctx_p)
3744
 
{
3745
 
    ref dict, *pdict = &dict, space[2], sname;
3746
 
    int index, code, depth, stage;
3747
 
    es_ptr ep = esp, pindex, pstage;
3748
 
    os_ptr op = osp;
3749
 
    gs_separation_name sep_name;
3750
 
 
3751
 
    pindex = &ep[-2];
3752
 
    pstage = &ep[-1];
3753
 
    index = (int)pindex->value.intval;
3754
 
    stage = (int)pstage->value.intval;
3755
 
    ref_assign(&dict, ep);
3756
 
 
3757
 
    do {
3758
 
        if (index >= dict_length(pdict)) {
3759
 
            esp -= 4;
3760
 
            return o_pop_estack;
3761
 
        }
3762
 
 
3763
 
        if (stage == 0) {
3764
 
            code = gs_gsave(igs);
3765
 
            if (code < 0)
3766
 
                return code;
3767
 
 
3768
 
            code = dict_index_entry(pdict, index, (ref *)&space);
3769
 
            if (code < 0) {
3770
 
                make_int(pindex, ++index);
3771
 
                code = gs_grestore(igs);
3772
 
                if (code < 0)
3773
 
                    return code;
3774
 
                continue;
3775
 
            }
3776
 
 
3777
 
            code = validate_spaces(i_ctx_p, &space[1], &depth);
3778
 
            if (code < 0) {
3779
 
                make_int(pindex, ++index);
3780
 
                code = gs_grestore(igs);
3781
 
                if (code < 0)
3782
 
                    return code;
3783
 
                return o_push_estack;
3784
 
            }
3785
 
 
3786
 
            /* If we get a continuation from a sub-procedure, we will want to come back
3787
 
             * here afterward, to do any remaining stages. We need to set up for that now.
3788
 
             * so that our continuation is ahead of the sub-proc's continuation.
3789
 
             */
3790
 
            check_estack(1);
3791
 
            push(1);
3792
 
            /* The push_op_estack macro increments esp before use, so we don't need to */
3793
 
            push_op_estack(devicencolorants_cont);
3794
 
 
3795
 
            make_int(pstage, 1);
3796
 
            *op = space[1];
3797
 
            code = zsetcolorspace(i_ctx_p);
3798
 
            if (code != 0)
3799
 
                return code;
3800
 
        } else {
3801
 
            stage = 0;
3802
 
            code = dict_index_entry(pdict, index, (ref *)&space);
3803
 
            if (code == 0) {
3804
 
                switch (r_type(&space[0])) {
3805
 
                    case t_string:
3806
 
                        code = name_from_string(imemory, &space[0], &sname);
3807
 
                        if (code == 0)
3808
 
                            sep_name = name_index(imemory, &sname);
3809
 
                        break;
3810
 
                    case t_name:
3811
 
                        sep_name = name_index(imemory, &space[0]);
3812
 
                        break;
3813
 
                    default:
3814
 
                        code = e_typecheck;
3815
 
                }
3816
 
            }
3817
 
            make_int(pindex, ++index);
3818
 
            make_int(pstage, stage);
3819
 
            if (code == 0)
3820
 
                gs_attachattributecolorspace(sep_name, igs);
3821
 
            code = gs_grestore(igs);
3822
 
            if (code < 0)
3823
 
                return code;
3824
 
        }
3825
 
    }
3826
 
    while(1);
3827
 
}
3828
 
 
3829
 
static int setdevicenspace(i_ctx_t * i_ctx_p, ref *devicenspace, int *stage, int *cont, int CIESubst)
3830
 
{
3831
 
    os_ptr  op = osp;   /* required by "push" macro */
3832
 
    int code = 0, num_components, i;
3833
 
    ref namesarray, proc, sname, tname, sref, tempref[2];
3834
 
    ref_colorspace cspace_old;
3835
 
    gs_color_space *pcs;
3836
 
    gs_color_space * pacs;
3837
 
    gs_function_t *pfn = NULL;
3838
 
    gs_separation_name *names;
3839
 
    gs_device_n_map *pmap;
3840
 
    gs_client_color cc;
3841
 
 
3842
 
    if (i_ctx_p->language_level < 3)
3843
 
        return_error(e_undefined);
3844
 
 
3845
 
    *cont = 0;
3846
 
    if ((*stage) == 2) {
3847
 
        if (r_size(devicenspace) == 5) {
3848
 
            /* We have a Colorants dictionary from a PDF file. We need to handle this by
3849
 
             * temporarily setting each of the spaces in the dict, and attaching the
3850
 
             * resulting space to the DeviceN array. This is complicated, because
3851
 
             * each space must be fully set up, and may result in running tint transform
3852
 
             * procedures and caching results. We need to handle this in yet another
3853
 
             * layering of continuation procedures.
3854
 
             */
3855
 
            code = array_get(imemory, devicenspace, 4, &sref);
3856
 
            if (code < 0)
3857
 
                return code;
3858
 
            if (!r_has_type(&sref, t_dictionary)) {
3859
 
                *stage = 0;
3860
 
                return 0;
3861
 
            }
3862
 
            if (dict_length(&sref) == 0)
3863
 
                return(0);
3864
 
 
3865
 
            code = dict_index_entry(&sref, 0, (ref *)&tempref);
3866
 
            if (code < 0)
3867
 
                return code;
3868
 
            name_string_ref(imemory, &tempref[0], &sname);
3869
 
            if (r_size(&sname) != 9 || strncmp((const char *)sname.value.const_bytes, "Colorants", r_size(&sname)) != 0) {
3870
 
                *stage = 0;
3871
 
                return 0;
3872
 
            }
3873
 
 
3874
 
            *stage = 3;
3875
 
            *cont = 1;
3876
 
            check_estack(5);
3877
 
            push_mark_estack(es_other, 0);
3878
 
            esp++;
3879
 
            /* variable to hold index of the space we are dealing with */
3880
 
            make_int(esp, 0);
3881
 
            esp++;
3882
 
            /* variable to hold processing step */
3883
 
            make_int(esp, 0);
3884
 
            esp++;
3885
 
            /* Store a pointer to the Colorants dictionary
3886
 
             */
3887
 
            ref_assign(esp, &tempref[1]);
3888
 
            push_op_estack(devicencolorants_cont);
3889
 
            return o_push_estack;
3890
 
        } else {
3891
 
            *stage = 0;
3892
 
            return 0;
3893
 
        }
3894
 
    }
3895
 
    if ((*stage) == 3) {
3896
 
        *stage = 0;
3897
 
        return 0;
3898
 
    }
3899
 
    if ((*stage) == 0) {
3900
 
        code = array_get(imemory, devicenspace, 3, &proc);
3901
 
        if (code < 0)
3902
 
            return code;
3903
 
        pfn = ref_function(&proc);
3904
 
        if (pfn == NULL) {
3905
 
            /* Convert tint transform to a PostScript function */
3906
 
            code = convert_transform(i_ctx_p, devicenspace, &proc);
3907
 
            if (code < 0)
3908
 
                return code;
3909
 
            if (code > 0) {
3910
 
                *cont = 1;
3911
 
                *stage = 1;
3912
 
                return code;
3913
 
            }
3914
 
            /* We can only get here if the transform converted to a function
3915
 
             * without requiring a continuation. Most likely this means its a
3916
 
             * type 4 function. If so then it is still on the stack.
3917
 
             */
3918
 
            op = osp;
3919
 
            pfn = ref_function(op);
3920
 
            pop (1);
3921
 
        }
3922
 
    } else {
3923
 
        /* The function is returned on the operand stack */
3924
 
        op = osp;
3925
 
        pfn = ref_function(op);
3926
 
        pop (1);
3927
 
    }
3928
 
 
3929
 
    *stage = 2;
3930
 
 
3931
 
    code = array_get(imemory, devicenspace, 1, &namesarray);
3932
 
    if (code < 0)
3933
 
        return code;
3934
 
    num_components = r_size(&namesarray);
3935
 
    /* The alternate color space has been selected as the current color space */
3936
 
    pacs = gs_currentcolorspace(igs);
3937
 
 
3938
 
    if (num_components == 1) {
3939
 
        array_get(imemory, &namesarray, (long)0, &sname);
3940
 
        switch (r_type(&sname)) {
3941
 
            case t_string:
3942
 
                tname = sname;
3943
 
                break;
3944
 
            case t_name:
3945
 
                name_string_ref(imemory, &sname, &tname);
3946
 
                break;
3947
 
            default:
3948
 
                return_error(e_typecheck);
3949
 
                break;
3950
 
        }
3951
 
        if (strncmp((const char *)tname.value.const_bytes, "All", 3) == 0 && r_size(&tname) == 3) {
3952
 
            separation_type sep_type;
3953
 
 
3954
 
            /* Sigh, Acrobat allows this, even though its contra the spec. Convert to
3955
 
             * a /Separation space and go on
3956
 
             */
3957
 
            sep_type = SEP_ALL;
3958
 
 
3959
 
            /* The alternate color space has been selected as the current color space */
3960
 
            pacs = gs_currentcolorspace(igs);
3961
 
 
3962
 
            cspace_old = istate->colorspace[0];
3963
 
            /* Now set the current color space as Separation */
3964
 
            code = gs_cspace_new_Separation(&pcs, pacs, imemory);
3965
 
            if (code < 0)
3966
 
                return code;
3967
 
            pcs->params.separation.sep_type = sep_type;
3968
 
            pcs->params.separation.sep_name = name_index(imemory, &sname);
3969
 
            pcs->params.separation.get_colorname_string = gs_get_colorname_string;
3970
 
            code = array_get(imemory, &namesarray, (long)0, &sname);
3971
 
            if (code < 0)
3972
 
                return code;
3973
 
            istate->colorspace[0].procs.special.separation.layer_name = sname;
3974
 
            code = array_get(imemory, devicenspace, 3, &proc);
3975
 
            if (code < 0)
3976
 
                return code;
3977
 
            istate->colorspace[0].procs.special.separation.tint_transform = proc;
3978
 
            if (code >= 0)
3979
 
                code = gs_cspace_set_sepr_function(pcs, pfn);
3980
 
            if (code >= 0)
3981
 
                code = gs_setcolorspace(igs, pcs);
3982
 
            /* release reference from construction */
3983
 
            rc_decrement_only_cs(pcs, "setseparationspace");
3984
 
            if (code < 0) {
3985
 
                istate->colorspace[0] = cspace_old;
3986
 
                return code;
3987
 
            }
3988
 
            cc.pattern = 0x00;
3989
 
            cc.paint.values[0] = 1.0;
3990
 
            code = gs_setcolor(igs, &cc);
3991
 
            return code;
3992
 
        }
3993
 
    }
3994
 
    code = gs_cspace_new_DeviceN(&pcs, num_components, pacs, imemory);
3995
 
    if (code < 0)
3996
 
        return code;
3997
 
    names = pcs->params.device_n.names;
3998
 
    pmap = pcs->params.device_n.map;
3999
 
    pcs->params.device_n.get_colorname_string = gs_get_colorname_string;
4000
 
 
4001
 
    /* Pick up the names of the components */
4002
 
    {
4003
 
        uint i;
4004
 
        ref sname;
4005
 
 
4006
 
        for (i = 0; i < num_components; ++i) {
4007
 
            array_get(imemory, &namesarray, (long)i, &sname);
4008
 
            switch (r_type(&sname)) {
4009
 
                case t_string:
4010
 
                    code = name_from_string(imemory, &sname, &sname);
4011
 
                    if (code < 0) {
4012
 
                        rc_decrement_cs(pcs, "setdevicenspace");
4013
 
                        return code;
4014
 
                    }
4015
 
                    /* falls through */
4016
 
                case t_name:
4017
 
                    names[i] = name_index(imemory, &sname);
4018
 
                    break;
4019
 
                default:
4020
 
                    rc_decrement_cs(pcs, "setdevicenspace");
4021
 
                    return_error(e_typecheck);
4022
 
            }
4023
 
        }
4024
 
    }
4025
 
 
4026
 
    /* Now set the current color space as DeviceN */
4027
 
 
4028
 
    cspace_old = istate->colorspace[0];
4029
 
    istate->colorspace[0].procs.special.device_n.layer_names = namesarray;
4030
 
    code = array_get(imemory, devicenspace, 3, &proc);
4031
 
    if (code < 0)
4032
 
        return code;
4033
 
    istate->colorspace[0].procs.special.device_n.tint_transform = proc;
4034
 
    gs_cspace_set_devn_function(pcs, pfn);
4035
 
    code = gs_setcolorspace(igs, pcs);
4036
 
    /* release reference from construction */
4037
 
    rc_decrement_only_cs(pcs, "setdevicenspace");
4038
 
    if (code < 0) {
4039
 
        istate->colorspace[0] = cspace_old;
4040
 
        return code;
4041
 
    }
4042
 
 
4043
 
    cc.pattern = 0x00;
4044
 
    for (i=0;i<num_components;i++)
4045
 
        cc.paint.values[i] = 1.0;
4046
 
    code = gs_setcolor(igs, &cc);
4047
 
    *cont = 1;
4048
 
    return code;
4049
 
}
4050
 
static int validatedevicenspace(i_ctx_t * i_ctx_p, ref **space)
4051
 
{
4052
 
    int i, code = 0;
4053
 
    ref *devicenspace = *space, proc;
4054
 
    ref nameref, sref, altspace, namesarray, sname;
4055
 
 
4056
 
    /* Check enough arguments in the space */
4057
 
    if (r_size(devicenspace) < 4)
4058
 
        return_error(e_rangecheck);
4059
 
    /* Check the names parameter is an array */
4060
 
    code = array_get(imemory, devicenspace, 1, &namesarray);
4061
 
    if (code < 0)
4062
 
        return code;
4063
 
    if (!r_is_array(&namesarray))
4064
 
        return_error(e_typecheck);
4065
 
    /* Ensure we have at least one ink */
4066
 
    if (r_size(&namesarray) < 1)
4067
 
        return_error(e_typecheck);
4068
 
    /* Make sure no more inks than we can cope with */
4069
 
    if (r_size(&namesarray) > GS_CLIENT_COLOR_MAX_COMPONENTS)
4070
 
        return_error(e_limitcheck);
4071
 
    /* Check the tint transform is a procedure */
4072
 
    code = array_get(imemory, devicenspace, 3, &proc);
4073
 
    if (code < 0)
4074
 
        return code;
4075
 
    check_proc(proc);
4076
 
 
4077
 
    /* Check the array of ink names only contains names or strings */
4078
 
    for (i = 0; i < r_size(&namesarray); ++i) {
4079
 
        array_get(imemory, &namesarray, (long)i, &sname);
4080
 
        switch (r_type(&sname)) {
4081
 
                case t_string:
4082
 
                case t_name:
4083
 
                    break;
4084
 
                default:
4085
 
                    return_error(e_typecheck);
4086
 
        }
4087
 
    }
4088
 
 
4089
 
    /* Get the name of the alternate space */
4090
 
    code = array_get(imemory, devicenspace, 2, &altspace);
4091
 
    if (code < 0)
4092
 
        return code;
4093
 
    if (r_has_type(&altspace, t_name))
4094
 
        ref_assign(&nameref, &altspace);
4095
 
    else {
4096
 
        /* Make sure the alternate space is an array */
4097
 
        if (!r_is_array(&altspace))
4098
 
            return_error(e_typecheck);
4099
 
        /* And has a name for its type */
4100
 
        code = array_get(imemory, &altspace, 0, &nameref);
4101
 
        if (code < 0)
4102
 
            return code;
4103
 
        if (!r_has_type(&nameref, t_name))
4104
 
            return_error(e_typecheck);
4105
 
    }
4106
 
    /* Convert alternate space name to string */
4107
 
    name_string_ref(imemory, &nameref, &sref);
4108
 
    /* Check its not /Indexed, /Pattern, /DeviceN */
4109
 
    if (r_size(&sref) == 7) {
4110
 
        if (strncmp((const char *)sref.value.const_bytes, "Indexed", 7) == 0)
4111
 
            return_error(e_typecheck);
4112
 
        if (strncmp((const char *)sref.value.const_bytes, "Pattern", 7) == 0)
4113
 
            return_error(e_typecheck);
4114
 
        if (strncmp((const char *)sref.value.const_bytes, "DeviceN", 7) == 0)
4115
 
            return_error(e_typecheck);
4116
 
    }
4117
 
    /* and also not /Separation */
4118
 
    if (r_size(&sref) == 9 && strncmp((const char *)sref.value.const_bytes, "Separation", 9) == 0)
4119
 
           return_error(e_typecheck);
4120
 
 
4121
 
    ref_assign(*space, &altspace);
4122
 
    return 0;
4123
 
}
4124
 
static int devicenalternatespace(i_ctx_t * i_ctx_p, ref *space, ref **r, int *CIESubst)
4125
 
{
4126
 
    ref altspace;
4127
 
    int code;
4128
 
 
4129
 
    code = array_get(imemory, space, 2, &altspace);
4130
 
    if (code < 0)
4131
 
        return code;
4132
 
    ref_assign(*r, &altspace);
4133
 
    return 0;
4134
 
}
4135
 
static int devicencomponents(i_ctx_t * i_ctx_p, ref *space, int *n)
4136
 
{
4137
 
    ref namesarray;
4138
 
    int code;
4139
 
 
4140
 
    code = array_get(imemory, space, 1, &namesarray);
4141
 
    if (code < 0)
4142
 
        return code;
4143
 
    *n = r_size(&namesarray);
4144
 
    return 0;
4145
 
}
4146
 
static int devicendomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
4147
 
{
4148
 
    int i, limit, code;
4149
 
    ref namesarray;
4150
 
 
4151
 
    code = array_get(imemory, space, 1, &namesarray);
4152
 
    if (code < 0)
4153
 
        return code;
4154
 
 
4155
 
    limit = r_size(&namesarray) * 2;
4156
 
    for (i = 0;i < limit;i+=2) {
4157
 
        ptr[i] = 0;
4158
 
        ptr[i+1] = 1;
4159
 
    }
4160
 
    return 0;
4161
 
}
4162
 
static int devicenrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
4163
 
{
4164
 
    int i, limit, code;
4165
 
    PS_colour_space_t *cspace;
4166
 
 
4167
 
    ref altspace;
4168
 
 
4169
 
    code = array_get(imemory, space, 1, &altspace);
4170
 
    if (code < 0)
4171
 
        return code;
4172
 
 
4173
 
    code = get_space_object(i_ctx_p, &altspace, &cspace);
4174
 
    if (code < 0)
4175
 
        return code;
4176
 
 
4177
 
    code = cspace->numcomponents(i_ctx_p, &altspace, &limit);
4178
 
    if (code < 0)
4179
 
        return code;
4180
 
 
4181
 
    for (i = 0;i < limit * 2;i+=2) {
4182
 
        ptr[i] = 0;
4183
 
        ptr[i+1] = 1;
4184
 
    }
4185
 
    return 0;
4186
 
}
4187
 
static int devicentransform(i_ctx_t *i_ctx_p, ref *devicenspace, int *usealternate, int *stage, int *stack_depth)
4188
 
{
4189
 
    gx_device * dev = igs->device;
4190
 
    ref narray, sname, proc;
4191
 
    int i, code, colorant_number;
4192
 
 
4193
 
    *usealternate = 0;
4194
 
    code = array_get(imemory, devicenspace, 1, &narray);
4195
 
    if (code < 0)
4196
 
        return code;
4197
 
    if (!r_is_array(&narray))
4198
 
        return_error(e_typecheck);
4199
 
 
4200
 
    for (i=0;i<r_size(&narray);i++) {
4201
 
        code = array_get(imemory, &narray, i, &sname);
4202
 
        if (code < 0)
4203
 
            return code;
4204
 
        if (r_has_type(&sname, t_name)) {
4205
 
            name_string_ref(imemory, &sname, &sname);
4206
 
        }
4207
 
 
4208
 
        /* Check for /All and /None, never need the alternate for these */
4209
 
        if (r_size(&sname) == 3 &&
4210
 
            strncmp("All", (const char *)sname.value.bytes, r_size(&sname)) == 0)
4211
 
            continue;
4212
 
        if (r_size(&sname) == 4 &&
4213
 
            strncmp("None", (const char *)sname.value.bytes, r_size(&sname)) == 0)
4214
 
            continue;
4215
 
        /*
4216
 
         * Compare the colorant name to the device's.  If the device's
4217
 
         * compare routine returns GX_DEVICE_COLOR_MAX_COMPONENTS then the
4218
 
         * colorant is in the SeparationNames list but not in the
4219
 
         * SeparationOrder list.
4220
 
         */
4221
 
        colorant_number = (*dev_proc(dev, get_color_comp_index))
4222
 
                (dev, (const char *)sname.value.bytes, r_size(&sname), SEPARATION_NAME);
4223
 
        if (colorant_number < 0) {              /* If not valid colorant name */
4224
 
            *usealternate = 1;
4225
 
            break;
4226
 
        }
4227
 
        if (r_size(&sname) == 4 &&
4228
 
            strncmp("Gray", (const char *)sname.value.bytes, r_size(&sname)) == 0) {
4229
 
            *usealternate = 1;
4230
 
            break;
4231
 
        }
4232
 
        if (r_size(&sname) == 4 &&
4233
 
            strncmp("Cyan", (const char *)sname.value.bytes, r_size(&sname)) == 0) {
4234
 
            *usealternate = 1;
4235
 
            break;
4236
 
        }
4237
 
        if (r_size(&sname) == 7 &&
4238
 
            strncmp("Magenta", (const char *)sname.value.bytes, r_size(&sname)) == 0) {
4239
 
            *usealternate = 1;
4240
 
            break;
4241
 
        }
4242
 
        if (r_size(&sname) == 6 &&
4243
 
            strncmp("Yellow", (const char *)sname.value.bytes, r_size(&sname)) == 0) {
4244
 
            *usealternate = 1;
4245
 
            break;
4246
 
        }
4247
 
        if (r_size(&sname) == 5 &&
4248
 
            strncmp("Black", (const char *)sname.value.bytes, r_size(&sname)) == 0) {
4249
 
            *usealternate = 1;
4250
 
            break;
4251
 
        }
4252
 
        if (r_size(&sname) == 3 &&
4253
 
            strncmp("Red", (const char *)sname.value.bytes, r_size(&sname)) == 0) {
4254
 
            *usealternate = 1;
4255
 
            break;
4256
 
        }
4257
 
        if (r_size(&sname) == 5 &&
4258
 
            strncmp("Green", (const char *)sname.value.bytes, r_size(&sname)) == 0) {
4259
 
            *usealternate = 1;
4260
 
            break;
4261
 
        }
4262
 
        if (r_size(&sname) == 4 &&
4263
 
            strncmp("Blue", (const char *)sname.value.bytes, r_size(&sname)) == 0) {
4264
 
            *usealternate = 1;
4265
 
            break;
4266
 
        }
4267
 
    }
4268
 
    if (*usealternate && *stage == 0) {
4269
 
        (*stage)++;
4270
 
        esp++;
4271
 
        code = array_get(imemory, devicenspace, 3, &proc);
4272
 
        if (code < 0)
4273
 
            return code;
4274
 
        *esp = proc;
4275
 
        return o_push_estack;
4276
 
    }
4277
 
 
4278
 
    if (*stage == 1){
4279
 
        *stack_depth = 0;
4280
 
        *stage = 0;
4281
 
    }
4282
 
    return 0;
4283
 
}
4284
 
static int devicenbasecolor(i_ctx_t * i_ctx_p, ref *space, int base, int *stage, int *cont, int *stack_depth)
4285
 
{
4286
 
    os_ptr  op = osp;   /* required by "push" macro */
4287
 
    int code, use, n_comp;
4288
 
    ref narray;
4289
 
 
4290
 
    code = devicentransform(i_ctx_p, space, &use, stage, stack_depth);
4291
 
    if (code !=  0)
4292
 
        return code;
4293
 
    if (!use) {
4294
 
        *stage = 0;
4295
 
        *cont = 0;
4296
 
        code = array_get(imemory, space, 1, &narray);
4297
 
        if (code < 0)
4298
 
            return code;
4299
 
        n_comp = r_size(&narray);
4300
 
        pop(n_comp);
4301
 
        op = osp;
4302
 
        switch(base) {
4303
 
        case 0:
4304
 
            push(1);
4305
 
            make_real(op, 0.0);
4306
 
            break;
4307
 
        case 1:
4308
 
        case 2:
4309
 
            push(3);
4310
 
            make_real(&op[-2], 0.0);
4311
 
            make_real(&op[-1], 0.0);
4312
 
            make_real(op, 0.0);
4313
 
            break;
4314
 
        case 3:
4315
 
            push(4);
4316
 
            make_real(&op[-3], 0.0);
4317
 
            make_real(&op[-2], 0.0);
4318
 
            make_real(&op[-1], 0.0);
4319
 
            make_real(op, 0.0);
4320
 
            break;
4321
 
        }
4322
 
    } else {
4323
 
        *stage = 0;
4324
 
        *cont = 1;
4325
 
    }
4326
 
    return 0;
4327
 
}
4328
 
static int devicenvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
4329
 
{
4330
 
    int i, code;
4331
 
    ref narray;
4332
 
    os_ptr op = osp;
4333
 
 
4334
 
    code = array_get(imemory, space, 1, &narray);
4335
 
    if (code < 0)
4336
 
        return code;
4337
 
    if (!r_is_array(&narray))
4338
 
        return_error(e_typecheck);
4339
 
 
4340
 
    if (num_comps < r_size(&narray))
4341
 
        return_error(e_stackunderflow);
4342
 
 
4343
 
    op -= r_size(&narray) - 1;
4344
 
 
4345
 
    for (i=0;i < r_size(&narray); i++) {
4346
 
        if (!r_has_type(op, t_integer) && !r_has_type(op, t_real))
4347
 
            return_error(e_typecheck);
4348
 
 
4349
 
        if (values[i] > 1.0)
4350
 
            values[i] = 1.0;
4351
 
 
4352
 
        if (values[i] < 0.0)
4353
 
            values[i] = 0.0;
4354
 
        op++;
4355
 
    }
4356
 
 
4357
 
    return 0;
4358
 
}
4359
 
static int devicencompareproc(i_ctx_t *i_ctx_p, ref *space, ref *testspace)
4360
 
{
4361
 
    ref sname1, sname2;
4362
 
    int code;
4363
 
 
4364
 
    code = array_get(imemory, space, 1, &sname1);
4365
 
    if (code < 0)
4366
 
        return 0;
4367
 
 
4368
 
    code = array_get(imemory, testspace, 1, &sname2);
4369
 
    if (code < 0)
4370
 
        return 0;
4371
 
 
4372
 
    if (!r_is_array(&sname1))
4373
 
        return 0;
4374
 
    if (!r_is_array(&sname2))
4375
 
        return 0;
4376
 
 
4377
 
    if (!comparearrays(i_ctx_p, &sname1, &sname2))
4378
 
        return 0;
4379
 
 
4380
 
    code = array_get(imemory, testspace, 2, &sname1);
4381
 
    if (code < 0)
4382
 
        return 0;
4383
 
    code = array_get(imemory, testspace, 2, &sname2);
4384
 
    if (code < 0)
4385
 
        return 0;
4386
 
    if (r_type(&sname1) != r_type(&sname2))
4387
 
        return 0;
4388
 
 
4389
 
    if (r_is_array(&sname1)) {
4390
 
        if (!comparearrays(i_ctx_p, &sname1, &sname2))
4391
 
            return 0;
4392
 
    } else {
4393
 
        if (!r_has_type(&sname1, t_name))
4394
 
            return 0;
4395
 
        if (!name_eq(&sname1, &sname2))
4396
 
            return 0;
4397
 
    }
4398
 
    code = array_get(imemory, space, 3, &sname1);
4399
 
    if (code < 0)
4400
 
        return 0;
4401
 
    code = array_get(imemory, testspace, 3, &sname2);
4402
 
    if (code < 0)
4403
 
        return 0;
4404
 
    return(comparearrays(i_ctx_p, &sname1, &sname2));
4405
 
}
4406
 
static int deviceninitialproc(i_ctx_t *i_ctx_p, ref *space)
4407
 
{
4408
 
    gs_client_color cc;
4409
 
    int i, num_components, code;
4410
 
    ref namesarray;
4411
 
 
4412
 
    code = array_get(imemory, space, 1, &namesarray);
4413
 
    if (code < 0)
4414
 
        return code;
4415
 
    num_components = r_size(&namesarray);
4416
 
    cc.pattern = 0x00;
4417
 
    for (i=0;i<num_components;i++)
4418
 
        cc.paint.values[i] = 1.0;
4419
 
    return gs_setcolor(igs, &cc);
4420
 
}
4421
 
 
4422
 
/* Indexed */
4423
 
/*
4424
 
 * This routine samples the indexed space, it pushes values from -1
4425
 
 * to 'hival', then executes the tint transform procedure. Returns here
4426
 
 * to store the resulting value(s) in the indexed map.
4427
 
 */
4428
 
static int
4429
 
indexed_cont(i_ctx_t *i_ctx_p)
4430
 
{
4431
 
    os_ptr op = osp;
4432
 
    es_ptr ep = esp;
4433
 
    int i = (int)ep[csme_index].value.intval;
4434
 
 
4435
 
    if (i >= 0) {               /* i.e., not first time */
4436
 
        int m = (int)ep[csme_num_components].value.intval;
4437
 
        int code = float_params(op, m, &r_ptr(&ep[csme_map], gs_indexed_map)->values[i * m]);
4438
 
 
4439
 
        if (code < 0)
4440
 
            return code;
4441
 
        pop(m);
4442
 
        op -= m;
4443
 
        if (i == (int)ep[csme_hival].value.intval) {    /* All done. */
4444
 
            esp -= num_csme;
4445
 
            return o_pop_estack;
4446
 
        }
4447
 
    }
4448
 
    push(1);
4449
 
    ep[csme_index].value.intval = ++i;
4450
 
    make_int(op, i);
4451
 
    make_op_estack(ep + 1, indexed_cont);
4452
 
    ep[2] = ep[csme_proc];      /* lookup proc */
4453
 
    esp = ep + 2;
4454
 
    return o_push_estack;
4455
 
}
4456
 
static int setindexedspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
4457
 
{
4458
 
    ref *pproc = &istate->colorspace[0].procs.special.index_proc;
4459
 
    int code = 0;
4460
 
    uint edepth = ref_stack_count(&e_stack);
4461
 
    ref_colorspace cspace_old;
4462
 
    ref hival, lookup;
4463
 
    gs_color_space *pcs;
4464
 
    gs_color_space *pcs_base;
4465
 
 
4466
 
    if (i_ctx_p->language_level < 2)
4467
 
        return_error(e_undefined);
4468
 
 
4469
 
    *cont = 0;
4470
 
    if (*stage == 1) {
4471
 
        *stage = 0;
4472
 
        return 0;
4473
 
    }
4474
 
 
4475
 
    cspace_old = istate->colorspace[0];
4476
 
 
4477
 
    pcs_base = gs_currentcolorspace(igs);
4478
 
 
4479
 
    code = array_get(imemory, r, 3, &lookup);
4480
 
    if (code < 0)
4481
 
        return code;
4482
 
    code = array_get(imemory, r, 2, &hival);
4483
 
    if (code < 0)
4484
 
        return code;
4485
 
    if (r_has_type(&lookup, t_string)) {
4486
 
        int num_values = (hival.value.intval + 1) * cs_num_components(pcs_base);
4487
 
        byte *data_tmp;
4488
 
 
4489
 
        check_read(lookup);
4490
 
        /*
4491
 
         * The PDF and PS specifications state that the lookup table must have
4492
 
         * the exact number of of data bytes needed.  However we have found
4493
 
         * PDF files from Amyuni with extra data bytes.  Acrobat 6.0 accepts
4494
 
         * these files without complaint, so we ignore the extra data.
4495
 
         */
4496
 
        if (r_size(&lookup) < num_values)
4497
 
            return_error(e_rangecheck);
4498
 
        pcs = gs_cspace_alloc(imemory, &gs_color_space_type_Indexed);
4499
 
        if (!pcs) {
4500
 
            return_error(e_VMerror);
4501
 
        }
4502
 
        pcs->base_space = pcs_base;
4503
 
        rc_increment_cs(pcs_base);
4504
 
        
4505
 
        data_tmp = (byte *) (pcs->params.indexed.lookup.table.data = ialloc_string (lookup.tas.rsize, "setindexedspace"));
4506
 
        if (!data_tmp) {
4507
 
            rc_decrement(pcs, "setindexedspace");
4508
 
            return_error(e_VMerror);
4509
 
        }
4510
 
 
4511
 
        memcpy(data_tmp, lookup.value.const_bytes, lookup.tas.rsize);
4512
 
 
4513
 
        pcs->params.indexed.lookup.table.size = num_values;
4514
 
        pcs->params.indexed.use_proc = 0;
4515
 
        make_null(pproc);
4516
 
        code = 0;
4517
 
    } else {
4518
 
        gs_indexed_map *map;
4519
 
 
4520
 
        /*
4521
 
         * We have to call zcs_begin_map before moving the parameters,
4522
 
         * since if the color space is a DeviceN or Separation space,
4523
 
         * the memmove will overwrite its parameters.
4524
 
         */
4525
 
        code = zcs_begin_map(i_ctx_p, &map, &lookup, (hival.value.intval + 1),
4526
 
                             pcs_base, indexed_cont);
4527
 
        if (code < 0)
4528
 
            return code;
4529
 
        pcs = gs_cspace_alloc(imemory, &gs_color_space_type_Indexed);
4530
 
        pcs->base_space = pcs_base;
4531
 
        rc_increment_cs(pcs_base);
4532
 
        pcs->params.indexed.use_proc = 1;
4533
 
        *pproc = lookup;
4534
 
        map->proc.lookup_index = lookup_indexed_map;
4535
 
        pcs->params.indexed.lookup.map = map;
4536
 
    }
4537
 
    pcs->params.indexed.hival = hival.value.intval;
4538
 
    pcs->params.indexed.n_comps = cs_num_components(pcs_base);
4539
 
    code = gs_setcolorspace(igs, pcs);
4540
 
    /* release reference from construction */
4541
 
    rc_decrement_only_cs(pcs, "setindexedspace");
4542
 
    if (code < 0) {
4543
 
        istate->colorspace[0] = cspace_old;
4544
 
        ref_stack_pop_to(&e_stack, edepth);
4545
 
        return code;
4546
 
    }
4547
 
    *stage = 0;
4548
 
    if (ref_stack_count(&e_stack) == edepth) {
4549
 
        return 0;
4550
 
    } else {
4551
 
        *cont = 1;
4552
 
        *stage = 1;
4553
 
        return o_push_estack; /* installation will load the caches */
4554
 
    }
4555
 
}
4556
 
static int validateindexedspace(i_ctx_t * i_ctx_p, ref **space)
4557
 
{
4558
 
    int code = 0;
4559
 
    ref *r = *space;
4560
 
    ref nameref, sref, hival, lookup, altspace;
4561
 
 
4562
 
    if (!r_is_array(r))
4563
 
        return_error(e_typecheck);
4564
 
    /* Validate parameters, check we have enough operands */
4565
 
    if (r_size(r) != 4)
4566
 
        return_error(e_rangecheck);
4567
 
    /* Check operand type(s) */
4568
 
    /* Make sure 'hival' is an integer */
4569
 
    code = array_get(imemory, r, 2, &hival);
4570
 
    if (code < 0)
4571
 
        return code;
4572
 
    if (!r_has_type(&hival, t_integer))
4573
 
        return_error(e_typecheck);
4574
 
    /* Make sure 'hival' lies between 0 and 4096 */
4575
 
    if (hival.value.intval < 0 || hival.value.intval > 4096)
4576
 
        return_error(e_rangecheck);
4577
 
    /* Ensure the 'lookup' is either a string or a procedure */
4578
 
    code = array_get(imemory, r, 3, &lookup);
4579
 
    if (code < 0)
4580
 
        return code;
4581
 
    if (!r_has_type(&lookup, t_string))
4582
 
        check_proc(lookup);
4583
 
 
4584
 
    /* Get the name of the alternate space */
4585
 
    code = array_get(imemory, r, 1, &altspace);
4586
 
    if (code < 0)
4587
 
        return code;
4588
 
    if (r_has_type(&altspace, t_name))
4589
 
        ref_assign(&nameref, &altspace);
4590
 
    else {
4591
 
        if (!r_is_array(&altspace))
4592
 
            return_error(e_typecheck);
4593
 
        code = array_get(imemory, &altspace, 0, &nameref);
4594
 
        if (code < 0)
4595
 
            return code;
4596
 
    }
4597
 
    /* Convert alternate space name to string */
4598
 
    name_string_ref(imemory, &nameref, &sref);
4599
 
    /* Check its not /Indexed or /Pattern */
4600
 
    if (r_size(&sref) == 7) {
4601
 
        if (strncmp((const char *)sref.value.const_bytes, "Indexed", 7) == 0)
4602
 
            return_error(e_typecheck);
4603
 
        if (strncmp((const char *)sref.value.const_bytes, "Pattern", 7) == 0)
4604
 
            return_error(e_typecheck);
4605
 
    }
4606
 
    ref_assign(*space, &altspace);
4607
 
    return 0;
4608
 
}
4609
 
static int indexedalternatespace(i_ctx_t * i_ctx_p, ref *space, ref **r, int *CIESubst)
4610
 
{
4611
 
    ref alt;
4612
 
    int code;
4613
 
 
4614
 
    code = array_get(imemory, *r, 1, &alt);
4615
 
    if (code < 0)
4616
 
        return code;
4617
 
    ref_assign(*r, &alt);
4618
 
    return 0;
4619
 
}
4620
 
static int indexeddomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
4621
 
{
4622
 
    ref hival;
4623
 
    int code;
4624
 
 
4625
 
    code = array_get(imemory, space, 2, &hival);
4626
 
    if (code < 0)
4627
 
        return code;
4628
 
    ptr[0] = 0;
4629
 
    ptr[1] = (float)hival.value.intval;
4630
 
    return 0;
4631
 
}
4632
 
static int indexedrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
4633
 
{
4634
 
    ref hival;
4635
 
    int code;
4636
 
 
4637
 
    code = array_get(imemory, space, 2, &hival);
4638
 
    if (code < 0)
4639
 
        return code;
4640
 
    ptr[0] = 0;
4641
 
    ptr[1] = (float)hival.value.intval;
4642
 
    return 0;
4643
 
}
4644
 
static int indexedbasecolor(i_ctx_t * i_ctx_p, ref *space, int base, int *stage, int *cont, int *stack_depth)
4645
 
{
4646
 
    int code;
4647
 
 
4648
 
    if (*stage == 0) {
4649
 
        /* Usefully /Indexed can't be the base of any other space, so we know
4650
 
         * the current space in the graphics state is this one.
4651
 
         */
4652
 
        gs_color_space *pcs;
4653
 
        pcs = gs_currentcolorspace(igs);
4654
 
 
4655
 
        /* Update the counters */
4656
 
        *stage = 1;
4657
 
        *cont = 1;
4658
 
 
4659
 
        /* Indexed spaces can have *either* a procedure or a string for the
4660
 
         * lookup.
4661
 
         */
4662
 
        if (pcs->params.indexed.use_proc) {
4663
 
            es_ptr ep = ++esp;
4664
 
            ref proc;
4665
 
 
4666
 
            /* We have a procedure, set up the continuation to run the
4667
 
             * lookup procedure. (The index is already on the operand stack)
4668
 
             */
4669
 
            check_estack(1);
4670
 
            code = array_get(imemory, space, 3, &proc);
4671
 
            if (code < 0)
4672
 
                return code;
4673
 
            *ep = proc; /* lookup proc */
4674
 
            return o_push_estack;
4675
 
        } else {
4676
 
            int i, index;
4677
 
            os_ptr op = osp;
4678
 
            unsigned char *ptr = (unsigned char *)pcs->params.indexed.lookup.table.data;
4679
 
 
4680
 
            *stage = 0;
4681
 
            /* We have a string, start by retrieving the index from the op stack */
4682
 
            /* Make sure its an integer! */
4683
 
            if (!r_has_type(op, t_integer))
4684
 
                return_error (e_typecheck);
4685
 
            index = op->value.intval;
4686
 
            /* And remove it from the stack. */
4687
 
            pop(1);
4688
 
            op = osp;
4689
 
 
4690
 
            /* Make sure we have enough space on the op stack to hold
4691
 
             * one value for each component of the alternate space
4692
 
             */
4693
 
            push(pcs->params.indexed.n_comps);
4694
 
            op -= pcs->params.indexed.n_comps - 1;
4695
 
 
4696
 
            /* Move along the lookup table, one byte for each component , the
4697
 
             * number of times required to get to the lookup for this index
4698
 
             */
4699
 
            ptr += index * pcs->params.indexed.n_comps;
4700
 
 
4701
 
            /* For all the components of the alternate space, push the value
4702
 
             * of the component on the stack. The value is given by the byte
4703
 
             * from the lookup table divided by 255 to give a value between
4704
 
             * 0 and 1.
4705
 
             */
4706
 
            for (i = 0; i < pcs->params.indexed.n_comps; i++, op++) {
4707
 
                float rval = (*ptr++) / 255.0;
4708
 
                make_real(op, rval);
4709
 
            }
4710
 
            return 0;
4711
 
        }
4712
 
    } else {
4713
 
        *stage = 0;
4714
 
        *cont = 1;
4715
 
        return 0;
4716
 
    }
4717
 
}
4718
 
static int indexedvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
4719
 
{
4720
 
    int code;
4721
 
    ref hival;
4722
 
    os_ptr op = osp;
4723
 
 
4724
 
    if (num_comps < 1)
4725
 
        return_error(e_stackunderflow);
4726
 
 
4727
 
    if (!r_has_type(op, t_integer) && !r_has_type(op, t_real))
4728
 
        return_error(e_typecheck);
4729
 
 
4730
 
    code = array_get(imemory, space, 2, &hival);
4731
 
    if (code < 0)
4732
 
        return code;
4733
 
 
4734
 
    if (*values > hival.value.intval)
4735
 
        *values = (float)hival.value.intval;
4736
 
 
4737
 
    if (*values < 0)
4738
 
        *values = 0;
4739
 
 
4740
 
    /* The PLRM says 'If it is a real number, it is rounded to the nearest integer
4741
 
     * but in fact Acrobat simply floors the value.
4742
 
     */
4743
 
    *values = floor(*values);
4744
 
 
4745
 
    return 0;
4746
 
}
4747
 
 
4748
 
/* Pattern */
4749
 
static int setpatternspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
4750
 
{
4751
 
    gs_color_space *pcs;
4752
 
    gs_color_space *pcs_base;
4753
 
    uint edepth = ref_stack_count(&e_stack);
4754
 
    int code = 0;
4755
 
 
4756
 
    if (i_ctx_p->language_level < 2)
4757
 
        return_error(e_undefined);
4758
 
 
4759
 
    *cont = 0;
4760
 
    pcs_base = NULL;
4761
 
    if (r_is_array(r)) {
4762
 
        check_read(*r);
4763
 
 
4764
 
        switch (r_size(r)) {
4765
 
            case 1:             /* no base space */
4766
 
                pcs_base = NULL;
4767
 
                break;
4768
 
            default:
4769
 
                return_error(e_rangecheck);
4770
 
            case 2:
4771
 
                pcs_base = gs_currentcolorspace(igs);
4772
 
                if (cs_num_components(pcs_base) < 0)       /* i.e., Pattern space */
4773
 
                    return_error(e_rangecheck);
4774
 
        }
4775
 
    }
4776
 
    pcs = gs_cspace_alloc(imemory, &gs_color_space_type_Pattern);
4777
 
    pcs->base_space = pcs_base;
4778
 
    pcs->params.pattern.has_base_space = (pcs_base != NULL);
4779
 
    rc_increment_cs(pcs_base);
4780
 
    code = gs_setcolorspace(igs, pcs);
4781
 
    /* release reference from construction */
4782
 
    rc_decrement_only_cs(pcs, "zsetpatternspace");
4783
 
    if (code < 0) {
4784
 
        ref_stack_pop_to(&e_stack, edepth);
4785
 
        return code;
4786
 
    }
4787
 
    make_null(&istate->pattern[0]); /* PLRM: initial color value is a null object */
4788
 
    *stage = 0;
4789
 
    return (ref_stack_count(&e_stack) == edepth ? 0 : o_push_estack);   /* installation will load the caches */
4790
 
}
4791
 
static int validatepatternspace(i_ctx_t * i_ctx_p, ref **r)
4792
 
{
4793
 
    int code;
4794
 
    ref tref;
4795
 
 
4796
 
    /* since makepattern has already been run, we don't need to do much validation */
4797
 
    if (!r_has_type(*r, t_name)) {
4798
 
        if (r_is_array(*r)) {
4799
 
            if (r_size(*r) > 1) {
4800
 
                code = array_get(imemory, *r, 1, &tref);
4801
 
                if (code < 0)
4802
 
                    return code;
4803
 
                ref_assign(*r, &tref);
4804
 
            } else
4805
 
                *r = 0;
4806
 
        } else
4807
 
            return_error(e_typecheck);
4808
 
    } else
4809
 
        *r = 0;
4810
 
    return 0;
4811
 
}
4812
 
static int patternalternatespace(i_ctx_t * i_ctx_p, ref *space, ref **r, int *CIESubst)
4813
 
{
4814
 
    ref tref;
4815
 
    int code;
4816
 
 
4817
 
    if (!r_has_type(*r, t_name)) {
4818
 
        if (r_is_array(*r)) {
4819
 
            if (r_size(*r) > 1) {
4820
 
                code = array_get(imemory, space, 1, &tref);
4821
 
                if (code < 0)
4822
 
                    return code;
4823
 
                ref_assign(*r, &tref);
4824
 
            } else
4825
 
                *r = 0;
4826
 
        } else
4827
 
            return_error(e_typecheck);
4828
 
    } else
4829
 
        *r = 0;
4830
 
    return 0;
4831
 
}
4832
 
static int patterncomponent(i_ctx_t * i_ctx_p, ref *space, int *n)
4833
 
{
4834
 
    os_ptr op = osp;
4835
 
    int n_comps, code;
4836
 
    const gs_color_space *  pcs = gs_currentcolorspace(igs);
4837
 
    gs_client_color         cc;
4838
 
 
4839
 
    /* check for a pattern color space */
4840
 
    if ((n_comps = cs_num_components(pcs)) < 0) {
4841
 
        n_comps = -n_comps;
4842
 
        if (r_has_type(op, t_dictionary)) {
4843
 
            ref     *pImpl, pPatInst;
4844
 
 
4845
 
            code = dict_find_string(op, "Implementation", &pImpl);
4846
 
            if (code < 0)
4847
 
                return code;
4848
 
            code = array_get(imemory, pImpl, 0, &pPatInst);
4849
 
            if (code < 0)
4850
 
                return code;
4851
 
            cc.pattern = r_ptr(&pPatInst, gs_pattern_instance_t);
4852
 
            if (pattern_instance_uses_base_space(cc.pattern))
4853
 
                *n = n_comps;
4854
 
            else
4855
 
                *n = 1;
4856
 
        } else
4857
 
            *n = 1;
4858
 
    } else
4859
 
        return_error(e_typecheck);
4860
 
 
4861
 
    return 0;
4862
 
}
4863
 
static int patternbasecolor(i_ctx_t * i_ctx_p, ref *space, int base, int *stage, int *cont, int *stack_depth)
4864
 
{
4865
 
    os_ptr op;
4866
 
    int i, components=0;
4867
 
 
4868
 
    if (r_size(space) > 1) {
4869
 
        const gs_color_space *  pcs = gs_currentcolorspace(igs);
4870
 
        const gs_client_color * pcc = gs_currentcolor(igs);
4871
 
        int                     n = cs_num_components(pcs);
4872
 
        bool                    push_pattern = n < 0;
4873
 
        gs_pattern_instance_t * pinst = pcc->pattern;
4874
 
 
4875
 
        if (pinst != 0 && pattern_instance_uses_base_space(pinst)) {
4876
 
            /* check for pattern */
4877
 
            if (push_pattern)
4878
 
                pop(1);     /* The pattern instance */
4879
 
            *stage = 0;
4880
 
            *cont = 1;
4881
 
            return 0;
4882
 
        }
4883
 
        /* If the pattern isn't yet initialised, or doesn't use the
4884
 
         * base space, treat as uncolored and return defaults below
4885
 
         * Fall Through.
4886
 
         */
4887
 
    }
4888
 
 
4889
 
    pop(1);
4890
 
    op = osp;
4891
 
    switch(base) {
4892
 
        case 0:
4893
 
            components = 1;
4894
 
            break;
4895
 
        case 1:
4896
 
        case 2:
4897
 
            components = 3;
4898
 
            break;
4899
 
        case 3:
4900
 
            components = 4;
4901
 
            break;
4902
 
    }
4903
 
    push(components);
4904
 
    op -= components-1;
4905
 
    for (i=0;i<components;i++) {
4906
 
        make_real(op, (float)0);
4907
 
        op++;
4908
 
    }
4909
 
    if (components == 4) {
4910
 
        op--;
4911
 
        make_real(op, (float)1);
4912
 
    }
4913
 
    *stage = 0;
4914
 
    *cont = 0;
4915
 
    return 0;
4916
 
}
4917
 
static int patternvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
4918
 
{
4919
 
    os_ptr op = osp;
4920
 
 
4921
 
    check_op(1);
4922
 
 
4923
 
    if (!r_has_type(op, t_dictionary) && !r_has_type(op, t_null))
4924
 
        return_error(e_typecheck);
4925
 
 
4926
 
    return 0;
4927
 
}
4928
 
 
4929
 
/* DevicePixel */
4930
 
static int setdevicepspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
4931
 
{
4932
 
    int code = 0;
4933
 
    gs_color_space *pcs;
4934
 
    ref bpp;
4935
 
 
4936
 
    /* The comment in the original PostScript (gs_lev2.ps) said
4937
 
     * "DevicePixel is actually a LanguageLevel 3 feature; it is here for
4938
 
     *  historical reasons." Actually DevicePixel is a Display PostScript
4939
 
     * space, as far as I can tell. It certainly isn't a level 3 space.
4940
 
     * Preserve the old behaviour anyway.
4941
 
     */
4942
 
    if (i_ctx_p->language_level < 2)
4943
 
        return_error(e_undefined);
4944
 
 
4945
 
    *cont = 0;
4946
 
    code = array_get(imemory, r, 1, &bpp);
4947
 
    if (code < 0)
4948
 
        return code;
4949
 
    if (!r_has_type(&bpp, t_integer))
4950
 
        return_error(e_typecheck);
4951
 
    code = gs_cspace_new_DevicePixel(imemory, &pcs, (int)bpp.value.intval);
4952
 
    if (code < 0)
4953
 
        return code;
4954
 
    code = gs_setcolorspace(igs, pcs);
4955
 
    /* release reference from construction */
4956
 
    *stage = 0;
4957
 
    rc_decrement_only_cs(pcs, "setseparationspace");
4958
 
    return code;
4959
 
}
4960
 
static int validatedevicepspace(i_ctx_t * i_ctx_p, ref **space)
4961
 
{
4962
 
    int code = 0;
4963
 
    ref *r = *space, bpp;
4964
 
 
4965
 
    if (!r_is_array(r))
4966
 
        return_error(e_typecheck);
4967
 
    /* Validate parameters, check we have enough operands */
4968
 
    if (r_size(r) != 2)
4969
 
        return_error(e_rangecheck);
4970
 
    /* Make sure 'bits per pixel' is an integer */
4971
 
    code = array_get(imemory, r, 1, &bpp);
4972
 
    if (code < 0)
4973
 
        return code;
4974
 
    if (!r_has_type(&bpp, t_integer))
4975
 
        return_error(e_typecheck);
4976
 
 
4977
 
    /* Make sure 'bits per pixel' lies between 0 and 31 */
4978
 
    if (bpp.value.intval < 0 || bpp.value.intval > 31)
4979
 
        return_error(e_rangecheck);
4980
 
 
4981
 
    *space = 0;
4982
 
    return code;
4983
 
}
4984
 
static int devicepdomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
4985
 
{
4986
 
    int code;
4987
 
    ref tref;
4988
 
 
4989
 
    code = array_get(imemory, space, 1, &tref);
4990
 
    if (code < 0)
4991
 
        return code;
4992
 
    ptr[0] = 0;
4993
 
    ptr[1] = (float)(1 << tref.value.intval);
4994
 
    return 0;
4995
 
}
4996
 
static int deviceprange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
4997
 
{
4998
 
    int code;
4999
 
    ref tref;
5000
 
 
5001
 
    code = array_get(imemory, space, 1, &tref);
5002
 
    if (code < 0)
5003
 
        return code;
5004
 
    ptr[0] = 0;
5005
 
    ptr[1] = (float)(1 << tref.value.intval);
5006
 
    return 0;
5007
 
}
5008
 
static int devicepbasecolor(i_ctx_t * i_ctx_p, ref *space, int base, int *stage, int *cont, int *stack_depth)
5009
 
{
5010
 
    os_ptr  op = osp;
5011
 
 
5012
 
    *stage = 0;
5013
 
    *cont = 0;
5014
 
    make_int(op, 0);
5015
 
    return 0;
5016
 
}
5017
 
static int devicepvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
5018
 
{
5019
 
    return 0;
5020
 
}
5021
 
 
5022
 
static int set_dev_space(i_ctx_t * i_ctx_p, int components)
5023
 
{
5024
 
    int code, stage = 1, cont = 0;
5025
 
    switch(components) {
5026
 
        case 1:
5027
 
            code = setgrayspace(i_ctx_p, (ref *)0, &stage, &cont, 1);
5028
 
            break;
5029
 
        case 3:
5030
 
            code = setrgbspace(i_ctx_p, (ref *)0, &stage, &cont, 1);
5031
 
            break;
5032
 
        case 4:
5033
 
            code = setcmykspace(i_ctx_p, (ref *)0, &stage, &cont, 1);
5034
 
            break;
5035
 
        default:
5036
 
            code = gs_note_error(e_rangecheck);
5037
 
            break;
5038
 
    }
5039
 
    return code;
5040
 
}
5041
 
 
5042
 
/* Lab Space */
5043
 
 
5044
 
/* Check that the range of a the ab values is valid */
5045
 
static int checkrangeab(i_ctx_t * i_ctx_p, ref *labdict)
5046
 
{
5047
 
    int code = 0, i;
5048
 
    float value[4];
5049
 
    ref *tempref, valref;
5050
 
 
5051
 
    code = dict_find_string(labdict, "Range", &tempref);
5052
 
    if (code >= 0 && !r_has_type(tempref, t_null)) {
5053
 
        if (!r_is_array(tempref))
5054
 
            return_error(e_typecheck);
5055
 
        if (r_size(tempref) != 4)
5056
 
            return_error(e_rangecheck);
5057
 
 
5058
 
        for (i=0;i<4;i++) {
5059
 
            code = array_get(imemory, tempref, i, &valref);
5060
 
            if (code < 0)
5061
 
                return code;
5062
 
            if (r_has_type(&valref, t_integer))
5063
 
                value[i] = (float)valref.value.intval;
5064
 
            else if (r_has_type(&valref, t_real))
5065
 
                value[i] = (float)valref.value.realval;
5066
 
            else
5067
 
                return_error(e_typecheck);
5068
 
        }
5069
 
        if (value[1] < value[0] || value[3] < value[2] )
5070
 
            return_error(e_rangecheck);
5071
 
    }
5072
 
    return 0;
5073
 
}
5074
 
 
5075
 
static int setlabspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, 
5076
 
                       int CIESubst)
5077
 
{
5078
 
    /* In this case, we will treat this as an ICC color space, with a 
5079
 
       CIELAB 16 bit profile */
5080
 
    ref labdict;
5081
 
    int code = 0;
5082
 
    float                   range_buff[4], white[3], black[3];
5083
 
    static const float      dflt_range[4] = { -100, 100, -100, 100 };
5084
 
    static const float      dflt_black[3] = {0,0,0}, dflt_white[3] = {0,0,0};
5085
 
    int i;
5086
 
    gs_client_color cc;
5087
 
  
5088
 
    *cont = 0;
5089
 
    code = array_get(imemory, r, 1, &labdict);
5090
 
    if (code < 0)
5091
 
        return code;
5092
 
/* Get all the parts */
5093
 
    code = dict_floats_param( imemory, &labdict, "Range", 4, range_buff,
5094
 
                              dflt_range );
5095
 
    for (i = 0; i < 4 && range_buff[i + 1] >= range_buff[i]; i += 2);
5096
 
    if (i != 4)
5097
 
        return_error(e_rangecheck);
5098
 
    code = dict_floats_param( imemory, &labdict, "BlackPoint", 3, black, 
5099
 
                              dflt_black );
5100
 
     code = dict_floats_param( imemory, &labdict, "WhitePoint", 3, white,
5101
 
                              dflt_white );
5102
 
     if (white[0] <= 0 || white[1] != 1.0 || white[2] <= 0)
5103
 
        return_error(e_rangecheck);
5104
 
    code = seticc_lab(i_ctx_p, white, black, range_buff);
5105
 
    if ( code < 0)
5106
 
        return gs_rethrow(code, "setting PDF lab color space");
5107
 
    cc.pattern = 0x00;
5108
 
    for (i=0;i<3;i++) 
5109
 
        cc.paint.values[i] = 0;
5110
 
    code = gs_setcolor(igs, &cc);
5111
 
    return code;
5112
 
}
5113
 
 
5114
 
static int validatelabspace(i_ctx_t * i_ctx_p, ref **r)
5115
 
{
5116
 
    int code=0;
5117
 
    ref *space, labdict;
5118
 
    
5119
 
    space = *r;
5120
 
    if (!r_is_array(space))
5121
 
        return_error(e_typecheck);
5122
 
    /* Validate parameters, check we have enough operands */
5123
 
    if (r_size(space) < 2)
5124
 
        return_error(e_rangecheck);
5125
 
    code = array_get(imemory, space, 1, &labdict);
5126
 
    if (code < 0)
5127
 
        return code;
5128
 
    /* Check the white point, which is required. */
5129
 
    code = checkWhitePoint(i_ctx_p, &labdict);
5130
 
    if (code != 0)
5131
 
        return code;
5132
 
    /* The rest are optional.  Need to validate though */
5133
 
    code = checkBlackPoint(i_ctx_p, &labdict);
5134
 
    if (code < 0)
5135
 
        return code;
5136
 
    /* Range on a b values */
5137
 
    code = checkrangeab(i_ctx_p, &labdict);
5138
 
    if (code < 0)
5139
 
        return code;
5140
 
    *r = 0;  /* No nested space */
5141
 
    return 0;
5142
 
}
5143
 
 
5144
 
static int labrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
5145
 
{
5146
 
    int i, code;
5147
 
    ref     CIEdict, *tempref, valref;
5148
 
 
5149
 
    code = array_get(imemory, space, 1, &CIEdict);
5150
 
    if (code < 0)
5151
 
        return code;
5152
 
 
5153
 
    /* If we have a Range entry, get the values from that */
5154
 
    code = dict_find_string(&CIEdict, "Range", &tempref);
5155
 
    if (code >= 0 && !r_has_type(tempref, t_null)) {
5156
 
        for (i=0;i<4;i++) {
5157
 
            code = array_get(imemory, tempref, i, &valref);
5158
 
            if (code < 0)
5159
 
                return code;
5160
 
            if (r_has_type(&valref, t_integer))
5161
 
                ptr[i] = (float)valref.value.intval;
5162
 
            else if (r_has_type(&valref, t_real))
5163
 
                ptr[i] = (float)valref.value.realval;
5164
 
            else
5165
 
                return_error(e_typecheck);
5166
 
        }
5167
 
    } else {
5168
 
        /* Default values for Lab */
5169
 
        for (i=0;i<2;i++) {
5170
 
            ptr[2 * i] = -100;
5171
 
            ptr[(2 * i) + 1] = 100;
5172
 
        }
5173
 
    }
5174
 
    return 0;
5175
 
}
5176
 
 
5177
 
 
5178
 
static int labdomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
5179
 
{
5180
 
    int i, code;
5181
 
    ref     CIEdict, *tempref, valref;
5182
 
 
5183
 
    code = array_get(imemory, space, 1, &CIEdict);
5184
 
    if (code < 0)
5185
 
        return code;
5186
 
 
5187
 
    /* If we have a Range, get the values from that */
5188
 
    code = dict_find_string(&CIEdict, "Range", &tempref);
5189
 
    if (code >= 0 && !r_has_type(tempref, t_null)) {
5190
 
        for (i=0;i<4;i++) {
5191
 
            code = array_get(imemory, tempref, i, &valref);
5192
 
            if (code < 0)
5193
 
                return code;
5194
 
            if (r_has_type(&valref, t_integer))
5195
 
                ptr[i] = (float)valref.value.intval;
5196
 
            else if (r_has_type(&valref, t_real))
5197
 
                ptr[i] = (float)valref.value.realval;
5198
 
            else
5199
 
                return_error(e_typecheck);
5200
 
        }
5201
 
    } else {
5202
 
        /* Default values for Lab */
5203
 
        for (i=0;i<2;i++) {
5204
 
            ptr[2 * i] = -100;
5205
 
            ptr[(2 * i) + 1] = 100;
5206
 
        }
5207
 
    }
5208
 
    return 0;
5209
 
}
5210
 
 
5211
 
static int labbasecolor(i_ctx_t * i_ctx_p, ref *space, int base, int *stage, int *cont, int *stack_depth)
5212
 
{
5213
 
    os_ptr op;
5214
 
    int i, components=1;
5215
 
 
5216
 
    components = 3;
5217
 
    pop(components);
5218
 
    op = osp;
5219
 
    components = 3;
5220
 
    push(components);
5221
 
    op -= components-1;
5222
 
    for (i=0;i<components;i++) {
5223
 
        make_real(op, (float)0);
5224
 
        op++;
5225
 
    }
5226
 
    *stage = 0;
5227
 
    *cont = 0;
5228
 
    return 0;
5229
 
}
5230
 
 
5231
 
static int labvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
5232
 
{
5233
 
    os_ptr op = osp;
5234
 
    int i;
5235
 
 
5236
 
    if (num_comps < 3)
5237
 
        return_error(e_stackunderflow);
5238
 
    op -= 2;
5239
 
    for (i=0;i<3;i++) {
5240
 
        if (!r_has_type(op, t_integer) && !r_has_type(op, t_real))
5241
 
            return_error(e_typecheck);
5242
 
        op++;
5243
 
    }
5244
 
    return 0;
5245
 
}
5246
 
 
5247
 
/* Check that the Matrix of a CalRGB and CalGray space is valid */
5248
 
static int checkCalMatrix(i_ctx_t * i_ctx_p, ref *CIEdict)
5249
 
{
5250
 
    int code = 0, i;
5251
 
    float value[9];
5252
 
    ref *tempref, valref;
5253
 
 
5254
 
    code = dict_find_string(CIEdict, "Matrix", &tempref);
5255
 
    if (code >= 0 && !r_has_type(tempref, t_null)) {
5256
 
        if (!r_is_array(tempref))
5257
 
            return_error(e_typecheck);
5258
 
        if (r_size(tempref) != 9)
5259
 
            return_error(e_rangecheck);
5260
 
        for (i=0;i<9;i++) {
5261
 
            code = array_get(imemory, tempref, i, &valref);
5262
 
            if (code < 0)
5263
 
                return code;
5264
 
            if (r_has_type(&valref, t_integer))
5265
 
                value[i] = (float)valref.value.intval;
5266
 
            else if (r_has_type(&valref, t_real))
5267
 
                value[i] = (float)valref.value.realval;
5268
 
            else
5269
 
                return_error(e_typecheck);
5270
 
        }
5271
 
    }
5272
 
    return 0;
5273
 
}
5274
 
 
5275
 
/* Check that the Gamma of a CalRGB and CalGray space is valid */
5276
 
static int checkGamma(i_ctx_t * i_ctx_p, ref *CIEdict, int numvalues)
5277
 
{
5278
 
    int code = 0, i;
5279
 
    float value[3];
5280
 
    ref *tempref, valref;
5281
 
 
5282
 
    code = dict_find_string(CIEdict, "Gamma", &tempref);
5283
 
    if (code >= 0 && !r_has_type(tempref, t_null)) {
5284
 
        if (numvalues > 1) {
5285
 
            /* Array of gammas (RGB) */
5286
 
            if (!r_is_array(tempref))
5287
 
                return_error(e_typecheck);
5288
 
            if (r_size(tempref) != numvalues)
5289
 
                return_error(e_rangecheck);
5290
 
            for (i=0;i<numvalues;i++) {
5291
 
                code = array_get(imemory, tempref, i, &valref);
5292
 
                if (code < 0)
5293
 
                    return code;
5294
 
                if (r_has_type(&valref, t_integer))
5295
 
                    value[i] = (float)valref.value.intval;
5296
 
                else if (r_has_type(&valref, t_real))
5297
 
                    value[i] = (float)valref.value.realval;
5298
 
                else
5299
 
                    return_error(e_typecheck);
5300
 
                if (value[i] <= 0) return_error(e_rangecheck);
5301
 
            }
5302
 
        } else {
5303
 
            /* Single gamma (gray) */
5304
 
            if (r_has_type(tempref, t_real)) 
5305
 
                value[0] = (float)(tempref->value.realval);
5306
 
            else if (r_has_type(tempref, t_integer))
5307
 
                    value[0] = (float)(tempref->value.intval);
5308
 
            else 
5309
 
                return_error(e_typecheck);
5310
 
            if (value[0] <= 0) return_error(e_rangecheck);
5311
 
        }
5312
 
    }
5313
 
    return 0;
5314
 
}
5315
 
 
5316
 
/* Here we set up an equivalent ICC form for the CalGray color space */
5317
 
static int setcalgrayspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
5318
 
{
5319
 
    ref graydict;
5320
 
    int code = 0;
5321
 
    float                   gamma, white[3], black[3];
5322
 
    floatp                  dflt_gamma = 1.0;
5323
 
    static const float      dflt_black[3] = {0,0,0}, dflt_white[3] = {0,0,0};
5324
 
    gs_client_color cc;
5325
 
  
5326
 
    *cont = 0;
5327
 
    code = array_get(imemory, r, 1, &graydict);
5328
 
    if (code < 0)
5329
 
        return code;
5330
 
/* Get all the parts */
5331
 
    code = dict_float_param(&graydict, "Gamma",
5332
 
                 dflt_gamma, &gamma);
5333
 
    if (gamma <= 0 ) return_error(e_rangecheck);
5334
 
     code = dict_floats_param( imemory, 
5335
 
                              &graydict,
5336
 
                              "BlackPoint",
5337
 
                              3,
5338
 
                              black,
5339
 
                              dflt_black );
5340
 
     code = dict_floats_param( imemory, 
5341
 
                              &graydict,
5342
 
                              "WhitePoint",
5343
 
                              3,
5344
 
                              white,
5345
 
                              dflt_white );
5346
 
     if (white[0] <= 0 || white[1] != 1.0 || white[2] <= 0)
5347
 
        return_error(e_rangecheck);
5348
 
    code = seticc_cal(i_ctx_p, white, black, &gamma, NULL, 1, 
5349
 
                        graydict.value.saveid);         
5350
 
    if ( code < 0)
5351
 
        return gs_rethrow(code, "setting CalGray  color space");
5352
 
    cc.pattern = 0x00;
5353
 
    cc.paint.values[0] = 0;
5354
 
    code = gs_setcolor(igs, &cc);
5355
 
    return code;
5356
 
}
5357
 
 
5358
 
static int validatecalgrayspace(i_ctx_t * i_ctx_p, ref **r)
5359
 
{
5360
 
    int code=0;
5361
 
    ref *space, calgraydict;
5362
 
    
5363
 
    space = *r;
5364
 
    if (!r_is_array(space))
5365
 
        return_error(e_typecheck);
5366
 
    /* Validate parameters, check we have enough operands */
5367
 
    if (r_size(space) < 2)
5368
 
        return_error(e_rangecheck);
5369
 
    code = array_get(imemory, space, 1, &calgraydict);
5370
 
    if (code < 0)
5371
 
        return code;
5372
 
    /* Check the white point, which is required */
5373
 
    /* We have to have a white point */
5374
 
    /* Check white point exists, and is an array of three numbers */
5375
 
    code = checkWhitePoint(i_ctx_p, &calgraydict);
5376
 
    if (code != 0)
5377
 
        return code;
5378
 
    /* The rest are optional.  Need to validate though */
5379
 
    code = checkBlackPoint(i_ctx_p, &calgraydict);
5380
 
    if (code < 0)
5381
 
        return code;
5382
 
    /* Check Gamma values */
5383
 
    code = checkGamma(i_ctx_p, &calgraydict, 1);
5384
 
    if (code < 0)
5385
 
        return code;
5386
 
    *r = 0;  /* No nested space */
5387
 
    return 0;
5388
 
}
5389
 
 
5390
 
/* Here we set up an equivalent ICC form for the CalRGB color space */
5391
 
static int setcalrgbspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
5392
 
{
5393
 
    ref rgbdict;
5394
 
    int code = 0;
5395
 
    float                   gamma[3], white[3], black[3], matrix[9];
5396
 
    static const float      dflt_gamma[3] = { 1.0, 1.0, 1.0 };
5397
 
    static const float      dflt_black[3] = {0,0,0}, dflt_white[3] = {0,0,0};
5398
 
    static const float      dflt_matrix[9] = {1,0,0,0,1,0,0,0,1};
5399
 
    int i;
5400
 
    gs_client_color cc;
5401
 
  
5402
 
    *cont = 0;
5403
 
    code = array_get(imemory, r, 1, &rgbdict);
5404
 
    if (code < 0)
5405
 
        return code;
5406
 
/* Get all the parts */
5407
 
    code = dict_floats_param( imemory, 
5408
 
                              &rgbdict,
5409
 
                              "Gamma",
5410
 
                              3,
5411
 
                              gamma,
5412
 
                              dflt_gamma );
5413
 
     if (gamma[0] <= 0 || gamma[1] <= 0 || gamma[2] <= 0)
5414
 
        return_error(e_rangecheck);
5415
 
     code = dict_floats_param( imemory, 
5416
 
                              &rgbdict,
5417
 
                              "BlackPoint",
5418
 
                              3,
5419
 
                              black,
5420
 
                              dflt_black );
5421
 
     code = dict_floats_param( imemory, 
5422
 
                              &rgbdict,
5423
 
                              "WhitePoint",
5424
 
                              3,
5425
 
                              white,
5426
 
                              dflt_white );
5427
 
     if (white[0] <= 0 || white[1] != 1.0 || white[2] <= 0)
5428
 
        return_error(e_rangecheck);
5429
 
     code = dict_floats_param( imemory, 
5430
 
                              &rgbdict,
5431
 
                              "Matrix",
5432
 
                              9,
5433
 
                              matrix,
5434
 
                              dflt_matrix );
5435
 
    code = seticc_cal(i_ctx_p, white, black, gamma, matrix, 3, rgbdict.value.saveid); 
5436
 
    if ( code < 0)
5437
 
        return gs_rethrow(code, "setting CalRGB  color space");
5438
 
    cc.pattern = 0x00;
5439
 
    for (i=0;i<3;i++) 
5440
 
        cc.paint.values[i] = 0;
5441
 
    code = gs_setcolor(igs, &cc);
5442
 
    return code;
5443
 
}
5444
 
 
5445
 
static int validatecalrgbspace(i_ctx_t * i_ctx_p, ref **r)
5446
 
{
5447
 
    int code=0;
5448
 
    ref *space, calrgbdict;
5449
 
    
5450
 
    space = *r;
5451
 
    if (!r_is_array(space))
5452
 
        return_error(e_typecheck);
5453
 
    /* Validate parameters, check we have enough operands */
5454
 
    if (r_size(space) < 2)
5455
 
        return_error(e_rangecheck);
5456
 
    code = array_get(imemory, space, 1, &calrgbdict);
5457
 
    if (code < 0)
5458
 
        return code;
5459
 
    /* Check the white point, which is required */
5460
 
    code = checkWhitePoint(i_ctx_p, &calrgbdict);
5461
 
    if (code != 0)
5462
 
        return code;
5463
 
    /* The rest are optional.  Need to validate though */
5464
 
    code = checkBlackPoint(i_ctx_p, &calrgbdict);
5465
 
    if (code < 0)
5466
 
        return code;
5467
 
    /* Check Gamma values */
5468
 
    code = checkGamma(i_ctx_p, &calrgbdict, 3);
5469
 
    if (code < 0)
5470
 
        return code;
5471
 
    /* Check Matrix */
5472
 
    code = checkCalMatrix(i_ctx_p, &calrgbdict);
5473
 
    if (code < 0)
5474
 
        return code;
5475
 
    *r = 0;  /* No nested space */
5476
 
    return 0;
5477
 
}
5478
 
 
5479
 
/* ICCBased */
5480
 
static int iccrange(i_ctx_t * i_ctx_p, ref *space, float *ptr);
5481
 
static int seticcspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
5482
 
{
5483
 
    os_ptr op = osp;
5484
 
    ref     ICCdict, *tempref, *altref=NULL, *nocie;
5485
 
    int components, code;
5486
 
    float range[8];
5487
 
 
5488
 
    code = dict_find_string(systemdict, "NOCIE", &nocie);
5489
 
    if (code < 0)
5490
 
        return code;
5491
 
    if (!r_has_type(nocie, t_boolean))
5492
 
        return_error(e_typecheck);
5493
 
    *cont = 0;
5494
 
    do {
5495
 
        switch(*stage) {
5496
 
            case 0:
5497
 
                (*stage)++;
5498
 
                code = array_get(imemory, r, 1, &ICCdict);
5499
 
                if (code < 0)
5500
 
                    return code;
5501
 
                code = dict_find_string(&ICCdict, "N", &tempref);
5502
 
                if (code < 0)
5503
 
                    return code;
5504
 
                components = tempref->value.intval;
5505
 
 
5506
 
                /* Don't allow ICCBased spaces if NOCIE is true */
5507
 
                if (nocie->value.boolval) {
5508
 
                    code = dict_find_string(&ICCdict, "Alternate", &altref); /* Alternate is optional */
5509
 
                    if (code < 0)
5510
 
                        return code;
5511
 
                    if ((altref != NULL) && (r_type(altref) != t_null)) {
5512
 
                        /* The PDF interpreter sets a null Alternate. If we have an
5513
 
                         * Alternate, and its not null, and NOCIE is true, then use the
5514
 
                         * Alternate instead of the ICC
5515
 
                         */
5516
 
                        push(1);
5517
 
                        ref_assign(op, altref);
5518
 
                        /* If CIESubst, we are already substituting for CIE, so use nosubst
5519
 
                         * to prevent further substitution!
5520
 
                         */
5521
 
                        return setcolorspace_nosubst(i_ctx_p);
5522
 
                    } else {
5523
 
                        /* There's no /Alternate (or it is null), set a default space
5524
 
                         * based on the number of components in the ICCBased space
5525
 
                         */
5526
 
                        code = set_dev_space(i_ctx_p, components);
5527
 
                        if (code != 0)
5528
 
                            return code;
5529
 
                        *stage = 0;
5530
 
                    }
5531
 
                } else {
5532
 
                    code = iccrange(i_ctx_p, r, (float *)&range);
5533
 
                    if (code < 0)
5534
 
                        return code;
5535
 
                    code = dict_find_string(&ICCdict, "DataSource", &tempref);
5536
 
                    if (code < 0)
5537
 
                        return code;
5538
 
                    /* Check for string based ICC and convert to a file */
5539
 
                    if (r_has_type(tempref, t_string)){
5540
 
                        uint n = r_size(tempref);
5541
 
                        ref rss;
5542
 
 
5543
 
                        code = make_rss(i_ctx_p, &rss, tempref->value.const_bytes, n, r_space(tempref), 0L, n, false);
5544
 
                        if (code < 0)
5545
 
                            return code;
5546
 
                        ref_assign(tempref, &rss);
5547
 
                    }
5548
 
                    /* Make space on operand stack to pass the ICC dictionary */
5549
 
                    push(1);
5550
 
                    ref_assign(op, &ICCdict);
5551
 
                    code = seticc(i_ctx_p, components, op, (float *)&range);
5552
 
                    if (code < 0) {
5553
 
                        code = dict_find_string(&ICCdict, "Alternate", &altref); /* Alternate is optional */
5554
 
                        if (code < 0)
5555
 
                            return code;
5556
 
                        if ((altref != NULL) && (r_type(altref) != t_null)) {
5557
 
                            /* We have a /Alternate in the ICC space */
5558
 
                            /* Our ICC dictionary still on operand stack, we can reuse the
5559
 
                             * slot on the stack to hold the alternate space.
5560
 
                             */
5561
 
                            ref_assign(op, (ref *)altref);
5562
 
                            /* If CIESubst, we are already substituting for CIE, so use nosubst
5563
 
                             * to prevent further substitution!
5564
 
                             */
5565
 
                            if (CIESubst)
5566
 
                                return setcolorspace_nosubst(i_ctx_p);
5567
 
                            else
5568
 
                                return zsetcolorspace(i_ctx_p);
5569
 
                        } else {
5570
 
                            /* We have no /Alternate in the ICC space, use hte /N key to
5571
 
                             * determine an 'appropriate' default space.
5572
 
                             */
5573
 
                            code = set_dev_space(i_ctx_p, components);
5574
 
                            if (code != 0)
5575
 
                                return code;
5576
 
                            *stage = 0;
5577
 
                        }
5578
 
                        pop(1);
5579
 
                    }
5580
 
                    if (code != 0)
5581
 
                        return code;
5582
 
                }
5583
 
                break;
5584
 
            case 1:
5585
 
                /* All done, exit */
5586
 
                *stage = 0;
5587
 
                code = 0;
5588
 
                break;
5589
 
            default:
5590
 
                return_error (e_rangecheck);
5591
 
                break;
5592
 
        }
5593
 
    }while(*stage);
5594
 
    return code;
5595
 
}
5596
 
static int validateiccspace(i_ctx_t * i_ctx_p, ref **r)
5597
 
{
5598
 
    int code=0, i, components = 0;
5599
 
    ref *space, *tempref, valref, ICCdict, sref;
5600
 
 
5601
 
    space = *r;
5602
 
    if (!r_is_array(space))
5603
 
        return_error(e_typecheck);
5604
 
    /* Validate parameters, check we have enough operands */
5605
 
    if (r_size(space) != 2)
5606
 
        return_error(e_rangecheck);
5607
 
 
5608
 
    code = array_get(imemory, space, 1, &ICCdict);
5609
 
    if (code < 0)
5610
 
        return code;
5611
 
 
5612
 
    code = dict_find_string(&ICCdict, "N", &tempref);
5613
 
    if (code <= 0)
5614
 
        return code;
5615
 
    if (!r_has_type(tempref, t_null)) {
5616
 
        if (!r_has_type(tempref, t_integer))
5617
 
            return_error(e_typecheck);
5618
 
        components = tempref->value.intval;
5619
 
    } else
5620
 
        return_error(e_typecheck);
5621
 
    code = dict_find_string(&ICCdict, "DataSource", &tempref);
5622
 
    if (code <= 0)
5623
 
        return_error(e_typecheck);
5624
 
    if (!r_has_type(tempref, t_null)) {
5625
 
        if (!r_has_type(tempref, t_string) && !r_has_type(tempref, t_file))
5626
 
            return_error(e_typecheck);
5627
 
    } else
5628
 
        return_error(e_typecheck);
5629
 
 
5630
 
    /* Following are optional entries */
5631
 
    code = dict_find_string(&ICCdict, "Range", &tempref);
5632
 
    if (code >= 0 && !r_has_type(tempref, t_null)) {
5633
 
        if (!r_is_array(tempref))
5634
 
            return_error(e_typecheck);
5635
 
        if (r_size(tempref) < (components * 2))
5636
 
            return_error(e_rangecheck);
5637
 
        for (i=0;i<components * 2;i++) {
5638
 
            code = array_get(imemory, tempref, i, &valref);
5639
 
            if (code < 0)
5640
 
                return code;
5641
 
            if (!r_has_type(&valref, t_integer) && !r_has_type(&valref, t_real))
5642
 
                return_error(e_typecheck);
5643
 
        }
5644
 
    }
5645
 
    code = dict_find_string(&ICCdict, "Alternate", &tempref);
5646
 
    if (code >= 0 && !r_has_type(tempref, t_null)) {
5647
 
        ref_assign(*r, tempref);
5648
 
        if (r_has_type(tempref, t_name)) {
5649
 
            name_string_ref(imemory, tempref, &sref);
5650
 
            if (sref.value.bytes && strncmp((const char *)sref.value.bytes, "Pattern", 7) == 0)
5651
 
                return_error(e_typecheck);
5652
 
        } else {
5653
 
            if (r_is_array(tempref)) {
5654
 
                code = array_get(imemory, tempref, 0, &valref);
5655
 
                if (code < 0)
5656
 
                    return code;
5657
 
                if (!r_has_type(&valref, t_name) && !r_has_type(&valref, t_string))
5658
 
                    return_error(e_typecheck);
5659
 
                if (r_has_type(&valref, t_name))
5660
 
                    name_string_ref(imemory, &valref, &sref);
5661
 
                else
5662
 
                    sref.value.bytes = valref.value.bytes;
5663
 
                if (sref.value.bytes && strncmp((const char *)sref.value.bytes, "Pattern", 7) == 0)
5664
 
                    return_error(e_typecheck);
5665
 
            } else
5666
 
                return_error(e_typecheck);
5667
 
        }
5668
 
    } else {
5669
 
        ref nameref;
5670
 
 
5671
 
        switch (components) {
5672
 
            case 1:
5673
 
                code = name_enter_string(imemory, "DeviceGray", &nameref);
5674
 
                break;
5675
 
            case 3:
5676
 
                code = name_enter_string(imemory, "DeviceRGB", &nameref);
5677
 
                break;
5678
 
            case 4:
5679
 
                code = name_enter_string(imemory, "DeviceCMYK", &nameref);
5680
 
                break;
5681
 
            default:
5682
 
                return_error(e_rangecheck);
5683
 
        }
5684
 
        /* In case this space is the /ALternate for a previous ICCBased space
5685
 
         * insert the named space into the ICC dictionary. If we simply returned
5686
 
         * the named space, as before, then we are replacing the second ICCBased
5687
 
         * space in the first ICCBased space with the named space!
5688
 
         */
5689
 
        code = idict_put_string(&ICCdict, "Alternate", &nameref);
5690
 
        if (code < 0)
5691
 
            return code;
5692
 
 
5693
 
        /* And now revalidate with the newly updated dictionary */
5694
 
        return validateiccspace(i_ctx_p, r);
5695
 
    }
5696
 
    return code;
5697
 
}
5698
 
 
5699
 
static int iccalternatespace(i_ctx_t * i_ctx_p, ref *space, ref **r, int *CIESubst)
5700
 
{
5701
 
    int components, code = 0;
5702
 
    ref *tempref, ICCdict;
5703
 
 
5704
 
    if (!r_is_array(space))
5705
 
        return_error(e_typecheck);
5706
 
    /* Validate parameters, check we have enough operands */
5707
 
    if (r_size(space) != 2)
5708
 
        return_error(e_rangecheck);
5709
 
 
5710
 
    code = array_get(imemory, space, 1, &ICCdict);
5711
 
    if (code < 0)
5712
 
        return code;
5713
 
 
5714
 
    code = dict_find_string(&ICCdict, "N", &tempref);
5715
 
    if (code <= 0)
5716
 
        return code;
5717
 
 
5718
 
    components = tempref->value.intval;
5719
 
 
5720
 
    code = dict_find_string(&ICCdict, "Alternate", &tempref);
5721
 
    if (code >= 0 && !r_has_type(tempref, t_null)) {
5722
 
        *r = tempref;
5723
 
    } else {
5724
 
        switch (components) {
5725
 
            case 1:
5726
 
                code = name_enter_string(imemory, "DeviceGray", *r);
5727
 
                break;
5728
 
            case 3:
5729
 
                code = name_enter_string(imemory, "DeviceRGB", *r);
5730
 
                break;
5731
 
            case 4:
5732
 
                code = name_enter_string(imemory, "DeviceCMYK", *r);
5733
 
                break;
5734
 
            default:
5735
 
                return_error(e_rangecheck);
5736
 
        }
5737
 
    }
5738
 
    *CIESubst = 1;
5739
 
    return code;
5740
 
}
5741
 
static int icccomponents(i_ctx_t * i_ctx_p, ref *space, int *n)
5742
 
{
5743
 
    int code = 0;
5744
 
    ref *tempref, ICCdict;
5745
 
 
5746
 
    code = array_get(imemory, space, 1, &ICCdict);
5747
 
    if (code < 0)
5748
 
        return code;
5749
 
 
5750
 
    code = dict_find_string(&ICCdict, "N", &tempref);
5751
 
    *n = tempref->value.intval;
5752
 
    return 0;
5753
 
}
5754
 
static int iccdomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
5755
 
{
5756
 
    int components, i, code = 0;
5757
 
    ref *tempref, ICCdict, valref;
5758
 
 
5759
 
    code = array_get(imemory, space, 1, &ICCdict);
5760
 
    if (code < 0)
5761
 
        return code;
5762
 
    code = dict_find_string(&ICCdict, "N", &tempref);
5763
 
    components = tempref->value.intval;
5764
 
    code = dict_find_string(&ICCdict, "Range", &tempref);
5765
 
    if (code >= 0 && !r_has_type(tempref, t_null)) {
5766
 
        for (i=0;i<components * 2;i++) {
5767
 
            code = array_get(imemory, tempref, i, &valref);
5768
 
            if (code < 0)
5769
 
                return code;
5770
 
            if (r_has_type(&valref, t_integer))
5771
 
                ptr[i * 2] = (float)valref.value.intval;
5772
 
            else
5773
 
                ptr[i * 2] = valref.value.realval;
5774
 
        }
5775
 
    } else {
5776
 
        for (i=0;i<components;i++) {
5777
 
            ptr[i * 2] = 0;
5778
 
            ptr[(i * 2) + 1] = 1;
5779
 
        }
5780
 
    }
5781
 
    return 0;
5782
 
}
5783
 
static int iccrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
5784
 
{
5785
 
    int components, i, code = 0;
5786
 
    ref *tempref, ICCdict, valref;
5787
 
 
5788
 
    code = array_get(imemory, space, 1, &ICCdict);
5789
 
    if (code < 0)
5790
 
        return code;
5791
 
    code = dict_find_string(&ICCdict, "N", &tempref);
5792
 
    components = tempref->value.intval;
5793
 
    code = dict_find_string(&ICCdict, "Range", &tempref);
5794
 
    if (code >= 0 && !r_has_type(tempref, t_null)) {
5795
 
        for (i=0;i<components * 2;i++) {
5796
 
            code = array_get(imemory, tempref, i, &valref);
5797
 
            if (code < 0)
5798
 
                return code;
5799
 
            if (r_has_type(&valref, t_integer))
5800
 
                ptr[i] = (float)valref.value.intval;
5801
 
            else
5802
 
                ptr[i] = (float)valref.value.realval;
5803
 
        }
5804
 
    } else {
5805
 
        for (i=0;i<components;i++) {
5806
 
            ptr[i * 2] = 0;
5807
 
            ptr[(i * 2) + 1] = 1;
5808
 
        }
5809
 
    }
5810
 
    return 0;
5811
 
}
5812
 
static int iccbasecolor(i_ctx_t * i_ctx_p, ref *space, int base, int *stage, int *cont, int *stack_depth)
5813
 
{
5814
 
    *stage = 0;
5815
 
    *cont = 1;
5816
 
    return 0;
5817
 
}
5818
 
static int iccvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
5819
 
{
5820
 
    return 0;
5821
 
}
5822
 
 
5823
 
static int dummydomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
5824
 
{
5825
 
    return 0;
5826
 
}
5827
 
static int dummyrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
5828
 
{
5829
 
    return 0;
5830
 
}
5831
 
static int onecomponent(i_ctx_t * i_ctx_p, ref *space, int *n)
5832
 
{
5833
 
    *n = 1;
5834
 
    return 0;
5835
 
}
5836
 
static int threecomponent(i_ctx_t * i_ctx_p, ref *space, int *n)
5837
 
{
5838
 
    *n = 3;
5839
 
    return 0;
5840
 
}
5841
 
static int fourcomponent(i_ctx_t * i_ctx_p, ref *space, int *n)
5842
 
{
5843
 
    *n = 4;
5844
 
    return 0;
5845
 
}
5846
 
static int truecompareproc(i_ctx_t *i_ctx_p, ref *space, ref *testspace)
5847
 
{
5848
 
    return 1;
5849
 
}
5850
 
static int falsecompareproc(i_ctx_t *i_ctx_p, ref *space, ref *testspace)
5851
 
{
5852
 
    return 0;
5853
 
}
5854
 
 
5855
 
PS_colour_space_t colorProcs[] = {
5856
 
    {(char *)"DeviceGray", setgrayspace, 0, 0, onecomponent, grayrange, graydomain,
5857
 
    graybasecolor, 0, grayvalidate, truecompareproc, grayinitialproc},
5858
 
    {(char *)"DeviceRGB", setrgbspace, 0, 0, threecomponent, rgbrange, rgbdomain,
5859
 
    rgbbasecolor, 0, rgbvalidate, truecompareproc, rgbinitialproc},
5860
 
    {(char *)"DeviceCMYK", setcmykspace, 0, 0, fourcomponent, cmykrange, cmykdomain,
5861
 
    cmykbasecolor, 0, cmykvalidate, truecompareproc, cmykinitialproc},
5862
 
    {(char *)"CIEBasedA", setcieaspace, validatecieaspace, 0, onecomponent, ciearange, cieadomain,
5863
 
    ciebasecolor, 0, cieavalidate, cieacompareproc, 0},
5864
 
    {(char *)"CIEBasedABC", setcieabcspace, validatecieabcspace, 0, threecomponent, cieabcrange, cieabcdomain,
5865
 
    ciebasecolor, 0, cieabcvalidate, cieabccompareproc, 0},
5866
 
    {(char *)"CIEBasedDEF", setciedefspace, validateciedefspace, 0, threecomponent, ciedefrange, ciedefdomain,
5867
 
    ciebasecolor, 0, ciedefvalidate, ciedefcompareproc, 0},
5868
 
    {(char *)"CIEBasedDEFG", setciedefgspace, validateciedefgspace, 0, fourcomponent, ciedefgrange, ciedefgdomain,
5869
 
    ciebasecolor, 0, ciedefgvalidate, ciedefgcompareproc, 0},
5870
 
    {(char *)"Separation", setseparationspace, validateseparationspace, separationalternatespace, onecomponent, seprange, sepdomain,
5871
 
    sepbasecolor, septransform, sepvalidate, sepcompareproc, sepinitialproc},
5872
 
    {(char *)"DeviceN", setdevicenspace, validatedevicenspace, devicenalternatespace, devicencomponents, devicenrange, devicendomain,
5873
 
    devicenbasecolor, devicentransform, devicenvalidate, devicencompareproc, deviceninitialproc},
5874
 
    {(char *)"Indexed", setindexedspace, validateindexedspace, indexedalternatespace, onecomponent, indexedrange, indexeddomain,
5875
 
    indexedbasecolor, 0, indexedvalidate, falsecompareproc, 0},
5876
 
    {(char *)"Pattern", setpatternspace, validatepatternspace, patternalternatespace, patterncomponent, dummyrange, dummydomain,
5877
 
    patternbasecolor, 0, patternvalidate, falsecompareproc, 0},
5878
 
    {(char *)"DevicePixel", setdevicepspace, validatedevicepspace, 0, onecomponent, deviceprange, devicepdomain,
5879
 
    devicepbasecolor, 0, devicepvalidate, falsecompareproc, 0},
5880
 
    {(char *)"ICCBased", seticcspace, validateiccspace, iccalternatespace, icccomponents, iccrange, iccdomain,
5881
 
    iccbasecolor, 0, iccvalidate, falsecompareproc, 0},
5882
 
    {(char *)"Lab", setlabspace, validatelabspace, 0, threecomponent, labrange, labdomain,
5883
 
    labbasecolor, 0, labvalidate, truecompareproc, 0},
5884
 
    {(char *)"CalGray", setcalgrayspace, validatecalgrayspace, 0, onecomponent, grayrange, graydomain,
5885
 
    graybasecolor, 0, grayvalidate, truecompareproc, grayinitialproc},
5886
 
    {(char *)"CalRGB", setcalrgbspace, validatecalrgbspace, 0, threecomponent, rgbrange, rgbdomain,
5887
 
    rgbbasecolor, 0, rgbvalidate, truecompareproc, rgbinitialproc}
5888
 
};
5889
 
 
5890
 
/*
5891
 
 * Given a color space, this finds the appropriate object from the list above
5892
 
 */
5893
 
int get_space_object(i_ctx_t *i_ctx_p, ref *arr, PS_colour_space_t **obj)
5894
 
{
5895
 
    ref spacename, nref;
5896
 
    int i, nprocs = sizeof(colorProcs) / sizeof(PS_colour_space_t), code;
5897
 
 
5898
 
    /* If the spaece is an array, the first element is always the name */
5899
 
    if (r_is_array(arr))
5900
 
        code = array_get(imemory, arr, 0, &spacename);
5901
 
    else
5902
 
        ref_assign(&spacename, arr);
5903
 
 
5904
 
    /* Check that it really is a name */
5905
 
    if (!r_has_type(&spacename, t_name))
5906
 
        return_error(e_typecheck);
5907
 
 
5908
 
    /* Find the relevant color space object */
5909
 
    for (i=0;i<nprocs;i++) {
5910
 
        code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)colorProcs[i].name, strlen(colorProcs[i].name), &nref, 0);
5911
 
        if (code < 0)
5912
 
            return code;
5913
 
        if (name_eq(&spacename, &nref)) {
5914
 
            *obj = &colorProcs[i];
5915
 
            return 0;
5916
 
        }
5917
 
    }
5918
 
    return_error(e_undefined);
5919
 
}
5920
 
/*
5921
 
 * This routine checks all the color spaces in an operand by
5922
 
 * calling the specific 'validate' method for each in turn. It also
5923
 
 * returns the 'depth' which is the number of nested spaces.
5924
 
 */
5925
 
static int validate_spaces(i_ctx_t *i_ctx_p, ref *arr, int *depth)
5926
 
{
5927
 
    ref space, *sp = &space;
5928
 
    int code = 0;
5929
 
    PS_colour_space_t *obj;
5930
 
 
5931
 
    ref_assign(&space, arr);
5932
 
    *depth = 0;
5933
 
    do {
5934
 
        code = get_space_object(i_ctx_p, sp, &obj);
5935
 
        if (code < 0)
5936
 
            return code;
5937
 
 
5938
 
        (*depth)++;
5939
 
        if (!obj->validateproc)
5940
 
            break;
5941
 
 
5942
 
        code = obj->validateproc(i_ctx_p, &sp);
5943
 
        if (code < 0)
5944
 
            return code;
5945
 
    }while(sp);
5946
 
    return 0;
5947
 
}
5948
 
/*
5949
 
 * The routine which does all the setcolor dispatching. This is initially set up by
5950
 
 * zsetcolor above. Because setcolorspace samples the space and converts the tint
5951
 
 * transform to a function, we don't need to run the PS tint transform in order to
5952
 
 * set the color. However, some applications, notably Photoshop 5 and above, rely
5953
 
 * on the tint transform being executed, so we must do so if the normal PostScript
5954
 
 * processing would result in the tintr transform being executed.
5955
 
 *
5956
 
 *  We check each space in turn to see whether we would normally run the tint
5957
 
 * transform, eg Indexed is always executed, Separation and DeviceN only if the
5958
 
 * required ink(s) aren't present in the device. If we discover that any space
5959
 
 * doesn't require a tint transform, then we can short-circuit the processing.
5960
 
 * Otherwise we set up to execute the tint transform.
5961
 
 */
5962
 
static int
5963
 
setcolor_cont(i_ctx_t *i_ctx_p)
5964
 
{
5965
 
    ref arr, *parr = &arr;
5966
 
    es_ptr ep = esp;
5967
 
    int i=0, code = 0,depth, usealternate, stage, stack_depth, CIESubst = 0;
5968
 
    PS_colour_space_t *obj;
5969
 
 
5970
 
    stack_depth = (int)ep[-3].value.intval;
5971
 
    depth = (int)ep[-2].value.intval;
5972
 
    stage = (int)ep[-1].value.intval;
5973
 
    /* If we get a continuation from a sub-procedure, we will want to come back
5974
 
     * here afterward, to do any remaining spaces. We need to set up for that now.
5975
 
     * so that our continuation is ahead of the sub-proc's continuation.
5976
 
     */
5977
 
    check_estack(1);
5978
 
    push_op_estack(setcolor_cont);
5979
 
 
5980
 
    while (code == 0) {
5981
 
        ref_assign(&arr, ep);
5982
 
        /* Run along the nested color spaces until we get to the first one
5983
 
         * that we haven't yet processed (given by 'depth')
5984
 
         */
5985
 
        for (i=0;i<=depth;i++) {
5986
 
            code = get_space_object(i_ctx_p, parr, &obj);
5987
 
            if (code < 0)
5988
 
                return code;
5989
 
 
5990
 
            if (i < (depth)) {
5991
 
                if (!obj->alternateproc) {
5992
 
                    return_error(e_typecheck);
5993
 
                }
5994
 
                code = obj->alternateproc(i_ctx_p, parr, &parr, &CIESubst);
5995
 
                if (code < 0)
5996
 
                    return code;
5997
 
            }
5998
 
        }
5999
 
        if (obj->runtransformproc) {
6000
 
            code = obj->runtransformproc(i_ctx_p, &istate->colorspace[0].array, &usealternate, &stage, &stack_depth);
6001
 
            make_int(&ep[-3], stack_depth);
6002
 
            make_int(&ep[-1], stage);
6003
 
            if (code != 0) {
6004
 
                return code;
6005
 
            }
6006
 
            make_int(&ep[-2], ++depth);
6007
 
            if (!usealternate)
6008
 
                break;
6009
 
        } else
6010
 
            break;
6011
 
    }
6012
 
    /* Remove our next continuation and our data */
6013
 
    obj->numcomponents(i_ctx_p, parr, &i);
6014
 
    pop(i);
6015
 
    esp -= 5;
6016
 
    return o_pop_estack;
6017
 
}
6018
 
/*
6019
 
 * The routine which does all the setcolorspace dispatching. This is initially set up by
6020
 
 * zsetcolorspace above. It starts by descending to the bottom-most space
6021
 
 * and setting that as the current space. It then descends the array again
6022
 
 * to the next-to-bottom- space and sets that as the current, and so on.
6023
 
 *
6024
 
 * The 'stage' parameter is passed in to each 'set' method. If a method needs
6025
 
 * to do a continuation itself (eg sample a space) then it should set the stage
6026
 
 * to a non-zero value. When the continuation is complete we return here, and
6027
 
 * attempt to 'set' the same space again. This time stage will be whatever was
6028
 
 * set the first time, which is a signal to the 'set' routine that a continuation
6029
 
 * took place, and is complete. Stage must always be set to 0 when a 'set'
6030
 
 * of a color space is complete.
6031
 
 */
6032
 
static int
6033
 
setcolorspace_cont(i_ctx_t *i_ctx_p)
6034
 
{
6035
 
    ref arr, *parr = &arr;
6036
 
    os_ptr op = osp;
6037
 
    es_ptr ep = esp, pdepth, pstage, pCIESubst;
6038
 
    int i, code = 0,depth, stage, cont, CIESubst = 0;
6039
 
    PS_colour_space_t *obj;
6040
 
 
6041
 
    pCIESubst = &ep[-3];
6042
 
    pdepth = &ep[-2];
6043
 
    pstage = &ep[-1];
6044
 
 
6045
 
    CIESubst = (int)pCIESubst->value.intval;
6046
 
    depth = (int)pdepth->value.intval;
6047
 
    stage = (int)pstage->value.intval;
6048
 
    /* If we get a continuation from a sub-procedure, we will want to come back
6049
 
     * here afterward, to do any remaining stages. We need to set up for that now.
6050
 
     * so that our continuation is ahead of the sub-proc's continuation.
6051
 
     */
6052
 
    check_estack(1);
6053
 
    push_op_estack(setcolorspace_cont);
6054
 
 
6055
 
    while (code == 0 && depth) {
6056
 
        ref_assign(&arr, ep);
6057
 
        /* Run along the nested color spaces until we get to the lowest one
6058
 
         * that we haven't yet processed (given by 'depth')
6059
 
         */
6060
 
        for (i = 0;i < depth;i++) {
6061
 
            code = get_space_object(i_ctx_p, parr, &obj);
6062
 
            if (code < 0)
6063
 
                return code;
6064
 
 
6065
 
            if (i < (depth - 1)) {
6066
 
                if (!obj->alternateproc) {
6067
 
                    return_error(e_typecheck);
6068
 
                }
6069
 
                code = obj->alternateproc(i_ctx_p, parr, &parr, &CIESubst);
6070
 
                if (code < 0)
6071
 
                    return code;
6072
 
            }
6073
 
        }
6074
 
 
6075
 
        code = obj->setproc(i_ctx_p, parr, &stage, &cont, CIESubst);
6076
 
        make_int(pstage, stage);
6077
 
        if (code != 0)
6078
 
            return code;
6079
 
        if (!cont) {
6080
 
            /* Completed that space, decrement the 'depth' */
6081
 
            make_int(pdepth, --depth);
6082
 
            parr = &arr;
6083
 
        }
6084
 
    }
6085
 
    if (code == 0) {
6086
 
        /* Remove our next continuation and our data */
6087
 
        esp -= 5;
6088
 
        op = osp;
6089
 
        istate->colorspace[0].array = *op;
6090
 
        /* Remove the colorspace array form the operand stack */
6091
 
        pop(1);
6092
 
        code = o_pop_estack;
6093
 
    }
6094
 
    return code;
6095
 
}
6096
 
/*
6097
 
 * The routine which does all the dispatching for the device-space specific
6098
 
 * operators below (eg setgray). This is initially set up by the routines below.
6099
 
 *
6100
 
 * It would seem unnecessary to have a continuation procedure, because at first
6101
 
 * sight these can only be a single space with no alternate and can't require
6102
 
 * sampling, because they are device space. However if UseCIEColor is true, then
6103
 
 * we will actually use a Default Color Space Array in place of the requested color
6104
 
 * space. These are often CIEBased spaces, and these do need to be sampled. So
6105
 
 * actually we do need a continuation procedure, unfortunately.
6106
 
 *
6107
 
 * Also, we need to set the initial color value after we have set the color space.
6108
 
 */
6109
 
static int
6110
 
setdevicecolor_cont(i_ctx_t *i_ctx_p)
6111
 
{
6112
 
    os_ptr op = osp;
6113
 
    es_ptr ep = esp, pstage;
6114
 
    int code = 0, stage, base;
6115
 
 
6116
 
    pstage = ep;
6117
 
    base = (int)ep[-1].value.intval;
6118
 
    stage = (int)pstage->value.intval;
6119
 
    /* If we get a continuation from a sub-procedure, we will want to come back
6120
 
     * here afterward, to do any remaining stages. We need to set up for that now.
6121
 
     * so that our continuation is ahead of the sub-proc's continuation.
6122
 
     */
6123
 
    check_estack(1);
6124
 
    /* May need to push a /Device... name on the stack so make sure we have space */
6125
 
    check_ostack(1);
6126
 
    /* The push_op_estack macro increments esp before use, so we don't need to */
6127
 
    push_op_estack(setdevicecolor_cont);
6128
 
 
6129
 
    do {
6130
 
        switch(stage) {
6131
 
            case 0:
6132
 
                make_int(pstage, ++stage);
6133
 
                push(1);
6134
 
                switch(base) {
6135
 
                    case 0: /* DeviceGray */
6136
 
                        code = name_enter_string(imemory, "DeviceGray", op);
6137
 
                        break;
6138
 
                    case 1: /* DeviceRGB */
6139
 
                        code = name_enter_string(imemory, "DeviceRGB", op);
6140
 
                        break;
6141
 
                    case 2: /* DeviceCMYK */
6142
 
                        code = name_enter_string(imemory, "DeviceCMYK", op);
6143
 
                        break;
6144
 
                }
6145
 
                if (code < 0)
6146
 
                    return code;
6147
 
                code = zsetcolorspace(i_ctx_p);
6148
 
                if (code != 0)
6149
 
                    return code;
6150
 
                break;
6151
 
            case 1:
6152
 
                make_int(pstage, ++stage);
6153
 
                code = zsetcolor(i_ctx_p);
6154
 
                if (code != 0)
6155
 
                    return code;
6156
 
                break;
6157
 
            case 2:
6158
 
                esp -= 3;
6159
 
                return o_pop_estack;
6160
 
                break;
6161
 
        }
6162
 
    }while(1);
6163
 
    return 0;
6164
 
}
6165
 
 
6166
 
/* These routines implement the device-space set color routines
6167
 
 * These set both the space and the color in a single operation.
6168
 
 * Previously these were implemented in PostScript.
6169
 
 */
6170
 
static int
6171
 
zsetgray(i_ctx_t * i_ctx_p)
6172
 
{
6173
 
    os_ptr  op = osp;   /* required by "push" macro */
6174
 
    float value;
6175
 
    int code;
6176
 
 
6177
 
    /* Gather numeric operand value(s) */
6178
 
    code = float_params(op, 1, &value);
6179
 
    if (code < 0)
6180
 
        return code;
6181
 
    /* Clamp numeric operand range(s) */
6182
 
    if (value < 0)
6183
 
        value = 0;
6184
 
    else if (value > 1)
6185
 
        value = 1;
6186
 
    code = make_floats(op, &value, 1);
6187
 
    if (code < 0)
6188
 
        return code;
6189
 
 
6190
 
    /* Set up for the continuation procedure which will do the work */
6191
 
    /* Make sure the exec stack has enough space */
6192
 
    check_estack(5);
6193
 
    push_mark_estack(es_other, 0);
6194
 
    esp++;
6195
 
    /* variable to hold base type (0 = gray) */
6196
 
    make_int(esp, 0);
6197
 
    esp++;
6198
 
    /* Store the 'stage' of processing (initially 0) */
6199
 
    make_int(esp, 0);
6200
 
    /* Finally, the actual continuation routine */
6201
 
    push_op_estack(setdevicecolor_cont);
6202
 
    return o_push_estack;
6203
 
}
6204
 
static int
6205
 
zsethsbcolor(i_ctx_t * i_ctx_p)
6206
 
{
6207
 
    os_ptr  op = osp;   /* required by "push" macro */
6208
 
    int code, i;
6209
 
    float values[3];
6210
 
 
6211
 
    /* Gather numeric operand value(s) (also checks type) */
6212
 
    code = float_params(op, 3, (float *)&values);
6213
 
    if (code < 0)
6214
 
        return code;
6215
 
    /* Clamp numeric operand range(s) */
6216
 
    for (i = 0;i < 3; i++) {
6217
 
        if (values[i] < 0)
6218
 
            values[i] = 0;
6219
 
        else if (values[i] > 1)
6220
 
            values[i] = 1;
6221
 
    }
6222
 
 
6223
 
    hsb2rgb((float *)&values);
6224
 
 
6225
 
    code = make_floats(&op[-2], (const float *)&values, 3);
6226
 
    if (code < 0)
6227
 
        return code;
6228
 
 
6229
 
    /* Set up for the continuation procedure which will do the work */
6230
 
    /* Make sure the exec stack has enough space */
6231
 
    check_estack(5);
6232
 
    push_mark_estack(es_other, 0);
6233
 
    esp++;
6234
 
    /* variable to hold base type (1 = RGB) */
6235
 
    make_int(esp, 1);
6236
 
    esp++;
6237
 
    /* Store the 'stage' of processing (initially 0) */
6238
 
    make_int(esp, 0);
6239
 
    /* Finally, the actual continuation routine */
6240
 
    push_op_estack(setdevicecolor_cont);
6241
 
    return o_push_estack;
6242
 
}
6243
 
static int
6244
 
zsetrgbcolor(i_ctx_t * i_ctx_p)
6245
 
{
6246
 
    os_ptr  op = osp;   /* required by "push" macro */
6247
 
    int code, i;
6248
 
    float values[3];
6249
 
 
6250
 
    /* Gather numeric operand value(s) (also checks type) */
6251
 
    code = float_params(op, 3, (float *)&values);
6252
 
    if (code < 0)
6253
 
        return code;
6254
 
    /* Clamp numeric operand range(s) */
6255
 
    for (i = 0;i < 3; i++) {
6256
 
        if (values[i] < 0)
6257
 
            values[i] = 0;
6258
 
        else if (values[i] > 1)
6259
 
            values[i] = 1;
6260
 
    }
6261
 
 
6262
 
    code = make_floats(&op[-2], (const float *)&values, 3);
6263
 
    if (code < 0)
6264
 
        return code;
6265
 
 
6266
 
    /* Set up for the continuation procedure which will do the work */
6267
 
    /* Make sure the exec stack has enough space */
6268
 
    check_estack(5);
6269
 
    push_mark_estack(es_other, 0);
6270
 
    esp++;
6271
 
    /* variable to hold base type (1 = RGB) */
6272
 
    make_int(esp, 1);
6273
 
    esp++;
6274
 
    /* Store the 'stage' of processing (initially 0) */
6275
 
    make_int(esp, 0);
6276
 
    /* Finally, the actual continuation routine */
6277
 
    push_op_estack(setdevicecolor_cont);
6278
 
    return o_push_estack;
6279
 
}
6280
 
 
6281
 
static int
6282
 
zsetcmykcolor(i_ctx_t * i_ctx_p)
6283
 
{
6284
 
    os_ptr  op = osp;   /* required by "push" macro */
6285
 
    int code, i;
6286
 
    float values[4];
6287
 
 
6288
 
    /* Gather numeric operand value(s) (also checks type) */
6289
 
    code = float_params(op, 4, (float *)&values);
6290
 
    if (code < 0)
6291
 
        return code;
6292
 
    /* Clamp numeric operand range(s) */
6293
 
    for (i = 0;i < 4; i++) {
6294
 
        if (values[i] < 0)
6295
 
            values[i] = 0;
6296
 
        else if (values[i] > 1)
6297
 
            values[i] = 1;
6298
 
    }
6299
 
 
6300
 
    code = make_floats(&op[-3], (const float *)&values, 4);
6301
 
    if (code < 0)
6302
 
        return code;
6303
 
 
6304
 
    /* Set up for the continuation procedure which will do the work */
6305
 
    /* Make sure the exec stack has enough space */
6306
 
    check_estack(5);
6307
 
    push_mark_estack(es_other, 0);
6308
 
    esp++;
6309
 
    /* variable to hold base type (2 = CMYK) */
6310
 
    make_int(esp, 2);
6311
 
    esp++;
6312
 
    /* Store the 'stage' of processing (initially 0) */
6313
 
    make_int(esp, 0);
6314
 
    /* Finally, the actual continuation routine */
6315
 
    push_op_estack(setdevicecolor_cont);
6316
 
    return o_push_estack;
6317
 
}
6318
 
 
6319
 
/*
6320
 
 * The routine which does all the dispatching for the device-space specific
6321
 
 * 'current color' routines currentgray, currentrgbcolo and currentcmykcolor.
6322
 
 *
6323
 
 * Starting with the top-level color space we need to take the current color
6324
 
 * value(s) and pass it through the tint transform procedure (actually we use the
6325
 
 * converted function) to get equivalent components for the next space. We then
6326
 
 * repeat with each alternate space in turn until we reach a 'terminal' space.
6327
 
 * That can be a device space (eg DeviceGray), a CIEBased or ICCBased space, or
6328
 
 * a Separation or DeviceN space which is not using its alternate space.
6329
 
 *
6330
 
 * Depending on which kind of terminal space we reach we will either return
6331
 
 * fixed values (all 0.0) or we will convert the terminal device space components
6332
 
 * into the requested device space.
6333
 
 *
6334
 
 * Because we might need to run a tint transform procedure, this requires a
6335
 
 * continuation procedure.
6336
 
 */
6337
 
static int
6338
 
currentbasecolor_cont(i_ctx_t *i_ctx_p)
6339
 
{
6340
 
    ref arr, *parr = &arr;
6341
 
    es_ptr ep = esp;
6342
 
    int i, code = 0,depth, stage, base, cont=1, stack_depth = 0, CIESubst=0;
6343
 
    PS_colour_space_t *obj;
6344
 
 
6345
 
    stack_depth = (int)ep[-4].value.intval;
6346
 
    base = (int)ep[-3].value.intval;
6347
 
    depth = (int)ep[-2].value.intval;
6348
 
    stage = (int)ep[-1].value.intval;
6349
 
    /* If we get a continuation from a sub-procedure, we will want to come back
6350
 
     * here afterward, to do any remaining stages. We need to set up for that now.
6351
 
     * so that our continuation is ahead of the sub-proc's continuation.
6352
 
     */
6353
 
    check_estack(1);
6354
 
    /* The push_op_estack macro increments esp before use, so we don't need to */
6355
 
    push_op_estack(currentbasecolor_cont);
6356
 
 
6357
 
    while (code == 0 && cont) {
6358
 
        ref_assign(&arr, ep);
6359
 
        parr = &arr;
6360
 
        /* Run along the nested color spaces until we get to the lowest one
6361
 
         * that we haven't yet processed (given by 'depth')
6362
 
         */
6363
 
        for (i = 0;i < depth;i++) {
6364
 
            code = get_space_object(i_ctx_p, parr, &obj);
6365
 
            if (code < 0)
6366
 
                return code;
6367
 
 
6368
 
            if (i < (depth - 1)) {
6369
 
                if (!obj->alternateproc) {
6370
 
                    return_error(e_typecheck);
6371
 
                }
6372
 
                code = obj->alternateproc(i_ctx_p, parr, &parr, &CIESubst);
6373
 
                if (code < 0)
6374
 
                    return code;
6375
 
            }
6376
 
        }
6377
 
 
6378
 
        code = obj->basecolorproc(i_ctx_p, parr, base, &stage, &cont, &stack_depth);
6379
 
        make_int(&ep[-4], stack_depth);
6380
 
        make_int(&ep[-1], stage);
6381
 
        if (code != 0)
6382
 
            return code;
6383
 
        /* Completed that space, increment the 'depth' */
6384
 
        make_int(&ep[-2], ++depth);
6385
 
    }
6386
 
    if (code == 0) {
6387
 
        /* Remove our next continuation and our data */
6388
 
        esp -= 7;
6389
 
        code = o_pop_estack;
6390
 
    }
6391
 
    return code;
6392
 
}
6393
 
 
6394
 
/* These routines implement the device-space 'current' color routines.
6395
 
 * Previously these were implemented in PostScript.
6396
 
 */
6397
 
static int
6398
 
zcurrentgray(i_ctx_t * i_ctx_p)
6399
 
{
6400
 
    int code, depth;
6401
 
 
6402
 
    code = validate_spaces(i_ctx_p, &istate->colorspace[0].array, &depth);
6403
 
    if (code < 0)
6404
 
        return code;
6405
 
 
6406
 
    code = zcurrentcolor(i_ctx_p);
6407
 
    if (code < 0)
6408
 
        return code;
6409
 
    /* Set up for the continuation procedure which will do the work */
6410
 
    /* Make sure the exec stack has enough space */
6411
 
    check_estack(7);
6412
 
    push_mark_estack(es_other, 0);
6413
 
    esp++;
6414
 
    /* variable to hold stack depth for tint transform */
6415
 
    make_int(&esp[0], 0);
6416
 
    esp++;
6417
 
    /* Store the 'base' type color wanted, in this case Gray */
6418
 
    make_int(&esp[0], 0);
6419
 
    make_int(&esp[1], 1);
6420
 
    /* Store the 'stage' of processing (initially 0) */
6421
 
    make_int(&esp[2], 0);
6422
 
    /* Store a pointer to the color space stored on the operand stack
6423
 
     * as the stack may grow unpredictably making further access
6424
 
     * to the space difficult
6425
 
     */
6426
 
    esp[3] = istate->colorspace[0].array;
6427
 
    esp += 3; /* The push_op_estack macro increments esp before using it */
6428
 
    /* Finally, the actual continuation routine */
6429
 
    push_op_estack(currentbasecolor_cont);
6430
 
    return o_push_estack;
6431
 
}
6432
 
static int
6433
 
zcurrenthsbcolor(i_ctx_t * i_ctx_p)
6434
 
{
6435
 
    int code, depth;
6436
 
 
6437
 
    code = validate_spaces(i_ctx_p, &istate->colorspace[0].array, &depth);
6438
 
    if (code < 0)
6439
 
        return code;
6440
 
 
6441
 
    code = zcurrentcolor(i_ctx_p);
6442
 
    if (code < 0)
6443
 
        return code;
6444
 
    /* Set up for the continuation procedure which will do the work */
6445
 
    /* Make sure the exec stack has enough space */
6446
 
    check_estack(7);
6447
 
    push_mark_estack(es_other, 0);
6448
 
    esp++;
6449
 
    /* variable to hold stack depth for tint transform */
6450
 
    make_int(&esp[0], 0);
6451
 
    esp++;
6452
 
    /* Store the 'base' type color wanted, in this case HSB */
6453
 
    make_int(&esp[0], 1);
6454
 
    make_int(&esp[1], 1);
6455
 
    /* Store the 'stage' of processing (initially 0) */
6456
 
    make_int(&esp[2], 0);
6457
 
    /* Store a pointer to the color space stored on the operand stack
6458
 
     * as the stack may grow unpredictably making further access
6459
 
     * to the space difficult
6460
 
     */
6461
 
    esp[3] = istate->colorspace[0].array;
6462
 
    esp += 3; /* The push_op_estack macro increments esp before using it */
6463
 
    /* Finally, the actual continuation routine */
6464
 
    push_op_estack(currentbasecolor_cont);
6465
 
    return o_push_estack;
6466
 
}
6467
 
static int
6468
 
zcurrentrgbcolor(i_ctx_t * i_ctx_p)
6469
 
{
6470
 
    int code;
6471
 
 
6472
 
    code = zcurrentcolor(i_ctx_p);
6473
 
    if (code < 0)
6474
 
        return code;
6475
 
    /* Set up for the continuation procedure which will do the work */
6476
 
    /* Make sure the exec stack has enough space */
6477
 
    check_estack(7);
6478
 
    push_mark_estack(es_other, 0);
6479
 
    esp++;
6480
 
    /* variable to hold stack depth for tint transform */
6481
 
    make_int(&esp[0], 0);
6482
 
    esp++;
6483
 
    /* Store the 'base' type color wanted, in this case RGB */
6484
 
    make_int(&esp[0], 2);
6485
 
    make_int(&esp[1], 1);
6486
 
    /* Store the 'stage' of processing (initially 0) */
6487
 
    make_int(&esp[2], 0);
6488
 
    /* Store a pointer to the color space stored on the operand stack
6489
 
     * as the stack may grow unpredictably making further access
6490
 
     * to the space difficult
6491
 
     */
6492
 
    esp[3] = istate->colorspace[0].array;
6493
 
    esp += 3; /* The push_op_estack macro increments esp before using it */
6494
 
    /* Finally, the actual continuation routine */
6495
 
    push_op_estack(currentbasecolor_cont);
6496
 
    return o_push_estack;
6497
 
}
6498
 
static int
6499
 
zcurrentcmykcolor(i_ctx_t * i_ctx_p)
6500
 
{
6501
 
    int code;
6502
 
 
6503
 
    code = zcurrentcolor(i_ctx_p);
6504
 
    if (code < 0)
6505
 
        return code;
6506
 
    /* Set up for the continuation procedure which will do the work */
6507
 
    /* Make sure the exec stack has enough space */
6508
 
    check_estack(7);
6509
 
    push_mark_estack(es_other, 0);
6510
 
    esp++;
6511
 
    /* variable to hold stack depth for tint transform */
6512
 
    make_int(&esp[0], 0);
6513
 
    esp++;
6514
 
    /* Store the 'base' type color wanted, in this case CMYK */
6515
 
    make_int(&esp[0], 3);
6516
 
    make_int(&esp[1], 1);
6517
 
    /* Store the 'stage' of processing (initially 0) */
6518
 
    make_int(&esp[2], 0);
6519
 
    /* Store a pointer to the color space stored on the operand stack
6520
 
     * as the stack may grow unpredictably making further access
6521
 
     * to the space difficult
6522
 
     */
6523
 
    esp[3] = istate->colorspace[0].array;
6524
 
    esp += 3; /* The push_op_estack macro increments esp before using it */
6525
 
    /* Finally, the actual continuation routine */
6526
 
    push_op_estack(currentbasecolor_cont);
6527
 
    return o_push_estack;
6528
 
}
6529
 
 
6530
 
static int
6531
 
zswapcolors(i_ctx_t * i_ctx_p)
6532
 
{
6533
 
    ref_colorspace tmp_cs;
6534
 
    ref            tmp_pat;
6535
 
 
6536
 
    tmp_cs                = istate->colorspace[0];
6537
 
    istate->colorspace[0] = istate->colorspace[1];
6538
 
    istate->colorspace[1] = tmp_cs;
6539
 
 
6540
 
    tmp_pat            = istate->pattern[0];
6541
 
    istate->pattern[0] = istate->pattern[1];
6542
 
    istate->pattern[1] = tmp_pat;
6543
 
 
6544
 
    return gs_swapcolors(igs);
6545
 
}
6546
 
 
6547
 
/* ------ Initialization procedure ------ */
6548
 
 
6549
 
/* We need to split the table because of the 16-element limit. */
6550
 
const op_def    zcolor_op_defs[] =
6551
 
{
6552
 
    { "0currentcolor", zcurrentcolor },
6553
 
    { "0currentcolorspace", zcurrentcolorspace },
6554
 
    { "0.getuseciecolor", zgetuseciecolor },
6555
 
    { "1setcolor", zsetcolor },
6556
 
    { "1setcolorspace", zsetcolorspace },
6557
 
 
6558
 
    /* basic transfer operators */
6559
 
    { "0currenttransfer", zcurrenttransfer },
6560
 
    { "0processcolors", zprocesscolors },
6561
 
    { "1settransfer", zsettransfer },
6562
 
 
6563
 
    /* internal operators */
6564
 
    { "1%zcolor_remap_one_finish", zcolor_remap_one_finish },
6565
 
    { "1%zcolor_remap_one_signed_finish", zcolor_remap_one_signed_finish },
6566
 
    { "0%zcolor_reset_transfer", zcolor_reset_transfer },
6567
 
    { "0%zcolor_remap_color", zcolor_remap_color },
6568
 
    { "0.color_test", zcolor_test },
6569
 
    { "1.color_test_all", zcolor_test_all },
6570
 
 
6571
 
    /* high level device support */
6572
 
    { "0.includecolorspace", zincludecolorspace },
6573
 
    op_def_end(0)
6574
 
};
6575
 
 
6576
 
const op_def    zcolor_ext_op_defs[] =
6577
 
{
6578
 
    { "0currentgray", zcurrentgray },
6579
 
    { "1setgray", zsetgray },
6580
 
    { "0currenthsbcolor", zcurrenthsbcolor },
6581
 
    { "3sethsbcolor", zsethsbcolor },
6582
 
    { "0currentrgbcolor", zcurrentrgbcolor },
6583
 
    { "3setrgbcolor", zsetrgbcolor },
6584
 
    { "0currentcmykcolor", zcurrentcmykcolor },
6585
 
    { "4setcmykcolor", zsetcmykcolor },
6586
 
 
6587
 
    /* Operators to deal with setting stroking/non-stroking colors
6588
 
     * individually */
6589
 
    { "1.swapcolors", zswapcolors },
6590
 
 
6591
 
    /* internal operators, entries here only used for error reporting */
6592
 
    { "0%setcolorspace_cont", setcolorspace_cont },
6593
 
    { "0%setcolor_cont", setcolor_cont },
6594
 
    { "0%devicencolorants_cont", devicencolorants_cont },
6595
 
    { "0%indexed_cont", indexed_cont },
6596
 
    { "0%setdevicecolor_cont", setdevicecolor_cont },
6597
 
    { "0%currentbasecolor_cont", currentbasecolor_cont },
6598
 
op_def_end(0)
6599
 
};