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 } 383