1/*
2 * "$Id: common.c 11560 2014-02-06 20:10:19Z msweet $"
3 *
4 * Common filter routines for CUPS.
5 *
6 * Copyright 2007-2014 by Apple Inc.
7 * Copyright 1997-2006 by Easy Software Products.
8 *
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law.  Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file.  If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
14 *
15 * This file is subject to the Apple OS-Developed Software exception.
16 */
17
18/*
19 * Include necessary headers...
20 */
21
22#include "common.h"
23#include <locale.h>
24
25
26/*
27 * Globals...
28 */
29
30int	Orientation = 0,		/* 0 = portrait, 1 = landscape, etc. */
31	Duplex = 0,			/* Duplexed? */
32	LanguageLevel = 1,		/* Language level of printer */
33	ColorDevice = 1;		/* Do color text? */
34float	PageLeft = 18.0f,		/* Left margin */
35	PageRight = 594.0f,		/* Right margin */
36	PageBottom = 36.0f,		/* Bottom margin */
37	PageTop = 756.0f,		/* Top margin */
38	PageWidth = 612.0f,		/* Total page width */
39	PageLength = 792.0f;		/* Total page length */
40
41
42/*
43 * 'SetCommonOptions()' - Set common filter options for media size, etc.
44 */
45
46ppd_file_t *				/* O - PPD file */
47SetCommonOptions(
48    int           num_options,		/* I - Number of options */
49    cups_option_t *options,		/* I - Options */
50    int           change_size)		/* I - Change page size? */
51{
52  ppd_file_t	*ppd;			/* PPD file */
53  ppd_size_t	*pagesize;		/* Current page size */
54  const char	*val;			/* Option value */
55
56
57#ifdef LC_TIME
58  setlocale(LC_TIME, "");
59#endif /* LC_TIME */
60
61  ppd = ppdOpenFile(getenv("PPD"));
62
63  ppdMarkDefaults(ppd);
64  cupsMarkOptions(ppd, num_options, options);
65
66  if ((pagesize = ppdPageSize(ppd, NULL)) != NULL)
67  {
68    PageWidth  = pagesize->width;
69    PageLength = pagesize->length;
70    PageTop    = pagesize->top;
71    PageBottom = pagesize->bottom;
72    PageLeft   = pagesize->left;
73    PageRight  = pagesize->right;
74
75    fprintf(stderr, "DEBUG: Page = %.0fx%.0f; %.0f,%.0f to %.0f,%.0f\n",
76            PageWidth, PageLength, PageLeft, PageBottom, PageRight, PageTop);
77  }
78
79  if (ppd != NULL)
80  {
81    ColorDevice   = ppd->color_device;
82    LanguageLevel = ppd->language_level;
83  }
84
85  if ((val = cupsGetOption("landscape", num_options, options)) != NULL)
86  {
87    if (_cups_strcasecmp(val, "no") != 0 && _cups_strcasecmp(val, "off") != 0 &&
88        _cups_strcasecmp(val, "false") != 0)
89    {
90      if (ppd && ppd->landscape > 0)
91        Orientation = 1;
92      else
93        Orientation = 3;
94    }
95  }
96  else if ((val = cupsGetOption("orientation-requested", num_options, options)) != NULL)
97  {
98   /*
99    * Map IPP orientation values to 0 to 3:
100    *
101    *   3 = 0 degrees   = 0
102    *   4 = 90 degrees  = 1
103    *   5 = -90 degrees = 3
104    *   6 = 180 degrees = 2
105    */
106
107    Orientation = atoi(val) - 3;
108    if (Orientation >= 2)
109      Orientation ^= 1;
110  }
111
112  if ((val = cupsGetOption("page-left", num_options, options)) != NULL)
113  {
114    switch (Orientation & 3)
115    {
116      case 0 :
117          PageLeft = (float)atof(val);
118	  break;
119      case 1 :
120          PageBottom = (float)atof(val);
121	  break;
122      case 2 :
123          PageRight = PageWidth - (float)atof(val);
124	  break;
125      case 3 :
126          PageTop = PageLength - (float)atof(val);
127	  break;
128    }
129  }
130
131  if ((val = cupsGetOption("page-right", num_options, options)) != NULL)
132  {
133    switch (Orientation & 3)
134    {
135      case 0 :
136          PageRight = PageWidth - (float)atof(val);
137	  break;
138      case 1 :
139          PageTop = PageLength - (float)atof(val);
140	  break;
141      case 2 :
142          PageLeft = (float)atof(val);
143	  break;
144      case 3 :
145          PageBottom = (float)atof(val);
146	  break;
147    }
148  }
149
150  if ((val = cupsGetOption("page-bottom", num_options, options)) != NULL)
151  {
152    switch (Orientation & 3)
153    {
154      case 0 :
155          PageBottom = (float)atof(val);
156	  break;
157      case 1 :
158          PageLeft = (float)atof(val);
159	  break;
160      case 2 :
161          PageTop = PageLength - (float)atof(val);
162	  break;
163      case 3 :
164          PageRight = PageWidth - (float)atof(val);
165	  break;
166    }
167  }
168
169  if ((val = cupsGetOption("page-top", num_options, options)) != NULL)
170  {
171    switch (Orientation & 3)
172    {
173      case 0 :
174          PageTop = PageLength - (float)atof(val);
175	  break;
176      case 1 :
177          PageRight = PageWidth - (float)atof(val);
178	  break;
179      case 2 :
180          PageBottom = (float)atof(val);
181	  break;
182      case 3 :
183          PageLeft = (float)atof(val);
184	  break;
185    }
186  }
187
188  if (change_size)
189    UpdatePageVars();
190
191  if (ppdIsMarked(ppd, "Duplex", "DuplexNoTumble") ||
192      ppdIsMarked(ppd, "Duplex", "DuplexTumble") ||
193      ppdIsMarked(ppd, "JCLDuplex", "DuplexNoTumble") ||
194      ppdIsMarked(ppd, "JCLDuplex", "DuplexTumble") ||
195      ppdIsMarked(ppd, "EFDuplex", "DuplexNoTumble") ||
196      ppdIsMarked(ppd, "EFDuplex", "DuplexTumble") ||
197      ppdIsMarked(ppd, "KD03Duplex", "DuplexNoTumble") ||
198      ppdIsMarked(ppd, "KD03Duplex", "DuplexTumble"))
199    Duplex = 1;
200
201  return (ppd);
202}
203
204
205/*
206 * 'UpdatePageVars()' - Update the page variables for the orientation.
207 */
208
209void
210UpdatePageVars(void)
211{
212  float		temp;			/* Swapping variable */
213
214
215  switch (Orientation & 3)
216  {
217    case 0 : /* Portait */
218        break;
219
220    case 1 : /* Landscape */
221	temp       = PageLeft;
222	PageLeft   = PageBottom;
223	PageBottom = temp;
224
225	temp       = PageRight;
226	PageRight  = PageTop;
227	PageTop    = temp;
228
229	temp       = PageWidth;
230	PageWidth  = PageLength;
231	PageLength = temp;
232	break;
233
234    case 2 : /* Reverse Portrait */
235	temp       = PageWidth - PageLeft;
236	PageLeft   = PageWidth - PageRight;
237	PageRight  = temp;
238
239	temp       = PageLength - PageBottom;
240	PageBottom = PageLength - PageTop;
241	PageTop    = temp;
242        break;
243
244    case 3 : /* Reverse Landscape */
245	temp       = PageWidth - PageLeft;
246	PageLeft   = PageWidth - PageRight;
247	PageRight  = temp;
248
249	temp       = PageLength - PageBottom;
250	PageBottom = PageLength - PageTop;
251	PageTop    = temp;
252
253	temp       = PageLeft;
254	PageLeft   = PageBottom;
255	PageBottom = temp;
256
257	temp       = PageRight;
258	PageRight  = PageTop;
259	PageTop    = temp;
260
261	temp       = PageWidth;
262	PageWidth  = PageLength;
263	PageLength = temp;
264	break;
265  }
266}
267
268
269/*
270 * 'WriteCommon()' - Write common procedures...
271 */
272
273void
274WriteCommon(void)
275{
276  puts("% x y w h ESPrc - Clip to a rectangle.\n"
277       "userdict/ESPrc/rectclip where{pop/rectclip load}\n"
278       "{{newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto\n"
279       "neg 0 rlineto closepath clip newpath}bind}ifelse put");
280  puts("% x y w h ESPrf - Fill a rectangle.\n"
281       "userdict/ESPrf/rectfill where{pop/rectfill load}\n"
282       "{{gsave newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto\n"
283       "neg 0 rlineto closepath fill grestore}bind}ifelse put");
284  puts("% x y w h ESPrs - Stroke a rectangle.\n"
285       "userdict/ESPrs/rectstroke where{pop/rectstroke load}\n"
286       "{{gsave newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto\n"
287       "neg 0 rlineto closepath stroke grestore}bind}ifelse put");
288}
289
290
291/*
292 * 'WriteLabelProlog()' - Write the prolog with the classification
293 *                        and page label.
294 */
295
296void
297WriteLabelProlog(const char *label,	/* I - Page label */
298		 float      bottom,	/* I - Bottom position in points */
299		 float      top,	/* I - Top position in points */
300		 float      width)	/* I - Width in points */
301{
302  const char	*classification;	/* CLASSIFICATION environment variable */
303  const char	*ptr;			/* Temporary string pointer */
304
305
306 /*
307  * First get the current classification...
308  */
309
310  if ((classification = getenv("CLASSIFICATION")) == NULL)
311    classification = "";
312  if (strcmp(classification, "none") == 0)
313    classification = "";
314
315 /*
316  * If there is nothing to show, bind an empty 'write labels' procedure
317  * and return...
318  */
319
320  if (!classification[0] && (label == NULL || !label[0]))
321  {
322    puts("userdict/ESPwl{}bind put");
323    return;
324  }
325
326 /*
327  * Set the classification + page label string...
328  */
329
330  printf("userdict");
331  if (strcmp(classification, "confidential") == 0)
332    printf("/ESPpl(CONFIDENTIAL");
333  else if (strcmp(classification, "classified") == 0)
334    printf("/ESPpl(CLASSIFIED");
335  else if (strcmp(classification, "secret") == 0)
336    printf("/ESPpl(SECRET");
337  else if (strcmp(classification, "topsecret") == 0)
338    printf("/ESPpl(TOP SECRET");
339  else if (strcmp(classification, "unclassified") == 0)
340    printf("/ESPpl(UNCLASSIFIED");
341  else
342  {
343    printf("/ESPpl(");
344
345    for (ptr = classification; *ptr; ptr ++)
346      if (*ptr < 32 || *ptr > 126)
347        printf("\\%03o", *ptr);
348      else if (*ptr == '_')
349        putchar(' ');
350      else
351      {
352	if (*ptr == '(' || *ptr == ')' || *ptr == '\\')
353	  putchar('\\');
354
355	putchar(*ptr);
356      }
357  }
358
359  if (label)
360  {
361    if (classification[0])
362      printf(" - ");
363
364   /*
365    * Quote the label string as needed...
366    */
367
368    for (ptr = label; *ptr; ptr ++)
369      if (*ptr < 32 || *ptr > 126)
370        printf("\\%03o", *ptr);
371      else
372      {
373	if (*ptr == '(' || *ptr == ')' || *ptr == '\\')
374	  putchar('\\');
375
376	putchar(*ptr);
377      }
378  }
379
380  puts(")put");
381
382 /*
383  * Then get a 14 point Helvetica-Bold font...
384  */
385
386  puts("userdict/ESPpf /Helvetica-Bold findfont 14 scalefont put");
387
388 /*
389  * Finally, the procedure to write the labels on the page...
390  */
391
392  puts("userdict/ESPwl{");
393  puts("  ESPpf setfont");
394  printf("  ESPpl stringwidth pop dup 12 add exch -0.5 mul %.0f add\n",
395         width * 0.5f);
396  puts("  1 setgray");
397  printf("  dup 6 sub %.0f 3 index 20 ESPrf\n", bottom - 2.0);
398  printf("  dup 6 sub %.0f 3 index 20 ESPrf\n", top - 18.0);
399  puts("  0 setgray");
400  printf("  dup 6 sub %.0f 3 index 20 ESPrs\n", bottom - 2.0);
401  printf("  dup 6 sub %.0f 3 index 20 ESPrs\n", top - 18.0);
402  printf("  dup %.0f moveto ESPpl show\n", bottom + 2.0);
403  printf("  %.0f moveto ESPpl show\n", top - 14.0);
404  puts("pop");
405  puts("}bind put");
406}
407
408
409/*
410 * 'WriteLabels()' - Write the actual page labels.
411 */
412
413void
414WriteLabels(int orient)	/* I - Orientation of the page */
415{
416  float	width,		/* Width of page */
417	length;		/* Length of page */
418
419
420  puts("gsave");
421
422  if ((orient ^ Orientation) & 1)
423  {
424    width  = PageLength;
425    length = PageWidth;
426  }
427  else
428  {
429    width  = PageWidth;
430    length = PageLength;
431  }
432
433  switch (orient & 3)
434  {
435    case 1 : /* Landscape */
436        printf("%.1f 0.0 translate 90 rotate\n", length);
437        break;
438    case 2 : /* Reverse Portrait */
439        printf("%.1f %.1f translate 180 rotate\n", width, length);
440        break;
441    case 3 : /* Reverse Landscape */
442        printf("0.0 %.1f translate -90 rotate\n", width);
443        break;
444  }
445
446  puts("ESPwl");
447  puts("grestore");
448}
449
450
451/*
452 * 'WriteTextComment()' - Write a DSC text comment.
453 */
454
455void
456WriteTextComment(const char *name,	/* I - Comment name ("Title", etc.) */
457                 const char *value)	/* I - Comment value */
458{
459  int	len;				/* Current line length */
460
461
462 /*
463  * DSC comments are of the form:
464  *
465  *   %%name: value
466  *
467  * The name and value must be limited to 7-bit ASCII for most printers,
468  * so we escape all non-ASCII and ASCII control characters as described
469  * in the Adobe Document Structuring Conventions specification.
470  */
471
472  printf("%%%%%s: (", name);
473  len = 5 + (int)strlen(name);
474
475  while (*value)
476  {
477    if (*value < ' ' || *value >= 127)
478    {
479     /*
480      * Escape this character value...
481      */
482
483      if (len >= 251)			/* Keep line < 254 chars */
484        break;
485
486      printf("\\%03o", *value & 255);
487      len += 4;
488    }
489    else if (*value == '\\')
490    {
491     /*
492      * Escape the backslash...
493      */
494
495      if (len >= 253)			/* Keep line < 254 chars */
496        break;
497
498      putchar('\\');
499      putchar('\\');
500      len += 2;
501    }
502    else
503    {
504     /*
505      * Put this character literally...
506      */
507
508      if (len >= 254)			/* Keep line < 254 chars */
509        break;
510
511      putchar(*value);
512      len ++;
513    }
514
515    value ++;
516  }
517
518  puts(")");
519}
520
521
522/*
523 * End of "$Id: common.c 11560 2014-02-06 20:10:19Z msweet $".
524 */
525