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