4 * Destination option/media support for CUPS.
6 * Copyright 2012 by Apple Inc.
8 * These coded instructions, statements, and computer programs are the
9 * property of Apple Inc. and are protected by Federal copyright
10 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
11 * which should have been included with this file. If this file is
12 * file is missing or damaged, see the license at "http://www.cups.org/".
14 * This file is subject to the Apple OS-Developed Software exception.
18 * cupsCheckDestSupported() - Check that the option and value are supported
20 * cupsCopyDestConflicts() - Get conflicts and resolutions for a new
22 * cupsCopyDestInfo() - Get the supported values/capabilities for the
24 * cupsFreeDestInfo() - Free destination information obtained using
25 * @link cupsCopyDestInfo@.
26 * cupsGetDestMediaByName() - Get media names, dimensions, and margins.
27 * cupsGetDestMediaBySize() - Get media names, dimensions, and margins.
28 * cups_compare_media_db() - Compare two media entries.
29 * cups_copy_media_db() - Copy a media entry.
30 * cups_create_media_db() - Create the media database.
31 * cups_free_media_cb() - Free a media entry.
32 * cups_get_media_db() - Lookup the media entry for a given size.
33 * cups_is_close_media_db() - Compare two media entries to see if they are
34 * close to the same size.
38 * Include necessary headers...
41 #include "cups-private.h"
48 static int cups_compare_media_db(_cups_media_db_t
*a
,
50 static _cups_media_db_t
*cups_copy_media_db(_cups_media_db_t
*mdb
);
51 static void cups_create_media_db(cups_dinfo_t
*dinfo
);
52 static void cups_free_media_db(_cups_media_db_t
*mdb
);
53 static int cups_get_media_db(cups_dinfo_t
*dinfo
,
54 _pwg_media_t
*pwg
, unsigned flags
,
56 static int cups_is_close_media_db(_cups_media_db_t
*a
,
60 * 'cupsCheckDestSupported()' - Check that the option and value are supported
63 * Returns 1 if supported, 0 otherwise.
68 int /* O - 1 if supported, 0 otherwise */
69 cupsCheckDestSupported(
70 http_t
*http
, /* I - Connection to destination */
71 cups_dest_t
*dest
, /* I - Destination */
72 cups_dinfo_t
*dinfo
, /* I - Destination information */
73 const char *option
, /* I - Option */
74 const char *value
) /* I - Value */
76 int i
; /* Looping var */
77 char temp
[1024]; /* Temporary string */
78 int int_value
; /* Integer value */
79 int xres_value
, /* Horizontal resolution */
80 yres_value
; /* Vertical resolution */
81 ipp_res_t units_value
; /* Resolution units */
82 ipp_attribute_t
*attr
; /* Attribute */
83 _ipp_value_t
*attrval
; /* Current attribute value */
87 * Range check input...
90 if (!http
|| !dest
|| !dinfo
|| !option
|| !value
)
94 * Lookup the attribute...
97 if (strstr(option
, "-supported"))
98 attr
= ippFindAttribute(dinfo
->attrs
, option
, IPP_TAG_ZERO
);
101 snprintf(temp
, sizeof(temp
), "%s-supported", option
);
102 attr
= ippFindAttribute(dinfo
->attrs
, temp
, IPP_TAG_ZERO
);
112 if (!strcmp(option
, "media") && !strncmp(value
, "custom_", 7))
115 * Check range of custom media sizes...
118 _pwg_media_t
*pwg
; /* Current PWG media size info */
119 int min_width
, /* Minimum width */
120 min_length
, /* Minimum length */
121 max_width
, /* Maximum width */
122 max_length
; /* Maximum length */
125 * Get the minimum and maximum size...
128 min_width
= min_length
= INT_MAX
;
129 max_width
= max_length
= 0;
131 for (i
= attr
->num_values
, attrval
= attr
->values
;
135 if (!strncmp(attrval
->string
.text
, "custom_min_", 11) &&
136 (pwg
= _pwgMediaForPWG(attrval
->string
.text
)) != NULL
)
138 min_width
= pwg
->width
;
139 min_length
= pwg
->length
;
141 else if (!strncmp(attrval
->string
.text
, "custom_max_", 11) &&
142 (pwg
= _pwgMediaForPWG(attrval
->string
.text
)) != NULL
)
144 max_width
= pwg
->width
;
145 max_length
= pwg
->length
;
153 if (min_width
< INT_MAX
&& max_width
> 0 &&
154 (pwg
= _pwgMediaForPWG(value
)) != NULL
&&
155 pwg
->width
>= min_width
&& pwg
->width
<= max_width
&&
156 pwg
->length
>= min_length
&& pwg
->length
<= max_length
)
162 * Check literal values...
165 switch (attr
->value_tag
)
167 case IPP_TAG_INTEGER
:
169 int_value
= atoi(value
);
171 for (i
= 0; i
< attr
->num_values
; i
++)
172 if (attr
->values
[i
].integer
== int_value
)
176 case IPP_TAG_BOOLEAN
:
177 return (attr
->values
[0].boolean
);
179 case IPP_TAG_RESOLUTION
:
180 if (sscanf(value
, "%dx%d%15s", &xres_value
, &yres_value
, temp
) != 3)
182 if (sscanf(value
, "%d%15s", &xres_value
, temp
) != 2)
185 yres_value
= xres_value
;
188 if (!strcmp(temp
, "dpi"))
189 units_value
= IPP_RES_PER_INCH
;
190 else if (!strcmp(temp
, "dpc"))
191 units_value
= IPP_RES_PER_CM
;
195 for (i
= attr
->num_values
, attrval
= attr
->values
;
199 if (attrval
->resolution
.xres
== xres_value
&&
200 attrval
->resolution
.yres
== yres_value
&&
201 attrval
->resolution
.units
== units_value
)
208 case IPP_TAG_KEYWORD
:
209 case IPP_TAG_CHARSET
:
211 case IPP_TAG_URISCHEME
:
212 case IPP_TAG_MIMETYPE
:
213 case IPP_TAG_LANGUAGE
:
214 case IPP_TAG_TEXTLANG
:
215 case IPP_TAG_NAMELANG
:
216 for (i
= 0; i
< attr
->num_values
; i
++)
217 if (!strcmp(attr
->values
[i
].string
.text
, value
))
227 * If we get there the option+value is not supported...
235 * 'cupsCopyDestConflicts()' - Get conflicts and resolutions for a new
238 * "num_options" and "options" represent the currently selected options by the
239 * user. "new_option" and "new_value" are the setting the user has just
242 * Returns 1 if there is a conflict and 0 otherwise.
244 * If "num_conflicts" and "conflicts" are not NULL, they are set to contain the
245 * list of conflicting option/value pairs. Similarly, if "num_resolved" and
246 * "resolved" are not NULL they will be set to the list of changes needed to
247 * resolve the conflict.
249 * If cupsCopyDestConflicts returns 1 but "num_resolved" and "resolved" are set
250 * to 0 and NULL, respectively, then the conflict cannot be resolved.
255 int /* O - 1 if there is a conflict */
256 cupsCopyDestConflicts(
257 http_t
*http
, /* I - Connection to destination */
258 cups_dest_t
*dest
, /* I - Destination */
259 cups_dinfo_t
*dinfo
, /* I - Destination information */
260 int num_options
, /* I - Number of current options */
261 cups_option_t
*options
, /* I - Current options */
262 const char *new_option
, /* I - New option */
263 const char *new_value
, /* I - New value */
264 int *num_conflicts
, /* O - Number of conflicting options */
265 cups_option_t
**conflicts
, /* O - Conflicting options */
266 int *num_resolved
, /* O - Number of options to resolve */
267 cups_option_t
**resolved
) /* O - Resolved options */
270 * Clear returned values...
286 * Range check input...
289 if (!http
|| !dest
|| !dinfo
|| !new_option
|| !new_value
||
290 (num_conflicts
!= NULL
) != (conflicts
!= NULL
) ||
291 (num_resolved
!= NULL
) != (resolved
!= NULL
))
295 * Check for an resolve any conflicts...
298 /* TODO: implement me! */
305 * 'cupsCopyDestInfo()' - Get the supported values/capabilities for the
308 * The caller is responsible for calling @link cupsFreeDestInfo@ on the return
309 * value. @code NULL@ is returned on error.
314 cups_dinfo_t
* /* O - Destination information */
316 http_t
*http
, /* I - Connection to destination */
317 cups_dest_t
*dest
) /* I - Destination */
319 cups_dinfo_t
*dinfo
; /* Destination information */
320 ipp_t
*request
, /* Get-Printer-Attributes request */
321 *response
; /* Supported attributes */
322 const char *uri
; /* Printer URI */
323 char resource
[1024]; /* Resource path */
324 int version
; /* IPP version */
325 ipp_status_t status
; /* Status of request */
326 static const char * const requested_attrs
[] =
327 { /* Requested attributes */
329 "media-col-database",
330 "printer-description"
334 DEBUG_printf(("cupsCopyDestSupported(http=%p, dest=%p(%s))", http
, dest
,
335 dest
? dest
->name
: ""));
338 * Range check input...
345 * Get the printer URI and resource path...
348 if ((uri
= _cupsGetDestResource(dest
, resource
, sizeof(resource
))) == NULL
)
352 * Get the supported attributes...
360 * Send a Get-Printer-Attributes request...
363 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
364 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri", NULL
,
366 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
368 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
369 "requested-attributes",
370 (int)(sizeof(requested_attrs
) / sizeof(requested_attrs
[0])),
371 NULL
, requested_attrs
);
372 response
= cupsDoRequest(http
, request
, resource
);
373 status
= cupsLastError();
375 if (status
> IPP_OK_SUBST
)
377 DEBUG_printf(("cupsCopyDestSupported: Get-Printer-Attributes for '%s' "
378 "returned %s (%s)", dest
->name
, ippErrorString(status
),
379 cupsLastErrorString()));
384 if (status
== IPP_VERSION_NOT_SUPPORTED
&& version
> 11)
393 * Allocate a cups_dinfo_t structure and return it...
396 if ((dinfo
= calloc(1, sizeof(cups_dinfo_t
))) == NULL
)
398 _cupsSetError(IPP_INTERNAL_ERROR
, strerror(errno
), 0);
404 dinfo
->resource
= _cupsStrAlloc(resource
);
405 dinfo
->attrs
= response
;
412 * 'cupsFreeDestInfo()' - Free destination information obtained using
413 * @link cupsCopyDestInfo@.
417 cupsFreeDestInfo(cups_dinfo_t
*dinfo
) /* I - Destination information */
420 * Range check input...
427 * Free memory and return...
430 _cupsStrFree(dinfo
->resource
);
432 ippDelete(dinfo
->attrs
);
434 cupsArrayDelete(dinfo
->constraints
);
436 cupsArrayDelete(dinfo
->localizations
);
438 cupsArrayDelete(dinfo
->media_db
);
445 * 'cupsGetDestMediaByName()' - Get media names, dimensions, and margins.
447 * The "media" string is a PWG media name, while "width" and "length" are the
448 * dimensions in hundredths of millimeters. "flags" provides some matching
449 * guidance (multiple flags can be combined):
451 * CUPS_MEDIA_FLAGS_DEFAULT = find the closest size supported by the printer
452 * CUPS_MEDIA_FLAGS_BORDERLESS = find a borderless size
453 * CUPS_MEDIA_FLAGS_DUPLEX = find a size compatible with 2-sided printing
454 * CUPS_MEDIA_FLAGS_EXACT = find an exact match for the size
455 * CUPS_MEDIA_FLAGS_READY = if the printer supports media sensing, find the
456 * size amongst the "ready" media.
458 * The matching result (if any) is returned in the "cups_size_t" structure.
460 * Returns 1 when there is a match and 0 if there is not a match.
465 int /* O - 1 on match, 0 on failure */
466 cupsGetDestMediaByName(
467 http_t
*http
, /* I - Connection to destination */
468 cups_dest_t
*dest
, /* I - Destination */
469 cups_dinfo_t
*dinfo
, /* I - Destination information */
470 const char *media
, /* I - Media name */
471 unsigned flags
, /* I - Media matching flags */
472 cups_size_t
*size
) /* O - Media size information */
474 _pwg_media_t
*pwg
; /* PWG media info */
478 * Range check input...
482 memset(size
, 0, sizeof(cups_size_t
));
484 if (!http
|| !dest
|| !dinfo
|| !media
|| !size
)
486 _cupsSetError(IPP_INTERNAL_ERROR
, strerror(EINVAL
), 0);
491 * Lookup the media size name...
494 if ((pwg
= _pwgMediaForPWG(media
)) == NULL
)
495 if ((pwg
= _pwgMediaForLegacy(media
)) == NULL
)
497 DEBUG_printf(("1cupsGetDestMediaByName: Unknown size '%s'.", media
));
498 _cupsSetError(IPP_INTERNAL_ERROR
, _("Unknown media size name."), 1);
506 return (cups_get_media_db(dinfo
, pwg
, flags
, size
));
511 * 'cupsGetDestMediaBySize()' - Get media names, dimensions, and margins.
513 * The "media" string is a PWG media name, while "width" and "length" are the
514 * dimensions in hundredths of millimeters. "flags" provides some matching
515 * guidance (multiple flags can be combined):
517 * CUPS_MEDIA_FLAGS_DEFAULT = find the closest size supported by the printer
518 * CUPS_MEDIA_FLAGS_BORDERLESS = find a borderless size
519 * CUPS_MEDIA_FLAGS_DUPLEX = find a size compatible with 2-sided printing
520 * CUPS_MEDIA_FLAGS_EXACT = find an exact match for the size
521 * CUPS_MEDIA_FLAGS_READY = if the printer supports media sensing, find the
522 * size amongst the "ready" media.
524 * The matching result (if any) is returned in the "cups_size_t" structure.
526 * Returns 1 when there is a match and 0 if there is not a match.
531 int /* O - 1 on match, 0 on failure */
532 cupsGetDestMediaBySize(
533 http_t
*http
, /* I - Connection to destination */
534 cups_dest_t
*dest
, /* I - Destination */
535 cups_dinfo_t
*dinfo
, /* I - Destination information */
536 int width
, /* I - Media width in hundredths of
538 int length
, /* I - Media length in hundredths of
540 unsigned flags
, /* I - Media matching flags */
541 cups_size_t
*size
) /* O - Media size information */
543 _pwg_media_t
*pwg
; /* PWG media info */
547 * Range check input...
551 memset(size
, 0, sizeof(cups_size_t
));
553 if (!http
|| !dest
|| !dinfo
|| width
<= 0 || length
<= 0 || !size
)
555 _cupsSetError(IPP_INTERNAL_ERROR
, strerror(EINVAL
), 0);
560 * Lookup the media size name...
563 if ((pwg
= _pwgMediaForSize(width
, length
)) == NULL
)
565 DEBUG_printf(("1cupsGetDestMediaBySize: Invalid size %dx%d.", width
,
567 _cupsSetError(IPP_INTERNAL_ERROR
, _("Invalid media size."), 1);
575 return (cups_get_media_db(dinfo
, pwg
, flags
, size
));
580 * 'cups_compare_media_db()' - Compare two media entries.
583 static int /* O - Result of comparison */
584 cups_compare_media_db(
585 _cups_media_db_t
*a
, /* I - First media entries */
586 _cups_media_db_t
*b
) /* I - Second media entries */
588 int result
; /* Result of comparison */
591 if ((result
= a
->width
- b
->width
) == 0)
592 result
= a
->length
- b
->length
;
599 * 'cups_copy_media_db()' - Copy a media entry.
602 static _cups_media_db_t
* /* O - New media entry */
604 _cups_media_db_t
*mdb
) /* I - Media entry to copy */
606 _cups_media_db_t
*temp
; /* New media entry */
609 if ((temp
= calloc(1, sizeof(_cups_media_db_t
))) == NULL
)
613 temp
->color
= _cupsStrAlloc(mdb
->color
);
615 temp
->key
= _cupsStrAlloc(mdb
->key
);
617 temp
->info
= _cupsStrAlloc(mdb
->info
);
619 temp
->size_name
= _cupsStrAlloc(mdb
->size_name
);
621 temp
->source
= _cupsStrAlloc(mdb
->source
);
623 temp
->type
= _cupsStrAlloc(mdb
->type
);
625 temp
->width
= mdb
->width
;
626 temp
->length
= mdb
->length
;
627 temp
->bottom
= mdb
->bottom
;
628 temp
->left
= mdb
->left
;
629 temp
->right
= mdb
->right
;
630 temp
->top
= mdb
->top
;
637 * 'cups_create_media_db()' - Create the media database.
641 cups_create_media_db(
642 cups_dinfo_t
*dinfo
) /* I - Destination information */
644 int i
; /* Looping var */
645 _ipp_value_t
*val
; /* Current value */
646 ipp_attribute_t
*media_col_db
, /* media-col-database */
647 *media_attr
, /* media-xxx */
648 *x_dimension
, /* x-dimension */
649 *y_dimension
; /* y-dimension */
650 _pwg_media_t
*pwg
; /* PWG media info */
651 _cups_media_db_t mdb
; /* Media entry */
654 dinfo
->media_db
= cupsArrayNew3((cups_array_func_t
)cups_compare_media_db
,
656 (cups_acopy_func_t
)cups_copy_media_db
,
657 (cups_afree_func_t
)cups_free_media_db
);
658 dinfo
->min_size
.width
= INT_MAX
;
659 dinfo
->min_size
.length
= INT_MAX
;
660 dinfo
->max_size
.width
= 0;
661 dinfo
->max_size
.length
= 0;
663 if ((media_col_db
= ippFindAttribute(dinfo
->attrs
, "media-col-database",
664 IPP_TAG_BEGIN_COLLECTION
)) != NULL
)
666 _ipp_value_t
*custom
= NULL
; /* Custom size range value */
668 for (i
= media_col_db
->num_values
, val
= media_col_db
->values
;
672 memset(&mdb
, 0, sizeof(mdb
));
674 if ((media_attr
= ippFindAttribute(val
->collection
, "media-size",
675 IPP_TAG_BEGIN_COLLECTION
)) != NULL
)
677 ipp_t
*media_size
= media_attr
->values
[0].collection
;
678 /* media-size collection value */
680 if ((x_dimension
= ippFindAttribute(media_size
, "x-dimension",
681 IPP_TAG_INTEGER
)) != NULL
&&
682 (y_dimension
= ippFindAttribute(media_size
, "y-dimension",
683 IPP_TAG_INTEGER
)) != NULL
)
685 mdb
.width
= x_dimension
->values
[0].integer
;
686 mdb
.length
= y_dimension
->values
[0].integer
;
688 else if ((x_dimension
= ippFindAttribute(media_size
, "x-dimension",
689 IPP_TAG_RANGE
)) != NULL
&&
690 (y_dimension
= ippFindAttribute(media_size
, "y-dimension",
691 IPP_TAG_RANGE
)) != NULL
)
694 * Custom size range; save this as the custom size value with default
695 * margins, then continue; we'll capture the real margins below...
700 dinfo
->min_size
.width
= x_dimension
->values
[0].range
.lower
;
701 dinfo
->min_size
.length
= y_dimension
->values
[0].range
.lower
;
702 dinfo
->min_size
.left
=
703 dinfo
->min_size
.right
= 635; /* Default 1/4" side margins */
704 dinfo
->min_size
.top
=
705 dinfo
->min_size
.bottom
= 1270; /* Default 1/2" top/bottom margins */
707 dinfo
->max_size
.width
= x_dimension
->values
[0].range
.upper
;
708 dinfo
->max_size
.length
= y_dimension
->values
[0].range
.upper
;
709 dinfo
->max_size
.left
=
710 dinfo
->max_size
.right
= 635; /* Default 1/4" side margins */
711 dinfo
->max_size
.top
=
712 dinfo
->max_size
.bottom
= 1270; /* Default 1/2" top/bottom margins */
718 if ((media_attr
= ippFindAttribute(val
->collection
, "media-color",
719 IPP_TAG_ZERO
)) != NULL
&&
720 (media_attr
->value_tag
== IPP_TAG_NAME
||
721 media_attr
->value_tag
== IPP_TAG_NAMELANG
||
722 media_attr
->value_tag
== IPP_TAG_KEYWORD
))
723 mdb
.color
= media_attr
->values
[0].string
.text
;
725 if ((media_attr
= ippFindAttribute(val
->collection
, "media-info",
726 IPP_TAG_TEXT
)) != NULL
)
727 mdb
.info
= media_attr
->values
[0].string
.text
;
729 if ((media_attr
= ippFindAttribute(val
->collection
, "media-key",
730 IPP_TAG_ZERO
)) != NULL
&&
731 (media_attr
->value_tag
== IPP_TAG_NAME
||
732 media_attr
->value_tag
== IPP_TAG_NAMELANG
||
733 media_attr
->value_tag
== IPP_TAG_KEYWORD
))
734 mdb
.key
= media_attr
->values
[0].string
.text
;
736 if ((media_attr
= ippFindAttribute(val
->collection
, "media-size-name",
737 IPP_TAG_ZERO
)) != NULL
&&
738 (media_attr
->value_tag
== IPP_TAG_NAME
||
739 media_attr
->value_tag
== IPP_TAG_NAMELANG
||
740 media_attr
->value_tag
== IPP_TAG_KEYWORD
))
741 mdb
.size_name
= media_attr
->values
[0].string
.text
;
743 if ((media_attr
= ippFindAttribute(val
->collection
, "media-source",
744 IPP_TAG_ZERO
)) != NULL
&&
745 (media_attr
->value_tag
== IPP_TAG_NAME
||
746 media_attr
->value_tag
== IPP_TAG_NAMELANG
||
747 media_attr
->value_tag
== IPP_TAG_KEYWORD
))
748 mdb
.source
= media_attr
->values
[0].string
.text
;
750 if ((media_attr
= ippFindAttribute(val
->collection
, "media-type",
751 IPP_TAG_ZERO
)) != NULL
&&
752 (media_attr
->value_tag
== IPP_TAG_NAME
||
753 media_attr
->value_tag
== IPP_TAG_NAMELANG
||
754 media_attr
->value_tag
== IPP_TAG_KEYWORD
))
755 mdb
.type
= media_attr
->values
[0].string
.text
;
757 if ((media_attr
= ippFindAttribute(val
->collection
, "media-bottom-margin",
758 IPP_TAG_INTEGER
)) != NULL
)
759 mdb
.bottom
= media_attr
->values
[0].integer
;
761 if ((media_attr
= ippFindAttribute(val
->collection
, "media-left-margin",
762 IPP_TAG_INTEGER
)) != NULL
)
763 mdb
.left
= media_attr
->values
[0].integer
;
765 if ((media_attr
= ippFindAttribute(val
->collection
, "media-right-margin",
766 IPP_TAG_INTEGER
)) != NULL
)
767 mdb
.right
= media_attr
->values
[0].integer
;
769 if ((media_attr
= ippFindAttribute(val
->collection
, "media-top-margin",
770 IPP_TAG_INTEGER
)) != NULL
)
771 mdb
.top
= media_attr
->values
[0].integer
;
773 cupsArrayAdd(dinfo
->media_db
, &mdb
);
778 if ((media_attr
= ippFindAttribute(custom
->collection
,
779 "media-bottom-margin",
780 IPP_TAG_INTEGER
)) != NULL
)
782 dinfo
->min_size
.top
=
783 dinfo
->max_size
.top
= media_attr
->values
[0].integer
;
786 if ((media_attr
= ippFindAttribute(custom
->collection
,
788 IPP_TAG_INTEGER
)) != NULL
)
790 dinfo
->min_size
.left
=
791 dinfo
->max_size
.left
= media_attr
->values
[0].integer
;
794 if ((media_attr
= ippFindAttribute(custom
->collection
,
795 "media-right-margin",
796 IPP_TAG_INTEGER
)) != NULL
)
798 dinfo
->min_size
.right
=
799 dinfo
->max_size
.right
= media_attr
->values
[0].integer
;
802 if ((media_attr
= ippFindAttribute(custom
->collection
,
804 IPP_TAG_INTEGER
)) != NULL
)
806 dinfo
->min_size
.top
=
807 dinfo
->max_size
.top
= media_attr
->values
[0].integer
;
811 else if ((media_attr
= ippFindAttribute(dinfo
->attrs
, "media-supported",
812 IPP_TAG_ZERO
)) != NULL
&&
813 (media_attr
->value_tag
== IPP_TAG_NAME
||
814 media_attr
->value_tag
== IPP_TAG_NAMELANG
||
815 media_attr
->value_tag
== IPP_TAG_KEYWORD
))
817 memset(&mdb
, 0, sizeof(mdb
));
820 mdb
.right
= 635; /* Default 1/4" side margins */
822 mdb
.bottom
= 1270; /* Default 1/2" top/bottom margins */
824 for (i
= media_col_db
->num_values
, val
= media_col_db
->values
;
828 if ((pwg
= _pwgMediaForPWG(val
->string
.text
)) == NULL
)
829 if ((pwg
= _pwgMediaForLegacy(val
->string
.text
)) == NULL
)
831 DEBUG_printf(("3cups_create_media_db: Ignoring unknown size '%s'.",
836 mdb
.width
= pwg
->width
;
837 mdb
.length
= pwg
->length
;
839 if (!strncmp(val
->string
.text
, "custom_min_", 11))
841 mdb
.size_name
= NULL
;
842 dinfo
->min_size
= mdb
;
844 else if (!strncmp(val
->string
.text
, "custom_max_", 11))
846 mdb
.size_name
= NULL
;
847 dinfo
->max_size
= mdb
;
851 mdb
.size_name
= val
->string
.text
;
853 cupsArrayAdd(dinfo
->media_db
, &mdb
);
861 * 'cups_free_media_cb()' - Free a media entry.
866 _cups_media_db_t
*mdb
) /* I - Media entry to free */
869 _cupsStrFree(mdb
->color
);
871 _cupsStrFree(mdb
->key
);
873 _cupsStrFree(mdb
->info
);
875 _cupsStrFree(mdb
->size_name
);
877 _cupsStrFree(mdb
->source
);
879 _cupsStrFree(mdb
->type
);
886 * 'cups_get_media_db()' - Lookup the media entry for a given size.
889 static int /* O - 1 on match, 0 on failure */
890 cups_get_media_db(cups_dinfo_t
*dinfo
, /* I - Destination information */
891 _pwg_media_t
*pwg
, /* I - PWG media info */
892 unsigned flags
, /* I - Media matching flags */
893 cups_size_t
*size
) /* O - Media size/margin/name info */
895 _cups_media_db_t
*mdb
, /* Current media database entry */
896 *best
= NULL
, /* Best matching entry */
897 key
; /* Search key */
901 * Create the media database as needed...
904 if (!dinfo
->media_db
)
905 cups_create_media_db(dinfo
);
911 memset(&key
, 0, sizeof(key
));
912 key
.width
= pwg
->width
;
913 key
.length
= pwg
->length
;
915 if ((mdb
= cupsArrayFind(dinfo
->media_db
, &key
)) != NULL
)
918 * Found an exact match, let's figure out the best margins for the flags
924 if (flags
& CUPS_MEDIA_FLAGS_BORDERLESS
)
927 * Look for the smallest margins...
930 if (best
->left
!= 0 || best
->right
!= 0 || best
->top
!= 0 ||
933 for (mdb
= (_cups_media_db_t
*)cupsArrayNext(dinfo
->media_db
);
934 mdb
&& !cups_compare_media_db(mdb
, &key
);
935 mdb
= (_cups_media_db_t
*)cupsArrayNext(dinfo
->media_db
))
937 if (mdb
->left
<= best
->left
&& mdb
->right
<= best
->right
&&
938 mdb
->top
<= best
->top
&& mdb
->bottom
<= best
->bottom
)
941 if (mdb
->left
== 0 && mdb
->right
== 0 && mdb
->bottom
== 0 &&
949 * If we need an exact match, return no-match if the size is not
953 if ((flags
& CUPS_MEDIA_FLAGS_EXACT
) &&
954 (best
->left
|| best
->right
|| best
->top
|| best
->bottom
))
957 else if (flags
& CUPS_MEDIA_FLAGS_DUPLEX
)
960 * Look for the largest margins...
963 for (mdb
= (_cups_media_db_t
*)cupsArrayNext(dinfo
->media_db
);
964 mdb
&& !cups_compare_media_db(mdb
, &key
);
965 mdb
= (_cups_media_db_t
*)cupsArrayNext(dinfo
->media_db
))
967 if (mdb
->left
>= best
->left
&& mdb
->right
>= best
->right
&&
968 mdb
->top
>= best
->top
&& mdb
->bottom
>= best
->bottom
)
975 * Look for the smallest non-zero margins...
978 for (mdb
= (_cups_media_db_t
*)cupsArrayNext(dinfo
->media_db
);
979 mdb
&& !cups_compare_media_db(mdb
, &key
);
980 mdb
= (_cups_media_db_t
*)cupsArrayNext(dinfo
->media_db
))
982 if (((mdb
->left
> 0 && mdb
->left
<= best
->left
) || best
->left
== 0) &&
983 ((mdb
->right
> 0 && mdb
->right
<= best
->right
) ||
985 ((mdb
->top
> 0 && mdb
->top
<= best
->top
) || best
->top
== 0) &&
986 ((mdb
->bottom
> 0 && mdb
->bottom
<= best
->bottom
) ||
992 else if (flags
& CUPS_MEDIA_FLAGS_EXACT
)
995 * See if we can do this as a custom size...
998 if (pwg
->width
< dinfo
->min_size
.width
||
999 pwg
->width
> dinfo
->max_size
.width
||
1000 pwg
->length
< dinfo
->min_size
.length
||
1001 pwg
->length
> dinfo
->max_size
.length
)
1002 return (0); /* Out of range */
1004 if ((flags
& CUPS_MEDIA_FLAGS_BORDERLESS
) &&
1005 (dinfo
->min_size
.left
> 0 || dinfo
->min_size
.right
> 0 ||
1006 dinfo
->min_size
.top
> 0 || dinfo
->min_size
.bottom
> 0))
1007 return (0); /* Not borderless */
1009 key
.size_name
= (char *)pwg
->pwg
;
1010 key
.bottom
= dinfo
->min_size
.bottom
;
1011 key
.left
= dinfo
->min_size
.left
;
1012 key
.right
= dinfo
->min_size
.right
;
1013 key
.top
= dinfo
->min_size
.top
;
1017 else if (pwg
->width
>= dinfo
->min_size
.width
&&
1018 pwg
->width
<= dinfo
->max_size
.width
&&
1019 pwg
->length
>= dinfo
->min_size
.length
&&
1020 pwg
->length
<= dinfo
->max_size
.length
)
1023 * Map to custom size...
1026 key
.size_name
= (char *)pwg
->pwg
;
1027 key
.bottom
= dinfo
->min_size
.bottom
;
1028 key
.left
= dinfo
->min_size
.left
;
1029 key
.right
= dinfo
->min_size
.right
;
1030 key
.top
= dinfo
->min_size
.top
;
1037 * Find a close size...
1040 for (mdb
= (_cups_media_db_t
*)cupsArrayFirst(dinfo
->media_db
);
1042 mdb
= (_cups_media_db_t
*)cupsArrayNext(dinfo
->media_db
))
1043 if (cups_is_close_media_db(mdb
, &key
))
1051 if (flags
& CUPS_MEDIA_FLAGS_BORDERLESS
)
1054 * Look for the smallest margins...
1057 if (best
->left
!= 0 || best
->right
!= 0 || best
->top
!= 0 ||
1060 for (mdb
= (_cups_media_db_t
*)cupsArrayNext(dinfo
->media_db
);
1061 mdb
&& cups_is_close_media_db(mdb
, &key
);
1062 mdb
= (_cups_media_db_t
*)cupsArrayNext(dinfo
->media_db
))
1064 if (mdb
->left
<= best
->left
&& mdb
->right
<= best
->right
&&
1065 mdb
->top
<= best
->top
&& mdb
->bottom
<= best
->bottom
)
1068 if (mdb
->left
== 0 && mdb
->right
== 0 && mdb
->bottom
== 0 &&
1075 else if (flags
& CUPS_MEDIA_FLAGS_DUPLEX
)
1078 * Look for the largest margins...
1081 for (mdb
= (_cups_media_db_t
*)cupsArrayNext(dinfo
->media_db
);
1082 mdb
&& cups_is_close_media_db(mdb
, &key
);
1083 mdb
= (_cups_media_db_t
*)cupsArrayNext(dinfo
->media_db
))
1085 if (mdb
->left
>= best
->left
&& mdb
->right
>= best
->right
&&
1086 mdb
->top
>= best
->top
&& mdb
->bottom
>= best
->bottom
)
1093 * Look for the smallest non-zero margins...
1096 for (mdb
= (_cups_media_db_t
*)cupsArrayNext(dinfo
->media_db
);
1097 mdb
&& cups_is_close_media_db(mdb
, &key
);
1098 mdb
= (_cups_media_db_t
*)cupsArrayNext(dinfo
->media_db
))
1100 if (((mdb
->left
> 0 && mdb
->left
<= best
->left
) || best
->left
== 0) &&
1101 ((mdb
->right
> 0 && mdb
->right
<= best
->right
) ||
1102 best
->right
== 0) &&
1103 ((mdb
->top
> 0 && mdb
->top
<= best
->top
) || best
->top
== 0) &&
1104 ((mdb
->bottom
> 0 && mdb
->bottom
<= best
->bottom
) ||
1114 * Return the matching size...
1117 if (best
->size_name
)
1118 strlcpy(size
->media
, best
->size_name
, sizeof(size
->media
));
1120 strlcpy(size
->media
, best
->key
, sizeof(size
->media
));
1122 strlcpy(size
->media
, pwg
->pwg
, sizeof(size
->media
));
1124 size
->width
= best
->width
;
1125 size
->length
= best
->length
;
1126 size
->bottom
= best
->bottom
;
1127 size
->left
= best
->left
;
1128 size
->right
= best
->right
;
1129 size
->top
= best
->top
;
1139 * 'cups_is_close_media_db()' - Compare two media entries to see if they are
1140 * close to the same size.
1142 * Currently we use 5 points (from PostScript) as the matching range...
1145 static int /* O - 1 if the sizes are close */
1146 cups_is_close_media_db(
1147 _cups_media_db_t
*a
, /* I - First media entries */
1148 _cups_media_db_t
*b
) /* I - Second media entries */
1150 int dwidth
, /* Difference in width */
1151 dlength
; /* Difference in length */
1154 dwidth
= a
->width
- b
->width
;
1155 dlength
= a
->length
- b
->length
;
1157 return (dwidth
>= -176 && dwidth
<= 176 &&
1158 dlength
>= -176 && dlength
<= 176);