]> git.ipfire.org Git - thirdparty/cups-filters.git/commitdiff
libcupsfilters: Make cupsRasterParseIPPOptions() work correctly with PPDs
authorTill Kamppeter <till.kamppeter@gmail.com>
Tue, 12 Oct 2021 11:33:26 +0000 (13:33 +0200)
committerTill Kamppeter <till.kamppeter@gmail.com>
Tue, 12 Oct 2021 11:33:26 +0000 (13:33 +0200)
cupsRasterParseIPPOptions() interprets job options/IPP attributes and
their settings just bei their names. This works well when the
destination printer is not described by a PPD file.

If there is a PPD file, their can be weird option and choice names
which do not tell what they are good for, giving wrong
impressions. Only the PostScript or PJL code assigned to the choices
in the PPD file tells what they actually are supposed to do.

A good example for that is the "Resolution" option of Gutenprint. As
the developers of Gutenprint do not want to solely and directly set
the print resolution with this option (as was Adobe's idea for it),
and instead, do more things with it, as having an "Automatic" choice
or variants of the same resolution (for example different dithering
algorithms), but PPD standards require the choices to be "XXXxYYYdpi"
without exceptions, they come with names like "601x600dpi" for the
variants and the PPD's embedded PostScript code contains the actual
resolution.

To avoid that cupsRasterParseIPPOptions() mis-interprets such weird
PPD options, we check whether we are using a PPD (fortunately, we
receive the complete filter data now, in the era of filter functions)
and if so we refrain from parsing options which are in the PPD. Only
if set_defaults = 1 is set, we use them but via a call of
ppdRasterInterpretPPD() and not interpreting them by ourselves
option/choice-name-only.

Now the Gutenprint Printer Application works again.

cupsfilters/raster.c

index 7e46bf2fcfe1ae858ec2003b2fff99cb8f55e0d0..01250bba3671165c7ff00ef0090e232e6431a138 100644 (file)
@@ -1043,10 +1043,11 @@ cupsRasterSetColorSpace(cups_page_header2_t *h, /* I  - Raster header */
 int                                          /* O - -1 on error, 0 on success */
 cupsRasterParseIPPOptions(cups_page_header2_t *h, /* I - Raster header */
                          filter_data_t *data,
-        int pwg_raster,         /* I - 1 if PWG Raster */
-                         int set_defaults)       /* I - If 1, se default values
-                                                    for all fields for which
-                                                    we did not get an option */
+                         int pwg_raster,         /* I - 1 if PWG Raster */
+                         int set_defaults)       /* I - If 1, set default
+                                                    values for all fields for
+                                                    which we did not get an
+                                                    option */
 {
 #ifdef HAVE_CUPS_1_7
   int          i;                      /* Looping var */
@@ -1061,6 +1062,8 @@ cupsRasterParseIPPOptions(cups_page_header2_t *h, /* I - Raster header */
   float         size;                   /* page size dimension */
   int num_options = 0;          /*  number of options */
   cups_option_t *options = NULL;  /*  Options */
+  ppd_option_t  *option;
+
 
  /*
   * Range check input...
@@ -1069,6 +1072,39 @@ cupsRasterParseIPPOptions(cups_page_header2_t *h, /* I - Raster header */
   if (!h)
     return (-1);
 
+ /*
+  * Join the IPP attributes and the CUPS options in a single list
+  */
+  num_options = joinJobOptionsAndAttrs(data, num_options, &options);
+
+ /*
+  * If we have a PPD file in the filter data, take it into account, by
+  * not parsing options which are in the PPD file here.
+  *
+  * They should get parsed and applied separately via the
+  * ppdRasterInterpretPPD() as that function parses the embedded
+  * PostScript code. This way weird things like Gutenprint's
+  * "Resolution" option (choice name is something odd, like
+  * 301x300dpi, and actual resolution can be completely different)
+  * will get treated correctly.
+  *
+  * We mark the option settings in the PPD and call ppdRasterInterpretPPD()
+  * only when we are called with set_defaults = 1. In any case we remove
+  * the options of the PPD from our option list before we start parsing. 
+  */
+
+  if (data->ppd)
+  {
+    if (set_defaults)
+    {
+      ppdMarkOptions(data->ppd, num_options, options);
+      ppdRasterInterpretPPD(h, data->ppd, num_options, options, NULL);
+    }
+    for (option = ppdFirstOption(data->ppd); option;
+        option = ppdNextOption(data->ppd))
+      num_options = cupsRemoveOption(option->keyword, num_options, &options);
+  }
+
  /*
   * Check if the supplied "media" option is a comma-separated list of any
   * combination of page size ("media"), media source ("media-position"),
@@ -1076,8 +1112,6 @@ cupsRasterParseIPPOptions(cups_page_header2_t *h, /* I - Raster header */
   * their dedicated options.
   */
 
-  num_options = joinJobOptionsAndAttrs(data, num_options, &options);
-
   page_size = NULL;
   media_source = NULL;
   media_type = NULL;
@@ -2137,7 +2171,6 @@ cupsRasterParseIPPOptions(cups_page_header2_t *h, /* I - Raster header */
   }
   else if (set_defaults)
     h->cupsRenderingIntent[0] = '\0';
-#endif /* HAVE_CUPS_1_7 */
 
   if (media_source != NULL)
     free(media_source);
@@ -2145,8 +2178,8 @@ cupsRasterParseIPPOptions(cups_page_header2_t *h, /* I - Raster header */
     free(media_type);
   if (page_size != NULL)
     free(page_size);
-
   cupsFreeOptions(num_options, options);
+#endif /* HAVE_CUPS_1_7 */
 
   return (0);
 }