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