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