Coverage Report

Created: 2026-08-08 08:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/pcl/pcl/pgdraw.c
Line
Count
Source
1
/* Copyright (C) 2001-2026 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,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
17
/* pgdraw.c - HP-GL/2 line drawing/path building routines. */
18
19
#include "stdio_.h"
20
#include "math_.h"
21
#include "gdebug.h"
22
#include "gstypes.h"            /* for gsstate.h */
23
#include "gsmatrix.h"           /* for gsstate.h */
24
#include "gsmemory.h"           /* for gsstate.h */
25
#include "gsstate.h"
26
#include "gscoord.h"
27
#include "gspath.h"
28
#include "gspaint.h"
29
#include "gsrop.h"              /* for gs_setrasterop */
30
#include "gxfarith.h"           /* for sincos */
31
#include "gxfixed.h"
32
#include "pgmand.h"
33
#include "pgdraw.h"
34
#include "pggeom.h"
35
#include "pgmisc.h"
36
#include "pcdraw.h"
37
#include "pcpalet.h"
38
#include "pcpatrn.h"
39
#include "pcpage.h"
40
41
#include "gzstate.h"
42
#include "gxdcolor.h"
43
/* hack to quiet compiler warnings */
44
#ifndef abs
45
extern int abs(int);
46
#endif
47
48
1.69M
#define round(x)    (((x) < 0.0) ? (ceil ((x) - 0.5)) : (floor ((x) + 0.5)))
49
50
static inline gs_point
51
hpgl_picture_frame_scale(hpgl_state_t * pgls)
52
4.25M
{
53
4.25M
    gs_point scale;
54
55
4.25M
    scale.x = scale.y = 0;
56
57
    /* this should not happen in a real system */
58
4.25M
    if ((pgls->g.picture_frame_height == 0) ||
59
4.25M
        (pgls->g.picture_frame_width == 0) ||
60
4.25M
        (pgls->g.plot_width == 0) || (pgls->g.plot_height == 0)) {
61
0
        dmprintf(pgls->memory, "bad picture frame coordinates\n");
62
4.25M
    } else {
63
4.25M
        scale.x = (pgls->g.plot_size_horizontal_specified) ?
64
4
            ((hpgl_real_t) pgls->g.picture_frame_width /
65
4.25M
             (hpgl_real_t) pgls->g.plot_width) : 1.0;
66
4.25M
        scale.y = (pgls->g.plot_size_vertical_specified) ?
67
3.29k
            ((hpgl_real_t) pgls->g.picture_frame_height /
68
4.24M
             (hpgl_real_t) pgls->g.plot_height) : 1.0;
69
4.25M
    }
70
4.25M
    return scale;
71
4.25M
}
72
73
static int
74
hpgl_set_picture_frame_scaling(hpgl_state_t * pgls)
75
6.15M
{
76
6.15M
    if (pgls->g.scaling_type != hpgl_scaling_point_factor) {
77
3.81M
        gs_point scale = hpgl_picture_frame_scale(pgls);
78
79
3.81M
        hpgl_call(gs_scale(pgls->pgs, scale.x, scale.y));
80
3.81M
    }
81
6.15M
    return 0;
82
6.15M
}
83
84
hpgl_real_t
85
hpgl_width_scale(hpgl_state_t * pgls)
86
439k
{
87
439k
    gs_point sc = hpgl_picture_frame_scale(pgls);
88
89
439k
    return min(sc.x, sc.y);
90
439k
}
91
92
/* ctm to translate from pcl space to plu space */
93
int
94
hpgl_set_pcl_to_plu_ctm(hpgl_state_t * pgls)
95
6.15M
{
96
6.15M
    hpgl_real_t fw_plu = (coord_2_plu(pgls->g.picture_frame_width));
97
6.15M
    hpgl_real_t fh_plu = (coord_2_plu(pgls->g.picture_frame_height));
98
99
    /* set up the default pcl ctm and from that derive the gl/2
100
       transformations */
101
6.15M
    hpgl_call(pcl_set_ctm(pgls, false));
102
    /* NB probably needs correction for RTL */
103
6.15M
    hpgl_call(gs_translate(pgls->pgs,
104
6.15M
                           pgls->g.picture_frame.anchor_point.x,
105
6.15M
                           pgls->g.picture_frame.anchor_point.y));
106
107
    /* the gl/2 coordinate system like postscript (and unlike pcl) is
108
       right-handed.   */
109
6.15M
    if (pgls->personality != rtl) {
110
6.15M
        hpgl_call(gs_translate(pgls->pgs, 0, pgls->g.picture_frame_height));
111
        /* scale to plotter units and a flip for y */
112
6.15M
        hpgl_call(gs_scale(pgls->pgs, (7200.0 / 1016.0), -(7200.0 / 1016.0)));
113
6.15M
    } else {
114
0
        if (pgls->g.picture_frame_width >= pgls->g.picture_frame_height) {
115
0
            hpgl_call(gs_rotate(pgls->pgs, -90));
116
0
            hpgl_call(gs_scale
117
0
                      (pgls->pgs, -(7200.0 / 1016.0), (7200.0 / 1016.0)));
118
0
        } else {
119
0
            hpgl_call(gs_translate
120
0
                      (pgls->pgs, pgls->g.picture_frame_height, 0));
121
0
            hpgl_call(gs_rotate(pgls->pgs, 180));
122
0
            hpgl_call(gs_scale
123
0
                      (pgls->pgs, (7200.0 / 1016.0), -(7200.0 / 1016.0)));
124
0
        }
125
0
    }
126
127
6.15M
    hpgl_call(gs_rotate(pgls->pgs, pgls->g.rotation));
128
129
6.15M
    switch (pgls->g.rotation) {
130
6.15M
        case 0:
131
6.15M
            hpgl_call(gs_translate(pgls->pgs, 0, 0));
132
6.15M
            break;
133
6.15M
        case 90:
134
0
            if (pgls->personality != rtl) {
135
0
                hpgl_call(gs_translate(pgls->pgs, 0, -fw_plu));
136
0
            } else {
137
0
                if (pgls->g.picture_frame_width >
138
0
                    pgls->g.picture_frame_height)
139
0
                    hpgl_call(gs_translate(pgls->pgs, 0, -fw_plu));
140
0
                else
141
0
                    hpgl_call(gs_translate(pgls->pgs, 0, -fh_plu));
142
0
            }
143
0
            break;
144
0
        case 180:
145
0
            if (pgls->personality != rtl) {
146
0
                hpgl_call(gs_translate(pgls->pgs, -fw_plu, -fh_plu));
147
0
            } else {
148
0
                if (pgls->g.picture_frame_width >
149
0
                    pgls->g.picture_frame_height)
150
0
                    hpgl_call(gs_translate(pgls->pgs, -fw_plu, -fh_plu));
151
0
                else
152
0
                    hpgl_call(gs_translate(pgls->pgs, -fh_plu, -fw_plu));
153
0
            }
154
0
            break;
155
0
        case 270:
156
0
            if (pgls->personality != rtl) {
157
0
                hpgl_call(gs_translate(pgls->pgs, -fh_plu, 0));
158
0
            } else {
159
0
                if (pgls->g.picture_frame_width >
160
0
                    pgls->g.picture_frame_height)
161
0
                    hpgl_call(gs_translate(pgls->pgs, -fh_plu, 0));
162
0
                else
163
0
                    hpgl_call(gs_translate(pgls->pgs, -fw_plu, 0));
164
0
            }
165
0
            break;
166
6.15M
    }
167
6.15M
    hpgl_call(hpgl_set_picture_frame_scaling(pgls));
168
6.15M
    {
169
6.15M
        gs_matrix mat;
170
171
6.15M
        gs_currentmatrix(pgls->pgs, &mat);
172
6.15M
        mat.ty = floor(mat.ty);
173
6.15M
        mat.tx = floor(mat.tx);
174
6.15M
        gs_setmatrix(pgls->pgs, &mat);
175
6.15M
    }
176
6.15M
    hpgl_call(gs_setdotorientation(pgls->pgs));
177
6.15M
    return 0;
178
6.15M
}
179
180
/* Set the CTM to map PLU to device units, regardless of scaling. */
181
/* (We need this for labels when scaling is on.) */
182
int
183
hpgl_set_plu_ctm(hpgl_state_t * pgls)
184
6.15M
{
185
6.15M
    hpgl_call(hpgl_set_pcl_to_plu_ctm(pgls));
186
6.15M
    return 0;
187
6.15M
}
188
189
int
190
hpgl_compute_user_units_to_plu_ctm(const hpgl_state_t * pgls,
191
                                   gs_matrix * pmat)
192
888k
{
193
888k
    double origin_x = pgls->g.P1.x, origin_y = pgls->g.P1.y;
194
195
888k
    switch (pgls->g.scaling_type) {
196
37.0k
        case hpgl_scaling_none:
197
37.0k
            gs_make_identity(pmat);
198
37.0k
            break;
199
0
        case hpgl_scaling_point_factor:
200
0
            hpgl_call(gs_make_translation(origin_x, origin_y, pmat));
201
0
            hpgl_call(gs_matrix_scale(pmat, pgls->g.scaling_params.factor.x,
202
0
                                      pgls->g.scaling_params.factor.y, pmat));
203
0
            hpgl_call(gs_matrix_translate(pmat,
204
0
                                          -pgls->g.scaling_params.pmin.x,
205
0
                                          -pgls->g.scaling_params.pmin.y,
206
0
                                          pmat));
207
0
            break;
208
850k
        default:
209
            /*case hpgl_scaling_anisotropic: */
210
            /*case hpgl_scaling_isotropic: */
211
850k
            {
212
850k
                double window_x = pgls->g.P2.x - origin_x,
213
850k
                    range_x = pgls->g.scaling_params.pmax.x -
214
850k
                    pgls->g.scaling_params.pmin.x,
215
850k
                    scale_x = window_x / range_x;
216
850k
                double window_y = pgls->g.P2.y - origin_y,
217
850k
                    range_y = pgls->g.scaling_params.pmax.y -
218
850k
                    pgls->g.scaling_params.pmin.y,
219
850k
                    scale_y = window_y / range_y;
220
850k
#define SIGN(x) ((x) < 0 ? -1.0 : 1.0)
221
222
850k
                if (pgls->g.scaling_type == hpgl_scaling_isotropic) {
223
2
                    if (fabs(scale_x) > fabs(scale_y)) {        /* Reduce the X scaling. */
224
0
                        origin_x +=
225
0
                            SIGN(scale_x) * (range_x *
226
0
                                             (fabs(scale_x) -
227
0
                                              fabs(scale_y)) *
228
0
                                             (pgls->g.scaling_params.left /
229
0
                                              100.0));
230
0
                        scale_x = SIGN(scale_x) * fabs(scale_y);
231
2
                    } else {    /* Reduce the Y scaling. */
232
2
                        origin_y +=
233
2
                            SIGN(scale_y) * (range_y *
234
2
                                             (fabs(scale_y) -
235
2
                                              fabs(scale_x)) *
236
2
                                             (pgls->g.scaling_params.bottom /
237
2
                                              100.0));
238
2
                        scale_y = SIGN(scale_y) * fabs(scale_x);
239
2
                    }
240
2
                }
241
242
850k
                hpgl_call(gs_make_translation(origin_x, origin_y, pmat));
243
850k
                hpgl_call(gs_matrix_scale(pmat, scale_x, scale_y, pmat));
244
850k
                hpgl_call(gs_matrix_translate(pmat,
245
850k
                                              -pgls->g.scaling_params.pmin.x,
246
850k
                                              -pgls->g.scaling_params.pmin.y,
247
850k
                                              pmat));
248
850k
                break;
249
850k
            }
250
888k
    }
251
888k
    return 0;
252
253
888k
}
254
255
/* set up ctm's.  Uses the current render mode to figure out which ctm
256
   is appropriate */
257
int
258
hpgl_set_ctm(hpgl_state_t * pgls)
259
2.97M
{
260
2.97M
    hpgl_call(hpgl_set_plu_ctm(pgls));
261
2.97M
    if (pgls->g.scaling_type != hpgl_scaling_none) {
262
845k
        gs_matrix mat;
263
264
845k
        hpgl_call(hpgl_compute_user_units_to_plu_ctm(pgls, &mat));
265
845k
        hpgl_call(gs_concat(pgls->pgs, &mat));
266
845k
        hpgl_call(gs_currentmatrix(pgls->pgs, &mat));
267
845k
        mat.tx = round(mat.tx);
268
845k
        mat.ty = round(mat.ty);
269
845k
        hpgl_call(gs_setmatrix(pgls->pgs, &mat));
270
845k
    }
271
2.97M
    return 0;
272
2.97M
}
273
274
/* Compute the pattern length.  Normally, if the pattern length is
275
   relative it is 4% of the diagonal distance from P1 to P2, for
276
   isotropic scaling we need 4% of the distance of the plotter unit
277
   equivalent of the scaling SC coordinates xmin, xmax, ymin, and
278
   ymax.. */
279
static double
280
hpgl_get_line_pattern_length(hpgl_state_t * pgls)
281
98
{
282
    /* dispense with the unusual "isotropic relative" case first.  The
283
       normal calculation afterward is straightforward */
284
98
    if ((pgls->g.line.current.pattern_length_relative == 0) &&
285
98
        (pgls->g.scaling_type == hpgl_scaling_isotropic)) {
286
        /* the box in user space */
287
0
        gs_rect isotropic_user_box;
288
        /* box in plotter units we compute 4% of the diagonal of this box */
289
0
        gs_rect isotropic_plu_box;
290
0
        gs_matrix user_to_plu_mat;
291
292
0
        hpgl_call(hpgl_compute_user_units_to_plu_ctm(pgls, &user_to_plu_mat));
293
294
0
        isotropic_user_box.p = pgls->g.scaling_params.pmin;
295
0
        isotropic_user_box.q = pgls->g.scaling_params.pmax;
296
297
0
        hpgl_call(gs_bbox_transform(&isotropic_user_box,
298
0
                                    &user_to_plu_mat, &isotropic_plu_box));
299
300
0
        return (pgls->g.line.current.pattern_length / 100.0) *
301
0
            hpgl_compute_distance(isotropic_plu_box.p.x,
302
0
                                  isotropic_plu_box.p.y,
303
0
                                  isotropic_plu_box.q.x,
304
0
                                  isotropic_plu_box.q.y);
305
0
    }
306
307
    /* simple case 4% of the diagonal of P1 and P2 or absolute in millimeters */
308
98
    return ((pgls->g.line.current.pattern_length_relative == 0) ?
309
98
            ((pgls->g.line.current.pattern_length / 100.0) *
310
98
             hpgl_compute_distance(pgls->g.P1.x,
311
98
                                   pgls->g.P1.y,
312
98
                                   pgls->g.P2.x,
313
98
                                   pgls->g.P2.y) *
314
98
             hpgl_width_scale(pgls)) :
315
98
            (mm_2_plu(pgls->g.line.current.pattern_length)));
316
98
}
317
318
static int
319
hpgl_set_graphics_dash_state(hpgl_state_t * pgls)
320
2.58M
{
321
2.58M
    int entry = abs(pgls->g.line.current.type);
322
2.58M
    bool adaptive;
323
2.58M
    const hpgl_line_type_t *pat;
324
2.58M
    float length;
325
2.58M
    float pattern[20] = {0};
326
2.58M
    float offset;
327
2.58M
    int count;
328
2.58M
    int i;
329
330
    /* handle the simple case (no dash) and return */
331
2.58M
    if (pgls->g.line.current.is_solid) {
332
        /* use a 0 count pattern to turn off dashing in case it is
333
           set, and allow drawing dots */
334
2.58M
        hpgl_call(gs_setdash(pgls->pgs, pattern, 0, 0));
335
2.58M
        hpgl_call(gs_setdotlength(pgls->pgs, 0.00098, true));
336
2.58M
        return 0;
337
2.58M
    }
338
339
49
    hpgl_call(gs_setdotlength(pgls->pgs, 0.0, false));
340
49
    if (entry == 0) {
341
        /* dot length NOTE this is in absolute 1/72" units not
342
           user space */
343
        /* Use an adaptive pattern with an infinitely long segment length
344
           to get the dots drawn just at the ends of lines. */
345
0
        pattern[0] = 0;
346
0
        pattern[1] = 1.0e6;     /* "infinity" */
347
0
        hpgl_call(gs_setdash(pgls->pgs, pattern, 2, 0));
348
0
        gs_setdashadapt(pgls->pgs, true);
349
0
        return 0;
350
0
    }
351
352
49
    adaptive = (pgls->g.line.current.type < 0);
353
49
    pat = ((adaptive) ?
354
0
           (&pgls->g.adaptive_line_type[entry - 1]) :
355
49
           (&pgls->g.fixed_line_type[entry - 1]));
356
357
49
    length = hpgl_get_line_pattern_length(pgls);
358
49
    gs_setdashadapt(pgls->pgs, adaptive);
359
    /*
360
     * The graphics library interprets odd pattern counts differently
361
     * from GL: if the pattern count is odd, we need to do something
362
     * a little special.
363
     */
364
49
    count = pat->count;
365
147
    for (i = 0; i < count; i++)
366
98
        pattern[i] = length * pat->gap[i];
367
49
    offset =
368
49
        pgls->g.line.current.pattern_offset *
369
49
        hpgl_get_line_pattern_length(pgls);
370
49
    if (count & 1) {
371
        /*
372
         * Combine the last gap with the first one, and change the
373
         * offset to compensate.  NOTE: this doesn't work right with
374
         * adaptive line type: we may need to change the library to
375
         * make this work properly.
376
         */
377
0
        --count;
378
0
        pattern[0] += pattern[count];
379
0
        offset += pattern[count];
380
0
    }
381
382
49
    hpgl_call(gs_setdash(pgls->pgs, pattern, count, offset));
383
384
49
    return 0;
385
49
}
386
387
/* catch pen not being in the palette */
388
int
389
hpgl_get_selected_pen(hpgl_state_t * pgls)
390
6.13M
{
391
    /* get the current pen */
392
6.13M
    int pen = pgls->g.pen.selected;
393
394
    /* 0 is the first pen */
395
6.13M
    int num_entries = pcl_palette_get_num_entries(pgls->ppalet);
396
397
    /* this is bad */
398
6.13M
    if ((pen < 0) || (pen >= num_entries)) {
399
0
        pen %= num_entries;
400
0
        if (pen < 0)
401
0
            pen += num_entries;
402
0
    }
403
6.13M
    return pen;
404
6.13M
}
405
406
/*
407
 * set up joins, caps, miter limit, and line width
408
 */
409
static int
410
hpgl_set_graphics_line_attribute_state(hpgl_state_t * pgls,
411
                                       hpgl_rendering_mode_t render_mode)
412
2.58M
{
413
2.58M
    const gs_line_cap cap_map[] = { gs_cap_butt,        /* 0 not supported */
414
2.58M
        gs_cap_butt,            /* 1 butt end */
415
2.58M
        gs_cap_square,          /* 2 square end */
416
2.58M
        gs_cap_triangle,        /* 3 triag. end */
417
2.58M
        gs_cap_round            /* 4 round cap */
418
2.58M
    };
419
420
2.58M
    const gs_line_join join_map[] = { gs_join_none,     /* 0 not supported */
421
2.58M
        gs_join_miter,          /* 1 mitered */
422
2.58M
        gs_join_miter,          /* 2 mitrd/bevld */
423
2.58M
        gs_join_triangle,       /* 3 triag. join */
424
2.58M
        gs_join_round,          /* 4 round join */
425
2.58M
        gs_join_bevel,          /* 5 bevel join */
426
2.58M
        gs_join_none            /* 6 no join */
427
2.58M
    };
428
2.58M
    const float *widths = pcl_palette_get_pen_widths(pgls->ppalet);
429
2.58M
    double pen_wid = widths[hpgl_get_selected_pen(pgls)];
430
431
2.58M
    gs_setfilladjust(pgls->pgs, 0.0, 0.0);
432
433
    /* character mode has already set up all of this information in
434
       the build character routine for the font */
435
2.58M
    if (render_mode == hpgl_rm_character)
436
209k
        return 0;
437
    /*
438
     * HP appears to use default line attributes if the the pen
439
     * width is less than or equal to .35mm or 14.0 plu.  This
440
     * is not documented PCLTRM.  Pen widths are maintained in
441
     * plotter units
442
     */
443
2.37M
    if (pen_wid <= 14.0) {
444
81.0k
        hpgl_call(gs_setlinejoin(pgls->pgs, gs_join_none));
445
81.0k
        hpgl_call(gs_setlinecap(pgls->pgs, gs_cap_butt));
446
81.0k
        hpgl_call(gs_setlinewidth(pgls->pgs, pen_wid));
447
81.0k
        hpgl_call(gs_setmiterlimit(pgls->pgs, 5.0));
448
81.0k
        return 0;
449
81.0k
    }
450
451
2.29M
    switch (render_mode) {
452
453
25.9k
        case hpgl_rm_polygon:
454
26.1k
        case hpgl_rm_clip_and_fill_polygon:
455
26.1k
            hpgl_call(gs_setlinejoin(pgls->pgs, gs_join_round));
456
26.1k
            hpgl_call(gs_setlinecap(pgls->pgs, gs_cap_round));
457
26.1k
            break;
458
459
2.25M
        case hpgl_rm_vector_fill:
460
2.26M
        case hpgl_rm_vector:
461
2.26M
          vector:
462
2.26M
            hpgl_call(gs_setlinejoin(pgls->pgs, join_map[pgls->g.line.join]));
463
2.26M
            hpgl_call(gs_setlinecap(pgls->pgs, cap_map[pgls->g.line.cap]));
464
2.26M
            hpgl_call(gs_setlinewidth(pgls->pgs, pen_wid));
465
2.26M
            break;
466
467
2.26M
        default:
468
            /* shouldn't happen; we must have a mode to properly parse hpgl file. */
469
0
            dmprintf(pgls->memory,
470
0
                     "warning no hpgl rendering mode set using vector mode\n");
471
0
            goto vector;
472
2.29M
    }
473
474
#ifdef COMMENT
475
    /* I do not remember the rational for the large miter */
476
    hpgl_call(gs_setmiterlimit(pgls->pgs, (pgls->g.line.join == 1)
477
                               ? 5000.0 : pgls->g.miter_limit));
478
#endif
479
2.29M
    hpgl_call(gs_setmiterlimit(pgls->pgs, pgls->g.miter_limit));
480
2.29M
    return 0;
481
2.29M
}
482
483
/*
484
 * A bounding box for the current polygon -- used for HPGL/2 vector
485
 * fills.
486
 */
487
static int
488
hpgl_polyfill_bbox(hpgl_state_t * pgls, gs_rect * bbox)
489
294
{
490
    /* get the bounding box for the current path / polygon */
491
294
    hpgl_call(gs_pathbbox(pgls->pgs, bbox));
492
294
    return 0;
493
294
}
494
495
/* set up an hpgl clipping region -- intersection of IW command and
496
   picture frame. */
497
int
498
hpgl_set_clipping_region(hpgl_state_t * pgls,
499
                         hpgl_rendering_mode_t render_mode)
500
2.61M
{
501
    /* if we are doing vector fill a clipping path has already
502
       been set up using the last polygon */
503
2.61M
    if (render_mode == hpgl_rm_vector_fill)
504
2.26M
        return 0;
505
353k
    else {
506
353k
        gs_fixed_rect fixed_box;
507
353k
        gs_rect pcl_clip_box;
508
353k
        gs_rect dev_clip_box;
509
353k
        gs_matrix save_ctm;
510
353k
        gs_matrix pcl_ctm;
511
512
        /* get pcl to device ctm and restore the current ctm */
513
353k
        hpgl_call(gs_currentmatrix(pgls->pgs, &save_ctm));
514
353k
        hpgl_call(pcl_set_ctm(pgls, false));
515
353k
        hpgl_call(gs_currentmatrix(pgls->pgs, &pcl_ctm));
516
353k
        hpgl_call(gs_setmatrix(pgls->pgs, &save_ctm));
517
        /* find the clipping region defined by the picture frame
518
           which is defined in pcl coordinates */
519
353k
        if (pgls->personality != rtl) {
520
353k
            pcl_clip_box.p.x = pgls->g.picture_frame.anchor_point.x;
521
353k
            pcl_clip_box.p.y = pgls->g.picture_frame.anchor_point.y;
522
353k
            pcl_clip_box.q.x = pcl_clip_box.p.x + pgls->g.picture_frame_width;
523
353k
            pcl_clip_box.q.y =
524
353k
                pcl_clip_box.p.y + pgls->g.picture_frame_height;
525
353k
        } else {
526
0
            pcl_clip_box.p.x = pgls->g.picture_frame.anchor_point.y;
527
0
            pcl_clip_box.p.y = pgls->g.picture_frame.anchor_point.x;
528
0
            pcl_clip_box.q.x =
529
0
                pcl_clip_box.p.y + pgls->g.picture_frame_height;
530
0
            pcl_clip_box.q.y = pcl_clip_box.p.x + pgls->g.picture_frame_width;
531
0
        }
532
533
353k
        hpgl_call(gs_bbox_transform(&pcl_clip_box, &pcl_ctm, &dev_clip_box));
534
        /* HP cheats and expands the clip box's extant by at least
535
           one device pixel in all directions */
536
353k
        dev_clip_box.q.x += 1.0;
537
353k
        dev_clip_box.q.y += 1.0;
538
353k
        dev_clip_box.p.x -= 1.0;
539
353k
        dev_clip_box.p.y -= 1.0;
540
        /* if the clipping window is active calculate the new clip
541
           box derived from IW and the intersection of the device
542
           space boxes replace the current box.  Note that IW
543
           coordinates are in current units and and the picture
544
           frame in pcl coordinates. */
545
353k
        if (pgls->g.soft_clip_window.active) {
546
638
            gs_rect dev_soft_window_box;
547
638
            gs_matrix ctm;
548
549
638
            if (pgls->g.soft_clip_window.isbound && pgls->personality != rtl) {
550
                /* we need the plotter unit matrix */
551
0
                hpgl_call(gs_currentmatrix(pgls->pgs, &save_ctm));
552
0
                hpgl_call(hpgl_set_plu_ctm(pgls));
553
0
                hpgl_call(gs_currentmatrix(pgls->pgs, &ctm));
554
0
                hpgl_call(gs_setmatrix(pgls->pgs, &save_ctm));
555
638
            } else {
556
638
                hpgl_call(gs_currentmatrix(pgls->pgs, &ctm));
557
638
            }
558
638
            hpgl_call(gs_bbox_transform(&pgls->g.soft_clip_window.rect,
559
638
                                        &ctm, &dev_soft_window_box));
560
            /* Enlarge IW by 1 device dot to compensate for it's
561
               'on the line' is not clipped behavior. */
562
638
            dev_clip_box.p.x =
563
638
                max(dev_clip_box.p.x, dev_soft_window_box.p.x - 1.0);
564
638
            dev_clip_box.p.y =
565
638
                max(dev_clip_box.p.y, dev_soft_window_box.p.y - 1.0);
566
638
            dev_clip_box.q.x =
567
638
                min(dev_clip_box.q.x, dev_soft_window_box.q.x + 1.0);
568
638
            dev_clip_box.q.y =
569
638
                min(dev_clip_box.q.y, dev_soft_window_box.q.y + 1.0);
570
571
638
        }
572
        /* convert intersection box to fixed point and clip */
573
353k
        fixed_box.p.x = float2fixed(floor(dev_clip_box.p.x));
574
353k
        fixed_box.p.y = float2fixed(floor(dev_clip_box.p.y));
575
353k
        fixed_box.q.x = float2fixed(ceil(dev_clip_box.q.x));
576
353k
        fixed_box.q.y = float2fixed(ceil(dev_clip_box.q.y));
577
353k
        hpgl_call(gx_clip_to_rectangle(pgls->pgs, &fixed_box));
578
353k
    }
579
353k
    return 0;
580
2.61M
}
581
582
/* Plot one vector for vector fill all these use absolute coordinates. */
583
static int
584
hpgl_draw_vector_absolute(hpgl_state_t * pgls,
585
                          hpgl_real_t x0,
586
                          hpgl_real_t y0,
587
                          hpgl_real_t x1,
588
                          hpgl_real_t y1, hpgl_rendering_mode_t render_mode)
589
2.26M
{
590
2.26M
    bool set_ctm = (render_mode != hpgl_rm_character);
591
592
2.26M
    hpgl_call(hpgl_add_point_to_path(pgls,
593
2.26M
                                     x0,
594
2.26M
                                     y0, hpgl_plot_move_absolute, set_ctm));
595
2.26M
    hpgl_call(hpgl_add_point_to_path(pgls,
596
2.26M
                                     x1,
597
2.26M
                                     y1, hpgl_plot_draw_absolute, set_ctm));
598
2.26M
    hpgl_call(hpgl_draw_current_path(pgls, hpgl_rm_vector_fill));
599
2.26M
    return 0;
600
2.26M
}
601
602
static int
603
hpgl_get_adjusted_corner(hpgl_real_t x_fill_increment,
604
                         hpgl_real_t y_fill_increment,
605
                         gs_rect * bbox,
606
                         gs_point * current_anchor_corner,
607
                         gs_point * adjusted_anchor_corner)
608
849
{
609
849
    adjusted_anchor_corner->x = current_anchor_corner->x;
610
849
    adjusted_anchor_corner->y = current_anchor_corner->y;
611
    /* account for anchor corner greater than origin */
612
849
    if (x_fill_increment != 0) {
613
284
        while (adjusted_anchor_corner->x > bbox->p.x)
614
1
            adjusted_anchor_corner->x -= x_fill_increment;
615
566
    } else if (adjusted_anchor_corner->x > bbox->p.x)
616
2
        adjusted_anchor_corner->x = bbox->p.x;
617
849
    if (y_fill_increment != 0) {
618
586
        while (adjusted_anchor_corner->y > bbox->p.y)
619
20
            adjusted_anchor_corner->y -= y_fill_increment;
620
566
    } else if (adjusted_anchor_corner->y > bbox->p.y)
621
1
        adjusted_anchor_corner->y = bbox->p.y;
622
849
    return 0;
623
849
}
624
625
static void
626
hpgl_alternate_line_pattern_offset(hpgl_state_t * pgls, uint lines_filled)
627
2.26M
{
628
2.26M
    if (lines_filled & 1)
629
1.13M
        pgls->g.line.current.pattern_offset = 0.5;
630
1.13M
    else
631
1.13M
        pgls->g.line.current.pattern_offset = 0.0;
632
2.26M
}
633
634
/* this definition is used to factor out the effect of the orientation
635
   of the pcl logical page.  HP printers prior to the 4500 series
636
   oriented the hpgl/2 fill lines relative to the logical page
637
   orientation (expected result), later printers do not.  Comment out
638
   the following definition to support the old (expected) behavior. */
639
#define FILL_IGNORES_PCL_ORIENTATION
640
641
/*
642
 * HAS should replicate lines beginning at the anchor corner to +X and
643
 * +Y.  Not quite right - anchor corner not yet supported.
644
 * pgls->g.anchor_corner needs to be used to set dash offsets
645
 */
646
static int
647
hpgl_polyfill(hpgl_state_t * pgls, hpgl_rendering_mode_t render_mode)
648
294
{
649
294
    hpgl_real_t diag_mag, endx, endy;
650
294
    gs_sincos_t sincos;
651
294
    gs_point start;
652
2.83k
#define sin_dir sincos.sin
653
1.98k
#define cos_dir sincos.cos
654
294
    gs_rect bbox;
655
294
    gs_matrix user_to_plu_mat;
656
294
    hpgl_pen_state_t saved_pen_state;
657
294
    hpgl_real_t x_fill_increment, y_fill_increment;
658
294
    hpgl_FT_pattern_source_t type = pgls->g.fill.type;
659
294
    bool cross = (type == hpgl_FT_pattern_two_lines);
660
294
    const hpgl_hatch_params_t *params =
661
294
        (cross ? &pgls->g.fill.param.crosshatch : &pgls->g.fill.param.hatch);
662
294
    gs_point spacing;
663
294
#ifdef FILL_IGNORES_PCL_ORIENTATION
664
294
    hpgl_real_t direction = params->angle + pgls->xfm_state.lp_orient * 90;
665
#else
666
    hpgl_real_t direction = params->angle;
667
#endif
668
294
    hpgl_real_t unscaled_direction;
669
294
    float saved_line_pattern_offset = pgls->g.line.current.pattern_offset;
670
294
    int lines_filled;
671
672
    /* spacing is always relevant to the scaling of the x-axis.  It
673
       can be specified in user space if provided to FT or by default
674
       it is 1% of the distance from P1 to P2 */
675
294
    spacing.x = params->spacing;
676
    /* save the pen position */
677
294
    hpgl_save_pen_state(pgls, &saved_pen_state, hpgl_pen_pos);
678
294
    hpgl_call(hpgl_compute_user_units_to_plu_ctm(pgls, &user_to_plu_mat));
679
294
    if (params->spacing == 0) {
680
        /* Per TRM 22-12, use 1% of the P1/P2 distance. */
681
682
22
        spacing.x = 0.01 * hpgl_compute_distance(pgls->g.P1.x,
683
22
                                                 pgls->g.P1.y,
684
22
                                                 pgls->g.P2.x, pgls->g.P2.y);
685
686
        /* 1% is in plu, convert back to user units */
687
22
        spacing.y = spacing.x / fabs(user_to_plu_mat.yy);
688
22
        spacing.x /= fabs(user_to_plu_mat.xx);
689
272
    } else {
690
        /* set spacing.y based on ratio of x/y scaling, still in user units */
691
272
        spacing.y =
692
272
            spacing.x * fabs(user_to_plu_mat.xx) / fabs(user_to_plu_mat.yy);
693
272
    }
694
    /* get the bounding box */
695
294
    hpgl_call(hpgl_polyfill_bbox(pgls, &bbox));
696
    /*
697
     * if the line width exceeds the spacing we use the line width
698
     * to avoid overlapping of the fill lines.  HAS this can be
699
     * integrated with the logic above for spacing as not to
700
     * duplicate alot of code.
701
     */
702
294
    {
703
294
        const float *widths = pcl_palette_get_pen_widths(pgls->ppalet);
704
294
        hpgl_real_t line_width = widths[hpgl_get_selected_pen(pgls)];
705
706
294
        line_width /= min(fabs(user_to_plu_mat.xx), fabs(user_to_plu_mat.yy));
707
294
        if (line_width >= spacing.x || line_width >= spacing.y) {
708
11
            hpgl_call(hpgl_draw_current_path(pgls, hpgl_rm_polygon));
709
11
            return 0;
710
11
        }
711
294
    }
712
713
    /* get rid of the current path */
714
715
283
    hpgl_call(hpgl_clear_current_path(pgls));
716
717
566
  start:                       /* Change direction, come back and draw crosshatch lines. */
718
719
    /* hatch angles are isotropic; ie 45degrees is not affected by y scale != x scale.
720
       unscaled_direction ::= user requested angle
721
       direction ::= the angle that when scaled will generate user requested angle */
722
723
    /* save unscaled angle */
724
566
    unscaled_direction = direction;
725
726
    /* not necessery if direction is orthogonal */
727
566
    if (!equal(fmod(direction, 90), 0)) {
728
0
        hpgl_real_t slope, scaled_slope;
729
730
0
        gs_sincos_degrees(direction, &sincos);
731
        /* take the tangent by dividing sin by cos.  Since we know
732
           the angle is non-orthogonal the cosine is non-zero */
733
0
        slope = sin_dir / cos_dir;
734
        /* scale the slope by the ratio of the scaling factors */
735
0
        scaled_slope = (user_to_plu_mat.xx / user_to_plu_mat.yy) * slope;
736
        /* preserved angle in user space */
737
0
        direction = radians_to_degrees * atan(scaled_slope);
738
0
    }
739
740
566
    lines_filled = 0;
741
742
    /* spacing is done with the unscaled angle
743
       spacing.x .y is already scaled hence the unscaled angle is used.
744
       scale * spacing * sin(unscaled_angle) */
745
566
    gs_sincos_degrees(unscaled_direction, &sincos);
746
566
    if (sin_dir < 0)
747
0
        sin_dir = -sin_dir, cos_dir = -cos_dir; /* ensure y_inc >= 0 */
748
566
    x_fill_increment = (sin_dir != 0) ? fabs(spacing.x / sin_dir) : 0;
749
566
    y_fill_increment = (cos_dir != 0) ? fabs(spacing.y / cos_dir) : 0;
750
751
    /* scaled angle is used for end point calculation
752
       distance * sin( scaled_angle )
753
       scale is applyed once and only once per calculation */
754
566
    gs_sincos_degrees(direction, &sincos);
755
566
    if (sin_dir < 0)
756
0
        sin_dir = -sin_dir, cos_dir = -cos_dir; /* ensure y_inc >= 0 */
757
758
566
    hpgl_call(hpgl_get_adjusted_corner(x_fill_increment,
759
566
                                       y_fill_increment,
760
566
                                       &bbox,
761
566
                                       &pgls->g.anchor_corner, &start));
762
763
    /*
764
     * calculate the diagonals magnitude.  Note we clip this
765
     * latter in the library.  If desired we could clip to the
766
     * actual bbox here to save processing time.  For now we simply
767
     * draw all fill lines using the diagonals magnitude
768
     */
769
566
    diag_mag = hpgl_compute_distance(start.x, start.y, bbox.q.x, bbox.q.y);
770
566
    endx = (diag_mag * cos_dir) + start.x;
771
566
    endy = (diag_mag * sin_dir) + start.y;
772
566
    hpgl_alternate_line_pattern_offset(pgls, lines_filled++);
773
566
    hpgl_call(hpgl_draw_vector_absolute(pgls,
774
566
                                        start.x,
775
566
                                        start.y, endx, endy, render_mode));
776
    /* Travel along +x using current spacing. */
777
566
    if (x_fill_increment != 0) {
778
331k
        while (endx += x_fill_increment,
779
331k
               (start.x += x_fill_increment) <= bbox.q.x) {
780
781
331k
            hpgl_alternate_line_pattern_offset(pgls, lines_filled++);
782
331k
            hpgl_call(hpgl_draw_vector_absolute(pgls,
783
331k
                                                start.x,
784
331k
                                                start.y,
785
331k
                                                endx, endy, render_mode));
786
331k
        }
787
283
    }
788
789
    /* Travel along +Y similarly. */
790
566
    if (y_fill_increment != 0) {
791
        /*
792
         * If the slope is negative, we have to travel along the right
793
         * edge of the box rather than the left edge.  Fortuitously,
794
         * the X loop left everything set up exactly right for this case.
795
         */
796
283
        if (cos_dir >= 0) {
797
283
            hpgl_call(hpgl_get_adjusted_corner(x_fill_increment,
798
283
                                               y_fill_increment,
799
283
                                               &bbox,
800
283
                                               &pgls->g.anchor_corner,
801
283
                                               &start));
802
283
            endx = (diag_mag * cos_dir) + start.x;
803
283
            endy = (diag_mag * sin_dir) + start.y;
804
283
        } else
805
0
            start.y -= y_fill_increment, endy -= y_fill_increment;
806
807
1.93M
        while (endy += y_fill_increment,
808
1.93M
               (start.y += y_fill_increment) <= bbox.q.y) {
809
1.93M
            hpgl_alternate_line_pattern_offset(pgls, lines_filled++);
810
1.93M
            hpgl_call(hpgl_draw_vector_absolute(pgls,
811
1.93M
                                                start.x,
812
1.93M
                                                start.y,
813
1.93M
                                                endx, endy, render_mode));
814
1.93M
        }
815
816
283
    }
817
566
    if (cross) {
818
        /* go back and draw the perpendicular lines, +90degress */
819
283
        cross = false;
820
283
        direction = unscaled_direction + 90;
821
283
        if (direction >= 180)
822
6
            direction -= 180;
823
283
        goto start;
824
283
    }
825
283
    hpgl_restore_pen_state(pgls, &saved_pen_state, hpgl_pen_pos);
826
283
    pgls->g.line.current.pattern_offset = saved_line_pattern_offset;
827
283
    return 0;
828
829
566
#undef sin_dir
830
566
#undef cos_dir
831
832
566
}
833
834
/* gl/2 vector filled objects always have a white background.  It can
835
   be either a transparent or white.  In the former case we don't have
836
   to do anything.  We expect the fill area of the object to already
837
   be defined in the graphics state. */
838
static int
839
hpgl_fill_polyfill_background(hpgl_state_t * pgls)
840
294
{
841
294
    int code, code2;
842
    /* conditionally mark page as dirty */
843
294
    hpgl_call(pcl_mark_page_for_path(pgls));
844
    /* if we are drawing on a transparent background */
845
294
    if (pgls->g.source_transparent)
846
293
        return 0;
847
    /* preserve the current foreground color */
848
1
    hpgl_call(hpgl_gsave(pgls));
849
    /* fill a white region. */
850
1
    code = gs_setgray(pgls->pgs, 1.0);
851
1
    if (code >= 0)
852
1
        code = gs_fill(pgls->pgs);
853
    /* restore the foreground color */
854
1
    code2 = hpgl_grestore(pgls);
855
1
    return (code < 0) ? code : code2;
856
1
}
857
858
static int
859
hpgl_polyfill_using_current_line_type(hpgl_state_t * pgls,
860
                                      hpgl_rendering_mode_t render_mode)
861
294
{
862
294
    int code;
863
864
    /* gsave and grestore used to preserve the clipping region */
865
294
    hpgl_call(hpgl_gsave(pgls));
866
867
    /*
868
     * Use the current path to set up a clipping path
869
     * beginning at the anchor corner replicate lines
870
     */
871
294
    if (pgls->g.fill_type == hpgl_even_odd_rule)
872
294
        code = gs_eoclip(pgls->pgs);
873
0
    else
874
0
        code = gs_clip(pgls->pgs);
875
294
    if (code >= 0)  code = hpgl_fill_polyfill_background(pgls);
876
294
    if (code >= 0)  code = hpgl_polyfill(pgls, render_mode);
877
878
294
    {
879
294
        int code2 = hpgl_grestore(pgls);
880
294
        if (code >= 0)  code = code2;
881
294
        return code;
882
294
    }
883
294
}
884
885
static gs_rop3_t
886
hpgl_rop(hpgl_state_t * pgls, hpgl_rendering_mode_t render_mode)
887
2.99M
{
888
2.99M
    gs_rop3_t rop = pgls->logical_op;
889
890
2.99M
    if (render_mode == hpgl_rm_vector || render_mode == hpgl_rm_vector_fill) {
891
2.33M
        if (rop == 0 || rop == 160 || rop == 170 || rop == 240 || rop == 250
892
2.33M
            || rop == 255) {
893
1.61k
            return rop;
894
2.33M
        } else {
895
2.33M
            return rop3_default;
896
2.33M
        }
897
2.33M
    }
898
657k
    return rop;
899
2.99M
}
900
901
int
902
hpgl_set_drawing_color(hpgl_state_t * pgls, hpgl_rendering_mode_t render_mode)
903
2.99M
{
904
2.99M
    int code = 0;
905
906
2.99M
    pcl_pattern_set_proc_t set_proc;
907
908
2.99M
    switch (render_mode) {
909
910
294
        case hpgl_rm_clip_and_fill_polygon:
911
294
            hpgl_call(hpgl_polyfill_using_current_line_type
912
294
                      (pgls, render_mode));
913
294
            return 0;
914
915
622k
        case hpgl_rm_character:
916
622k
            switch (pgls->g.character.fill_mode) {
917
918
622k
                case hpgl_char_solid_edge:     /* fall through */
919
622k
                case hpgl_char_edge:
920
622k
                    set_proc =
921
622k
                        pcl_pattern_get_proc_FT(hpgl_FT_pattern_solid_pen1);
922
622k
                    code = set_proc(pgls, hpgl_get_selected_pen(pgls), false);
923
622k
                    break;
924
925
0
                case hpgl_char_fill:
926
902
                case hpgl_char_fill_edge:
927
902
                    if ((pgls->g.fill.type == hpgl_FT_pattern_one_line) ||
928
902
                        (pgls->g.fill.type == hpgl_FT_pattern_two_lines)) {
929
0
                        hpgl_call(hpgl_polyfill_using_current_line_type(pgls,
930
0
                                                                        render_mode));
931
0
                        return 0;
932
0
                    } else
933
902
                        goto fill;
934
935
0
                default:
936
0
                    dmprintf(pgls->memory,
937
0
                             "hpgl_set_drawing_color: internal error illegal fill\n");
938
0
                    return 0;
939
622k
            }
940
622k
            break;
941
942
            /* fill like a polygon */
943
622k
        case hpgl_rm_polygon:
944
35.1k
          fill:
945
35.1k
            set_proc = pcl_pattern_get_proc_FT(pgls->g.fill.type);
946
35.1k
            switch (pgls->g.fill.type) {
947
948
1.76k
                case hpgl_FT_pattern_solid_pen1:
949
1.77k
                case hpgl_FT_pattern_solid_pen2:
950
                    /*
951
                     * this is documented incorrectly PCLTRM 22-12 says
952
                     * these should be solid black but they are actually
953
                     * set to the value of the current pen - (i.e pen 0 is
954
                     * solid white
955
                     */
956
1.77k
                    code = set_proc(pgls, hpgl_get_selected_pen(pgls), false);
957
1.77k
                    break;
958
959
0
                case hpgl_FT_pattern_one_line:
960
11
                case hpgl_FT_pattern_two_lines:
961
11
                    set_proc =
962
11
                        pcl_pattern_get_proc_FT(hpgl_FT_pattern_solid_pen1);
963
11
                    code = set_proc(pgls, hpgl_get_selected_pen(pgls), false);
964
11
                    break;
965
966
0
                case hpgl_FT_pattern_cross_hatch:
967
0
                    code = set_proc(pgls,
968
0
                                    pgls->g.fill.param.pattern_type,
969
0
                                    hpgl_get_selected_pen(pgls)
970
0
                        );
971
0
                    break;
972
973
946
                case hpgl_FT_pattern_shading:
974
946
                    code = set_proc(pgls,
975
946
                                    pgls->g.fill.param.shading,
976
946
                                    hpgl_get_selected_pen(pgls)
977
946
                        );
978
946
                    break;
979
980
0
                case hpgl_FT_pattern_user_defined:
981
0
                    code = set_proc(pgls,
982
0
                                    pgls->g.fill.param.pattern_id,
983
0
                                    hpgl_get_selected_pen(pgls)
984
0
                        );
985
0
                    break;
986
987
32.4k
                case hpgl_FT_pattern_RF:
988
                    /* pcl5e does not care about the current pen it always uses black (1). */
989
32.4k
                    if (pgls->personality == pcl5e)
990
32.4k
                        code = set_proc(pgls,
991
32.4k
                                        -pgls->g.fill.param.user_defined.
992
32.4k
                                        pattern_index, 1);
993
0
                    else
994
0
                        code = set_proc(pgls,
995
0
                                        (pgls->g.fill.param.user_defined.
996
0
                                         use_current_pen ? -pgls->g.fill.
997
0
                                         param.user_defined.
998
0
                                         pattern_index : pgls->g.fill.param.
999
0
                                         user_defined.pattern_index),
1000
0
                                        hpgl_get_selected_pen(pgls)
1001
0
                            );
1002
1003
32.4k
                    break;
1004
0
                default:
1005
0
                    dmprintf(pgls->memory,
1006
0
                             "hpgl_set_drawing_color: internal error illegal fill\n");
1007
0
                    break;
1008
35.1k
            }
1009
35.1k
            break;
1010
1011
72.7k
        case hpgl_rm_vector:
1012
2.33M
        case hpgl_rm_vector_fill:
1013
2.33M
            set_proc = pcl_pattern_get_proc_SV(pgls->g.screen.type);
1014
2.33M
            switch (pgls->g.screen.type) {
1015
1016
2.33M
                case hpgl_SV_pattern_solid_pen:
1017
2.33M
                    code = set_proc(pgls, hpgl_get_selected_pen(pgls), false);
1018
2.33M
                    break;
1019
1020
0
                case hpgl_SV_pattern_shade:
1021
0
                    code = set_proc(pgls,
1022
0
                                    pgls->g.screen.param.shading,
1023
0
                                    hpgl_get_selected_pen(pgls)
1024
0
                        );
1025
0
                    break;
1026
1027
0
                case hpgl_SV_pattern_cross_hatch:
1028
0
                    code = set_proc(pgls,
1029
0
                                    pgls->g.screen.param.pattern_type,
1030
0
                                    hpgl_get_selected_pen(pgls)
1031
0
                        );
1032
0
                    break;
1033
1034
0
                case hpgl_SV_pattern_RF:
1035
0
                    code = set_proc(pgls,
1036
0
                                    (pgls->g.screen.param.user_defined.
1037
0
                                     use_current_pen ? -pgls->g.screen.param.
1038
0
                                     user_defined.pattern_index : pgls->g.
1039
0
                                     screen.param.user_defined.pattern_index),
1040
0
                                    hpgl_get_selected_pen(pgls)
1041
0
                        );
1042
0
                    break;
1043
1044
0
                case hpgl_SV_pattern_user_defined:
1045
0
                    code = set_proc(pgls,
1046
0
                                    pgls->g.screen.param.pattern_id,
1047
0
                                    hpgl_get_selected_pen(pgls)
1048
0
                        );
1049
0
                    break;
1050
1051
0
                default:
1052
0
                    dmprintf(pgls->memory,
1053
0
                             "hpgl_set_drawing_color: internal error illegal fill\n");
1054
0
                    break;
1055
2.33M
            }
1056
2.33M
            break;
1057
1058
2.33M
        default:
1059
0
            dmprintf(pgls->memory,
1060
0
                     "hpgl_set_drawing_color: internal error illegal mode\n");
1061
0
            break;
1062
2.99M
    }
1063
1064
2.99M
    if (code >= 0) {
1065
2.99M
        code = check_rasterops(pgls, pgls->logical_op);
1066
2.99M
        if (code >= 0) {
1067
2.99M
            code = gs_setrasterop(pgls->pgs, hpgl_rop(pgls, render_mode));
1068
2.99M
            if (code < 0)
1069
0
                return code;
1070
2.99M
        }
1071
2.99M
        code = gx_set_dev_color(pgls->pgs);
1072
2.99M
        if (code == gs_error_Remap_Color)
1073
0
            code = pixmap_high_level_pattern(pgls->pgs);
1074
2.99M
    }
1075
1076
2.99M
    if (code < 0)
1077
0
        return code;
1078
1079
    /* make sure the halftone is set */
1080
2.99M
    return pcl_ht_set_halftone(pgls);
1081
2.99M
}
1082
1083
static int
1084
hpgl_set_drawing_state(hpgl_state_t * pgls, hpgl_rendering_mode_t render_mode)
1085
2.58M
{
1086
    /* do dash stuff. */
1087
2.58M
    hpgl_call(hpgl_set_graphics_dash_state(pgls));
1088
1089
    /* joins, caps, and line width. */
1090
2.58M
    hpgl_call(hpgl_set_graphics_line_attribute_state(pgls, render_mode));
1091
1092
    /* set up a clipping region */
1093
2.58M
    hpgl_call(hpgl_set_clipping_region(pgls, render_mode));
1094
1095
    /* set up the hpgl fills (GL's source transp. is PCL's pattern trasp. */
1096
2.58M
    pgls->pattern_transparent = pgls->g.source_transparent;
1097
2.58M
    hpgl_call(hpgl_set_drawing_color(pgls, render_mode));
1098
1099
2.58M
    return 0;
1100
2.58M
}
1101
1102
int
1103
hpgl_get_current_position(hpgl_state_t * pgls, gs_point * pt)
1104
395k
{
1105
395k
    *pt = pgls->g.pos;
1106
395k
    return 0;
1107
395k
}
1108
1109
int
1110
hpgl_update_carriage_return_pos(hpgl_state_t * pgls)
1111
630k
{
1112
630k
    pgls->g.carriage_return_pos = pgls->g.pos;
1113
630k
    return 0;
1114
630k
}
1115
1116
int
1117
hpgl_set_current_position(hpgl_state_t * pgls, gs_point * pt)
1118
9.54M
{
1119
9.54M
    pgls->g.pos = *pt;
1120
9.54M
    return 0;
1121
9.54M
}
1122
1123
static int
1124
update_pos(hpgl_state_t * pgls, double x, double y, hpgl_plot_function_t func)
1125
9.34M
{
1126
9.34M
    gs_point point;
1127
1128
9.34M
    if (hpgl_plot_is_absolute(func))
1129
9.06M
        hpgl_set_lost_mode(pgls, hpgl_lost_mode_cleared);
1130
1131
    /* update hpgl's state position */
1132
9.34M
    if (hpgl_plot_is_absolute(func)) {
1133
9.06M
        point.x = x;
1134
9.06M
        point.y = y;
1135
9.06M
    } else {
1136
283k
        hpgl_call(hpgl_get_current_position(pgls, &point));
1137
283k
        point.x += x;
1138
283k
        point.y += y;
1139
283k
    }
1140
1141
9.34M
    hpgl_call(hpgl_set_current_position(pgls, &point));
1142
9.34M
    return 0;
1143
9.34M
}
1144
1145
int
1146
hpgl_add_point_to_path(hpgl_state_t * pgls,
1147
                       double x,
1148
                       double y, hpgl_plot_function_t func, bool set_ctm)
1149
9.34M
{
1150
9.34M
    static int (*const gs_procs[]) (gs_gstate *, double, double)
1151
9.34M
        = {
1152
9.34M
    hpgl_plot_function_procedures};
1153
9.34M
    int code = 0;
1154
9.34M
    gx_path *ppath = gx_current_path(pgls->pgs);
1155
1156
9.34M
    if (gx_path_is_null(ppath)) {
1157
        /* Start a new GL/2 path. */
1158
2.74M
        gs_point current_pt;
1159
1160
2.74M
        if (set_ctm)
1161
2.74M
            hpgl_call(hpgl_set_ctm(pgls));
1162
2.74M
        if ((func != hpgl_plot_move_absolute) &&
1163
73.9k
            (!pgls->g.subpolygon_started)) {
1164
            /* moveto the current position */
1165
73.9k
            hpgl_call(hpgl_get_current_position(pgls, &current_pt));
1166
73.9k
            hpgl_call_check_lost(gs_moveto(pgls->pgs,
1167
73.9k
                                           current_pt.x, current_pt.y));
1168
73.9k
        }
1169
2.74M
    }
1170
1171
    /* start a new subpath if necessary */
1172
9.34M
    if (pgls->g.subpolygon_started == true) {
1173
35.9k
        hpgl_plot_function_t startup_func;
1174
1175
35.9k
        pgls->g.subpolygon_started = false;
1176
35.9k
        if (hpgl_plot_is_relative(func))
1177
3
            startup_func = hpgl_plot_move_relative;
1178
35.9k
        else
1179
35.9k
            startup_func = hpgl_plot_move_absolute;
1180
35.9k
        hpgl_set_hpgl_path_mode(pgls, false);
1181
35.9k
        code = (*gs_procs[startup_func]) (pgls->pgs, x, y);
1182
35.9k
        hpgl_set_hpgl_path_mode(pgls, true);
1183
35.9k
        update_pos(pgls, x, y, func);
1184
9.31M
    } else {                    /* no new subpath */
1185
9.31M
        code = (*gs_procs[func]) (pgls->pgs, x, y);
1186
9.31M
        if (code < 0) {
1187
0
            if (code == gs_error_limitcheck)
1188
0
                hpgl_set_lost_mode(pgls, hpgl_lost_mode_entered);
1189
9.31M
        } else {
1190
9.31M
            update_pos(pgls, x, y, func);
1191
9.31M
        }
1192
9.31M
    }
1193
9.34M
    return code;
1194
9.34M
}
1195
1196
void
1197
hpgl_set_hpgl_path_mode(hpgl_state_t * pgls, bool enable)
1198
445k
{
1199
    /*
1200
     * This was used to make paths for high level devices not containn 'gapto' segments. I
1201
     * have no idea why, because the vector devices handle gapto and removing it prevents
1202
     * proper handling of things like Fill Polygon (FP) HP-GL/2 commands.
1203
     * I've removed the test, but left it commented out in case there really is a good reason.
1204
        if (!pgls->high_level_device)
1205
     */
1206
445k
    gs_sethpglpathmode(pgls->pgs, enable);
1207
445k
}
1208
/* destroy the current path. */
1209
int
1210
hpgl_clear_current_path(hpgl_state_t * pgls)
1211
1.10M
{
1212
1.10M
    hpgl_call(gs_newpath(pgls->pgs));
1213
1.10M
    return 0;
1214
1.10M
}
1215
1216
/* closes the current path, making the first point and last point coincident */
1217
int
1218
hpgl_close_current_path(hpgl_state_t * pgls)
1219
108k
{
1220
108k
    gx_path *ppath = gx_current_path(pgls->pgs);
1221
1222
108k
    if (ppath->subpath_count) {
1223
74.5k
        gs_point pt;
1224
1225
74.5k
        hpgl_call(gs_closepath(pgls->pgs));
1226
74.5k
        hpgl_call(gs_currentpoint(pgls->pgs, &pt));
1227
74.5k
        hpgl_call(hpgl_set_current_position(pgls, &pt));
1228
74.5k
    }
1229
108k
    return 0;
1230
108k
}
1231
1232
/* converts pcl coordinate to device space and back to hpgl space */
1233
int
1234
hpgl_add_pcl_point_to_path(hpgl_state_t * pgls, const gs_point * pcl_pt)
1235
1.45k
{
1236
1.45k
    gs_point dev_pt, hpgl_pt;
1237
1238
1.45k
    hpgl_call(hpgl_clear_current_path(pgls));
1239
1.45k
    pcl_set_ctm(pgls, true);
1240
1.45k
    hpgl_call(gs_transform(pgls->pgs, pcl_pt->x, pcl_pt->y, &dev_pt));
1241
1.45k
    hpgl_call(hpgl_set_ctm(pgls));
1242
1.45k
    hpgl_call(gs_itransform(pgls->pgs, dev_pt.x, dev_pt.y, &hpgl_pt));
1243
1.45k
    hpgl_call(hpgl_add_point_to_path(pgls, hpgl_pt.x, hpgl_pt.y,
1244
1.45k
                                     hpgl_plot_move_absolute, true));
1245
1.45k
    return 0;
1246
1.45k
}
1247
1248
static double
1249
compute_chord_angle(double chord_angle)
1250
35.9k
{
1251
35.9k
    double ca = fmod(chord_angle, 360);
1252
1253
35.9k
    if (ca >= 0) {
1254
35.9k
        if (ca > 180)
1255
2
            ca = 360 - ca;
1256
35.9k
        if (ca < 5)
1257
60
            ca = 5;
1258
35.9k
    } else {                    /* negative ca */
1259
1260
0
        if (ca > -5)
1261
0
            ca = -5;
1262
0
    }
1263
35.9k
    return ca;
1264
35.9k
}
1265
1266
int
1267
hpgl_add_arc_to_path(hpgl_state_t * pgls, double center_x, double center_y,
1268
                     double radius, double start_angle, double sweep_angle,
1269
                     double chord_angle, bool start_moveto,
1270
                     hpgl_plot_function_t draw, bool set_ctm)
1271
35.9k
{
1272
35.9k
    double num_chordsf = sweep_angle / compute_chord_angle(chord_angle);
1273
35.9k
    int num_chords =
1274
35.9k
        (int)(num_chordsf >= 0.0 ? ceil(num_chordsf) : floor(num_chordsf));
1275
35.9k
    double integral_chord_angle = fabs(sweep_angle / num_chords);
1276
35.9k
    int i;
1277
35.9k
    double arccoord_x, arccoord_y;
1278
1279
35.9k
    if (hpgl_plot_is_draw(draw))
1280
35.9k
        pgls->g.have_drawn_in_path = true;
1281
1282
35.9k
    (void)hpgl_compute_arc_coords(radius, center_x, center_y,
1283
35.9k
                                  start_angle, &arccoord_x, &arccoord_y);
1284
1285
35.9k
    pgls->g.pos.x = arccoord_x;
1286
35.9k
    pgls->g.pos.y = arccoord_y;
1287
1288
35.9k
    if (start_moveto)
1289
35.9k
        pgls->g.subpolygon_started = true;
1290
1291
35.9k
    hpgl_call(hpgl_add_point_to_path(pgls, arccoord_x, arccoord_y,
1292
35.9k
                                     (draw && !start_moveto ?
1293
35.9k
                                      hpgl_plot_draw_absolute :
1294
35.9k
                                      hpgl_plot_move_absolute), set_ctm));
1295
1296
2.62M
    for (i = 0; i < abs(num_chords); i++) {
1297
2.58M
        if (sweep_angle > 0)
1298
2.58M
            start_angle += integral_chord_angle;
1299
0
        else
1300
0
            start_angle -= integral_chord_angle;
1301
2.58M
        hpgl_compute_arc_coords(radius, center_x, center_y,
1302
2.58M
                                start_angle, &arccoord_x, &arccoord_y);
1303
2.58M
        hpgl_call(hpgl_add_point_to_path(pgls, arccoord_x, arccoord_y,
1304
2.58M
                                         (draw ? hpgl_plot_draw_absolute :
1305
2.58M
                                          hpgl_plot_move_absolute), set_ctm));
1306
2.58M
    }
1307
    /* NB this is suspicious - why not any +- multiple of 360 if this
1308
       is correct at all. */
1309
35.9k
    if (sweep_angle - 360.0 > -0.0001)
1310
35.9k
        hpgl_call(hpgl_close_current_path(pgls));
1311
35.9k
    return 0;
1312
35.9k
}
1313
1314
/* add a 3 point arc to the path */
1315
int
1316
hpgl_add_arc_3point_to_path(hpgl_state_t * pgls, double start_x, double
1317
                            start_y, double inter_x, double inter_y,
1318
                            double end_x, double end_y, double chord_angle,
1319
                            hpgl_plot_function_t draw)
1320
9
{
1321
    /* handle unusual cases as per pcltrm */
1322
9
    if (hpgl_3_same_points(start_x, start_y, inter_x, inter_y, end_x, end_y)) {
1323
0
        hpgl_call(hpgl_add_point_to_path(pgls, start_x, start_y, draw, true));
1324
0
        return 0;
1325
0
    }
1326
9
    if (hpgl_3_no_intermediate(start_x, start_y,
1327
9
                               inter_x, inter_y, end_x, end_y)) {
1328
0
        hpgl_call(hpgl_add_point_to_path(pgls, start_x, start_y, draw, true));
1329
0
        hpgl_call(hpgl_add_point_to_path(pgls, end_x, end_y, draw, true));
1330
0
        return 0;
1331
0
    }
1332
9
    if (hpgl_3_same_endpoints(start_x, start_y,
1333
9
                              inter_x, y_inter, end_x, end_y)) {
1334
0
        hpgl_call(hpgl_add_arc_to_path(pgls, (start_x + inter_x) / 2.0,
1335
0
                                       (start_y + inter_y) / 2.0,
1336
0
                                       (hypot((inter_x - start_x),
1337
0
                                              (inter_y - start_y)) / 2.0),
1338
0
                                       0.0, 360.0, chord_angle, false,
1339
0
                                       draw, true));
1340
0
        return 0;
1341
0
    }
1342
1343
9
    if (hpgl_3_colinear_points
1344
9
        (start_x, start_y, inter_x, inter_y, end_x, end_y)) {
1345
0
        if (hpgl_3_intermediate_between
1346
0
            (start_x, start_y, inter_x, inter_y, end_x, end_y)) {
1347
0
            hpgl_call(hpgl_add_point_to_path
1348
0
                      (pgls, start_x, start_y, draw, true));
1349
0
            hpgl_call(hpgl_add_point_to_path(pgls, end_x, end_x, draw, true));
1350
0
        } else {
1351
0
            hpgl_call(hpgl_add_point_to_path
1352
0
                      (pgls, start_x, start_y, draw, true));
1353
0
            hpgl_call(hpgl_add_point_to_path
1354
0
                      (pgls, inter_x, inter_y, draw, true));
1355
0
            hpgl_call(hpgl_add_point_to_path(pgls, end_x, end_y, draw, true));
1356
0
        }
1357
0
        return 0;
1358
0
    }
1359
1360
    /* normal 3 point arc case */
1361
9
    {
1362
9
        hpgl_real_t center_x, center_y, radius;
1363
9
        hpgl_real_t start_angle, inter_angle, end_angle;
1364
9
        hpgl_real_t sweep_angle;
1365
1366
9
        hpgl_call(hpgl_compute_arc_center(start_x, start_y,
1367
9
                                          inter_x, inter_y,
1368
9
                                          end_x, end_y,
1369
9
                                          &center_x, &center_y));
1370
1371
9
        radius = hypot(start_x - center_x, start_y - center_y);
1372
9
        start_angle = radians_to_degrees *
1373
9
            hpgl_compute_angle(start_x - center_x, start_y - center_y);
1374
1375
9
        inter_angle = radians_to_degrees *
1376
9
            hpgl_compute_angle(inter_x - center_x, inter_y - center_y);
1377
1378
9
        end_angle = radians_to_degrees *
1379
9
            hpgl_compute_angle(end_x - center_x, end_y - center_y);
1380
9
        sweep_angle = end_angle - start_angle;
1381
1382
        /*
1383
         * Figure out which direction to draw the arc, depending on the
1384
         * relative position of start, inter, and end.  Case analysis
1385
         * shows that we should draw the arc counter-clockwise from S to
1386
         * E iff exactly 2 of S<I, I<E, and E<S are true, and clockwise
1387
         * if exactly 1 of these relations is true.  (These are the only
1388
         * possible cases if no 2 of the points coincide.)
1389
         */
1390
1391
9
        if ((start_angle < inter_angle) + (inter_angle < end_angle) +
1392
9
            (end_angle < start_angle) == 1) {
1393
0
            if (sweep_angle > 0)
1394
0
                sweep_angle -= 360;
1395
9
        } else {
1396
9
            if (sweep_angle < 0)
1397
0
                sweep_angle += 360;
1398
9
        }
1399
1400
9
        hpgl_call(hpgl_add_arc_to_path(pgls, center_x, center_y,
1401
9
                                       radius, start_angle, sweep_angle,
1402
9
                                       (sweep_angle < 0.0) ?
1403
9
                                       -chord_angle : chord_angle, false,
1404
9
                                       draw, true));
1405
9
        return 0;
1406
9
    }
1407
9
}
1408
1409
/* Bezier's are handled a bit differently than arcs as we use the
1410
   gs_curveto() operator directly in lieue of flattening and using
1411
   gs_moveto() and gs_lineto(). */
1412
1413
int
1414
hpgl_add_bezier_to_path(hpgl_state_t * pgls, double x1, double y1,
1415
                        double x2, double y2, double x3, double y3,
1416
                        double x4, double y4, hpgl_plot_function_t draw)
1417
0
{
1418
0
    gx_path *ppath = gx_current_path(pgls->pgs);
1419
1420
    /* Don't add superflous points in polygon mode */
1421
0
    if ((!pgls->g.polygon_mode) || (!ppath->current_subpath))
1422
0
        hpgl_call(hpgl_add_point_to_path(pgls, x1, y1,
1423
0
                                         draw ?
1424
0
                                         hpgl_plot_draw_absolute :
1425
0
                                         hpgl_plot_move_absolute, true));
1426
0
    if (draw)
1427
0
        hpgl_call(gs_curveto(pgls->pgs, x2, y2, x3, y3, x4, y4));
1428
    /* update hpgl's state position to last point of the curve. */
1429
0
    {
1430
0
        gs_point point;
1431
1432
0
        point.x = x4;
1433
0
        point.y = y4;
1434
0
        hpgl_call(hpgl_set_current_position(pgls, &point));
1435
0
    }
1436
0
    return 0;
1437
0
}
1438
1439
/*
1440
 * an implicit gl/2 style closepath.  If the first and last point are
1441
 * the same the path gets closed. HAS - eliminate CSE gx_current_path
1442
 */
1443
int
1444
hpgl_close_path(hpgl_state_t * pgls)
1445
2.76M
{
1446
2.76M
    gs_fixed_point first, current;
1447
2.76M
    gx_path *ppath = gx_current_path(pgls->pgs);
1448
1449
2.76M
    if (!ppath->current_subpath)
1450
178k
        return 0;
1451
1452
    /* if we do not have a subpath there is nothing to do, get the
1453
       first points of the path in device space and convert to floats */
1454
2.58M
    if (gx_path_subpath_start_point(ppath, &first) < 0)
1455
0
        return 0;
1456
1457
2.58M
    if (gx_path_current_point(ppath, &current) < 0)
1458
0
        return 0;
1459
1460
2.58M
    if (first.x == current.x && first.y == current.y)
1461
2.58M
        hpgl_call(gs_closepath(pgls->pgs));
1462
1463
2.58M
    return 0;
1464
2.58M
}
1465
1466
/* To implement centered we move the points in the path to a pixel boundary.
1467
   Note this routine is sensitive to the orientation of the device.
1468
   Since rounding 0.5 is used here and 0.5 fill adjust this can fail to reduce and
1469
   object in size by 1 pixel left/bottom for some user scale factors.  This is not a
1470
   grave concern as the objects will still seam together. */
1471
1472
static int
1473
hpgl_set_special_pixel_placement(hpgl_state_t * pgls,
1474
                                 hpgl_rendering_mode_t render_mode)
1475
34.2k
{
1476
34.2k
    if (pgls->pp_mode == 1) {
1477
0
        gs_matrix default_matrix;
1478
0
        gs_point distance, adjust;
1479
0
        gx_path *ppath = gx_current_path(pgls->pgs);
1480
1481
        /* arbitrary just need the signs after transformation to
1482
           device space */
1483
0
        gs_setfilladjust(pgls->pgs, 0, 0);
1484
0
        adjust.x = -1;
1485
0
        adjust.y = -1;
1486
        /* determine the adjustment in device space */
1487
0
        hpgl_call(gs_defaultmatrix(pgls->pgs, &default_matrix));
1488
0
        hpgl_call(gs_distance_transform
1489
0
                  (adjust.x, adjust.y, &default_matrix, &distance));
1490
        /* modify the path but first it should be "unshared" so the
1491
           translation (next statement) does not update the polygon
1492
           buffer */
1493
0
        hpgl_call(gx_path_unshare(ppath));
1494
1495
        /* translate all points in the path by the adjustment.  */
1496
0
        hpgl_call(gx_path_translate(ppath,
1497
0
                                    float2fixed(distance.x /
1498
0
                                                fabs(distance.x)),
1499
0
                                    float2fixed(distance.y /
1500
0
                                                fabs(distance.y))));
1501
0
    }
1502
34.2k
    return 0;
1503
34.2k
}
1504
1505
/*
1506
 * Draw (stroke or fill) the current path.
1507
 */
1508
int
1509
hpgl_draw_current_path(hpgl_state_t * pgls, hpgl_rendering_mode_t render_mode)
1510
3.36M
{
1511
3.36M
    gs_gstate *pgs = pgls->pgs;
1512
3.36M
    pcl_pattern_set_proc_t set_proc;
1513
3.36M
    int code = 0;
1514
3.36M
    gx_path *ppath = gx_current_path(pgls->pgs);
1515
1516
    /* check if we have a current path - we don't need the current
1517
       point */
1518
3.36M
    if ((ppath->segments != NULL) && (!ppath->current_subpath)) {
1519
        /* NB this clear shouldn't be necessary. */
1520
782k
        hpgl_call(hpgl_clear_current_path(pgls));
1521
782k
        return 0;
1522
782k
    }
1523
1524
2.58M
    if (render_mode == hpgl_rm_vector_no_close)
1525
30
        render_mode = hpgl_rm_vector;
1526
2.58M
    else
1527
2.58M
        hpgl_call(hpgl_close_path(pgls));
1528
1529
2.58M
    hpgl_call(hpgl_set_drawing_state(pgls, render_mode));
1530
1531
2.58M
    switch (render_mode) {
1532
209k
        case hpgl_rm_character:
1533
209k
            {
1534
                /* HAS need to set attributes in set_drawing color (next 2) */
1535
1536
                /* Intellifonts require eofill, but TrueType require fill. */
1537
            /****** HACK: look at the scaling technology of ******/
1538
            /****** the current font to decide. ******/
1539
209k
                int (*fill) (gs_gstate *);
1540
1541
209k
                if (pgls->g.font->scaling_technology == plfst_Intellifont)
1542
0
                    fill = gs_eofill;
1543
209k
                else
1544
209k
                    fill = gs_fill;
1545
1546
209k
                switch (pgls->g.character.fill_mode) {
1547
1548
208k
                    case hpgl_char_solid_edge:
1549
208k
                        set_proc =
1550
208k
                            pcl_pattern_get_proc_FT
1551
208k
                            (hpgl_FT_pattern_solid_pen1);
1552
208k
                        if ((code =
1553
208k
                             set_proc(pgls, hpgl_get_selected_pen(pgls),
1554
208k
                                      false)) < 0)
1555
0
                            return code;
1556
208k
                        hpgl_call((*fill) (pgs));
1557
                        /* falls through */
1558
1559
208k
                    case hpgl_char_edge:
1560
208k
                        if (pgls->g.bitmap_fonts_allowed)
1561
0
                            break;      /* no edging */
1562
208k
                        set_proc =
1563
208k
                            pcl_pattern_get_proc_FT
1564
208k
                            (hpgl_FT_pattern_solid_pen1);
1565
208k
                        if ((code =
1566
208k
                             set_proc(pgls, hpgl_get_character_edge_pen(pgls),
1567
208k
                                      false)) < 0)
1568
0
                            return code;
1569
208k
                        if (hpgl_is_currentfont_stick_or_arc(pgls)) {
1570
207k
                            hpgl_call((*fill) (pgs));
1571
207k
                            break;
1572
207k
                        }
1573
1574
1.79k
                        hpgl_call(hpgl_set_plu_ctm(pgls));
1575
1.79k
                        {
1576
1.79k
                            gs_point scale = hpgl_current_char_scale(pgls);
1577
1578
                            /* NB fix and comment */
1579
1.79k
                            hpgl_call(gs_setlinewidth
1580
1.79k
                                      (pgls->pgs,
1581
1.79k
                                       min(scale.x,
1582
1.79k
                                           scale.y) * 0.0375 * 0.2835));
1583
1.79k
                        }
1584
1.79k
                        hpgl_call(pcl_mark_page_for_path(pgls));
1585
1.79k
                        hpgl_call(gs_stroke(pgls->pgs));
1586
1.79k
                        break;
1587
1588
1.79k
                    case hpgl_char_fill:
1589
                        /* the fill has already been done if the fill type is
1590
                           hpgl/2 vector fills.  This was handled when we set
1591
                           the drawing color */
1592
0
                        if ((pgls->g.fill.type != hpgl_FT_pattern_one_line) &&
1593
0
                            (pgls->g.fill.type != hpgl_FT_pattern_two_lines))
1594
0
                            hpgl_call((*fill) (pgs));
1595
0
                        else
1596
0
                            hpgl_call(hpgl_clear_current_path(pgls));
1597
0
                        break;
1598
902
                    case hpgl_char_fill_edge:
1599
                        /* the fill has already been done if the fill type is
1600
                           hpgl/2 vector fills.  This was handled when we set
1601
                           the drawing color.  gsave to preserve the path for
1602
                           subsequent edging */
1603
902
                        if ((pgls->g.fill.type != hpgl_FT_pattern_one_line) &&
1604
902
                            (pgls->g.fill.type !=
1605
902
                             hpgl_FT_pattern_two_lines)) {
1606
902
                            int code2 = 0;
1607
902
                            hpgl_call(hpgl_gsave(pgls));
1608
                            /* all character fills appear to have 0 fill adjustment */
1609
902
                            gs_setfilladjust(pgls->pgs, 0, 0);
1610
                            /* Always restore before handling any error. */
1611
902
                            code = (*fill) (pgs);
1612
902
                            code2 = hpgl_grestore(pgls);
1613
902
                            if (code >=0 && code2 < 0) {
1614
0
                                code = code2;
1615
0
                            }
1616
902
                            hpgl_call(code);
1617
902
                        }
1618
902
                        if ((pgls->g.bitmap_fonts_allowed) || (hpgl_is_currentfont_stick_or_arc(pgls))) /* no edging */
1619
902
                            hpgl_call(hpgl_clear_current_path(pgls));
1620
0
                        else {
1621
0
                            set_proc =
1622
0
                                pcl_pattern_get_proc_FT
1623
0
                                (hpgl_FT_pattern_solid_pen1);
1624
0
                            if ((code =
1625
0
                                 set_proc(pgls,
1626
0
                                          hpgl_get_character_edge_pen(pgls),
1627
0
                                          false)) < 0)
1628
0
                                return code;
1629
0
                            hpgl_call(hpgl_set_plu_ctm(pgls));
1630
                            /* use the default raster operation for the edge.  It
1631
                               is automaticall restored next drawing operation */
1632
0
                            hpgl_call(gs_setrasterop
1633
0
                                      (pgls->pgs, (gs_rop3_t) 252));
1634
0
                            hpgl_call(gs_setlinewidth
1635
0
                                      (pgls->pgs,
1636
0
                                       pgls->g.font_selection[pgls->g.
1637
0
                                                              font_selected].
1638
0
                                       params.height_4ths * 0.0375));
1639
0
                            hpgl_call(gs_stroke(pgls->pgs));
1640
0
                        }
1641
902
                        break;
1642
1643
209k
                }
1644
209k
                break;
1645
209k
            }
1646
209k
            break;
1647
209k
        case hpgl_rm_polygon:
1648
34.2k
            hpgl_set_special_pixel_placement(pgls, hpgl_rm_polygon);
1649
34.2k
            if ((code = pcl_mark_page_for_path(pgls)) < 0)
1650
0
                return code;
1651
34.2k
            if (pgls->g.fill_type == hpgl_even_odd_rule)
1652
34.2k
                hpgl_call(gs_eofill(pgs));
1653
1
            else                /* hpgl_winding_number_rule */
1654
34.2k
                hpgl_call(gs_fill(pgs));
1655
34.2k
            break;
1656
1657
34.2k
        case hpgl_rm_clip_and_fill_polygon:
1658
            /*
1659
             * A bizarre HPISM - If the pen is white we do a solid
1660
             * white fill this is true for *all* fill types (arg!) as
1661
             * tested on the 6mp.  If pen 1 (black)
1662
             * hpgl_set_drawing_color() handles this case by drawing
1663
             * the lines that comprise the vector fill
1664
             */
1665
294
            if (hpgl_get_selected_pen(pgls) == 0) {
1666
5
                hpgl_call(pcl_mark_page_for_path(pgls));
1667
5
                hpgl_call(gs_fill(pgls->pgs));
1668
5
            }
1669
294
            hpgl_call(hpgl_clear_current_path(pgls));
1670
294
            break;
1671
1672
72.7k
        case hpgl_rm_vector:
1673
2.33M
        case hpgl_rm_vector_fill:
1674
            /*
1675
             * we reset the ctm before stroking to preserve the line width
1676
             * information, then restore the ctm.
1677
             */
1678
2.33M
            {
1679
2.33M
                gs_matrix save_ctm;
1680
2.33M
                int save_scaling_type = pgls->g.scaling_type;
1681
1682
2.33M
                hpgl_call(gs_currentmatrix(pgs, &save_ctm));
1683
1684
                /* force no picture frame scaling */
1685
2.33M
                pgls->g.scaling_type = hpgl_scaling_point_factor;
1686
2.33M
                hpgl_call(hpgl_set_plu_ctm(pgls));
1687
2.33M
                pgls->g.scaling_type = save_scaling_type;
1688
1689
                /* NB: what does reversing the path do? Currently DEAD code see pglfill.c */
1690
2.33M
                if (!pgls->g.line.current.is_solid
1691
49
                    && (pgls->g.line.current.type == 0))
1692
2.33M
                    hpgl_call(gs_reversepath(pgls->pgs));
1693
2.33M
                hpgl_call(pcl_mark_page_for_path(pgls));
1694
2.33M
                hpgl_call(gs_stroke(pgls->pgs));
1695
2.33M
                gs_setmatrix(pgs, &save_ctm);
1696
2.33M
                break;
1697
2.33M
            }
1698
0
        default:
1699
0
            dmprintf(pgls->memory, "unknown render mode\n");
1700
2.58M
    }
1701
1702
2.58M
    return 0;
1703
2.58M
}
1704
1705
int
1706
hpgl_copy_current_path_to_polygon_buffer(hpgl_state_t * pgls)
1707
139k
{
1708
139k
    gx_path *ppath = gx_current_path(pgls->pgs);
1709
1710
139k
    gx_path_assign_preserve(&pgls->g.polygon.buffer.path, ppath);
1711
139k
    return 0;
1712
139k
}
1713
1714
int
1715
hpgl_copy_polygon_buffer_to_current_path(hpgl_state_t * pgls)
1716
46.0k
{
1717
46.0k
    gx_path *ppath = gx_current_path(pgls->pgs);
1718
1719
46.0k
    gx_path_assign_preserve(ppath, &pgls->g.polygon.buffer.path);
1720
46.0k
    return 0;
1721
46.0k
}