--- a/cups/ppd-cache.c
+++ b/cups/ppd-cache.c
@@ -472,6 +472,8 @@
   _pwg_print_color_mode_t print_color_mode;
 					/* Print color mode for preset */
   _pwg_print_quality_t print_quality;	/* Print quality for preset */
+  _pwg_print_content_optimize_t print_content_optimize;
+                                        /* Content optimize for preset */
 
 
   DEBUG_printf(("_ppdCacheCreateWithFile(filename=\"%s\")", filename));
@@ -897,6 +899,28 @@
           cupsParseOptions(valueptr, 0,
 	                   pc->presets[print_color_mode] + print_quality);
     }
+    else if (!_cups_strcasecmp(line, "OptimizePreset"))
+    {
+     /*
+      * Preset print_content_optimize name=value ...
+      */
+
+      print_content_optimize = (_pwg_print_content_optimize_t)strtol(value, &valueptr, 10);
+
+      if (print_content_optimize < _PWG_PRINT_CONTENT_OPTIMIZE_AUTO ||
+          print_content_optimize >= _PWG_PRINT_CONTENT_OPTIMIZE_MAX ||
+	  valueptr == value || !*valueptr)
+      {
+        DEBUG_printf(("ppdCacheCreateWithFile: Bad Optimize Preset on line %d.",
+	              linenum));
+	_cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
+	goto create_error;
+      }
+
+      pc->num_optimize_presets[print_content_optimize] =
+          cupsParseOptions(valueptr, 0,
+	                   pc->optimize_presets + print_content_optimize);
+    }
     else if (!_cups_strcasecmp(line, "SidesOption"))
       pc->sides_option = strdup(value);
     else if (!_cups_strcasecmp(line, "Sides1Sided"))
@@ -1024,6 +1048,7 @@
 			*ppd_option;	/* Other PPD option */
   ppd_choice_t		*choice;	/* Current InputSlot/MediaType */
   pwg_map_t		*map;		/* Current source/type map */
+  int                   preset_added = 0; /* Preset definition found in PPD? */
   ppd_attr_t		*ppd_attr;	/* Current PPD preset attribute */
   int			num_options;	/* Number of preset options and props */
   cups_option_t		*options;	/* Preset options and properties */
@@ -1434,6 +1459,10 @@
   if ((ppd_attr = ppdFindAttr(ppd, "APPrinterPreset", NULL)) != NULL)
   {
    /*
+    * "Classic" Mac OS approach
+    */
+
+   /*
     * Copy and convert APPrinterPreset (output-mode + print-quality) data...
     */
 
@@ -1533,114 +1562,133 @@
 	      _ppdParseOptions(ppd_attr->value, 0,
 	                       pc->presets[pwg_print_color_mode] +
 			           pwg_print_quality, _PPD_PARSE_OPTIONS);
+	preset_added = 1;
       }
 
       cupsFreeOptions(num_options, options);
     }
     while ((ppd_attr = ppdFindNextAttr(ppd, "APPrinterPreset", NULL)) != NULL);
-  }
-
-  if (!pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][_PWG_PRINT_QUALITY_DRAFT] &&
-      !pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][_PWG_PRINT_QUALITY_NORMAL] &&
-      !pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][_PWG_PRINT_QUALITY_HIGH])
-  {
-   /*
-    * Try adding some common color options to create grayscale presets.  These
-    * are listed in order of popularity...
-    */
-
-    const char	*color_option = NULL,	/* Color control option */
-		*gray_choice = NULL;	/* Choice to select grayscale */
-
-    if ((color_model = ppdFindOption(ppd, "ColorModel")) != NULL &&
-        ppdFindChoice(color_model, "Gray"))
-    {
-      color_option = "ColorModel";
-      gray_choice  = "Gray";
-    }
-    else if ((color_model = ppdFindOption(ppd, "HPColorMode")) != NULL &&
-             ppdFindChoice(color_model, "grayscale"))
-    {
-      color_option = "HPColorMode";
-      gray_choice  = "grayscale";
-    }
-    else if ((color_model = ppdFindOption(ppd, "BRMonoColor")) != NULL &&
-             ppdFindChoice(color_model, "Mono"))
-    {
-      color_option = "BRMonoColor";
-      gray_choice  = "Mono";
-    }
-    else if ((color_model = ppdFindOption(ppd, "CNIJSGrayScale")) != NULL &&
-             ppdFindChoice(color_model, "1"))
-    {
-      color_option = "CNIJSGrayScale";
-      gray_choice  = "1";
-    }
-    else if ((color_model = ppdFindOption(ppd, "HPColorAsGray")) != NULL &&
-             ppdFindChoice(color_model, "True"))
-    {
-      color_option = "HPColorAsGray";
-      gray_choice  = "True";
-    }
 
-    if (color_option && gray_choice)
+    if (preset_added &&
+	!pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][_PWG_PRINT_QUALITY_DRAFT] &&
+	!pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][_PWG_PRINT_QUALITY_NORMAL] &&
+	!pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][_PWG_PRINT_QUALITY_HIGH])
     {
      /*
-      * Copy and convert ColorModel (output-mode) data...
+      * Try adding some common color options to create grayscale presets. These
+      * are listed in order of popularity...
       */
 
-      cups_option_t	*coption,	/* Color option */
-			  *moption;	/* Monochrome option */
+      const char	*color_option = NULL,	/* Color control option */
+	                *gray_choice = NULL;	/* Choice to select grayscale */
 
-      for (pwg_print_quality = _PWG_PRINT_QUALITY_DRAFT;
-	   pwg_print_quality < _PWG_PRINT_QUALITY_MAX;
-	   pwg_print_quality ++)
+      if ((color_model = ppdFindOption(ppd, "ColorModel")) != NULL &&
+	  ppdFindChoice(color_model, "Gray"))
       {
-	if (pc->num_presets[_PWG_PRINT_COLOR_MODE_COLOR][pwg_print_quality])
-	{
-	 /*
-	  * Copy the color options...
-	  */
+	color_option = "ColorModel";
+	gray_choice  = "Gray";
+      }
+      else if ((color_model = ppdFindOption(ppd, "HPColorMode")) != NULL &&
+	       ppdFindChoice(color_model, "grayscale"))
+      {
+	color_option = "HPColorMode";
+	gray_choice  = "grayscale";
+      }
+      else if ((color_model = ppdFindOption(ppd, "BRMonoColor")) != NULL &&
+	       ppdFindChoice(color_model, "Mono"))
+      {
+	color_option = "BRMonoColor";
+	gray_choice  = "Mono";
+      }
+      else if ((color_model = ppdFindOption(ppd, "CNIJSGrayScale")) != NULL &&
+	       ppdFindChoice(color_model, "1"))
+      {
+	color_option = "CNIJSGrayScale";
+	gray_choice  = "1";
+      }
+      else if ((color_model = ppdFindOption(ppd, "HPColorAsGray")) != NULL &&
+	       ppdFindChoice(color_model, "True"))
+      {
+	color_option = "HPColorAsGray";
+	gray_choice  = "True";
+      }
+
+      if (color_option && gray_choice)
+      {
+       /*
+	* Copy and convert ColorModel (output-mode) data...
+	*/
+
+	cups_option_t	*coption,	/* Color option */
+			*moption;	/* Monochrome option */
 
-	  num_options = pc->num_presets[_PWG_PRINT_COLOR_MODE_COLOR]
-					[pwg_print_quality];
-	  options     = calloc(sizeof(cups_option_t), (size_t)num_options);
-
-	  if (options)
-	  {
-	    for (i = num_options, moption = options,
-		     coption = pc->presets[_PWG_PRINT_COLOR_MODE_COLOR]
-					   [pwg_print_quality];
-		 i > 0;
-		 i --, moption ++, coption ++)
+	for (pwg_print_quality = _PWG_PRINT_QUALITY_DRAFT;
+	     pwg_print_quality < _PWG_PRINT_QUALITY_MAX;
+	     pwg_print_quality ++)
+        {
+	  if (pc->num_presets[_PWG_PRINT_COLOR_MODE_COLOR][pwg_print_quality])
+	  {
+	   /*
+	    * Copy the color options...
+	    */
+
+	    num_options = pc->num_presets[_PWG_PRINT_COLOR_MODE_COLOR]
+	                                 [pwg_print_quality];
+	    options     = calloc(sizeof(cups_option_t), (size_t)num_options);
+
+	    if (options)
 	    {
-	      moption->name  = _cupsStrRetain(coption->name);
-	      moption->value = _cupsStrRetain(coption->value);
-	    }
+	      for (i = num_options, moption = options,
+		       coption = pc->presets[_PWG_PRINT_COLOR_MODE_COLOR]
+					    [pwg_print_quality];
+		   i > 0;
+		   i --, moption ++, coption ++)
+	      {
+		moption->name  = _cupsStrRetain(coption->name);
+		moption->value = _cupsStrRetain(coption->value);
+	      }
 
-	    pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][pwg_print_quality] =
+	      pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][pwg_print_quality] =
 		num_options;
-	    pc->presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][pwg_print_quality] =
+	      pc->presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][pwg_print_quality] =
 		options;
+	    }
 	  }
-	}
-	else if (pwg_print_quality != _PWG_PRINT_QUALITY_NORMAL)
-	  continue;
-
-       /*
-	* Add the grayscale option to the preset...
-	*/
+	  else if (pwg_print_quality != _PWG_PRINT_QUALITY_NORMAL)
+	    continue;
 
-	pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][pwg_print_quality] =
-	    cupsAddOption(color_option, gray_choice,
-			  pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME]
-					  [pwg_print_quality],
-			  pc->presets[_PWG_PRINT_COLOR_MODE_MONOCHROME] +
+	  /*
+	   * Add the grayscale option to the preset...
+	   */
+
+	  pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][pwg_print_quality] =
+	      cupsAddOption(color_option, gray_choice,
+			    pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME]
+					   [pwg_print_quality],
+			    pc->presets[_PWG_PRINT_COLOR_MODE_MONOCHROME] +
 			      pwg_print_quality);
+	}
       }
     }
   }
 
+  if (!preset_added)
+  {
+   /*
+    * Auto-association of PPD file option settings with the IPP job attributes
+    * print-color-mode, print-quality, and print-content-optimize
+    *
+    * This is used to retro-fit PPD files and classic CUPS drivers into
+    * Printer Applications, which are IPP printers for the clients and so
+    * should get controlled by standard IPP attributes as far as possible
+    *
+    * Note that settings assigned to print-content-optimize are only used
+    * when printing with "high" print-quality
+    */
+
+    _ppdCacheAssignPresets(ppd, pc);
+  }
+
  /*
   * Copy and convert Duplex (sides) data...
   */
@@ -1974,13 +2022,996 @@
 
 
 /*
+ * '_ppdCacheAssignPresets()' - Go through all the options and choices in
+ *                              the PPD to find out which influence
+ *                              color/bw, print quality, and content
+ *                              optimizations to assign them to the prsets
+ *                              so that jobs can easily be controlled with
+ *                              standard IPP attributes
+ */
+
+void
+_ppdCacheAssignPresets(ppd_file_t *ppd,
+		       _ppd_cache_t *pc)
+{
+  /* properties and scores for each choice of the option under evaluation */
+  typedef struct choice_properties_s
+  {
+    int sets_mono,     /* Does this choice switch to monochrome printing? */
+        sets_color,    /*                     ... to color printing? */
+        sets_draft,    /*                     ... to draft/lower quality? */
+        sets_normal,   /*                     ... to standard/normal quality? */
+        sets_high,     /*                     ... to high/better quality? */
+        for_photo,     /* Does this choice improve photo printing? */
+        for_graphics,  /*                      ... graphics printing? */
+        for_text,      /*                      ... text printing? */
+        for_tg,        /*                      ... text & graphics printing? */
+        is_default;    /* Is this choice the PPD default? */
+    unsigned int res_x,/* Does this choice set resolution (0 if not)? */
+                 res_y;
+  } choice_properties_t;
+  int                    i, j, k, l;
+  unsigned int           m;                /* Ratio for lowering or improving
+					      resolution */
+  int                    pass;             /* Passes to go through to find best
+					      choice */
+  ppd_group_t            *group;           /* PPD option group */
+  ppd_option_t	         *option;          /* PPD option */
+  int                    is_color;         /* Is this PPD for a color printer */
+  unsigned int           base_res_x = 0,   /* Base resolution of the pPD file */
+                         base_res_y = 0;
+  cups_page_header2_t    header,           /* CUPS Raster header to investigate
+					      embedded code in PPD */
+                         optheader;        /* CUPS Raster header to investigate
+					      embedded code in one PPD option */
+  int                    preferred_bits;   /* for _cupsRasterExecPS() function
+					      call */
+  ppd_attr_t             *ppd_attr;        /* PPD attribute */
+  int                    res_factor = 1;   /* Weights of the scores for the */
+  int                    name_factor = 10; /* print quality */
+  int                    color_factor = 1000;
+
+  /* Do we have a color printer ? */
+  is_color = (ppd->color_device ? 1 : 0);
+
+  /* what is the base/default resolution for this PPD? */
+  ppdMarkDefaults(ppd);
+  cupsRasterInterpretPPD(&header, ppd, 0, NULL, NULL);
+  if (header.HWResolution[0] != 100 || header.HWResolution[1] != 100)
+  {
+    base_res_x = header.HWResolution[0];
+    base_res_y = header.HWResolution[1];
+  }
+  else if ((ppd_attr = ppdFindAttr(ppd, "DefaultResolution", NULL)) != NULL)
+  {
+    /* Use the PPD-defined default resolution... */
+    if (sscanf(ppd_attr->value, "%dx%d", &base_res_x, &base_res_y) == 1)
+      base_res_y = base_res_x;
+  }
+
+  /* Go through all options of the PPD file */
+  for (i = ppd->num_groups, group = ppd->groups;
+       i > 0;
+       i --, group ++)
+  {
+    /* Skip the "Installable Options" group */
+    if (_cups_strncasecmp(group->name, "Installable", 11) == 0)
+      continue;
+
+    for (j = group->num_options, option = group->options;
+         j > 0;
+         j --, option ++)
+    {
+      int sets_color_mode = 0,         /* Scores for current choice */
+	  sets_quality = 0,
+	  sets_optimization = 0;
+      int best_mono_draft = 0,         /* Best score for each preset for this
+				          option */
+          best_mono_normal = 0,
+          best_mono_high = 0,
+          best_color_draft = 0,
+          best_color_normal = 0,
+          best_color_high = 0,
+          best_photo = 0,
+          best_graphics = 0,
+          best_text = 0,
+	  best_tg = 0;
+      int default_ch = -1,             /* Index of default choice */
+	  best_mono_draft_ch = -1,     /* Index of choice with best score */
+          best_mono_normal_ch = -1,
+          best_mono_high_ch = -1,
+          best_color_draft_ch = -1,
+          best_color_normal_ch = -1,
+          best_color_high_ch = -1,
+          best_photo_ch = -1,
+          best_graphics_ch = -1,
+          best_text_ch = -1,
+	  best_tg_ch = -1;
+      cups_array_t *choice_properties; /* Array of properties of all choices
+					  of this option */
+      choice_properties_t *properties; /* Properties of current choice */
+      char *o,                         /* Name of current option */
+	   *c,                         /* Name of current choice */
+	   *p;                         /* Pointer into string */
+      int  score;                      /* Temp variable for score
+					  calculations */
+
+      o = option->keyword;
+
+      /* Skip options which do not change color mode and quality or
+         generally do not make sense in presets */
+      if (_cups_strcasecmp(o, "PageSize") == 0 ||
+	  _cups_strcasecmp(o, "PageRegion") == 0 ||
+	  _cups_strcasecmp(o, "InputSlot") == 0 ||
+	  _cups_strcasecmp(o, "MediaSource") == 0 ||
+	  _cups_strcasecmp(o, "MediaType") == 0 ||
+	  _cups_strcasecmp(o, "OutputBin") == 0 ||
+	  _cups_strcasecmp(o, "Duplex") == 0 ||
+	  _cups_strcasecmp(o, "JCLDuplex") == 0 ||
+	  _cups_strcasecmp(o, "EFDuplex") == 0 ||
+	  _cups_strcasecmp(o, "EFDuplexing") == 0 ||
+	  _cups_strcasecmp(o, "ARDuplex") == 0 ||
+	  _cups_strcasecmp(o, "KD03Duplex") == 0 ||
+	  _cups_strcasecmp(o, "Collate") == 0)
+	continue;
+
+      /* Set members options of composite options in Foomatic to stay
+         controlled by the composite option */
+
+      /* Composite options in Foomatic are options which set a number
+	 of other options, so each choice of them is the same as a
+	 preset in CUPS.  In addition, some PPDs in Foomatic have a
+	 composite option named "PrintoutMode" with 6 choices, exactly
+	 the 6 of the grid of CUPS presets, color/mono in draft,
+	 mediaum, and high quality. The composite options are created
+	 by hand, so they surely do for what they are intended for and
+	 so they are safer as this preset auto-generation
+	 algorithm. Therefore we only let the composite option be set
+	 in our presets and set the member options to leave the
+	 control at the composite option */
+
+      if (strstr(ppd->nickname, "Foomatic") &&
+	  !strncmp(option->choices[0].choice, "From", 4) &&
+	  ppdFindOption(ppd, option->choices[0].choice + 4))
+      {
+	for (k = 0; k < 2; k ++)
+	  for (l = 0; l < 3; l ++)
+	    if (cupsGetOption(option->choices[0].choice + 4,
+			      pc->num_presets[k][l], pc->presets[k][l]))
+	      pc->num_presets[k][l] =
+		cupsAddOption(o, option->choices[0].choice,
+			      pc->num_presets[k][l], &(pc->presets[k][l]));
+	for (k = 0; k < 5; k ++)
+	  if (cupsGetOption(option->choices[0].choice + 4,
+			    pc->num_optimize_presets[k],
+			    pc->optimize_presets[k]))
+	    pc->num_optimize_presets[k] =
+	      cupsAddOption(o, option->choices[0].choice,
+			    pc->num_optimize_presets[k],
+			    &(pc->optimize_presets[k]));
+	continue;
+      }
+
+      /* Array for properties of the choices */
+      choice_properties = cupsArrayNew(NULL, NULL);
+
+      /*
+       * Gather the data for each choice
+       */
+
+      for (k = 0; k < option->num_choices; k ++)
+      {
+	properties =
+	  (choice_properties_t *)calloc(1, sizeof(choice_properties_t));
+
+	c = option->choices[k].choice;
+
+	/* Is this the default choice? (preferred for "normal" quality,
+	   used for color if no choice name suggests being color */
+	if (strcmp(c, option->defchoice) == 0)
+	{
+	  properties->is_default = 1;
+	  default_ch = k;
+	}
+
+       /*
+	* Color/Gray - print-color-mode
+	*/
+
+	/* If we have a color device, check whether this option sets mono or
+	   color printing */
+	if (is_color)
+	{
+	  if (_cups_strcasecmp(o, "CNIJSGrayScale") == 0)
+	  {
+	    if (_cups_strcasecmp(c, "1") == 0)
+	      properties->sets_mono = 2;
+	    else
+	      properties->sets_color = 1;
+	  }
+	  else if (_cups_strcasecmp(o, "HPColorAsGray") == 0 ||  /* HP PostScript */
+		   _cups_strcasecmp(o, "HPPJLColorAsGray") == 0) /* HP PostScript */
+	  {
+	    if (_cups_strcasecmp(c, "True") == 0 ||
+		_cups_strcasecmp(c, "yes") == 0)
+	      properties->sets_mono = 2;
+	    else
+	      properties->sets_color = 1;
+	  }
+	  else if (_cups_strcasecmp(o, "ColorModel") == 0 ||
+		   _cups_strcasecmp(o, "ColorMode") == 0 ||
+		   _cups_strcasecmp(o, "OutputMode") == 0 ||
+		   _cups_strcasecmp(o, "PrintoutMode") == 0 ||
+		   _cups_strcasecmp(o, "ARCMode") == 0 || /* Sharp */
+		   _cups_strcasestr(o, "ColorMode") ||
+		   _cups_strcasecmp(o, "ColorResType") == 0 || /* Toshiba */
+		   _cups_strcasestr(o, "MonoColor")) /* Brother */
+	  {
+	    /* Monochrome/grayscale printing */
+	    if (_cups_strcasestr(c, "Mono") ||
+		_cups_strcasecmp(c, "Black") == 0 ||
+		((p = _cups_strcasestr(c, "Black")) && _cups_strcasestr(p, "White")) ||
+		(_cups_strncasecmp(c, "BW", 2) == 0 && !isalpha(c[2])))
+	      properties->sets_mono = 2;
+	    else if (_cups_strcasestr(c, "Gray") ||
+		     _cups_strcasestr(c, "Grey") ||
+		     _cups_strcasecmp(c, "BlackOnly") == 0) /* Lexmark */
+	      properties->sets_mono = 3;
+
+	    /* Color printing */
+	    if (((p = _cups_strcasestr(c, "CMY")) && !_cups_strcasestr(p, "Gray")) ||
+		_cups_strcasecmp(c, "ColorOnly") == 0 || /* Lexmark */
+		((p = _cups_strcasestr(c, "Adobe")) && _cups_strcasestr(p, "RGB")))
+	      properties->sets_color = 2;
+	    else if (_cups_strcasestr(c, "sRGB"))
+	      properties->sets_color = 4;
+	    else if (_cups_strcasestr(c, "RGB") ||
+		     _cups_strcasestr(c, "Color"))
+	      properties->sets_color = 3;
+	  }
+
+	  /* This option actually sets color mode */
+	  if (properties->sets_mono || properties->sets_color)
+	    sets_color_mode = 1;
+	}
+
+       /*
+	* Output Quality - print-quality
+	*/
+
+	/* check whether this option affects print quality or content
+	   optimization */
+
+	/* Determine influence of the options and choices on the print
+	   quality by their names */
+
+	/* Vendor-specific option and choice names */
+	if (_cups_strcasecmp(o, "ARCPPriority") == 0) /* Sharp */
+	{
+	  if (_cups_strcasecmp(c, "Quality") == 0)
+	    properties->sets_high = 10;
+	  else if (_cups_strcasecmp(c, "Speed") == 0)
+	    properties->sets_draft = 10;
+	}
+	else if (_cups_strcasecmp(o, "BRJpeg") == 0) /* Brother */
+	{
+	  if (_cups_strcasecmp(c, "QualityPrior") == 0)
+	    properties->sets_high = 10;
+	  else if (_cups_strcasecmp(c, "SpeedPrior") == 0)
+	    properties->sets_draft = 10;
+	}
+	else if (_cups_strcasecmp(o, "RIPrintMode") == 0) /* Ricoh & OEM */
+	{
+	  if (_cups_strcasecmp(c, "1rhit") == 0)
+	    properties->sets_high = 7;
+	  else if (_cups_strcasecmp(c, "6rhit") == 0)
+	    properties->sets_high = 10;
+	  else if (_cups_strcasecmp(c, "3rhit") == 0 ||
+		   _cups_strcasecmp(c, "4rhit") == 0 ||
+		   _cups_strcasecmp(c, "5rhit") == 0)
+	    properties->sets_draft = 10;
+	  else if (_cups_strcasecmp(c, "0rhit") == 0)
+	    properties->sets_normal = 10;
+	}
+	else if (_cups_strcasecmp(o, "EconoMode") == 0 || /* Foomatic */
+		 _cups_strcasecmp(o, "EconoFast") == 0)   /* Foomatic (HP PPA) */
+	{
+	  if (_cups_strcasecmp(c, "Off") == 0 ||
+	      _cups_strcasecmp(c, "False") == 0)
+	    properties->sets_high = 1;
+	  else if (_cups_strcasecmp(c, "On") == 0 ||
+		   _cups_strcasecmp(c, "True") == 0 ||
+		   _cups_strcasecmp(c, "Low") == 0)
+	    properties->sets_draft = 10;
+	  else if (_cups_strcasecmp(c, "High") == 0)
+	    properties->sets_draft = 11;
+	}
+	else if (_cups_strcasestr(o, "ColorPrecision")) /* Gutenprint */
+	{
+	  if (_cups_strcasecmp(c, "best") == 0)
+	    properties->sets_high = 10;
+	}
+	/* Generic boolean options which enhance quality if true */
+	else if (((p = _cups_strcasestr(o, "slow")) && _cups_strcasestr(p, "dry")) ||
+		 ((p = _cups_strcasestr(o, "color")) && _cups_strcasestr(p, "enhance")) ||
+		 ((p = _cups_strcasestr(o, "resolution")) &&
+		  !_cups_strcasestr(p, "enhance")) ||
+		 _cups_strcasecmp(o, "RET") == 0 ||
+		 _cups_strcasecmp(o, "Smoothing") == 0 || /* HPLIP */
+		 ((p = _cups_strcasestr(o, "uni")) && _cups_strcasestr(p, "direction")))
+	{
+	  if (_cups_strcasecmp(c, "True") == 0 ||
+	      _cups_strcasecmp(c, "On") == 0 ||
+	      _cups_strcasecmp(c, "Yes") == 0 ||
+	      _cups_strcasecmp(c, "1") == 0 ||
+	      _cups_strcasecmp(c, "Medium") == 0) /* Resolution Enhancement/RET (HP)*/
+	    properties->sets_high = 3;
+	  else if (_cups_strcasecmp(c, "False") == 0 ||
+		   _cups_strcasecmp(c, "Off") == 0 ||
+		   _cups_strcasecmp(c, "No") == 0 ||
+		   _cups_strcasecmp(c, "0") == 0)
+	    properties->sets_draft = 3;
+	}
+	/* Generic boolean options which reduce quality if true */
+	else if (_cups_strcasestr(o, "draft") ||
+		 _cups_strcasestr(o, "economy") ||
+		 ((p = _cups_strcasestr(o, "eco")) && _cups_strcasestr(p, "mode")) ||
+		 ((p = _cups_strcasestr(o, "toner")) && _cups_strcasestr(p, "sav")) ||
+		 ((p = _cups_strcasestr(o, "bi")) && _cups_strcasestr(p, "direction")) ||
+		 _cups_strcasecmp(o, "EcoBlack") == 0 || /* Foomatic (Alps) */
+		 _cups_strcasecmp(o, "bidi") == 0 ||
+		 _cups_strcasecmp(o, "bi-di") == 0)
+	{
+	  if (_cups_strcasecmp(c, "True") == 0 ||
+	      _cups_strcasecmp(c, "On") == 0 ||
+	      _cups_strcasecmp(c, "Yes") == 0 ||
+	      _cups_strcasecmp(c, "1") == 0 ||
+	      _cups_strcasecmp(c, "Medium") == 0) /* EconomyMode (Brother) */
+	    properties->sets_draft = 3;
+	  else if (_cups_strcasecmp(c, "False") == 0 ||
+		   _cups_strcasecmp(c, "Off") == 0 ||
+		   _cups_strcasecmp(c, "No") == 0 ||
+		   _cups_strcasecmp(c, "0") == 0)
+	    properties->sets_high = 3;
+	}
+	/* Generic enumerated choice option and choice names */
+	else if (_cups_strcasecmp(o, "ColorModel") == 0 ||
+		 _cups_strcasecmp(o, "ColorMode") == 0 ||
+		 _cups_strcasecmp(o, "OutputMode") == 0 || /* HPLIP hpcups */
+		 _cups_strcasecmp(o, "PrintoutMode") == 0 || /* Foomatic */
+		 _cups_strcasecmp(o, "PrintQuality") == 0 ||
+		 _cups_strcasecmp(o, "PrintMode") == 0 ||
+		 _cups_strcasestr(o, "ColorMode") ||
+		 _cups_strcasestr(o, "HalfTone") || /* HPLIP */
+		 _cups_strcasecmp(o, "ColorResType") == 0 || /* Toshiba */
+		 _cups_strcasestr(o, "MonoColor") || /* Brother */
+		 _cups_strcasestr(o, "Quality") ||
+		 _cups_strcasestr(o, "Resolution") ||
+		 _cups_strcasestr(o, "Precision") || /* ex. stpColorPrecision
+						  in Gutenprint */
+		 _cups_strcasestr(o, "PrintingDirection")) /* Gutenprint */
+	{
+	  /* High quality */
+	  if (_cups_strcasecmp(c, "Quality") == 0 ||
+	      _cups_strcasecmp(c, "5") == 0)
+	    properties->sets_high = 1;
+	  else if (_cups_strcasestr(c, "Photo") ||
+		   _cups_strcasestr(c, "Enhance") ||
+		   _cups_strcasestr(c, "slow") ||
+		   _cups_strncasecmp(c, "ProRes", 6) == 0 || /* HPLIP */
+		   _cups_strncasecmp(c, "ImageREt", 8) == 0 || /* HPLIP */
+		   ((p = _cups_strcasestr(c, "low")) && _cups_strcasestr(p, "speed")))
+	    properties->sets_high = 2;
+	  else if (_cups_strcasestr(c, "fine") ||
+		   _cups_strcasestr(c, "deep") ||
+		   ((p = _cups_strcasestr(c, "high")) && !_cups_strcasestr(p, "speed")) ||
+		   _cups_strcasestr(c, "HQ") ||
+		   _cups_strcasecmp(c, "ProRes600") == 0 || /* HPLIP */
+		   _cups_strcasecmp(c, "ImageREt1200") == 0 || /* HPLIP */
+		   _cups_strcasecmp(c, "Enhanced") == 0)
+	    properties->sets_high = 3;
+	  else if (_cups_strcasestr(c, "best") ||
+		   _cups_strcasecmp(c, "high") == 0 ||
+		   _cups_strcasecmp(c, "fine") == 0 ||
+		   _cups_strcasecmp(c, "HQ") == 0 ||
+		   _cups_strcasecmp(c, "CMYGray") == 0 || /* HPLIP */
+		   _cups_strcasecmp(c, "ProRes1200") == 0 || /* HPLIP */
+		   _cups_strcasecmp(c, "ImageREt2400") == 0 || /* HPLIP */
+		   _cups_strcasestr(c, "unidir"))
+	    properties->sets_high = 4;
+	  else if (_cups_strcasecmp(c, "best") == 0 ||
+		   _cups_strcasecmp(c, "ProRes2400") == 0 || /* HPLIP */
+		   _cups_strcasecmp(c, "monolowdetail") == 0) /* Toshiba */
+	    properties->sets_high = 5;
+
+	  /* Low/Draft quality */
+	  if (_cups_strcasecmp(c, "monolowdetail") == 0 || /* Toshiba */
+	      _cups_strcasecmp(c, "3") == 0)
+	    properties->sets_draft = 1;
+	  else if (((p = _cups_strcasestr(c, "fast")) && _cups_strcasestr(p, "draft")) ||
+		   ((p = _cups_strcasestr(c, "high")) && _cups_strcasestr(p, "speed")) ||
+		   (_cups_strcasestr(c, "speed") && !_cups_strcasestr(c, "low")))
+	    properties->sets_draft = 2;
+	  else if (_cups_strcasestr(c, "quick") ||
+		   (_cups_strcasestr(c, "fast") &&
+		    !(_cups_strncasecmp(c, "FastRes", 7) == 0 && isdigit(*(c + 7)))))
+	    /* HPLIP has FastRes600, FastRes1200, ... which are not draft */
+	    properties->sets_draft = 3;
+	  else if (_cups_strcasecmp(c, "quick") == 0 ||
+		   _cups_strcasecmp(c, "fast") == 0 ||
+		   _cups_strcasestr(c, "draft") ||
+		   (_cups_strcasestr(c, "low") && !_cups_strcasestr(c, "slow")) ||
+		   _cups_strcasestr(c, "coarse"))
+	    properties->sets_draft = 4;
+	  else if (_cups_strcasecmp(c, "draft") == 0 ||
+		   _cups_strcasecmp(c, "low") == 0 ||
+		   _cups_strcasecmp(c, "coarse") == 0 ||
+		   _cups_strcasestr(c, "bidir"))
+	    properties->sets_draft = 5;
+
+	  /* Use high or low quality but not the extremes */
+	  if (_cups_strcasestr(c, "ultra") ||
+	      _cups_strcasestr(c, "very") ||
+	      _cups_strcasestr(c, "super"))
+	  {
+	    if (properties->sets_high > 1)
+	      properties->sets_high --;
+	    if (properties->sets_draft > 1)
+	      properties->sets_draft --;
+	  }
+
+	  /* Normal quality */
+	  if (_cups_strcasestr(c, "automatic") ||
+	      _cups_strcasecmp(c, "none") == 0 ||
+	      _cups_strcasecmp(c, "4") == 0 ||
+	      _cups_strcasecmp(c, "FastRes1200") == 0) /* HPLIP */
+	    properties->sets_normal = 1;
+	  else if (_cups_strcasestr(c, "normal") ||
+		   _cups_strcasestr(c, "standard") ||
+		   _cups_strcasestr(c, "default") ||
+		   _cups_strcasecmp(c, "FastRes600") == 0) /* HPLIP */
+	    properties->sets_normal = 2;
+	  else if (_cups_strcasecmp(c, "normal") == 0 ||
+		   _cups_strcasecmp(c, "standard") == 0 ||
+		   _cups_strcasecmp(c, "default") == 0)
+	    properties->sets_normal = 4;
+	}
+
+	/* Apply the weight factor for option/choice-name-related scores */
+	properties->sets_high *= name_factor;
+	properties->sets_draft *= name_factor;
+	properties->sets_normal *= name_factor;
+
+	/* Determine influence of the options and choices on the print
+	   quality by how they change the output resolution compared to
+	   the base/default resolution */
+	if (base_res_x && base_res_y)
+	{
+	  /* First, analyse the code snippet (PostScript, PJL) assigned
+	     to each choice of the option whether it sets resolution */
+	  if (option->choices[k].code && option->choices[k].code[0])
+	  {
+	    /* Assume code to be PostScript (also used for CUPS Raster) */
+	    preferred_bits = 0;
+	    optheader = header;
+	    if (_cupsRasterExecPS(&optheader, &preferred_bits,
+				  option->choices[k].code) == 0)
+	    {
+	      properties->res_x = optheader.HWResolution[0];
+	      properties->res_y = optheader.HWResolution[1];
+	    }
+	    else
+	      properties->res_x = properties->res_y = 0; /* invalid */
+	    if (properties->res_x == 0 || properties->res_y == 0)
+	    {
+	      /* Now try PJL */
+	      if ((p = strstr(option->choices[k].code, "SET")) &&
+		  isspace(*(p + 3)) && (p = strstr(p + 4, "RESOLUTION=")))
+	      {
+		p += 11;
+		if (sscanf(p, "%dX%d",
+			   &(properties->res_x), &(properties->res_y)) == 1)
+		    properties->res_y = properties->res_x;
+	      }
+	    }
+	    if (properties->res_x == 100 && properties->res_y == 100)
+	      properties->res_x = properties->res_y = 0; /* Code does not
+							    set resolution */
+	  }
+	  else
+	    properties->res_x = properties->res_y = 0; /* invalid */
+
+	  /* Then parse the choice name whether it contains a
+	     resolution value (Must have "dpi", as otherwise can be
+	     something else, like a page size */
+	  if ((properties->res_x == 0 || properties->res_y == 0) &&
+	      (p = _cups_strcasestr(c, "dpi")) != NULL)
+	  {
+	    if (p > c)
+	    {
+	      p --;
+	      while (p > c && isspace(*p))
+		p --;
+	      if (p > c && isdigit(*p))
+	      {
+		char x;
+		while (p > c && isdigit(*p))
+		  p --;
+		if (p > c && (*p == 'x' || *p == 'X'))
+		  p --;
+		while (p > c && isdigit(*p))
+		  p --;
+		while (!isdigit(*p))
+		  p ++;
+		if (sscanf(p, "%d%c%d",
+			   &(properties->res_x), &x, &(properties->res_y)) == 2)
+		    properties->res_y = properties->res_x;
+	      }
+	    }
+	  }
+
+	  if (properties->res_x != 0 && properties->res_y != 0)
+	  {
+	    /* Choice suggests to set the resolution */
+	    /* Raising resolution compared to default? */
+	    m = (properties->res_x * properties->res_y) /
+	        (base_res_x * base_res_y);
+	    /* No or small change -> Normal quality */
+	    if (m == 1)
+	      properties->sets_normal += res_factor * 4;
+	    /* At least double the pixels -> High quality */
+	    else if (m == 2)
+	      properties->sets_high += res_factor * 3;
+	    else if (m > 2 && m <= 8)
+	      properties->sets_high += res_factor * 4;
+	    else if (m > 8 && m <= 32)
+	      properties->sets_high += res_factor * 2;
+	    else if (m > 32)
+	      properties->sets_high += res_factor * 1;
+	    else if (m < 1)
+	    {
+	      /* Reducing resolution compared to default? */
+	      m = (base_res_x * base_res_y) /
+		  (properties->res_x * properties->res_y);
+	      /* No or small change -> Normal quality */
+	      if (m == 1)
+		properties->sets_normal += res_factor * 1;
+	      /* At most half the pixels -> Draft quality */
+	      else if (m == 2)
+		properties->sets_draft += res_factor * 3;
+	      else if (m > 2 && m < 8)
+		properties->sets_draft += res_factor * 4;
+	      else if (m >= 8 && m < 32)
+		properties->sets_draft += res_factor * 2;
+	      else if (m >= 32)
+		properties->sets_draft += res_factor * 1;
+	    }
+	  }
+	}
+
+	/* This option actually sets print quality */
+	if (properties->sets_draft || properties->sets_high)
+	  sets_quality = 1;
+
+	/* Add the properties of this choice */
+	cupsArrayAdd(choice_properties, properties);
+      }
+
+     /*
+      * Find the best choice for each field of the color/quality preset
+      * grid
+      */
+
+      for (pass = 0; pass < 3; pass ++)
+      {
+	for (k = 0; k < option->num_choices; k ++)
+        {
+	  properties = cupsArrayIndex(choice_properties, k);
+
+	  /* presets[0][0]: Mono/Draft */
+	  if (best_mono_draft >= 0 &&
+	      !properties->sets_color &&
+	      (!properties->sets_high || pass > 0))
+	  {
+	    score = color_factor * properties->sets_mono +
+	      properties->sets_draft;
+	    if (score > best_mono_draft)
+	    {
+	      best_mono_draft = score;
+	      best_mono_draft_ch = k;
+	    }
+	  }
+
+	  /* presets[0][1]: Mono/Normal */
+	  if (best_mono_normal >= 0 &&
+	      !properties->sets_color &&
+	      (!properties->sets_draft || pass > 1) &&
+	      (!properties->sets_high  || pass > 0))
+	  {
+	    score = color_factor * properties->sets_mono +
+	      properties->sets_normal;
+	    if (score > best_mono_normal)
+	    {
+	      best_mono_normal = score;
+	      best_mono_normal_ch = k;
+	    }
+	  }
+
+	  /* presets[0][2]: Mono/High */
+	  if (best_mono_high >= 0 &&
+	      !properties->sets_color &&
+	      (!properties->sets_draft || pass > 0))
+	  {
+	    score = color_factor * properties->sets_mono +
+	      properties->sets_high;
+	    if (score > best_mono_high)
+	    {
+	      best_mono_high = score;
+	      best_mono_high_ch = k;
+	    }
+	  }
+
+	  /* presets[1][0]: Color/Draft */
+	  if (best_color_draft >= 0 &&
+	      !properties->sets_mono &&
+	      (!properties->sets_high || pass > 0))
+	  {
+	    score = color_factor * properties->sets_color +
+	      properties->sets_draft;
+	    if (score > best_color_draft)
+	    {
+	      best_color_draft = score;
+	      best_color_draft_ch = k;
+	    }
+	  }
+
+	  /* presets[1][1]: Color/Normal */
+	  if (best_color_normal >= 0 &&
+	      !properties->sets_mono &&
+	      (!properties->sets_draft || pass > 1) &&
+	      (!properties->sets_high  || pass > 0))
+	  {
+	    score = color_factor * properties->sets_color +
+	      properties->sets_normal;
+	    if (score > best_color_normal)
+	    {
+	      best_color_normal = score;
+	      best_color_normal_ch = k;
+	    }
+	  }
+
+	  /* presets[1][2]: Color/High */
+	  if (best_color_high >= 0 &&
+	      !properties->sets_mono &&
+	      (!properties->sets_draft || pass > 0))
+	  {
+	    score = color_factor * properties->sets_color +
+	      properties->sets_high;
+	    if (score > best_color_high)
+	    {
+	      best_color_high = score;
+	      best_color_high_ch = k;
+	    }
+	  }
+	}
+	/* Block next passes for the presets where we are done */
+	if (best_mono_draft_ch >= 0)
+	  best_mono_draft = -1;
+	if (best_mono_normal_ch >= 0)
+	  best_mono_normal = -1;
+	if (best_mono_high_ch >= 0)
+	  best_mono_high = -1;
+	if (best_color_draft_ch >= 0)
+	  best_color_draft = -1;
+	if (best_color_normal_ch >= 0)
+	  best_color_normal = -1;
+	if (best_color_high_ch >= 0)
+	  best_color_high = -1;
+      }
+
+     /*
+      * Content Optimization - print-content-optimize
+      */
+
+      for (k = 0; k < option->num_choices; k ++)
+      {
+	properties = cupsArrayIndex(choice_properties, k);
+	c = option->choices[k].choice;
+
+	/* Vendor-specific options */
+	if (_cups_strcasecmp(o, "ARCOType") == 0) /* Sharp */
+	{
+	  if (_cups_strcasecmp(c, "COTDrawing") == 0)
+	  {
+	    properties->for_text = 3;
+	    properties->for_graphics = 2;
+	    properties->for_tg = 2;
+	  }
+	  else if (_cups_strcasecmp(c, "COTGraphics") == 0)
+	  {
+	    properties->for_graphics = 3;
+	    properties->for_tg = 3;
+	  }
+	  else if (_cups_strcasecmp(c, "COTPhoto") == 0)
+	    properties->for_photo = 3;
+	}
+	else if (_cups_strcasecmp(o, "HPRGBEmulation") == 0) /* HP */
+	{
+	  if (_cups_strcasecmp(c, "DefaultSRGB") == 0)
+	    properties->for_text = 3;
+	  else if (_cups_strcasecmp(c, "VividSRGB") == 0)
+	  {
+	    properties->for_graphics = 3;
+	    properties->for_tg = 3;
+	  }
+	  else if (_cups_strcasecmp(c, "PhotoSRGB") == 0)
+	    properties->for_photo = 3;
+	}
+	else
+	/* Generic choice names */
+	{
+	  if (_cups_strcasestr(c, "photo"))
+	    properties->for_photo = 6;
+	  else if (_cups_strcasecmp(c, "photo") == 0)
+	    properties->for_photo = 7;
+
+	  if (_cups_strcasestr(c, "graphic"))
+	    properties->for_graphics = 6;
+	  else if (_cups_strcasecmp(c, "graphic") == 0 ||
+		   _cups_strcasecmp(c, "graphics") == 0)
+	    properties->for_graphics = 7;
+
+	  if (_cups_strcasestr(c, "text"))
+	  {
+	    if (_cups_strcasestr(c, "graphic"))
+	      properties->for_tg = 7;
+	    else
+	      properties->for_text = 6;
+	  }
+	  else if (_cups_strcasecmp(c, "text") == 0)
+	    properties->for_text = 7;
+
+	  if (_cups_strcasestr(c, "presentation"))
+	  {
+	    properties->for_text = 4;
+	    properties->for_graphics = 4;
+	    properties->for_tg = 4;
+	  }
+	  else if (_cups_strcasecmp(c, "presentation") == 0)
+	  {
+	    properties->for_text = 5;
+	    properties->for_graphics = 5;
+	    properties->for_tg = 5;
+	  }
+
+	  if (_cups_strcasestr(c, "lineart"))
+	  {
+	    properties->for_graphics = 2;
+	    properties->for_tg = 2;
+	  }
+	  else if (_cups_strcasecmp(c, "lineart") == 0)
+	  {
+	    properties->for_graphics = 3;
+	    properties->for_tg = 3;
+	  }
+
+	  if (_cups_strcasestr(c, "drawing"))
+	  {
+	    properties->for_graphics = 4;
+	    properties->for_tg = 4;
+	  }
+	  else if (_cups_strcasecmp(c, "drawing") == 0)
+	  {
+	    properties->for_graphics = 5;
+	    properties->for_tg = 5;
+	  }
+
+	  if (_cups_strcasestr(c, "natural"))
+	    properties->for_photo = 2;
+	  else if (_cups_strcasecmp(c, "natural") == 0)
+	    properties->for_photo = 3;
+
+	  if (_cups_strcasestr(c, "vivid"))
+	  {
+	    properties->for_text = 2;
+	    properties->for_graphics = 2;
+	    properties->for_tg = 2;
+	  }
+	  else if (_cups_strcasecmp(c, "vivid") == 0)
+	  {
+	    properties->for_text = 3;
+	    properties->for_graphics = 3;
+	    properties->for_tg = 3;
+	  }
+	}
+
+	/* We apply these optimizations only in high quality mode
+	   therefore we prefer settings for high quality */
+	if (properties->sets_high && !properties->sets_draft)
+	{
+	  if (properties->for_photo)
+	    properties->for_photo += 10;
+	  if (properties->for_graphics)
+	    properties->for_graphics += 10;
+	  if (properties->for_text)
+	    properties->for_text += 10;
+	  if (properties->for_tg)
+	    properties->for_tg += 10;
+	}
+
+       /*
+	* Find the best choice for each field of the content optimize presets
+	*/
+
+	/* Find best choice for each task */
+	/* optimize_presets[1]: Photo */
+	if (properties->for_photo > best_photo)
+	{
+	  best_photo = properties->for_photo;
+	  best_photo_ch = k;
+	}
+	/* optimize_presets[2]: Graphics */
+	if (properties->for_graphics > best_graphics)
+	{
+	  best_graphics = properties->for_graphics;
+	  best_graphics_ch = k;
+	}
+	/* optimize_presets[3]: Text */
+	if (properties->for_text > best_text)
+	{
+	  best_text = properties->for_text;
+	  best_text_ch = k;
+	}
+	/* optimize_presets[4]: Text and Graphics */
+	if (properties->for_tg > best_tg)
+	{
+	  best_tg = properties->for_tg;
+	  best_tg_ch = k;
+	}
+
+	/* This option actually does content optimization */
+	if (properties->for_text || properties->for_graphics ||
+	    properties->for_tg || properties->for_photo)
+	  sets_optimization = 1;
+      }
+
+     /*
+      * Fill in the presets
+      */
+
+      if (sets_color_mode || sets_quality)
+      {
+	/* presets[0][0]: Mono/Draft */
+	if (best_mono_draft_ch < 0)
+	  best_mono_draft_ch = default_ch;
+	if (best_mono_draft_ch >= 0)
+	  pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME]
+	                 [_PWG_PRINT_QUALITY_DRAFT] =
+	    cupsAddOption(o, option->choices[best_mono_draft_ch].choice,
+			  pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME]
+			                 [_PWG_PRINT_QUALITY_DRAFT],
+			  &(pc->presets[_PWG_PRINT_COLOR_MODE_MONOCHROME]
+			               [_PWG_PRINT_QUALITY_DRAFT]));
+
+	/* presets[0][1]: Mono/Normal */
+	if (best_mono_normal_ch < 0)
+	  best_mono_normal_ch = default_ch;
+	if (best_mono_normal_ch >= 0)
+	  pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME]
+	                 [_PWG_PRINT_QUALITY_NORMAL] =
+	    cupsAddOption(o, option->choices[best_mono_normal_ch].choice,
+			  pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME]
+			                 [_PWG_PRINT_QUALITY_NORMAL],
+			  &(pc->presets[_PWG_PRINT_COLOR_MODE_MONOCHROME]
+			               [_PWG_PRINT_QUALITY_NORMAL]));
+
+	/* presets[0][2]: Mono/High */
+	if (best_mono_high_ch < 0)
+	  best_mono_high_ch = default_ch;
+	if (best_mono_high_ch >= 0)
+	  pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME]
+	                 [_PWG_PRINT_QUALITY_HIGH] =
+	    cupsAddOption(o, option->choices[best_mono_high_ch].choice,
+			  pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME]
+			                 [_PWG_PRINT_QUALITY_HIGH],
+			  &(pc->presets[_PWG_PRINT_COLOR_MODE_MONOCHROME]
+			               [_PWG_PRINT_QUALITY_HIGH]));
+
+	/* presets[1][0]: Color/Draft */
+	if (best_color_draft_ch < 0)
+	  best_color_draft_ch = default_ch;
+	if (best_color_draft_ch >= 0)
+	  pc->num_presets[_PWG_PRINT_COLOR_MODE_COLOR]
+	                 [_PWG_PRINT_QUALITY_DRAFT] =
+	    cupsAddOption(o, option->choices[best_color_draft_ch].choice,
+			  pc->num_presets[_PWG_PRINT_COLOR_MODE_COLOR]
+			                 [_PWG_PRINT_QUALITY_DRAFT],
+			  &(pc->presets[_PWG_PRINT_COLOR_MODE_COLOR]
+			               [_PWG_PRINT_QUALITY_DRAFT]));
+
+	/* presets[1][1]: Color/Normal */
+	if (best_color_normal_ch < 0)
+	  best_color_normal_ch = default_ch;
+	if (best_color_normal_ch >= 0)
+	  pc->num_presets[_PWG_PRINT_COLOR_MODE_COLOR]
+	                 [_PWG_PRINT_QUALITY_NORMAL] =
+	    cupsAddOption(o, option->choices[best_color_normal_ch].choice,
+			  pc->num_presets[_PWG_PRINT_COLOR_MODE_COLOR]
+			                 [_PWG_PRINT_QUALITY_NORMAL],
+			  &(pc->presets[_PWG_PRINT_COLOR_MODE_COLOR]
+			               [_PWG_PRINT_QUALITY_NORMAL]));
+
+	/* presets[1][2]: Color/High */
+	if (best_color_high_ch < 0)
+	  best_color_high_ch = default_ch;
+	if (best_color_high_ch >= 0)
+	  pc->num_presets[_PWG_PRINT_COLOR_MODE_COLOR]
+	                 [_PWG_PRINT_QUALITY_HIGH] =
+	    cupsAddOption(o, option->choices[best_color_high_ch].choice,
+			  pc->num_presets[_PWG_PRINT_COLOR_MODE_COLOR]
+			                 [_PWG_PRINT_QUALITY_HIGH],
+			  &(pc->presets[_PWG_PRINT_COLOR_MODE_COLOR]
+			               [_PWG_PRINT_QUALITY_HIGH]));
+
+      }
+
+      if (sets_optimization)
+      {
+
+	/* optimize_presets[1]: Photo */
+	if (best_photo_ch >= 0)
+	  pc->num_optimize_presets[_PWG_PRINT_CONTENT_OPTIMIZE_PHOTO] =
+	    cupsAddOption
+	      (o, option->choices[best_photo_ch].choice,
+	       pc->num_optimize_presets[_PWG_PRINT_CONTENT_OPTIMIZE_PHOTO],
+	       &(pc->optimize_presets[_PWG_PRINT_CONTENT_OPTIMIZE_PHOTO]));
+
+	/* optimize_presets[2]: Graphics */
+	if (best_graphics_ch >= 0)
+	  pc->num_optimize_presets[_PWG_PRINT_CONTENT_OPTIMIZE_GRAPHICS] =
+	    cupsAddOption
+	      (o, option->choices[best_graphics_ch].choice,
+	       pc->num_optimize_presets
+	         [_PWG_PRINT_CONTENT_OPTIMIZE_GRAPHICS],
+	       &(pc->optimize_presets
+		 [_PWG_PRINT_CONTENT_OPTIMIZE_GRAPHICS]));
+
+	/* optimize_presets[1]: Text */
+	if (best_text_ch >= 0)
+	  pc->num_optimize_presets[_PWG_PRINT_CONTENT_OPTIMIZE_TEXT] =
+	    cupsAddOption
+	      (o, option->choices[best_text_ch].choice,
+	       pc->num_optimize_presets[_PWG_PRINT_CONTENT_OPTIMIZE_TEXT],
+	       &(pc->optimize_presets[_PWG_PRINT_CONTENT_OPTIMIZE_TEXT]));
+
+	/* optimize_presets[1]: Text and Graphics */
+	if (best_tg_ch >= 0)
+	  pc->num_optimize_presets
+	    [_PWG_PRINT_CONTENT_OPTIMIZE_TEXT_AND_GRAPHICS] =
+	    cupsAddOption
+	      (o, option->choices[best_tg_ch].choice,
+	       pc->num_optimize_presets
+	         [_PWG_PRINT_CONTENT_OPTIMIZE_TEXT_AND_GRAPHICS],
+	       &(pc->optimize_presets
+		   [_PWG_PRINT_CONTENT_OPTIMIZE_TEXT_AND_GRAPHICS]));
+
+      }
+
+      for (k = 0; k < option->num_choices; k ++)
+	free(cupsArrayIndex(choice_properties, k));
+      cupsArrayDelete(choice_properties);
+    }
+  }
+}
+
+/*
  * '_ppdCacheDestroy()' - Free all memory used for PWG mapping data.
  */
 
 void
 _ppdCacheDestroy(_ppd_cache_t *pc)	/* I - PPD cache and mapping data */
 {
-  int		i;			/* Looping var */
+  int		i, j;			/* Looping vars */
   pwg_map_t	*map;			/* Current map */
   pwg_size_t	*size;			/* Current size */
 
@@ -2059,6 +3090,15 @@
 
   cupsArrayDelete(pc->strings);
 
+  for (i = _PWG_PRINT_COLOR_MODE_MONOCHROME; i < _PWG_PRINT_COLOR_MODE_MAX; i ++)
+    for (j = _PWG_PRINT_QUALITY_DRAFT; j < _PWG_PRINT_QUALITY_MAX; j ++)
+      if (pc->num_presets[i][j])
+	cupsFreeOptions(pc->num_presets[i][j], pc->presets[i][j]);
+
+  for (i = _PWG_PRINT_CONTENT_OPTIMIZE_AUTO; i < _PWG_PRINT_CONTENT_OPTIMIZE_MAX; i ++)
+    if (pc->num_optimize_presets[i])
+      cupsFreeOptions(pc->num_optimize_presets[i], pc->optimize_presets[i]);
+
   free(pc);
 }
 
@@ -2928,6 +3968,21 @@
       }
 
  /*
+  * Optimization Presets...
+  */
+
+  for (i = _PWG_PRINT_CONTENT_OPTIMIZE_AUTO; i < _PWG_PRINT_CONTENT_OPTIMIZE_MAX; i ++)
+    if (pc->num_optimize_presets[i])
+    {
+      cupsFilePrintf(fp, "OptimizePreset %d", i);
+      for (k = pc->num_optimize_presets[i], option = pc->optimize_presets[i];
+	   k > 0;
+	   k --, option ++)
+	cupsFilePrintf(fp, " %s=%s", option->name, option->value);
+      cupsFilePutChar(fp, '\n');
+    }
+
+ /*
   * Duplex/sides...
   */
 
--- a/cups/ppd-private.h
+++ b/cups/ppd-private.h
@@ -36,7 +36,7 @@
  * Constants...
  */
 
-#  define _PPD_CACHE_VERSION	10	/* Version number in cache file */
+#  define _PPD_CACHE_VERSION	11	/* Version number in cache file */
 
 
 /*
@@ -101,6 +101,16 @@
   _PWG_PRINT_QUALITY_MAX
 } _pwg_print_quality_t;
 
+typedef enum _pwg_print_content_optimize_e /** PWG print-content-optimize **/
+{
+  _PWG_PRINT_CONTENT_OPTIMIZE_AUTO = 0, /* print-content-optimize=auto */
+  _PWG_PRINT_CONTENT_OPTIMIZE_PHOTO,	/* print-content-optimize=photo */
+  _PWG_PRINT_CONTENT_OPTIMIZE_GRAPHICS, /* print-content-optimize=graphics */
+  _PWG_PRINT_CONTENT_OPTIMIZE_TEXT,	/* print-content-optimize=text */
+  _PWG_PRINT_CONTENT_OPTIMIZE_TEXT_AND_GRAPHICS, /* ...=text-and-graphics */
+  _PWG_PRINT_CONTENT_OPTIMIZE_MAX
+} _pwg_print_content_optimize_t;
+
 typedef struct _pwg_finishings_s	/**** PWG finishings mapping data ****/
 {
   ipp_finishings_t	value;		/* finishings value */
@@ -131,6 +141,11 @@
 					/* Number of print-color-mode/print-quality options */
   cups_option_t	*presets[_PWG_PRINT_COLOR_MODE_MAX][_PWG_PRINT_QUALITY_MAX];
 					/* print-color-mode/print-quality options */
+  int		num_optimize_presets[_PWG_PRINT_CONTENT_OPTIMIZE_MAX];
+					/* Number of print-content-optimize
+					   options */
+  cups_option_t	*optimize_presets[_PWG_PRINT_CONTENT_OPTIMIZE_MAX];
+					/* print-content-optimize options */
   char		*sides_option,		/* PPD option for sides */
 		*sides_1sided,		/* Choice for one-sided */
 		*sides_2sided_long,	/* Choice for two-sided-long-edge */
@@ -214,6 +229,8 @@
 extern const char	*_pwgPageSizeForMedia(pwg_media_t *media,
 			                      char *name, size_t namesize) _CUPS_PRIVATE;
 
+extern void             _ppdCacheAssignPresets(ppd_file_t *ppd, _ppd_cache_t *pc) _CUPS_PRIVATE;
+
 
 /*
  * C++ magic...
--- a/cups/string-private.h
+++ b/cups/string-private.h
@@ -150,6 +150,8 @@
 
 extern int	_cups_strncasecmp(const char *, const char *, size_t n) _CUPS_PRIVATE;
 
+extern char	*_cups_strcasestr(const char *, const char *) _CUPS_PRIVATE;
+
 #  ifndef HAVE_STRLCAT
 extern size_t _cups_strlcat(char *, const char *, size_t) _CUPS_PRIVATE;
 #    define strlcat _cups_strlcat
--- a/cups/string.c
+++ b/cups/string.c
@@ -670,6 +670,36 @@
     return (-1);
 }
 
+/*
+ * '_cups_strcasestr()' - Do a case-insensitive search for a sub-string.
+ */
+
+char *					/* O - Pointer to found sub-string  or
+					       NULL if not found */
+_cups_strcasestr(const char *haystack,	/* I - String in which to searh */
+                 const char *needle)	/* I - Sub-string */
+{
+  char     cn,  /* Character in needle */
+           ch;  /* Character in haystack */
+  size_t   len; /* Length of needle */
+
+  if ((cn = *needle++) != 0)
+  {
+    cn = _cups_tolower(cn);
+    len = strlen(needle);
+    do
+    {
+      do
+      {
+	if ((ch = *haystack++) == 0)
+	  return (NULL);
+      } while (_cups_tolower(ch) != cn);
+    } while (_cups_strncasecmp(haystack, needle, len) != 0);
+    haystack --;
+  }
+  return ((char *)haystack);
+}
+
 
 #ifndef HAVE_STRLCAT
 /*
--- a/scheduler/job.c
+++ b/scheduler/job.c
@@ -3633,9 +3633,13 @@
   cups_option_t		*pwgppds,	/* PWG->PPD options */
 			*pwgppd,	/* Current PWG->PPD option */
 			*preset;	/* Current preset option */
-  int			print_color_mode,
+  int			print_color_mode = _PWG_PRINT_COLOR_MODE_COLOR,
 					/* Output mode (if any) */
-			print_quality;	/* Print quality (if any) */
+			print_quality = _PWG_PRINT_QUALITY_NORMAL,
+                                        /* Print quality (if any) */
+			print_content_optimize =
+                          _PWG_PRINT_CONTENT_OPTIMIZE_AUTO;
+                                        /* Print content type (if any)*/
   const char		*ppd;		/* PPD option choice */
   int			exact;		/* Did we get an exact match? */
   static char		*options = NULL;/* Full list of options */
@@ -3657,7 +3661,7 @@
   if (pc &&
       !ippFindAttribute(job->attrs, "com.apple.print.DocumentTicket.PMSpoolFormat", IPP_TAG_ZERO) &&
       !ippFindAttribute(job->attrs, "APPrinterPreset", IPP_TAG_ZERO) &&
-      (ippFindAttribute(job->attrs, "print-color-mode", IPP_TAG_ZERO) || ippFindAttribute(job->attrs, "print-quality", IPP_TAG_ZERO) || ippFindAttribute(job->attrs, "cupsPrintQuality", IPP_TAG_ZERO)))
+      (ippFindAttribute(job->attrs, "print-color-mode", IPP_TAG_ZERO) || ippFindAttribute(job->attrs, "print-quality", IPP_TAG_ZERO) || ippFindAttribute(job->attrs, "print-content-optimize", IPP_TAG_ZERO) || ippFindAttribute(job->attrs, "cupsPrintQuality", IPP_TAG_ZERO)))
   {
    /*
     * Map print-color-mode and print-quality to a preset...
@@ -3719,6 +3723,12 @@
       }
     }
 
+    cupsdLogJob(job, CUPSD_LOG_DEBUG,
+		"print-color-mode=%s, print-quality=%s",
+		print_color_mode == _PWG_PRINT_COLOR_MODE_MONOCHROME ?
+		"gray" : "color",
+		print_quality == _PWG_PRINT_QUALITY_DRAFT ? "draft" :
+		(print_quality == _PWG_PRINT_QUALITY_HIGH ? "high" : "normal"));
     if (pc->num_presets[print_color_mode][print_quality] > 0)
     {
      /*
@@ -3733,7 +3743,72 @@
       {
         if (!ippFindAttribute(job->attrs, preset->name, IPP_TAG_ZERO))
         {
-          cupsdLogJob(job, CUPSD_LOG_DEBUG2, "Adding preset option %s=%s", preset->name, preset->value);
+          cupsdLogJob(job, CUPSD_LOG_DEBUG, "Adding preset option %s=%s", preset->name, preset->value);
+
+	  num_pwgppds = cupsAddOption(preset->name, preset->value, num_pwgppds, &pwgppds);
+        }
+      }
+    }
+  }
+
+  if (pc &&
+      ippFindAttribute(job->attrs, "print-content-optimize", IPP_TAG_ZERO))
+  {
+   /*
+    * Map print-content-optimize to a preset...
+    */
+
+    if ((attr = ippFindAttribute(job->attrs, "print-content-optimize",
+				 IPP_TAG_KEYWORD)) != NULL)
+    {
+      if (!strcmp(attr->values[0].string.text, "auto"))
+	print_content_optimize = _PWG_PRINT_CONTENT_OPTIMIZE_AUTO;
+      else if (!strcmp(attr->values[0].string.text, "photo"))
+	print_content_optimize = _PWG_PRINT_CONTENT_OPTIMIZE_PHOTO;
+      else if (!strcmp(attr->values[0].string.text, "graphics") ||
+	       !strcmp(attr->values[0].string.text, "graphic"))
+	print_content_optimize = _PWG_PRINT_CONTENT_OPTIMIZE_GRAPHICS;
+      else if (!strcmp(attr->values[0].string.text, "text"))
+	print_content_optimize = _PWG_PRINT_CONTENT_OPTIMIZE_TEXT;
+      else if (!strcmp(attr->values[0].string.text, "text-and-graphics") ||
+	       !strcmp(attr->values[0].string.text, "text-and-graphic"))
+	print_content_optimize = _PWG_PRINT_CONTENT_OPTIMIZE_TEXT_AND_GRAPHICS;
+      else
+	print_content_optimize = _PWG_PRINT_CONTENT_OPTIMIZE_AUTO;
+    }
+    else
+      print_content_optimize = _PWG_PRINT_CONTENT_OPTIMIZE_AUTO;
+
+  cupsdLogJob(job, CUPSD_LOG_DEBUG,
+	      "print-content-optimize=%s",
+              (print_content_optimize == _PWG_PRINT_CONTENT_OPTIMIZE_AUTO ?
+	       "automatic" :
+               (print_content_optimize == _PWG_PRINT_CONTENT_OPTIMIZE_PHOTO ?
+		"photo" :
+                (print_content_optimize == _PWG_PRINT_CONTENT_OPTIMIZE_GRAPHICS ?
+		 "graphics" :
+                 (print_content_optimize == _PWG_PRINT_CONTENT_OPTIMIZE_TEXT ?
+		  "text" :
+                  "text and graphics")))));
+    if (pc->num_optimize_presets[print_content_optimize] > 0)
+    {
+     /*
+      * Copy the preset options as long as the corresponding names are not
+      * already defined in the IPP request and also if it does not change
+      * the print quality preset (as long as we do not print in high quality)
+      * ...
+      */
+
+      for (i = pc->num_optimize_presets[print_content_optimize],
+	       preset = pc->optimize_presets[print_content_optimize];
+	   i > 0;
+	   i --, preset ++)
+      {
+        if (!ippFindAttribute(job->attrs, preset->name, IPP_TAG_ZERO) &&
+	    (print_quality == _PWG_PRINT_QUALITY_HIGH ||
+	     cupsGetOption(preset->name, num_pwgppds, pwgppds) == NULL))
+        {
+          cupsdLogJob(job, CUPSD_LOG_DEBUG, "Adding content optimization preset option %s=%s", preset->name, preset->value);
 
 	  num_pwgppds = cupsAddOption(preset->name, preset->value, num_pwgppds, &pwgppds);
         }
