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