Imported Upstream version 2.2.2
[platform/upstream/cups.git] / cups / ppd-page.c
1 /*
2  * Page size functions for CUPS.
3  *
4  * Copyright 2007-2015 by Apple Inc.
5  * Copyright 1997-2007 by Easy Software Products, all rights reserved.
6  *
7  * These coded instructions, statements, and computer programs are the
8  * property of Apple Inc. and are protected by Federal copyright
9  * law.  Distribution and use rights are outlined in the file "LICENSE.txt"
10  * which should have been included with this file.  If this file is
11  * missing or damaged, see the license at "http://www.cups.org/".
12  *
13  * PostScript is a trademark of Adobe Systems, Inc.
14  *
15  * This file is subject to the Apple OS-Developed Software exception.
16  */
17
18 /*
19  * Include necessary headers...
20  */
21
22 #include "string-private.h"
23 #include "debug-private.h"
24 #include "ppd.h"
25
26
27 /*
28  * 'ppdPageSize()' - Get the page size record for the named size.
29  */
30
31 ppd_size_t *                            /* O - Size record for page or NULL */
32 ppdPageSize(ppd_file_t *ppd,            /* I - PPD file record */
33             const char *name)           /* I - Size name */
34 {
35   int           i;                      /* Looping var */
36   ppd_size_t    *size;                  /* Current page size */
37   double        w, l;                   /* Width and length of page */
38   char          *nameptr;               /* Pointer into name */
39   struct lconv  *loc;                   /* Locale data */
40   ppd_coption_t *coption;               /* Custom option for page size */
41   ppd_cparam_t  *cparam;                /* Custom option parameter */
42
43
44   DEBUG_printf(("2ppdPageSize(ppd=%p, name=\"%s\")", ppd, name));
45
46   if (!ppd)
47   {
48     DEBUG_puts("3ppdPageSize: Bad PPD pointer, returning NULL...");
49     return (NULL);
50   }
51
52   if (name)
53   {
54     if (!strncmp(name, "Custom.", 7) && ppd->variable_sizes)
55     {
56      /*
57       * Find the custom page size...
58       */
59
60       for (i = ppd->num_sizes, size = ppd->sizes; i > 0; i --, size ++)
61         if (!strcmp("Custom", size->name))
62           break;
63
64       if (!i)
65       {
66         DEBUG_puts("3ppdPageSize: No custom sizes, returning NULL...");
67         return (NULL);
68       }
69
70      /*
71       * Variable size; size name can be one of the following:
72       *
73       *    Custom.WIDTHxLENGTHin    - Size in inches
74       *    Custom.WIDTHxLENGTHft    - Size in feet
75       *    Custom.WIDTHxLENGTHcm    - Size in centimeters
76       *    Custom.WIDTHxLENGTHmm    - Size in millimeters
77       *    Custom.WIDTHxLENGTHm     - Size in meters
78       *    Custom.WIDTHxLENGTH[pt]  - Size in points
79       */
80
81       loc = localeconv();
82       w   = _cupsStrScand(name + 7, &nameptr, loc);
83       if (!nameptr || *nameptr != 'x')
84         return (NULL);
85
86       l = _cupsStrScand(nameptr + 1, &nameptr, loc);
87       if (!nameptr)
88         return (NULL);
89
90       if (!_cups_strcasecmp(nameptr, "in"))
91       {
92         w *= 72.0;
93         l *= 72.0;
94       }
95       else if (!_cups_strcasecmp(nameptr, "ft"))
96       {
97         w *= 12.0 * 72.0;
98         l *= 12.0 * 72.0;
99       }
100       else if (!_cups_strcasecmp(nameptr, "mm"))
101       {
102         w *= 72.0 / 25.4;
103         l *= 72.0 / 25.4;
104       }
105       else if (!_cups_strcasecmp(nameptr, "cm"))
106       {
107         w *= 72.0 / 2.54;
108         l *= 72.0 / 2.54;
109       }
110       else if (!_cups_strcasecmp(nameptr, "m"))
111       {
112         w *= 72.0 / 0.0254;
113         l *= 72.0 / 0.0254;
114       }
115
116       size->width  = (float)w;
117       size->length = (float)l;
118       size->left   = ppd->custom_margins[0];
119       size->bottom = ppd->custom_margins[1];
120       size->right  = (float)(w - ppd->custom_margins[2]);
121       size->top    = (float)(l - ppd->custom_margins[3]);
122
123      /*
124       * Update the custom option records for the page size, too...
125       */
126
127       if ((coption = ppdFindCustomOption(ppd, "PageSize")) != NULL)
128       {
129         if ((cparam = ppdFindCustomParam(coption, "Width")) != NULL)
130           cparam->current.custom_points = (float)w;
131
132         if ((cparam = ppdFindCustomParam(coption, "Height")) != NULL)
133           cparam->current.custom_points = (float)l;
134       }
135
136      /*
137       * Return the page size...
138       */
139
140       DEBUG_printf(("3ppdPageSize: Returning %p (\"%s\", %gx%g)", size,
141                     size->name, size->width, size->length));
142
143       return (size);
144     }
145     else
146     {
147      /*
148       * Lookup by name...
149       */
150
151       for (i = ppd->num_sizes, size = ppd->sizes; i > 0; i --, size ++)
152         if (!_cups_strcasecmp(name, size->name))
153         {
154           DEBUG_printf(("3ppdPageSize: Returning %p (\"%s\", %gx%g)", size,
155                         size->name, size->width, size->length));
156
157           return (size);
158         }
159     }
160   }
161   else
162   {
163    /*
164     * Find default...
165     */
166
167     for (i = ppd->num_sizes, size = ppd->sizes; i > 0; i --, size ++)
168       if (size->marked)
169       {
170         DEBUG_printf(("3ppdPageSize: Returning %p (\"%s\", %gx%g)", size,
171                       size->name, size->width, size->length));
172
173         return (size);
174       }
175   }
176
177   DEBUG_puts("3ppdPageSize: Size not found, returning NULL");
178
179   return (NULL);
180 }
181
182
183 /*
184  * 'ppdPageSizeLimits()' - Return the custom page size limits.
185  *
186  * This function returns the minimum and maximum custom page sizes and printable
187  * areas based on the currently-marked (selected) options.
188  *
189  * If the specified PPD file does not support custom page sizes, both
190  * "minimum" and "maximum" are filled with zeroes.
191  *
192  * @since CUPS 1.4/macOS 10.6@
193  */
194
195 int                                     /* O - 1 if custom sizes are supported, 0 otherwise */
196 ppdPageSizeLimits(ppd_file_t *ppd,      /* I - PPD file record */
197                   ppd_size_t *minimum,  /* O - Minimum custom size */
198                   ppd_size_t *maximum)  /* O - Maximum custom size */
199 {
200   ppd_choice_t  *qualifier2,            /* Second media qualifier */
201                 *qualifier3;            /* Third media qualifier */
202   ppd_attr_t    *attr;                  /* Attribute */
203   float         width,                  /* Min/max width */
204                 length;                 /* Min/max length */
205   char          spec[PPD_MAX_NAME];     /* Selector for min/max */
206
207
208  /*
209   * Range check input...
210   */
211
212   if (!ppd || !ppd->variable_sizes || !minimum || !maximum)
213   {
214     if (minimum)
215       memset(minimum, 0, sizeof(ppd_size_t));
216
217     if (maximum)
218       memset(maximum, 0, sizeof(ppd_size_t));
219
220     return (0);
221   }
222
223  /*
224   * See if we have the cupsMediaQualifier2 and cupsMediaQualifier3 attributes...
225   */
226
227   cupsArraySave(ppd->sorted_attrs);
228
229   if ((attr = ppdFindAttr(ppd, "cupsMediaQualifier2", NULL)) != NULL &&
230       attr->value)
231     qualifier2 = ppdFindMarkedChoice(ppd, attr->value);
232   else
233     qualifier2 = NULL;
234
235   if ((attr = ppdFindAttr(ppd, "cupsMediaQualifier3", NULL)) != NULL &&
236       attr->value)
237     qualifier3 = ppdFindMarkedChoice(ppd, attr->value);
238   else
239     qualifier3 = NULL;
240
241  /*
242   * Figure out the current minimum width and length...
243   */
244
245   width  = ppd->custom_min[0];
246   length = ppd->custom_min[1];
247
248   if (qualifier2)
249   {
250    /*
251     * Try getting cupsMinSize...
252     */
253
254     if (qualifier3)
255     {
256       snprintf(spec, sizeof(spec), ".%s.%s", qualifier2->choice,
257                qualifier3->choice);
258       attr = ppdFindAttr(ppd, "cupsMinSize", spec);
259     }
260     else
261       attr = NULL;
262
263     if (!attr)
264     {
265       snprintf(spec, sizeof(spec), ".%s.", qualifier2->choice);
266       attr = ppdFindAttr(ppd, "cupsMinSize", spec);
267     }
268
269     if (!attr && qualifier3)
270     {
271       snprintf(spec, sizeof(spec), "..%s", qualifier3->choice);
272       attr = ppdFindAttr(ppd, "cupsMinSize", spec);
273     }
274
275     if ((attr && attr->value &&
276          sscanf(attr->value, "%f%f", &width, &length) != 2) || !attr)
277     {
278       width  = ppd->custom_min[0];
279       length = ppd->custom_min[1];
280     }
281   }
282
283   minimum->width  = width;
284   minimum->length = length;
285   minimum->left   = ppd->custom_margins[0];
286   minimum->bottom = ppd->custom_margins[1];
287   minimum->right  = width - ppd->custom_margins[2];
288   minimum->top    = length - ppd->custom_margins[3];
289
290  /*
291   * Figure out the current maximum width and length...
292   */
293
294   width  = ppd->custom_max[0];
295   length = ppd->custom_max[1];
296
297   if (qualifier2)
298   {
299    /*
300     * Try getting cupsMaxSize...
301     */
302
303     if (qualifier3)
304     {
305       snprintf(spec, sizeof(spec), ".%s.%s", qualifier2->choice,
306                qualifier3->choice);
307       attr = ppdFindAttr(ppd, "cupsMaxSize", spec);
308     }
309     else
310       attr = NULL;
311
312     if (!attr)
313     {
314       snprintf(spec, sizeof(spec), ".%s.", qualifier2->choice);
315       attr = ppdFindAttr(ppd, "cupsMaxSize", spec);
316     }
317
318     if (!attr && qualifier3)
319     {
320       snprintf(spec, sizeof(spec), "..%s", qualifier3->choice);
321       attr = ppdFindAttr(ppd, "cupsMaxSize", spec);
322     }
323
324     if (!attr ||
325         (attr->value && sscanf(attr->value, "%f%f", &width, &length) != 2))
326     {
327       width  = ppd->custom_max[0];
328       length = ppd->custom_max[1];
329     }
330   }
331
332   maximum->width  = width;
333   maximum->length = length;
334   maximum->left   = ppd->custom_margins[0];
335   maximum->bottom = ppd->custom_margins[1];
336   maximum->right  = width - ppd->custom_margins[2];
337   maximum->top    = length - ppd->custom_margins[3];
338
339  /*
340   * Return the min and max...
341   */
342
343   cupsArrayRestore(ppd->sorted_attrs);
344
345   return (1);
346 }
347
348
349 /*
350  * 'ppdPageWidth()' - Get the page width for the given size.
351  */
352
353 float                           /* O - Width of page in points or 0.0 */
354 ppdPageWidth(ppd_file_t *ppd,   /* I - PPD file record */
355              const char *name)  /* I - Size name */
356 {
357   ppd_size_t    *size;          /* Page size */
358
359
360   if ((size = ppdPageSize(ppd, name)) == NULL)
361     return (0.0);
362   else
363     return (size->width);
364 }
365
366
367 /*
368  * 'ppdPageLength()' - Get the page length for the given size.
369  */
370
371 float                           /* O - Length of page in points or 0.0 */
372 ppdPageLength(ppd_file_t *ppd,  /* I - PPD file */
373               const char *name) /* I - Size name */
374 {
375   ppd_size_t    *size;          /* Page size */
376
377
378   if ((size = ppdPageSize(ppd, name)) == NULL)
379     return (0.0);
380   else
381     return (size->length);
382 }