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