Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/contrib/pcl3/eprn/gdeveprn.c
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
  File:     $Id: gdeveprn.c,v 1.25 2001/04/30 05:15:51 Martin Rel $
3
  Contents: Implementation of the abstract ghostscript device 'eprn':
4
            general functions and page layout
5
  Author:   Martin Lottermoser, Greifswaldstrasse 28, 38124 Braunschweig,
6
            Germany. E-mail: Martin.Lottermoser@t-online.de.
7
8
*******************************************************************************
9
*                                                                             *
10
*       Copyright (C) 2000, 2001 by Martin Lottermoser                        *
11
*       All rights reserved                                                   *
12
*                                                                             *
13
*******************************************************************************
14
15
  Preprocessor variables:
16
17
    EPRN_NO_PAGECOUNTFILE
18
        Define this if you do not want to use eprn's pagecount-file feature.
19
        You very likely must define this on Microsoft Windows.
20
21
    EPRN_TRACE
22
        Define this to enable tracing. Only useful for development.
23
24
    EPRN_USE_GSTATE (integer)
25
        Define this to be non-zero if the graphics state should be accessed
26
        directly instead of via the interpreter context state. Newer ghostscript
27
        versions require the latter path. The default is zero unless
28
        GS_REVISION is defined and less than 600.
29
30
    GS_REVISION (integer)
31
        If defined, this must be the ghostscript version number, e.g., 601 for
32
        ghostscript 6.01.
33
34
******************************************************************************/
35
36
/*****************************************************************************/
37
38
#ifndef _XOPEN_SOURCE
39
#define _XOPEN_SOURCE   500
40
#endif
41
42
/* Preprocessor symbol with version-dependent default */
43
#ifndef EPRN_USE_GSTATE
44
#if !defined(GS_REVISION) || GS_REVISION >= 600
45
#define EPRN_USE_GSTATE 0
46
#else
47
#define EPRN_USE_GSTATE 1
48
#endif
49
#endif  /* !EPRN_USE_GSTATE */
50
51
/*****************************************************************************/
52
53
/* Special Aladdin header, must be included before <sys/types.h> on some
54
   platforms (e.g., FreeBSD). */
55
#include "std.h"
56
57
/* Standard headers */
58
#include <assert.h>
59
#include <math.h>
60
#include <string.h>
61
#include <stdio.h>
62
#include <stdlib.h>
63
#ifdef EPRN_TRACE
64
#include <time.h>
65
#endif  /* EPRN_TRACE */
66
67
/*  Ghostscript headers. With the exception of gdebug.h, these files are only
68
    needed to compile eprn_forget_defaultmatrix() which needs the prototypes
69
    for gs_setdefaultmatrix() (in gscoord.h) and gs_main_instance_default()
70
    (in imain.h). Unfortunately and in disregard of good SE practice,
71
    ghostscript's header files are not self-contained. Therefore, if this file
72
    does not compile because of undefined symbols, just add include directives
73
    until it does.  */
74
#include "gserrors.h"
75
#include "iref.h"       /* needed by icstate.h */
76
#include "gsmemraw.h"   /* needed by icstate.h */
77
#include "gsmemory.h"   /* needed by icstate.h */
78
#include "gstypes.h"    /* needed by gsstate.h */
79
#include "gsstate.h"    /* needed by icstate.h */
80
#include "icstate.h"    /* for struct gs_context_state_s */
81
#if !defined(GS_REVISION) || GS_REVISION >= 700
82
#include "iapi.h"       /* needed by iminst.h */
83
#endif  /* GS_REVISION */
84
#include "iminst.h"     /* for struct gs_main_instance_s */
85
#include "imain.h"      /* for gs_main_instance_default() */
86
#include "gscoord.h"    /* for gs_setdefaultmatrix() */
87
#if EPRN_USE_GSTATE
88
#include "igstate.h"
89
#endif  /* EPRN_USE_GSTATE */
90
#ifdef EPRN_TRACE
91
#include "gdebug.h"
92
#endif  /* EPRN_TRACE */
93
#include "gxstdio.h"
94
95
/* Special headers for this device */
96
#ifndef EPRN_NO_PAGECOUNTFILE
97
#include "pagecount.h"
98
#endif  /* EPRN_NO_PAGECOUNTFILE */
99
#include "gdeveprn.h"
100
101
/*****************************************************************************/
102
103
/* Prefix for error messages */
104
#define ERRPREF "? eprn: "
105
106
107
/******************************************************************************
108
109
  Function: eprn_get_initial_matrix
110
111
  This function returns the initial matrix for the device.
112
113
  The result is based on the following parameters:
114
  - eprn: default_orientation, down_shift, right_shift, soft_tumble
115
  - HWResolution, MediaSize, ShowpageCount
116
117
******************************************************************************/
118
119
void eprn_get_initial_matrix(gx_device *device, gs_matrix *mptr)
120
0
{
121
0
  eprn_Device *dev = (eprn_Device *)device;
122
0
  float
123
    /*  The following two arrays are oriented w.r.t. pixmap device space, i.e.,
124
        the index 0 refers to the x coordinate (horizontal) and the index 1 to
125
        the y coordinate (vertical) in pixmap device space. */
126
0
    extension[2],       /* media extension in pixels */
127
0
    pixels_per_bp[2];   /* resolution */
128
0
  int
129
0
    j,
130
0
    quarters;
131
132
#ifdef EPRN_TRACE
133
  if_debug0(EPRN_TRACE_CHAR, "! eprn_get_initial_matrix()...\n");
134
#endif
135
136
  /* We need 'default_orientation' and also the margins. */
137
0
  if (dev->eprn.code == ms_none) {
138
#ifdef EPRN_TRACE
139
    if_debug0(EPRN_TRACE_CHAR,
140
      "! eprn_get_initial_matrix(): code is still ms_none.\n");
141
#endif
142
0
    if (eprn_set_page_layout(dev) != 0)
143
0
      eprintf("  Processing can't be stopped at this point although this error "
144
0
        "occurred.\n");
145
      /* The current function has a signature without the ability to signal
146
         an error condition. */
147
0
  }
148
149
0
  quarters = dev->eprn.default_orientation +
150
0
    (dev->MediaSize[0] <= dev->MediaSize[1]? 0: 1);
151
     /* Number of quarter-circle rotations by +90 degrees necessary to obtain
152
        default user space starting with the y axis upwards in pixmap device
153
        space.
154
        It's not documented, but 'MediaSize' is the requested "PageSize" page
155
        device parameter value and hence is to be interpreted in default (not
156
        default default!) user space. The condition above therefore tests
157
        whether landscape orientation has been requested.
158
      */
159
160
  /* Soft tumble option: rotate default user space by 180 degrees on every
161
     second page */
162
0
  if (dev->eprn.soft_tumble && dev->ShowpageCount % 2 != 0) quarters += 2;
163
164
  /* Prepare auxiliary data */
165
0
  for (j = 0; j < 2; j++) pixels_per_bp[j] = dev->HWResolution[j]/BP_PER_IN;
166
  /*  'HWResolution[]' contains the standard PostScript page device parameter
167
      'HWResolution' which is defined in pixels per inch with respect to
168
       device space. */
169
0
  if (quarters % 2 == 0) {
170
    /* Default user space and pixmap device space agree in what is "horizontal"
171
       and what is "vertical". */
172
0
    extension[0] = dev->MediaSize[0];
173
0
    extension[1] = dev->MediaSize[1];
174
0
  }
175
0
  else {
176
0
    extension[0] = dev->MediaSize[1];
177
0
    extension[1] = dev->MediaSize[0];
178
0
  }
179
  /* Convert from bp to pixels: */
180
0
  for (j = 0; j < 2; j++) extension[j] *= pixels_per_bp[j];
181
   /* Note that we are using the user-specified extension of the sheet, not the
182
      "official" one we could obtain in most cases from 'size'. */
183
184
0
  switch (quarters % 4) {
185
0
  case 0:
186
    /*  The y axis of default user space points upwards in pixmap device space.
187
        The CTM is uniquely characterized by the following mappings from
188
        default user space to pixmap device space:
189
          (0, 0)                -> (0, height in pixels)
190
          (width in bp, 0)      -> (width in pixels, height in pixels)
191
          (0, height in bp)     -> (0, 0)
192
        'width' and 'height' refer to the sheet's extension as seen from pixmap
193
        device space, i.e., width in pixels == extension[0] and
194
        height in pixels == extension[1].
195
196
        From the PLR we find that the CTM is a PostScript matrix
197
        [a b c d tx ty] used for mapping user space coordinates (x, y) to
198
        device space coordinates (x', y') as follows:
199
          x' = a*x + c*y + tx
200
          y' = b*x + d*y + ty
201
        Ghostscript's matrix type 'gs_matrix' writes its structure components
202
        'xx' etc. in storage layout order into a PostScript matrix (see
203
        write_matrix() in iutil.c), hence we obtain by comparison with
204
        gsmatrix.h the PostScript matrix [ xx xy yx yy tx ty ].
205
        The correspondence can also be seen by comparison of the equations
206
        above with the code in gs_point_transform() in gsmatrix.c.
207
        It would, however, still be reassuring to have a corresponding
208
        statement in ghostscript's documentation.
209
    */
210
0
    gx_default_get_initial_matrix(device, mptr);
211
    /*  Of course, I could also set this directly:
212
          mptr->xx = pixels_per_bp[0];
213
          mptr->xy = 0;
214
          mptr->yx = 0;
215
          mptr->yy = -pixels_per_bp[1];
216
          mptr->tx = 0;
217
          mptr->ty = extension[1];
218
        Doing it in this way is, however, more stable against dramatic changes
219
        in ghostscript.
220
    */
221
0
    break;
222
0
  case 1:
223
    /*  The y axis of default user space points to the left in pixmap device
224
        space. The CTM is uniquely characterized by the following mappings from
225
        default user space to pixmap device space:
226
          (0, 0)                -> (width in pixels, height in pixels)
227
          (height in bp, 0)     -> (width in pixels, 0)
228
          (0, width in bp)      -> (0, height in pixels)
229
    */
230
0
    mptr->xx = 0;
231
0
    mptr->xy = -pixels_per_bp[1];
232
0
    mptr->yx = -pixels_per_bp[0];
233
0
    mptr->yy = 0;
234
0
    mptr->tx = extension[0];
235
0
    mptr->ty = extension[1];
236
0
    break;
237
0
  case 2:
238
    /*  The y axis of default user space points downwards in pixmap device
239
        space. The CTM is uniquely characterized by the following mappings from
240
        default user space to pixmap device space:
241
          (0, 0)                -> (width in pixels, 0)
242
          (width in bp, 0)      -> (0, 0)
243
          (0, height in bp)     -> (width in pixels, height in pixels)
244
    */
245
0
    mptr->xx = -pixels_per_bp[0];
246
0
    mptr->xy = 0;
247
0
    mptr->yx = 0;
248
0
    mptr->yy = pixels_per_bp[1];
249
0
    mptr->tx = extension[0];
250
0
    mptr->ty = 0;
251
0
    break;
252
0
  case 3:
253
    /*  The y axis of default user space points to the right in pixmap device
254
        space. The CTM is uniquely characterized by the following mappings from
255
        default user space to pixmap device space:
256
          (0, 0)                -> (0, 0)
257
          (height in bp, 0)     -> (0, height in pixels)
258
          (0, width in bp)      -> (width in pixels, 0)
259
    */
260
0
    mptr->xx = 0;
261
0
    mptr->xy = pixels_per_bp[1];
262
0
    mptr->yx = pixels_per_bp[0];
263
0
    mptr->yy = 0;
264
0
    mptr->tx = 0;
265
0
    mptr->ty = 0;
266
0
    break;
267
0
  }
268
269
  /*  Finally, shift the device space origin to the top-left corner of the
270
      printable area. I am deliberately not using the corresponding shift
271
      feature in gx_device_set_margins() because it achieves its effect by
272
      using the 'Margins' array which should remain at the user's disposal for
273
      correcting misadjustments. In addition, gx_device_set_margins() will not
274
      work correctly for quarters % 4 != 0 anyway.
275
  */
276
0
  {
277
0
    gs_matrix translation;
278
279
    /*  Translation of pixmap device space origin by top and left margins in
280
        pixmap device space */
281
0
    gs_make_translation(
282
0
      -dev->eprn.right_shift*pixels_per_bp[0],
283
0
      -dev->eprn.down_shift *pixels_per_bp[1],
284
0
      &translation);
285
286
    /* Multiply the initial matrix from the right with the translation matrix,
287
       i.e., in going from user to device space the translation will be applied
288
       last. */
289
0
    gs_matrix_multiply(mptr, &translation, mptr);
290
0
  }
291
292
#ifdef EPRN_TRACE
293
  if_debug6(EPRN_TRACE_CHAR, "  Returning [%g %g %g %g %g %g].\n",
294
    mptr->xx, mptr->xy, mptr->yx, mptr->yy, mptr->tx, mptr->ty);
295
#endif
296
0
  return;
297
0
}
298
299
/******************************************************************************
300
301
  Function: print_flags
302
303
  Print a textual description of 'flags' to the error stream.
304
305
******************************************************************************/
306
307
static void print_flags(ms_MediaCode flags, const ms_Flag *user_flags)
308
0
{
309
  /* Non-standard flags first */
310
0
  if (user_flags != NULL) {
311
0
    while (user_flags->code != ms_none) {
312
0
      if (user_flags->code & flags) {
313
0
        eprintf1("%s", user_flags->name);
314
0
        flags &= ~user_flags->code;
315
0
      }
316
0
      user_flags++;
317
0
    }
318
0
  }
319
320
  /* Standard substrings */
321
0
  if (flags & MS_SMALL_FLAG) eprintf(MS_SMALL_STRING);
322
0
  if (flags & MS_BIG_FLAG  ) eprintf(MS_BIG_STRING);
323
0
  if (flags & MS_EXTRA_FLAG) eprintf(MS_EXTRA_STRING);
324
0
  flags &= ~(MS_SMALL_FLAG | MS_BIG_FLAG | MS_EXTRA_FLAG);
325
326
  /* Completeness check */
327
0
  if (flags & ~MS_TRANSVERSE_FLAG)
328
0
    eprintf1("0x%04X", (unsigned int)(flags & ~MS_TRANSVERSE_FLAG));
329
330
  /* Standard qualifier */
331
0
  if (flags & MS_TRANSVERSE_FLAG) eprintf("." MS_TRANSVERSE_STRING);
332
333
0
  return;
334
0
}
335
336
/******************************************************************************
337
338
  Function: eprn_flag_mismatch
339
340
  This routine is called if the media size can be supported for some
341
  combination of flags but not for that combination which has been requested.
342
  The parameter 'no_match' indicates whether these flags are supported at all
343
  for any of the supported sizes or not.
344
345
  If the derived device has set a flag mismatch error reporting function, the
346
  call will be passed to that function. Otherwise a general error message is
347
  written through the graphics library's eprintf().
348
349
******************************************************************************/
350
351
static void eprn_flag_mismatch(const struct s_eprn_Device *eprn,
352
  bool no_match)
353
0
{
354
0
  if (eprn->fmr != NULL) (*eprn->fmr)(eprn, no_match);
355
0
  else {
356
0
    const char *epref = eprn->CUPS_messages? CUPS_ERRPREF: "";
357
358
0
    eprintf2("%s" ERRPREF "The %s does not support ",
359
0
      epref, eprn->cap->name);
360
0
    if (eprn->desired_flags == 0) eprintf("an empty set of media flags");
361
0
    else {
362
0
      eprintf("the \"");
363
0
      print_flags(eprn->desired_flags, eprn->flag_desc);
364
0
      eprintf("\" flag(s)");
365
0
    }
366
0
    eprintf1("\n%s  (ignoring presence or absence of \"", epref);
367
0
    {
368
0
      ms_MediaCode optional = MS_TRANSVERSE_FLAG;
369
0
      if (eprn->optional_flags != NULL) {
370
0
        const ms_MediaCode *of = eprn->optional_flags;
371
0
        while (*of != ms_none) optional |= *of++;
372
0
      }
373
0
      print_flags(optional, eprn->flag_desc);
374
0
    }
375
0
    eprintf("\") for ");
376
0
    if (no_match) eprintf("any"); else eprintf("this");
377
0
    eprintf(" page size.\n");
378
0
  }
379
380
0
  return;
381
0
}
382
383
/******************************************************************************
384
385
  Function: better_flag_match
386
387
  This function returns true iff the flags in 'new_code' match the requested
388
  flags (strictly) better than those in 'old_code'.
389
390
******************************************************************************/
391
392
static bool better_flag_match(ms_MediaCode desired,
393
  const ms_MediaCode *optional, ms_MediaCode old_code, ms_MediaCode new_code)
394
0
{
395
0
  ms_MediaCode
396
0
    old_diff,   /* difference between old flags and desired flags */
397
0
    new_diff;   /* difference between new flags and desired flags */
398
399
  /* Ignore the size information */
400
0
  old_code = ms_flags(old_code);
401
0
  new_code = ms_flags(new_code);
402
403
  /* Determine differences to desired flags */
404
0
  old_diff = old_code ^ desired;
405
0
  new_diff = new_code ^ desired;
406
407
  /* Check for exact matches */
408
0
  if (old_diff == 0) return false;
409
0
  if (new_diff == 0) return true;
410
411
  /* Is the difference at most MS_TRANSVERSE_FLAG? */
412
0
  old_diff = old_diff & ~MS_TRANSVERSE_FLAG;
413
0
  new_diff = new_diff & ~MS_TRANSVERSE_FLAG;
414
0
  if (old_diff == 0) return false;
415
0
  if (new_diff == 0) return true;
416
417
  /* Loop over the remaining optional flags */
418
0
  if (optional != NULL) {
419
0
    const ms_MediaCode *opt = optional;
420
421
0
    while (*opt != ms_none) {
422
0
      old_diff = old_diff & ~*opt;
423
0
      new_diff = new_diff & ~*opt;
424
0
      if (old_diff == 0) {
425
0
        if (new_diff != 0) return false;
426
        /* At this point both are matches at the same level of optional flags.
427
           Now look for the last preceding flag in which they differ. */
428
0
        {
429
0
          ms_MediaCode diff = ms_flags(old_code ^ new_code);
430
0
          while (optional < opt && (diff & *opt) == 0) opt--;
431
0
          if ((diff & *opt) == 0) {
432
0
            if ((diff & MS_TRANSVERSE_FLAG) == 0) return false;
433
            /* old and new differ in MS_TRANSVERSE_FLAG */
434
0
            return (new_code & MS_TRANSVERSE_FLAG) ==
435
0
              (desired & MS_TRANSVERSE_FLAG);
436
0
          }
437
0
          return (new_code & *opt) == (desired & *opt);
438
0
        }
439
0
      }
440
0
      if (new_diff == 0) return true;
441
0
      opt++;
442
0
    }
443
0
  }
444
445
0
  return false; /* Both codes are mismatches at this point */
446
0
}
447
448
/******************************************************************************
449
450
  Function: flag_match
451
452
  This function returns true iff 'code' is an acceptable match for the flag
453
  request.
454
455
******************************************************************************/
456
457
static bool flag_match(ms_MediaCode desired,
458
  const ms_MediaCode *optional, ms_MediaCode code)
459
0
{
460
0
  code = (ms_flags(code) ^ desired) & ~MS_TRANSVERSE_FLAG;
461
0
  if (code == 0) return true;
462
463
0
  if (optional == NULL) return false;
464
465
0
  while (*optional != ms_none && code != 0) {
466
0
    code = code & ~*optional;
467
0
    optional++;
468
0
  }
469
470
0
  return code == 0;
471
0
}
472
473
/******************************************************************************
474
475
  Function: eprn_set_page_layout
476
477
  This function determines media size, sheet orientation in pixmap device space,
478
  the orientation of default user space, and the imageable area. It should be
479
  called whenever the page device parameters "PageSize" and "LeadingEdge",
480
  the media flags, or the page descriptions have been changed.
481
482
  The function returns zero on success and a non-zero value otherwise.
483
  In the latter case, an error message has been issued. This can only
484
  occur if the media size is not supported with the flags requested.
485
486
  On success, the following variables in the device structure are consistent:
487
  width, height, MediaSize[], HWMargins[], eprn.code, eprn.default_orientation,
488
  eprn.right_shift, eprn.down_shift.
489
490
******************************************************************************/
491
492
int eprn_set_page_layout(eprn_Device *dev)
493
0
{
494
0
  bool
495
0
    no_match = true,
496
     /* Are the requested flags supported for some size? */
497
0
    landscape = dev->MediaSize[0] > dev->MediaSize[1];
498
     /* It's not documented, but 'MediaSize' is the requested "PageSize" page
499
        device parameter value and hence is to be interpreted in default (not
500
        default default!) user space. */
501
0
  const char *epref = dev->eprn.CUPS_messages? CUPS_ERRPREF: "";
502
0
  const eprn_CustomPageDescription
503
0
    *best_cmatch = NULL;        /* best custom page size match */
504
0
  eprn_Eprn
505
0
    *eprn = &dev->eprn;
506
0
  const eprn_PageDescription
507
0
    *best_cdmatch = NULL,     /* best custom page size match in discrete list*/
508
0
    *best_dmatch = NULL,        /* best discrete match */
509
0
    *pd;                        /* loop variable */
510
0
  float
511
    /* Page width and height in bp with w <= h (in a moment): */
512
0
    w = dev->MediaSize[0],
513
0
    h = dev->MediaSize[1],
514
    /* pixmap device space margins in bp (canonical order): */
515
0
    margins[4];
516
0
  int
517
0
    quarters;
518
0
  ms_MediaCode
519
0
    desired = eprn->desired_flags;
520
521
#ifdef EPRN_TRACE
522
  if_debug3(EPRN_TRACE_CHAR,
523
    "! eprn_set_page_layout(): PageSize = [%.0f %.0f], "
524
      "desired_flags = 0x%04X.\n",
525
    dev->MediaSize[0], dev->MediaSize[1], (unsigned int)desired);
526
#endif
527
528
  /* Ensure w <= h */
529
0
  if (w > h) {
530
0
    float temp;
531
0
    temp = w; w = h; h = temp;
532
    /* This has effectively split 'MediaSize[]' into 'w', 'h' and 'landscape'.
533
     */
534
0
  }
535
536
  /* Initialization of primary return value */
537
0
  eprn->code = ms_none;
538
539
  /* Put the LeadingEdge value into the desired flag pattern if it's set */
540
0
  if (eprn->leading_edge_set) {
541
0
    if (eprn->default_orientation % 2 == 0)     /* true on short edge first */
542
0
      desired &= ~MS_TRANSVERSE_FLAG;
543
0
    else
544
0
      desired |= MS_TRANSVERSE_FLAG;
545
0
  }
546
547
  /* Find best match in discrete sizes */
548
0
  if (eprn->media_overrides == NULL) pd = eprn->cap->sizes;
549
0
  else pd = eprn->media_overrides;
550
0
  while (pd->code != ms_none) {
551
0
    const ms_SizeDescription *ms = ms_find_size_from_code(pd->code);
552
0
    if (ms->dimen[0] > 0.0 /* ignore variable sizes */ &&
553
0
        fabs(w - ms->dimen[0])  <= 5.0 &&
554
0
        fabs(h - ms->dimen[1]) <= 5.0) {
555
       /* The size does match at 5 bp tolerance. This value has been chosen
556
          arbitrarily to be equal to PostScript's PageSize matching tolerance
557
          during media selection. The tolerance should really be that at which
558
          the printer in question distinguishes between sizes or smaller than
559
          that in order to at least prevent printing on unsupported sizes.
560
        */
561
0
      if (best_dmatch == NULL ||
562
0
          better_flag_match(desired, eprn->optional_flags, best_dmatch->code,
563
0
            pd->code))
564
0
        best_dmatch = pd;
565
0
      if (flag_match(desired, eprn->optional_flags, pd->code))
566
0
        no_match = false;
567
0
    }
568
0
    pd++;
569
0
  }
570
571
  /* Next find the best match among the custom size descriptions */
572
0
  if (eprn->cap->custom != NULL) {
573
0
    const eprn_CustomPageDescription *cp = eprn->cap->custom;
574
575
    /* First check whether the size is in the supported range */
576
0
    while (cp->width_max > 0.0) {
577
0
      if (cp->width_min  <= w && w <= cp->width_max &&
578
0
          cp->height_min <= h && h <= cp->height_max) {
579
        /* The size does match. */
580
0
        if (best_cmatch == NULL ||
581
0
            better_flag_match(desired, eprn->optional_flags, best_cmatch->code,
582
0
              cp->code))
583
0
          best_cmatch = cp;
584
0
        if (eprn->media_overrides == NULL &&
585
0
            flag_match(desired, eprn->optional_flags, cp->code))
586
0
          no_match = false;
587
0
      }
588
0
      cp++;
589
0
    }
590
591
    /* If we have read a media configuration file, the flags to be matched
592
       must be sought in 'media_overrides'. */
593
0
    if (best_cmatch != NULL && eprn->media_overrides != NULL) {
594
0
      for (pd = eprn->media_overrides; pd->code != ms_none; pd++) {
595
0
        if (ms_without_flags(pd->code) == ms_CustomPageSize) {
596
0
          if (best_cdmatch == NULL ||
597
0
              better_flag_match(desired, eprn->optional_flags,
598
0
                best_cdmatch->code, pd->code))
599
0
            best_cdmatch = pd;
600
0
          if (flag_match(desired, eprn->optional_flags, pd->code))
601
0
            no_match = false;
602
0
        }
603
0
      }
604
0
    }
605
0
  }
606
607
  /*  Now the 'best_*match' variables indicate for each of the categories of
608
      page descriptions to which extent the size is supported at all (non-NULL
609
      value) and what the best flag match in the category is. Here we now check
610
      for NULL values, i.e., size matches. */
611
0
  if (best_dmatch == NULL) {
612
    /* No discrete match */
613
0
    if (best_cmatch == NULL) {
614
      /* No match at all. */
615
0
      eprintf3("%s" ERRPREF
616
0
        "This document requests a page size of %.0f x %.0f bp.\n",
617
0
           epref, dev->MediaSize[0], dev->MediaSize[1]);
618
0
      if (eprn->cap->custom == NULL) {
619
        /* The printer does not support custom page sizes */
620
0
        if (eprn->media_overrides != NULL)
621
0
          eprintf1(
622
0
            "%s  The media configuration file does not contain an entry for "
623
0
              " this size.\n", epref);
624
0
        else
625
0
          eprintf2("%s  This size is not supported by the %s.\n",
626
0
            epref, eprn->cap->name);
627
0
      }
628
0
      else
629
0
        eprintf3(
630
0
          "%s  This size is not supported as a discrete size and it exceeds "
631
0
            "the\n"
632
0
          "%s  custom page size limits for the %s.\n",
633
0
          epref, epref, eprn->cap->name);
634
0
      return -1;
635
0
    }
636
0
    if (eprn->media_overrides != NULL && best_cdmatch == NULL) {
637
0
      eprintf6("%s" ERRPREF
638
0
        "This document requests a page size of %.0f x %.0f bp\n"
639
0
        "%s  but there is no entry for this size in the "
640
0
          "media configuration file\n"
641
0
        "%s  %s.\n",
642
0
        epref, dev->MediaSize[0], dev->MediaSize[1], epref, epref,
643
0
        eprn->media_file);
644
0
      return -1;
645
0
    }
646
0
  }
647
  /* Now we have: best_dmatch != NULL || best_cmatch != NULL &&
648
     (eprn->media_overrides == NULL || best_cdmatch != NULL). */
649
650
  /* Find a flag match among the size matches found so far */
651
0
  {
652
0
    ms_MediaCode custom_code = ms_none;
653
      /* best custom page size match (either from cmatch or dcmatch) */
654
0
    if (best_cmatch != NULL &&
655
0
        (eprn->media_overrides == NULL || best_cdmatch != NULL))
656
0
      custom_code = (eprn->media_overrides == NULL?
657
0
        best_cmatch->code: best_cdmatch->code);
658
659
0
    if (best_dmatch == NULL ||
660
0
        (best_cmatch != NULL &&
661
0
         better_flag_match(desired, eprn->optional_flags, best_dmatch->code,
662
0
                           custom_code))) {
663
0
      if (flag_match(desired, eprn->optional_flags, custom_code)) {
664
0
        if (eprn->media_overrides == NULL) {
665
0
          eprn->code = best_cmatch->code;
666
0
          margins[0] = best_cmatch->left;
667
0
          margins[1] = best_cmatch->bottom;
668
0
          margins[2] = best_cmatch->right;
669
0
          margins[3] = best_cmatch->top;
670
0
        }
671
0
        else {
672
0
          eprn->code = best_cdmatch->code;
673
0
          margins[0] = best_cdmatch->left;
674
0
          margins[1] = best_cdmatch->bottom;
675
0
          margins[2] = best_cdmatch->right;
676
0
          margins[3] = best_cdmatch->top;
677
0
        }
678
0
      }
679
0
    }
680
0
    else {
681
0
      if (flag_match(desired, eprn->optional_flags, best_dmatch->code)) {
682
0
        eprn->code = best_dmatch->code;
683
0
        margins[0] = best_dmatch->left;
684
0
        margins[1] = best_dmatch->bottom;
685
0
        margins[2] = best_dmatch->right;
686
0
        margins[3] = best_dmatch->top;
687
0
      }
688
0
    }
689
0
  }
690
  /* If we've found a match, 'code' is no longer 'ms_none'. */
691
0
  if (eprn->code == ms_none) {
692
0
    eprn_flag_mismatch(eprn, no_match);
693
0
    return -1;
694
0
  }
695
696
  /* Adapt the orientation of default default user space if not prescribed */
697
0
  if (!eprn->leading_edge_set) {
698
0
    if (eprn->code & MS_TRANSVERSE_FLAG) eprn->default_orientation = 3;
699
     /* This leads to 0 if landscape orientation is requested. */
700
0
    else eprn->default_orientation = 0;
701
0
  }
702
703
  /*
704
    Now 'eprn->default_orientation % 2' describes the sheet's orientation in
705
    pixmap device space. If this does not agree with the width and height
706
    values in the device instance, we'll have to adapt them.
707
    This is only necessary if there is a significant difference between width
708
    and height.
709
   */
710
0
  if (fabs(w - h) > 1 /* arbitrary */ &&
711
0
    (eprn->default_orientation % 2 == 0) !=
712
0
        (dev->width/dev->HWResolution[0] <= dev->height/dev->HWResolution[1])) {
713
0
    bool reallocate = false;
714
715
#ifdef EPRN_TRACE
716
    if_debug0(EPRN_TRACE_CHAR,
717
      "! eprn_set_page_layout(): width-height change is necessary.\n");
718
#endif
719
720
    /* Free old storage if the device is open */
721
0
    if (dev->is_open) {
722
#ifdef EPRN_TRACE
723
      if_debug0(EPRN_TRACE_CHAR, "! eprn_set_page_layout(): Device is open.\n");
724
#endif
725
0
      reallocate = true;
726
       /* One could try and call the allocation/reallocation routines of the
727
          prn device directly, but they are not available in older ghostscript
728
          versions and this method is safer anyway because it relies on a
729
          documented API. */
730
0
      gdev_prn_close((gx_device *)dev);         /* ignore the result */
731
0
    }
732
733
    /*  Now set width and height via gx_device_set_media_size(). This function
734
        sets 'MediaSize[]', 'width', and 'height' based on the assumption that
735
        default user space has a y axis which is vertical in pixmap device
736
        space. This may be wrong and we have to fix it. Because fixing
737
        'MediaSize[]' is simpler, gx_device_set_media_size() is called such
738
        that it gives the correct values for 'width' and 'height'. */
739
0
    if (eprn->default_orientation % 2 == 0) {
740
      /* portrait orientation of the sheet in pixmap device space */
741
0
      gx_device_set_media_size((gx_device *)dev, w, h);
742
0
      if (landscape) {
743
0
        dev->MediaSize[0] = h;
744
0
        dev->MediaSize[1] = w;
745
0
      }
746
0
    }
747
0
    else {
748
      /* landscape orientation in pixmap device space (transverse) */
749
0
      gx_device_set_media_size((gx_device *)dev, h, w);
750
0
      if (!landscape) {
751
0
        dev->MediaSize[0] = w;
752
0
        dev->MediaSize[1] = h;
753
0
      }
754
0
    }
755
756
    /* If the device is/was open, reallocate storage */
757
0
    if (reallocate) {
758
0
      int rc;
759
760
0
      rc = gdev_prn_open((gx_device *)dev);
761
0
      if (rc < 0) {
762
0
        eprintf2("%s" ERRPREF
763
0
          "Failure of gdev_prn_open(), code is %d.\n",
764
0
          epref, rc);
765
0
        return rc;
766
0
      }
767
0
    }
768
0
  }
769
770
  /* Increase the bottom margin for coloured modes except if it is exactly
771
     zero */
772
0
  if (eprn->colour_model != eprn_DeviceGray && margins[1] != 0.0)
773
0
    margins[1] += eprn->cap->bottom_increment;
774
775
  /* Number of +90-degree rotations needed for default user space: */
776
0
  quarters = eprn->default_orientation;
777
0
  if (landscape) quarters = (quarters + 1)%4;
778
779
  /* Store the top and left margins in the device structure for use by
780
     eprn_get_initial_matrix() and set the margins of the printable area if
781
     we may.
782
     gx_device_set_margins() (see gsdevice.c) copies the margins[] array to
783
     HWMargins[] which is presumably to be interpreted in default user space
784
     (see gs_initclip() in gspath.c), and if its second argument is true it
785
     also modifies the offset variable Margins[]. The first property means
786
     that gx_device_set_margins() can only be used if default user space and
787
     pixmap device space have the same "up" direction, and the second
788
     appropriates a parameter which is intended for the user.
789
  */
790
0
  if (eprn->keep_margins) {
791
0
    eprn->down_shift  = dev->HWMargins[3 - quarters];
792
0
    eprn->right_shift = dev->HWMargins[(4 - quarters)%4];
793
0
  }
794
0
  else {
795
0
    int j;
796
797
0
    eprn->down_shift  = margins[3];
798
0
    eprn->right_shift = margins[0];
799
800
0
    if (quarters != 0) {
801
       /* The "canonical margin order" for ghostscript is left, bottom, right,
802
          top. Hence for, e.g., a +90-degree rotation ('quarters' is 1) of
803
          default user space with respect to pixmap device space the left
804
          margin (index 0) in default user space is actually the bottom margin
805
          (index 1) in pixmap device space, the bottom margin is the right one,
806
          etc.
807
        */
808
0
      for (j = 0; j < 4; j++) dev->HWMargins[j] = margins[(j+quarters)%4];
809
      /* 'HWMargins[]' is in bp (see gxdevcli.h) */
810
0
    }
811
0
    else {
812
      /* Convert to inches */
813
0
      for (j = 0; j < 4; j++) margins[j] /= BP_PER_IN;
814
815
0
      gx_device_set_margins((gx_device *)dev, margins, false);
816
       /* Of course, I could set HWMargins[] directly also in this case. This
817
          way is however less prone to break on possible future incompatible
818
          changes to ghostscript and it covers the most frequent case (portrait
819
          and short edge first). */
820
0
    }
821
0
  }
822
823
0
  return 0;
824
0
}
825
826
/******************************************************************************
827
828
  Function: eprn_init_device
829
830
  This function sets 'cap' to 'desc' and all device parameters which are
831
  modified through the put_params routines to default values. The resolution is
832
  left at its old value (and don't ask me why or I'll start to whimper). If the
833
  device is open when this function is called the device will be closed
834
  afterwards.
835
836
  'desc' may not be NULL.
837
838
******************************************************************************/
839
840
int eprn_init_device(eprn_Device *dev, const eprn_PrinterDescription *desc)
841
0
{
842
0
  eprn_Eprn *eprn = &dev->eprn;
843
0
  int j;
844
0
  float hres, vres;
845
0
  int code;
846
847
0
  if (dev->is_open) gs_closedevice((gx_device *)dev);
848
849
0
  assert(desc != NULL);
850
0
  eprn->cap = desc;
851
0
  eprn_set_media_data(dev, NULL, 0);
852
853
  /* The media flags are retained because they have not been prescribed by the
854
     user directly in contact with eprn but are completely under the control
855
     of the derived device. */
856
857
0
  eprn->code = ms_none;
858
0
  eprn->leading_edge_set = false;
859
0
  eprn->right_shift = 0;
860
0
  eprn->down_shift = 0;
861
0
  eprn->keep_margins = false;
862
0
  eprn->soft_tumble = false;
863
0
  for (j = 0; j < 4; j++) dev->HWMargins[j] = 0;
864
865
  /* Set to default colour state, ignoring request failures */
866
0
  eprn->colour_model = eprn_DeviceGray;
867
0
  eprn->black_levels = 2;
868
0
  eprn->non_black_levels = 0;
869
0
  eprn->intensity_rendering = eprn_IR_halftones;
870
0
  hres = dev->HWResolution[0];
871
0
  vres = dev->HWResolution[1];
872
0
  code = eprn_check_colour_info(desc->colour_info, &eprn->colour_model,
873
0
      &hres, &vres, &eprn->black_levels, &eprn->non_black_levels);
874
0
  if (code) {
875
0
    return code;
876
0
  }
877
0
  if (eprn->pagecount_file != NULL) {
878
0
    gs_free(dev->memory->non_gc_memory, eprn->pagecount_file, strlen(eprn->pagecount_file) + 1,
879
0
      sizeof(char), "eprn_init_device");
880
0
    eprn->pagecount_file = NULL;
881
0
  }
882
883
0
  eprn->media_position_set = false;
884
885
0
  return 0;
886
0
}
887
888
/******************************************************************************
889
890
  Function: eprn_set_media_flags
891
892
******************************************************************************/
893
894
void eprn_set_media_flags(eprn_Device *dev, ms_MediaCode desired,
895
  const ms_MediaCode *optional)
896
0
{
897
0
  dev->eprn.code = ms_none;
898
899
0
  dev->eprn.desired_flags = desired;
900
0
  dev->eprn.optional_flags = optional;
901
902
0
  return;
903
0
}
904
905
/******************************************************************************
906
907
  Function: eprn_open_device
908
909
  This function "opens" the device. According to Drivers.htm, the 'open_device'
910
  functions are called before any output is sent to the device, and they must
911
  ensure that the device instance is valid, possibly by doing suitable
912
  initialization.
913
914
  This particular implementation also checks whether the requested page size
915
  is supported by the printer. This discovery must, unfortunately, be
916
  delayed until the moment this function is called. Note that this also implies
917
  that various eprn parameters depending on the page size (e.g., 'eprn.code')
918
  can be relied upon to have valid values only after the device has been
919
  successfully opened. The same applies to rendering parameters.
920
921
  This function also opens the parts defined by base classes.
922
923
  The function returns zero on success and a ghostscript error value otherwise.
924
925
******************************************************************************/
926
927
int eprn_open_device(gx_device *device)
928
0
{
929
0
  eprn_Eprn *eprn = &((eprn_Device *)device)->eprn;
930
0
  const char *epref = eprn->CUPS_messages? CUPS_ERRPREF: "";
931
0
  int rc;
932
933
#ifdef EPRN_TRACE
934
  if_debug0(EPRN_TRACE_CHAR, "! eprn_open_device()...\n");
935
#endif
936
937
  /* Checks on page size and determination of derived values */
938
0
  if (eprn_set_page_layout((eprn_Device *)device) != 0)
939
0
    return_error(gs_error_rangecheck);
940
941
  /* Check the rendering parameters */
942
0
  if (eprn_check_colour_info(eprn->cap->colour_info, &eprn->colour_model,
943
0
      &device->HWResolution[0], &device->HWResolution[1],
944
0
      &eprn->black_levels, &eprn->non_black_levels) != 0) {
945
0
    gs_param_string str;
946
947
0
    eprintf1("%s" ERRPREF "The requested combination of colour model (",
948
0
      epref);
949
0
    str.size = 0;
950
0
    if (eprn_get_string(eprn->colour_model, eprn_colour_model_list, &str) != 0)
951
0
      assert(0); /* Bug. No harm on NDEBUG because I've just set the size. */
952
0
    errwrite(device->memory, (const char *)str.data, str.size * sizeof(str.data[0]));
953
0
    eprintf7("),\n"
954
0
      "%s  resolution (%gx%g ppi) and intensity levels (%d, %d) is\n"
955
0
      "%s  not supported by the %s.\n",
956
0
      epref, device->HWResolution[0], device->HWResolution[1],
957
0
      eprn->black_levels, eprn->non_black_levels, epref, eprn->cap->name);
958
0
    return_error(gs_error_rangecheck);
959
0
  }
960
961
  /* Initialization for colour rendering */
962
0
  if (device->color_info.num_components == 4) {
963
    /* Native colour space is 'DeviceCMYK' */
964
0
    set_dev_proc(device, map_rgb_color, NULL);
965
966
0
    if (eprn->intensity_rendering == eprn_IR_FloydSteinberg)
967
0
      set_dev_proc(device, map_cmyk_color, &eprn_map_cmyk_color_max);
968
0
    else if (device->color_info.max_gray > 1 || device->color_info.max_color > 1)
969
0
      set_dev_proc(device, map_cmyk_color, &eprn_map_cmyk_color_flex);
970
0
    else
971
0
      set_dev_proc(device, map_cmyk_color, &eprn_map_cmyk_color);
972
973
0
    if (eprn->intensity_rendering == eprn_IR_FloydSteinberg)
974
0
      set_dev_proc(device, map_rgb_color, &eprn_map_rgb_color_for_CMY_or_K_max);
975
0
    else if (device->color_info.max_gray > 1 || device->color_info.max_color > 1)
976
0
      set_dev_proc(device, map_rgb_color, &eprn_map_rgb_color_for_CMY_or_K_flex);
977
0
    else
978
0
      set_dev_proc(device, map_rgb_color, &eprn_map_rgb_color_for_CMY_or_K);
979
980
0
  }
981
0
  else {
982
0
    set_dev_proc(device, map_cmyk_color, NULL);
983
984
0
    if (eprn->colour_model == eprn_DeviceRGB) {
985
0
      if (eprn->intensity_rendering == eprn_IR_FloydSteinberg)
986
0
        set_dev_proc(device, map_rgb_color, &eprn_map_rgb_color_for_RGB_max);
987
0
      else if (device->color_info.max_color > 1)
988
0
        set_dev_proc(device, map_rgb_color, &eprn_map_rgb_color_for_RGB_flex);
989
0
      else
990
0
        set_dev_proc(device, map_rgb_color, &eprn_map_rgb_color_for_RGB);
991
0
    } else {
992
0
      if (eprn->intensity_rendering == eprn_IR_FloydSteinberg)
993
0
        set_dev_proc(device, map_rgb_color, &eprn_map_rgb_color_for_CMY_or_K_max);
994
0
      else if (device->color_info.max_gray > 1 || device->color_info.max_color > 1)
995
0
        set_dev_proc(device, map_rgb_color, &eprn_map_rgb_color_for_CMY_or_K_flex);
996
0
      else
997
0
        set_dev_proc(device, map_rgb_color, &eprn_map_rgb_color_for_CMY_or_K);
998
0
    }
999
0
  }
1000
0
  eprn->output_planes = eprn_bits_for_levels(eprn->black_levels) +
1001
0
    3 * eprn_bits_for_levels(eprn->non_black_levels);
1002
1003
0
#if !defined(GS_REVISION) || GS_REVISION >= 600
1004
  /*  According to my understanding, the following call should be superfluous
1005
      (because the colour mapping functions may not be called while the device
1006
      is closed) and I am also not aware of any situation where it does make a
1007
      difference. It shouldn't do any harm, though, and I feel safer with it :-)
1008
  */
1009
0
  gx_device_decache_colors(device);
1010
0
#endif
1011
1012
0
#ifndef EPRN_NO_PAGECOUNTFILE
1013
  /* Read the page count value */
1014
0
  if (eprn->pagecount_file != NULL) {
1015
0
    unsigned long count;
1016
0
    if (pcf_getcount(device->memory, eprn->pagecount_file, &count) == 0)
1017
0
      device->PageCount = count;
1018
       /* unsigned to signed. The C standard permits
1019
          an implementation to generate an overflow indication if the value is
1020
          too large. I consider this to mean that the type of 'PageCount' is
1021
          inappropriate :-). Note that eprn does not use 'PageCount' for
1022
          updating the file. */
1023
0
    else {
1024
      /* pcf_getcount() has issued an error message. */
1025
0
      eprintf(
1026
0
        "  No further attempts will be made to access the page count file.\n");
1027
0
      gs_free(device->memory->non_gc_memory, eprn->pagecount_file, strlen(eprn->pagecount_file) + 1,
1028
0
        sizeof(char), "eprn_open_device");
1029
0
      eprn->pagecount_file = NULL;
1030
0
    }
1031
0
  }
1032
0
#endif  /* !EPRN_NO_PAGECOUNTFILE */
1033
1034
  /* Open the "prn" device part */
1035
0
  if ((rc = gdev_prn_open(device)) != 0) return rc;
1036
1037
  /* if device has been subclassed (FirstPage/LastPage device) then make sure we use
1038
   * the subclassed device.
1039
   */
1040
0
  while (device->child)
1041
0
      device = device->child;
1042
0
  eprn = &((eprn_Device *)device)->eprn;
1043
1044
  /* Just in case a previous open call failed in a derived device (note that
1045
     'octets_per_line' is still the same as then): */
1046
0
  if (eprn->scan_line.str != NULL)
1047
0
    gs_free(device->memory->non_gc_memory, eprn->scan_line.str, eprn->octets_per_line, sizeof(eprn_Octet),
1048
0
      "eprn_open_device");
1049
0
  if (eprn->next_scan_line.str != NULL) {
1050
0
    gs_free(device->memory->non_gc_memory, eprn->next_scan_line.str, eprn->octets_per_line, sizeof(eprn_Octet),
1051
0
      "eprn_open_device");
1052
0
    eprn->next_scan_line.str = NULL;
1053
0
  }
1054
1055
  /* Calls which might depend on prn having been initialized */
1056
0
  eprn->octets_per_line = gdev_prn_raster((gx_device_printer *)device);
1057
0
  eprn->scan_line.str = (eprn_Octet *) gs_malloc(device->memory->non_gc_memory, eprn->octets_per_line,
1058
0
    sizeof(eprn_Octet), "eprn_open_device");
1059
0
  if (eprn->intensity_rendering == eprn_IR_FloydSteinberg) {
1060
0
    eprn->next_scan_line.str = (eprn_Octet *) gs_malloc(device->memory->non_gc_memory, eprn->octets_per_line,
1061
0
      sizeof(eprn_Octet), "eprn_open_device");
1062
0
    if (eprn->next_scan_line.str == NULL && eprn->scan_line.str != NULL) {
1063
0
      gs_free(device->memory->non_gc_memory, eprn->scan_line.str, eprn->octets_per_line, sizeof(eprn_Octet),
1064
0
        "eprn_open_device");
1065
0
      eprn->scan_line.str = NULL;
1066
0
    }
1067
0
  }
1068
0
  if (eprn->scan_line.str == NULL) {
1069
0
    eprintf1("%s" ERRPREF
1070
0
      "Memory allocation failure from gs_malloc() in eprn_open_device().\n",
1071
0
      epref);
1072
0
    return_error(gs_error_VMerror);
1073
0
  }
1074
1075
0
  return rc;
1076
0
}
1077
1078
/******************************************************************************
1079
1080
  Function: eprn_close_device
1081
1082
******************************************************************************/
1083
1084
int eprn_close_device(gx_device *device)
1085
0
{
1086
0
  eprn_Eprn *eprn = &((eprn_Device *)device)->eprn;
1087
1088
#ifdef EPRN_TRACE
1089
  if_debug0(EPRN_TRACE_CHAR, "! eprn_close_device()...\n");
1090
#endif
1091
1092
0
  if (eprn->scan_line.str != NULL) {
1093
0
    gs_free(device->memory->non_gc_memory, eprn->scan_line.str, eprn->octets_per_line, sizeof(eprn_Octet),
1094
0
      "eprn_close_device");
1095
0
    eprn->scan_line.str = NULL;
1096
0
  }
1097
0
  if (eprn->next_scan_line.str != NULL) {
1098
0
    gs_free(device->memory->non_gc_memory, eprn->next_scan_line.str, eprn->octets_per_line, sizeof(eprn_Octet),
1099
0
      "eprn_close_device");
1100
0
    eprn->next_scan_line.str = NULL;
1101
0
  }
1102
1103
0
  return gdev_prn_close(device);
1104
0
}
1105
1106
/******************************************************************************
1107
1108
  Function: eprn_forget_defaultmatrix
1109
1110
  This function tells the ghostscript kernel to forget the default matrix,
1111
  i.e., to consult the get_initial_matrix device procedure the next time the
1112
  default CTM is needed.
1113
1114
******************************************************************************/
1115
1116
static void eprn_forget_defaultmatrix(gx_device *device)
1117
0
{
1118
0
  eprn_Eprn *eprn = &((eprn_Device *)device)->eprn;
1119
1120
0
  gs_setdefaultmatrix((gs_gstate *)eprn->pgs, NULL);
1121
1122
0
  return;
1123
0
}
1124
1125
/******************************************************************************
1126
1127
  Function: eprn_output_page
1128
1129
  This function is a wrapper for gdev_prn_output_page() in order to catch the
1130
  number of pages printed and to initialize the eprn_get_planes() API.
1131
1132
******************************************************************************/
1133
1134
int eprn_output_page(gx_device *dev, int num_copies, int flush)
1135
0
{
1136
0
  eprn_Eprn *eprn = &((eprn_Device *)dev)->eprn;
1137
0
  int rc;
1138
1139
#ifdef EPRN_TRACE
1140
  clock_t start_time = clock();
1141
  if_debug0(EPRN_TRACE_CHAR, "! eprn_output_page()...\n");
1142
#endif
1143
1144
  /* Initialize eprn_get_planes() data */
1145
0
  eprn->next_y = 0;
1146
0
  if (eprn->intensity_rendering == eprn_IR_FloydSteinberg) {
1147
    /* Fetch the first line and store it in 'next_scan_line'. */
1148
0
    if (eprn_fetch_scan_line((eprn_Device *)dev, &eprn->next_scan_line) == 0)
1149
0
      eprn->next_y++;
1150
0
  }
1151
1152
  /* Ship out */
1153
0
  rc = gdev_prn_output_page(dev, num_copies, flush);
1154
1155
  /*  CUPS page accounting message. The CUPS documentation is not perfectly
1156
      clear on whether one should generate this message before printing a page
1157
      or after printing has been successful. The rasterto* filters generate it
1158
      before sending the page, but as the scheduler uses these messages for
1159
      accounting, this seems unfair.
1160
  */
1161
0
  if (rc == 0 && eprn->CUPS_accounting)
1162
0
    eprintf2("PAGE: %ld %d\n", dev->ShowpageCount, num_copies);
1163
    /* The arguments are the number of the page, starting at 1, and the number
1164
       of copies of that page. */
1165
1166
0
#ifndef EPRN_NO_PAGECOUNTFILE
1167
  /* On success, record the number of pages printed */
1168
0
  if (rc == 0 && eprn->pagecount_file != NULL) {
1169
0
    assert(num_copies > 0);     /* because of signed/unsigned */
1170
0
    if (pcf_inccount(dev->memory, eprn->pagecount_file, num_copies) != 0) {
1171
      /* pcf_inccount() has issued an error message. */
1172
0
      eprintf(
1173
0
        "  No further attempts will be made to access the page count file.\n");
1174
0
      gs_free(dev->memory->non_gc_memory, eprn->pagecount_file, strlen(eprn->pagecount_file) + 1,
1175
0
        sizeof(char), "eprn_output_page");
1176
0
      eprn->pagecount_file = NULL;
1177
0
    }
1178
0
  }
1179
0
#endif  /* !EPRN_NO_PAGECOUNTFILE */
1180
1181
  /* If soft tumble has been demanded, ensure the get_initial_matrix procedure
1182
     is consulted for the next page */
1183
0
  if (eprn->soft_tumble) eprn_forget_defaultmatrix(dev);
1184
1185
#ifdef EPRN_TRACE
1186
  if_debug1(EPRN_TRACE_CHAR, "! eprn_output_page() terminates after %f s.\n",
1187
    ((float)(clock() - start_time))/CLOCKS_PER_SEC);
1188
#endif
1189
1190
0
  return rc;
1191
0
}