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

« back to all changes in this revision

Viewing changes to psi/zupath.c

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

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2001-2006 Artifex Software, Inc.
 
2
   All Rights Reserved.
 
3
  
 
4
   This software is provided AS-IS with no warranty, either express or
 
5
   implied.
 
6
 
 
7
   This software is distributed under license and may not be copied, modified
 
8
   or distributed except as expressly authorized under the terms of that
 
9
   license.  Refer to licensing information at http://www.artifex.com/
 
10
   or contact Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134,
 
11
   San Rafael, CA  94903, U.S.A., +1(415)492-9861, for further information.
 
12
*/
 
13
 
 
14
/* $Id: zupath.c 9043 2008-08-28 22:48:19Z giles $ */
 
15
/* Operators related to user paths */
 
16
#include "ghost.h"
 
17
#include "oper.h"
 
18
#include "oparc.h"
 
19
#include "idict.h"
 
20
#include "dstack.h"
 
21
#include "igstate.h"
 
22
#include "iname.h"
 
23
#include "iutil.h"
 
24
#include "store.h"
 
25
#include "stream.h"
 
26
#include "ibnum.h"
 
27
#include "gsmatrix.h"
 
28
#include "gsstate.h"
 
29
#include "gscoord.h"
 
30
#include "gspaint.h"
 
31
#include "gxfixed.h"
 
32
#include "gxdevice.h"
 
33
#include "gspath.h"
 
34
#include "gzpath.h"             /* for saving path */
 
35
#include "gzstate.h"            /* for accessing path */
 
36
 
 
37
/* Imported data */
 
38
extern const gx_device gs_hit_device;
 
39
extern const int gs_hit_detected;
 
40
 
 
41
/*
 
42
 * CPSI mode affects two algorithms in this file:
 
43
 * - CPSI allows ucache to appear anywhere in user paths, even though the
 
44
 *   PLRM says ucache must appear (if at all) at the beginning
 
45
 *   (PLRM3 p, 199);
 
46
 * - After appending an empty user path, in CPSI the current point is
 
47
 *   defined, even though the PLRM strongly implies this is incorrect
 
48
 *   (PLRM3 p. 712).
 
49
 * The 'upath_compat' Boolean controls this behavior.
 
50
 */
 
51
 
 
52
extern bool CPSI_mode;
 
53
 
 
54
/* Forward references */
 
55
static int upath_append(os_ptr, i_ctx_t *, bool);
 
56
static int upath_stroke(i_ctx_t *, gs_matrix *, bool);
 
57
 
 
58
/* ---------------- Insideness testing ---------------- */
 
59
 
 
60
/* Forward references */
 
61
static int in_test(i_ctx_t *, int (*)(gs_state *));
 
62
static int in_path(os_ptr, i_ctx_t *, gx_device *);
 
63
static int in_path_result(i_ctx_t *, int, int);
 
64
static int in_utest(i_ctx_t *, int (*)(gs_state *));
 
65
static int in_upath(i_ctx_t *, gx_device *);
 
66
static int in_upath_result(i_ctx_t *, int, int);
 
67
 
 
68
/* <x> <y> ineofill <bool> */
 
69
/* <userpath> ineofill <bool> */
 
70
static int
 
71
zineofill(i_ctx_t *i_ctx_p)
 
72
{
 
73
    return in_test(i_ctx_p, gs_eofill);
 
74
}
 
75
 
 
76
/* <x> <y> infill <bool> */
 
77
/* <userpath> infill <bool> */
 
78
static int
 
79
zinfill(i_ctx_t *i_ctx_p)
 
80
{
 
81
    return in_test(i_ctx_p, gs_fill);
 
82
}
 
83
 
 
84
/* <x> <y> instroke <bool> */
 
85
/* <userpath> instroke <bool> */
 
86
static int
 
87
zinstroke(i_ctx_t *i_ctx_p)
 
88
{
 
89
    return in_test(i_ctx_p, gs_stroke);
 
90
}
 
91
 
 
92
/* <x> <y> <userpath> inueofill <bool> */
 
93
/* <userpath1> <userpath2> inueofill <bool> */
 
94
static int
 
95
zinueofill(i_ctx_t *i_ctx_p)
 
96
{
 
97
    return in_utest(i_ctx_p, gs_eofill);
 
98
}
 
99
 
 
100
/* <x> <y> <userpath> inufill <bool> */
 
101
/* <userpath1> <userpath2> inufill <bool> */
 
102
static int
 
103
zinufill(i_ctx_t *i_ctx_p)
 
104
{
 
105
    return in_utest(i_ctx_p, gs_fill);
 
106
}
 
107
 
 
108
/* <x> <y> <userpath> inustroke <bool> */
 
109
/* <x> <y> <userpath> <matrix> inustroke <bool> */
 
110
/* <userpath1> <userpath2> inustroke <bool> */
 
111
/* <userpath1> <userpath2> <matrix> inustroke <bool> */
 
112
static int
 
113
zinustroke(i_ctx_t *i_ctx_p)
 
114
{       /* This is different because of the optional matrix operand. */
 
115
    os_ptr op = osp;
 
116
    int code = gs_gsave(igs);
 
117
    int spop, npop;
 
118
    gs_matrix mat;
 
119
    gx_device hdev;
 
120
 
 
121
    if (code < 0)
 
122
        return code;
 
123
    if ((spop = upath_stroke(i_ctx_p, &mat, false)) < 0) {
 
124
        gs_grestore(igs);
 
125
        return spop;
 
126
    }
 
127
    if ((npop = in_path(op - spop, i_ctx_p, &hdev)) < 0) {
 
128
        gs_grestore(igs);
 
129
        return npop;
 
130
    }
 
131
    if (npop > 1)               /* matrix was supplied */
 
132
        code = gs_concat(igs, &mat);
 
133
    if (code >= 0)
 
134
        code = gs_stroke(igs);
 
135
    return in_upath_result(i_ctx_p, npop + spop, code);
 
136
}
 
137
 
 
138
/* ------ Internal routines ------ */
 
139
 
 
140
/* Do the work of the non-user-path insideness operators. */
 
141
static int
 
142
in_test(i_ctx_t *i_ctx_p, int (*paintproc)(gs_state *))
 
143
{
 
144
    os_ptr op = osp;
 
145
    gx_device hdev;
 
146
    int npop = in_path(op, i_ctx_p, &hdev);
 
147
    int code;
 
148
 
 
149
    if (npop < 0)
 
150
        return npop;
 
151
    code = (*paintproc)(igs);
 
152
    return in_path_result(i_ctx_p, npop, code);
 
153
}
 
154
 
 
155
/* Set up a clipping path and device for insideness testing. */
 
156
static int
 
157
in_path(os_ptr oppath, i_ctx_t *i_ctx_p, gx_device * phdev)
 
158
{
 
159
    int code = gs_gsave(igs);
 
160
    int npop;
 
161
    double uxy[2];
 
162
 
 
163
    if (code < 0)
 
164
        return code;
 
165
    code = num_params(oppath, 2, uxy);
 
166
    if (code >= 0) {            /* Aperture is a single pixel. */
 
167
        gs_point dxy;
 
168
        gs_fixed_rect fr;
 
169
 
 
170
        gs_transform(igs, uxy[0], uxy[1], &dxy);
 
171
        fr.p.x = fixed_floor(float2fixed(dxy.x));
 
172
        fr.p.y = fixed_floor(float2fixed(dxy.y));
 
173
        fr.q.x = fr.p.x + fixed_1;
 
174
        fr.q.y = fr.p.y + fixed_1;
 
175
        code = gx_clip_to_rectangle(igs, &fr);
 
176
        npop = 2;
 
177
    } else if (code == e_stackunderflow) {
 
178
        /* If 0 elements, definitely a stackunderflow; otherwise, */
 
179
        /* only 1 number, also a stackunderflow. */
 
180
        npop = code;
 
181
    } else {                    /* Aperture is a user path. */
 
182
        /* We have to set the clipping path without disturbing */
 
183
        /* the current path. */
 
184
        gx_path *ipath = igs->path;
 
185
        gx_path save;
 
186
 
 
187
        gx_path_init_local(&save, imemory);
 
188
        gx_path_assign_preserve(&save, ipath);
 
189
        gs_newpath(igs);
 
190
        code = upath_append(oppath, i_ctx_p, false);
 
191
        if (code >= 0)
 
192
            code = gx_clip_to_path(igs);
 
193
        gx_path_assign_free(igs->path, &save);
 
194
        npop = 1;
 
195
    }
 
196
    if (code < 0) {
 
197
        gs_grestore(igs);
 
198
        return code;
 
199
    }
 
200
    /* Install the hit detection device. */
 
201
    gx_set_device_color_1(igs);
 
202
    gx_device_init((gx_device *) phdev, (const gx_device *)&gs_hit_device,
 
203
                   NULL, true);
 
204
    phdev->width = phdev->height = max_int;
 
205
    gx_device_fill_in_procs(phdev);
 
206
    gx_set_device_only(igs, phdev);
 
207
    return npop;
 
208
}
 
209
 
 
210
/* Finish an insideness test. */
 
211
static int
 
212
in_path_result(i_ctx_t *i_ctx_p, int npop, int code)
 
213
{
 
214
    os_ptr op = osp;
 
215
    bool result;
 
216
 
 
217
    gs_grestore(igs);           /* matches gsave in in_path */
 
218
    if (code == gs_hit_detected)
 
219
        result = true;
 
220
    else if (code == 0)         /* completed painting without a hit */
 
221
        result = false;
 
222
    else                        /* error */
 
223
        return code;
 
224
    npop--;
 
225
    pop(npop);
 
226
    op -= npop;
 
227
    make_bool(op, result);
 
228
    return 0;
 
229
 
 
230
}
 
231
 
 
232
/* Do the work of the user-path insideness operators. */
 
233
static int
 
234
in_utest(i_ctx_t *i_ctx_p, int (*paintproc)(gs_state *))
 
235
{
 
236
    gx_device hdev;
 
237
    int npop = in_upath(i_ctx_p, &hdev);
 
238
    int code;
 
239
 
 
240
    if (npop < 0)
 
241
        return npop;
 
242
    code = (*paintproc)(igs);
 
243
    return in_upath_result(i_ctx_p, npop, code);
 
244
}
 
245
 
 
246
/* Set up a clipping path and device for insideness testing */
 
247
/* with a user path. */
 
248
static int
 
249
in_upath(i_ctx_t *i_ctx_p, gx_device * phdev)
 
250
{
 
251
    os_ptr op = osp;
 
252
    int code = gs_gsave(igs);
 
253
    int npop;
 
254
 
 
255
    if (code < 0)
 
256
        return code;
 
257
    if ((code = upath_append(op, i_ctx_p, false)) < 0 ||
 
258
        (code = npop = in_path(op - 1, i_ctx_p, phdev)) < 0
 
259
        ) {
 
260
        gs_grestore(igs);
 
261
        return code;
 
262
    }
 
263
    return npop + 1;
 
264
}
 
265
 
 
266
/* Finish an insideness test with a user path. */
 
267
static int
 
268
in_upath_result(i_ctx_t *i_ctx_p, int npop, int code)
 
269
{
 
270
    gs_grestore(igs);           /* matches gsave in in_upath */
 
271
    return in_path_result(i_ctx_p, npop, code);
 
272
}
 
273
 
 
274
/* ---------------- User paths ---------------- */
 
275
 
 
276
/* User path operator codes */
 
277
typedef enum {
 
278
    upath_op_setbbox = 0,
 
279
    upath_op_moveto = 1,
 
280
    upath_op_rmoveto = 2,
 
281
    upath_op_lineto = 3,
 
282
    upath_op_rlineto = 4,
 
283
    upath_op_curveto = 5,
 
284
    upath_op_rcurveto = 6,
 
285
    upath_op_arc = 7,
 
286
    upath_op_arcn = 8,
 
287
    upath_op_arct = 9,
 
288
    upath_op_closepath = 10,
 
289
    upath_op_ucache = 11
 
290
} upath_op;
 
291
 
 
292
/* User path interpretation states */
 
293
typedef enum {
 
294
    UPS_INITIAL = 1,            /* (no ops yet) */
 
295
    UPS_UCACHE = 2,             /* ucache */
 
296
    UPS_SETBBOX = 4,            /* [ucache] setbbox */
 
297
    UPS_PATH = 8                /* (within path) */
 
298
} upath_state;
 
299
 
 
300
typedef struct up_data_s {
 
301
    byte num_args;
 
302
    byte states_before;
 
303
    byte state_after;
 
304
} up_data_t;
 
305
#define UP_DATA_PATH(n) {n, UPS_SETBBOX | UPS_PATH, UPS_PATH}
 
306
 
 
307
#define UPATH_MAX_OP 11
 
308
#define UPATH_REPEAT 32
 
309
static const up_data_t up_data[UPATH_MAX_OP + 1] = {
 
310
    {4, UPS_INITIAL | UPS_UCACHE, UPS_SETBBOX}, /* setbbox */
 
311
    UP_DATA_PATH(2),
 
312
    UP_DATA_PATH(2),
 
313
    UP_DATA_PATH(2),
 
314
    UP_DATA_PATH(2),
 
315
    UP_DATA_PATH(6),
 
316
    UP_DATA_PATH(6),
 
317
    UP_DATA_PATH(5),
 
318
    UP_DATA_PATH(5),
 
319
    UP_DATA_PATH(5),
 
320
    UP_DATA_PATH(0),
 
321
    {0, UPS_INITIAL, UPS_UCACHE}        /* ucache */
 
322
};
 
323
 
 
324
/* Declare operator procedures not declared in opextern.h. */
 
325
int zsetbbox(i_ctx_t *);
 
326
static int zucache(i_ctx_t *);
 
327
 
 
328
#undef zp
 
329
static const op_proc_t up_ops[UPATH_MAX_OP + 1] = {
 
330
    zsetbbox, zmoveto, zrmoveto, zlineto, zrlineto,
 
331
    zcurveto, zrcurveto, zarc, zarcn, zarct,
 
332
    zclosepath, zucache
 
333
};
 
334
 
 
335
/* - ucache - */
 
336
static int
 
337
zucache(i_ctx_t *i_ctx_p)
 
338
{
 
339
    /* A no-op for now. */
 
340
    return 0;
 
341
}
 
342
 
 
343
/* <userpath> uappend - */
 
344
static int
 
345
zuappend(i_ctx_t *i_ctx_p)
 
346
{
 
347
    os_ptr op = osp;
 
348
    int code = gs_gsave(igs);
 
349
 
 
350
    if (code < 0)
 
351
        return code;
 
352
    if ((code = upath_append(op, i_ctx_p, false)) >= 0)
 
353
        code = gs_upmergepath(igs);
 
354
    gs_grestore(igs);
 
355
    if (code < 0)
 
356
        return code;
 
357
    pop(1);
 
358
    return 0;
 
359
}
 
360
 
 
361
/* <userpath> ueofill - */
 
362
static int
 
363
zueofill(i_ctx_t *i_ctx_p)
 
364
{
 
365
    os_ptr op = osp;
 
366
    int code = gs_gsave(igs);
 
367
 
 
368
    if (code < 0)
 
369
        return code;
 
370
    if ((code = upath_append(op, i_ctx_p, CPSI_mode)) >= 0)
 
371
        code = gs_eofill(igs);
 
372
    gs_grestore(igs);
 
373
    if (code < 0)
 
374
        return code;
 
375
    pop(1);
 
376
    return 0;
 
377
}
 
378
 
 
379
/* <userpath> ufill - */
 
380
static int
 
381
zufill(i_ctx_t *i_ctx_p)
 
382
{
 
383
    os_ptr op = osp;
 
384
    int code = gs_gsave(igs);
 
385
 
 
386
    if (code < 0)
 
387
        return code;
 
388
    if ((code = upath_append(op, i_ctx_p, CPSI_mode)) >= 0)
 
389
        code = gs_fill(igs);
 
390
    gs_grestore(igs);
 
391
    if (code < 0)
 
392
        return code;
 
393
    pop(1);
 
394
    return 0;
 
395
}
 
396
 
 
397
/* <userpath> ustroke - */
 
398
/* <userpath> <matrix> ustroke - */
 
399
static int
 
400
zustroke(i_ctx_t *i_ctx_p)
 
401
{
 
402
    int code = gs_gsave(igs);
 
403
    int npop;
 
404
 
 
405
    if (code < 0)
 
406
        return code;
 
407
    if ((code = npop = upath_stroke(i_ctx_p, NULL, CPSI_mode)) >= 0)
 
408
        code = gs_stroke(igs);
 
409
    gs_grestore(igs);
 
410
    if (code < 0)
 
411
        return code;
 
412
    pop(npop);
 
413
    return 0;
 
414
}
 
415
 
 
416
/* <userpath> ustrokepath - */
 
417
/* <userpath> <matrix> ustrokepath - */
 
418
static int
 
419
zustrokepath(i_ctx_t *i_ctx_p)
 
420
{
 
421
    gx_path save;
 
422
    gs_matrix saved_matrix;
 
423
    int npop, code = gs_currentmatrix(igs, &saved_matrix);
 
424
 
 
425
    if (code < 0)
 
426
        return code;
 
427
    /* Save and reset the path. */
 
428
    gx_path_init_local(&save, imemory);
 
429
    gx_path_assign_preserve(&save, igs->path);
 
430
    if ((code = npop = upath_stroke(i_ctx_p, NULL, false)) < 0 ||
 
431
        (code = gs_strokepath(igs)) < 0
 
432
        ) {
 
433
        gx_path_assign_free(igs->path, &save);
 
434
        return code;
 
435
    }
 
436
    /*
 
437
     * If a matrix was specified then restore the previous matrix.
 
438
     */
 
439
    if (npop > 1) {
 
440
        if ((code = gs_setmatrix(igs, &saved_matrix)) < 0) {
 
441
            gx_path_assign_free(igs->path, &save);
 
442
            return code;
 
443
        }
 
444
    }
 
445
    gx_path_free(&save, "ustrokepath");
 
446
    pop(npop);
 
447
    return 0;
 
448
}
 
449
 
 
450
/* <with_ucache> upath <userpath> */
 
451
/* We do all the work in a procedure that is also used to construct */
 
452
/* the UnpaintedPath user path for ImageType 2 images. */
 
453
int make_upath(i_ctx_t *i_ctx_p, ref *rupath, gs_state *pgs, gx_path *ppath,
 
454
               bool with_ucache);
 
455
static int
 
456
zupath(i_ctx_t *i_ctx_p)
 
457
{
 
458
    os_ptr op = osp;
 
459
 
 
460
    check_type(*op, t_boolean);
 
461
    return make_upath(i_ctx_p, op, igs, igs->path, op->value.boolval);
 
462
}
 
463
 
 
464
/* Compute the path length for user path purposes. */
 
465
static int 
 
466
path_length_for_upath(const gx_path *ppath)
 
467
{
 
468
    gs_path_enum penum;
 
469
    int op, size = 0;
 
470
    gs_fixed_point pts[3];
 
471
 
 
472
    gx_path_enum_init(&penum, ppath);
 
473
    while ((op = gx_path_enum_next(&penum, pts)) != 0) {
 
474
        switch (op) {
 
475
            case gs_pe_moveto:
 
476
            case gs_pe_lineto:
 
477
                size += 3;
 
478
                continue;
 
479
            case gs_pe_curveto:
 
480
                size += 7;
 
481
                continue;
 
482
            case gs_pe_closepath:
 
483
                size += 1;
 
484
                continue;
 
485
            default:
 
486
                return_error(e_unregistered);
 
487
        }
 
488
    }
 
489
    return size;
 
490
}
 
491
 
 
492
int
 
493
make_upath(i_ctx_t *i_ctx_p, ref *rupath, gs_state *pgs, gx_path *ppath,
 
494
           bool with_ucache)
 
495
{
 
496
    int size = (with_ucache ? 6 : 5);
 
497
    gs_path_enum penum;
 
498
    gs_rect bbox;
 
499
    int op;
 
500
    ref *next;
 
501
    int code;
 
502
 
 
503
 
 
504
    /* Compute the bounding box. */
 
505
    if ((code = gs_upathbbox(pgs, &bbox, true)) < 0) {
 
506
        /*
 
507
         * Note: Adobe throws 'nocurrentpoint' error, but the PLRM does
 
508
         * not list this as a possible error from 'upath', so if we are
 
509
         * not in CPSI compatibility mode, we set a reasonable default
 
510
         * bbox instead.
 
511
         */
 
512
        if (code != e_nocurrentpoint || CPSI_mode)
 
513
            return code;
 
514
        bbox.p.x = bbox.p.y = bbox.q.x = bbox.q.y = 0;
 
515
    }
 
516
 
 
517
    code = path_length_for_upath(ppath);
 
518
    if (code < 0)
 
519
        return code;
 
520
    size += code;
 
521
    if (size >= 65536)
 
522
        return_error(e_limitcheck);
 
523
 
 
524
    code = ialloc_ref_array(rupath, a_all | a_executable, size,
 
525
                            "make_upath");
 
526
    if (code < 0)
 
527
        return code;
 
528
    /* Construct the path. */
 
529
    next = rupath->value.refs;
 
530
    if (with_ucache) {
 
531
        if ((code = name_enter_string(pgs->memory, "ucache", next)) < 0)
 
532
            return code;
 
533
        r_set_attrs(next, a_executable | l_new);
 
534
        ++next;
 
535
    }
 
536
    make_real_new(next, bbox.p.x);
 
537
    make_real_new(next + 1, bbox.p.y);
 
538
    make_real_new(next + 2, bbox.q.x);
 
539
    make_real_new(next + 3, bbox.q.y);
 
540
    next += 4;
 
541
    if ((code = name_enter_string(pgs->memory, "setbbox", next)) < 0)
 
542
        return code;
 
543
    r_set_attrs(next, a_executable | l_new);
 
544
    ++next;
 
545
    {
 
546
        gs_point pts[3];
 
547
 
 
548
        /* Patch the path in the gstate to set up the enumerator. */
 
549
        gx_path *save_path = pgs->path;
 
550
 
 
551
        pgs->path = ppath;
 
552
        gs_path_enum_copy_init(&penum, pgs, false);
 
553
        pgs->path = save_path;
 
554
        while ((op = gs_path_enum_next(&penum, pts)) != 0) {
 
555
            const char *opstr;
 
556
 
 
557
            switch (op) {
 
558
                case gs_pe_moveto:
 
559
                    opstr = "moveto";
 
560
                    goto ml;
 
561
                case gs_pe_lineto:
 
562
                    opstr = "lineto";
 
563
                  ml:make_real_new(next, pts[0].x);
 
564
                    make_real_new(next + 1, pts[0].y);
 
565
                    next += 2;
 
566
                    break;
 
567
                case gs_pe_curveto:
 
568
                    opstr = "curveto";
 
569
                    make_real_new(next, pts[0].x);
 
570
                    make_real_new(next + 1, pts[0].y);
 
571
                    make_real_new(next + 2, pts[1].x);
 
572
                    make_real_new(next + 3, pts[1].y);
 
573
                    make_real_new(next + 4, pts[2].x);
 
574
                    make_real_new(next + 5, pts[2].y);
 
575
                    next += 6;
 
576
                    break;
 
577
                case gs_pe_closepath:
 
578
                    opstr = "closepath";
 
579
                    break;
 
580
                default:
 
581
                    return_error(e_unregistered);
 
582
            }
 
583
            if ((code = name_enter_string(pgs->memory, opstr, next)) < 0)
 
584
                return code;
 
585
            r_set_attrs(next, a_executable);
 
586
            ++next;
 
587
        }
 
588
    }
 
589
    return 0;
 
590
}
 
591
 
 
592
 
 
593
static int
 
594
zgetpath(i_ctx_t *i_ctx_p)
 
595
{
 
596
    os_ptr op = osp;
 
597
    int i, code, path_size, leaf_count;
 
598
    ref *main_ref, *operators[5];
 
599
 
 
600
    push(1);
 
601
    path_size = code = path_length_for_upath(igs->path);
 
602
    if (code < 0)
 
603
        return code;
 
604
    leaf_count = (path_size + max_array_size - 1) / max_array_size;
 
605
    code = ialloc_ref_array(op, a_all, leaf_count, "zgetpath_master");
 
606
    if (code < 0)
 
607
        return code;
 
608
    if (path_size == 0)
 
609
        return 0;
 
610
 
 
611
    if (dict_find_string(systemdict, "moveto", &operators[1]) <= 0 ||
 
612
        dict_find_string(systemdict, "lineto", &operators[2]) <= 0 ||
 
613
        dict_find_string(systemdict, "curveto", &operators[3]) <= 0 ||
 
614
        dict_find_string(systemdict, "closepath", &operators[4]) <= 0)
 
615
          return_error(e_undefined);
 
616
 
 
617
    main_ref = op->value.refs;
 
618
    for (i = 0; i < leaf_count; i++) {
 
619
       int leaf_size = ( i == leaf_count - 1) ? path_size - i * max_array_size : max_array_size;
 
620
       code = ialloc_ref_array(&main_ref[i], a_all | a_executable, leaf_size, "zgetpath_leaf");
 
621
       if (code < 0)
 
622
            return code;
 
623
    }
 
624
 
 
625
    {
 
626
        int pe, j, k;
 
627
        gs_path_enum penum;
 
628
        static const int oper_count[5] = { 0, 2, 2, 6, 0 };
 
629
        gs_point pts[3];
 
630
        const double  *fts[6]; 
 
631
 
 
632
        fts[0] = &pts[0].x;
 
633
        fts[1] = &pts[0].y;
 
634
        fts[2] = &pts[1].x;
 
635
        fts[3] = &pts[1].y;
 
636
        fts[4] = &pts[2].x;
 
637
        fts[5] = &pts[2].y;
 
638
 
 
639
        main_ref = op->value.refs;
 
640
        gs_path_enum_copy_init(&penum, igs, false);
 
641
        pe = gs_path_enum_next(&penum, pts);
 
642
        k = 0;
 
643
 
 
644
        for (i = 0; i < leaf_count; i++) {
 
645
            int leaf_size = ( i == leaf_count - 1) ? path_size - i * max_array_size : max_array_size;
 
646
            ref *leaf_ref = main_ref[i].value.refs;
 
647
            
 
648
            for (j = 0; j < leaf_size; j++) {
 
649
                if (k < oper_count[pe])
 
650
                   make_real_new(&leaf_ref[j], (float)*fts[k++]);
 
651
                else {
 
652
                    k = 0;
 
653
                    ref_assign(&leaf_ref[j], operators[pe]);
 
654
                    pe = gs_path_enum_next(&penum, pts);
 
655
                    if (pe == 0)
 
656
                        goto out;
 
657
                    if (pe >= 5)
 
658
                        return_error(e_unregistered);
 
659
                }
 
660
            }
 
661
        }
 
662
     }
 
663
  out:
 
664
  return 0;
 
665
}
 
666
 
 
667
/* ------ Internal routines ------ */
 
668
 
 
669
/* Append a user path to the current path. */
 
670
static inline int
 
671
upath_append_aux(os_ptr oppath, i_ctx_t *i_ctx_p, int *pnargs, bool upath_compat)
 
672
{
 
673
    upath_state ups = UPS_INITIAL;
 
674
    ref opcodes;
 
675
 
 
676
    if (r_has_type(oppath, t__invalid))
 
677
        return_error(e_stackunderflow);
 
678
    if (!r_is_array(oppath))
 
679
        return_error(e_typecheck);
 
680
    check_read(*oppath);
 
681
    gs_newpath(igs);
 
682
    /****** ROUND tx AND ty ******/
 
683
    
 
684
    if ( r_size(oppath) == 2 &&
 
685
         array_get(imemory, oppath, 1, &opcodes) >= 0 &&
 
686
         r_has_type(&opcodes, t_string)
 
687
        ) {                     /* 1st element is operands, 2nd is operators */
 
688
        ref operands;
 
689
        int code, format;
 
690
        int repcount = 1;
 
691
        const byte *opp;
 
692
        uint ocount, i = 0;
 
693
 
 
694
        array_get(imemory, oppath, 0, &operands);
 
695
        code = num_array_format(&operands);
 
696
        if (code < 0)
 
697
            return code;
 
698
        format = code;
 
699
        check_read(opcodes);
 
700
        opp = opcodes.value.bytes;
 
701
        ocount = r_size(&opcodes);
 
702
        while (ocount--) {
 
703
            byte opx = *opp++;
 
704
 
 
705
            if (opx > UPATH_REPEAT)
 
706
                repcount = opx - UPATH_REPEAT;
 
707
            else if (opx > UPATH_MAX_OP)
 
708
                return_error(e_rangecheck);
 
709
            else {              /* operator */
 
710
                const up_data_t data = up_data[opx];
 
711
 
 
712
                *pnargs = 0;    /* in case of error */
 
713
                if (upath_compat && opx == upath_op_ucache) {
 
714
                    /* CPSI does not complain about incorrect ucache
 
715
                       placement, even though PLRM3 says it's illegal. */
 
716
                    ups = ups > UPS_UCACHE ? ups : data.state_after;
 
717
                } else {
 
718
                    if (!(ups & data.states_before))
 
719
                        return_error(e_typecheck);
 
720
                    ups = data.state_after;
 
721
                }
 
722
                do {
 
723
                    os_ptr op = osp;
 
724
                    byte opargs = data.num_args;
 
725
 
 
726
                    while (opargs--) {
 
727
                        push(1);
 
728
                        (*pnargs)++; /* in case of error */
 
729
                        code = num_array_get(imemory, &operands, format, i++, op);
 
730
                        switch (code) {
 
731
                            case t_integer:
 
732
                                r_set_type_attrs(op, t_integer, 0);
 
733
                                break;
 
734
                            case t_real:
 
735
                                r_set_type_attrs(op, t_real, 0);
 
736
                                break;
 
737
                            default:
 
738
                                return_error(e_typecheck);
 
739
                        }
 
740
                    }
 
741
                    code = (*up_ops[opx])(i_ctx_p);
 
742
                    if (code < 0)
 
743
                        return code;
 
744
                }
 
745
                while (--repcount);
 
746
                repcount = 1;
 
747
            }
 
748
        }
 
749
    } else {    /* Ordinary executable array. */
 
750
        const ref *arp = oppath;
 
751
        uint ocount = r_size(oppath);
 
752
        long index = 0;
 
753
        int argcount = 0;
 
754
        op_proc_t oproc;
 
755
        int opx, code;
 
756
 
 
757
        for (; index < ocount; index++) {
 
758
            ref rup;
 
759
            ref *defp;
 
760
            os_ptr op = osp;
 
761
            up_data_t data;
 
762
 
 
763
            *pnargs = argcount;
 
764
            array_get(imemory, arp, index, &rup);
 
765
            switch (r_type(&rup)) {
 
766
                case t_integer:
 
767
                case t_real:
 
768
                    argcount++;
 
769
                    push(1);
 
770
                    *op = rup;
 
771
                    break;
 
772
                case t_name:
 
773
                    if (!r_has_attr(&rup, a_executable) ||
 
774
                        dict_find(systemdict, &rup, &defp) <= 0 ||
 
775
                        r_btype(defp) != t_operator)
 
776
                        return_error(e_typecheck); /* all errors = typecheck */
 
777
                    goto xop;
 
778
                case t_operator:
 
779
                    defp = &rup;
 
780
                  xop:if (!r_has_attr(defp, a_executable))
 
781
                        return_error(e_typecheck);
 
782
                    oproc = real_opproc(defp);
 
783
                    for (opx = 0; opx <= UPATH_MAX_OP; opx++)
 
784
                        if (oproc == up_ops[opx])
 
785
                            break;
 
786
                    if (opx > UPATH_MAX_OP)
 
787
                        return_error(e_typecheck);
 
788
                    data = up_data[opx];
 
789
                    if (argcount != data.num_args)
 
790
                        return_error(e_typecheck);
 
791
                    if (upath_compat && opx == upath_op_ucache) {
 
792
                        /* CPSI does not complain about incorrect ucache
 
793
                           placement, even though PLRM3 says it's illegal. */
 
794
                        ups = ups > UPS_UCACHE ? ups : data.state_after;
 
795
                    } else {
 
796
                        if (!(ups & data.states_before))
 
797
                            return_error(e_typecheck);
 
798
                        ups = data.state_after;
 
799
                    }
 
800
                    code = (*up_ops[opx])(i_ctx_p);
 
801
                    if (code < 0) {
 
802
                        if (code == e_nocurrentpoint)
 
803
                            return_error(e_rangecheck); /* CET 11-22 */
 
804
                        return code;
 
805
                    }
 
806
                    argcount = 0;
 
807
                    break;
 
808
                default:
 
809
                    return_error(e_typecheck);
 
810
            }
 
811
        }
 
812
        if (argcount) {
 
813
            *pnargs = argcount;
 
814
            return_error(e_typecheck);  /* leftover args */
 
815
        }
 
816
    }
 
817
    if (ups < UPS_SETBBOX)
 
818
        return_error(e_typecheck);      /* no setbbox */
 
819
    if (ups == UPS_SETBBOX && upath_compat) {
 
820
        /*
 
821
         * In CPSI compatibility mode, an empty path with a setbbox also
 
822
         * does a moveto (but only if the path is empty).  Since setbbox
 
823
         * was the last operator, its operands are still on the o-stack.
 
824
         */
 
825
        osp += 2;
 
826
        return zmoveto(i_ctx_p);
 
827
    }
 
828
    return 0;
 
829
}
 
830
static int
 
831
upath_append(os_ptr oppath, i_ctx_t *i_ctx_p, bool upath_compat)
 
832
{
 
833
    int nargs = 0;
 
834
    int code = upath_append_aux(oppath, i_ctx_p, &nargs, upath_compat);
 
835
 
 
836
    if (code < 0) {
 
837
        /* Pop args on error, to match Adobe interpreters. */
 
838
        pop(nargs);
 
839
        return code;
 
840
    }
 
841
    return 0;
 
842
}
 
843
 
 
844
/* Append a user path to the current path, and then apply or return */
 
845
/* a transformation if one is supplied. */
 
846
static int
 
847
upath_stroke(i_ctx_t *i_ctx_p, gs_matrix *pmat, bool upath_compat)
 
848
{
 
849
    os_ptr op = osp;
 
850
    int code, npop;
 
851
    gs_matrix mat;
 
852
 
 
853
    if ((code = read_matrix(imemory, op, &mat)) >= 0) {
 
854
        if ((code = upath_append(op - 1, i_ctx_p, upath_compat)) >= 0) {
 
855
            if (pmat)
 
856
                *pmat = mat;
 
857
            else
 
858
                code = gs_concat(igs, &mat);
 
859
        }
 
860
        npop = 2;
 
861
    } else {
 
862
        if ((code = upath_append(op, i_ctx_p, upath_compat)) >= 0)
 
863
            if (pmat)
 
864
                gs_make_identity(pmat);
 
865
        npop = 1;
 
866
    }
 
867
    return (code < 0 ? code : npop);
 
868
}
 
869
 
 
870
/* ---------------- Initialization procedure ---------------- */
 
871
 
 
872
const op_def zupath_l2_op_defs[] =
 
873
{
 
874
    op_def_begin_level2(),
 
875
                /* Insideness testing */
 
876
    {"1ineofill", zineofill},
 
877
    {"1infill", zinfill},
 
878
    {"1instroke", zinstroke},
 
879
    {"2inueofill", zinueofill},
 
880
    {"2inufill", zinufill},
 
881
    {"2inustroke", zinustroke},
 
882
                /* User paths */
 
883
    {"1uappend", zuappend},
 
884
    {"0ucache", zucache},
 
885
    {"1ueofill", zueofill},
 
886
    {"1ufill", zufill},
 
887
    {"1upath", zupath},
 
888
    {"1ustroke", zustroke},
 
889
    {"1ustrokepath", zustrokepath},
 
890
                /* Path access for PDF */
 
891
    {"0.getpath", zgetpath},
 
892
    op_def_end(0)
 
893
};