8048328: CUPS Printing does not report supported printer resolutions

Reviewed-by: bae, jgodinez
This commit is contained in:
Phil Race 2014-07-11 11:12:59 -07:00
parent 93f94161b3
commit d7f59acb44
9 changed files with 294 additions and 10 deletions
jdk
make/mapfiles
libawt
libawt_headless
libawt_xawt
src
share/classes/sun/print
solaris
test/javax/print/attribute

@ -204,6 +204,7 @@ SUNWprivate_1.1 {
Java_sun_print_CUPSPrinter_canConnect;
Java_sun_print_CUPSPrinter_getMedia;
Java_sun_print_CUPSPrinter_getPageSizes;
Java_sun_print_CUPSPrinter_getResolutions;
Java_com_sun_java_swing_plaf_gtk_GTKEngine_native_1paint_1arrow;
Java_com_sun_java_swing_plaf_gtk_GTKEngine_native_1paint_1box;

@ -76,6 +76,7 @@ SUNWprivate_1.1 {
Java_sun_print_CUPSPrinter_canConnect;
Java_sun_print_CUPSPrinter_getMedia;
Java_sun_print_CUPSPrinter_getPageSizes;
Java_sun_print_CUPSPrinter_getResolutions;
# libfontmanager entry points
AWTIsHeadless;

@ -442,6 +442,7 @@ SUNWprivate_1.1 {
Java_sun_print_CUPSPrinter_canConnect;
Java_sun_print_CUPSPrinter_getMedia;
Java_sun_print_CUPSPrinter_getPageSizes;
Java_sun_print_CUPSPrinter_getResolutions;
awt_GetDrawingSurface;
awt_FreeDrawingSurface;

@ -168,13 +168,6 @@ public class PSPrinterJob extends RasterPrinterJob {
private static final String IMAGE_STR = " string /imStr exch def";
private static final String IMAGE_RESTORE = "imSave restore";
private static final String COORD_PREP = " 0 exch translate "
+ "1 -1 scale"
+ "[72 " + PS_XRES + " div "
+ "0 0 "
+ "72 " + PS_YRES + " div "
+ "0 0]concat";
private static final String SetFontName = "F";
private static final String DrawStringName = "S";
@ -275,6 +268,9 @@ public class PSPrinterJob extends RasterPrinterJob {
private AffineTransform mLastTransform;
private double xres = PS_XRES;
private double yres = PS_XRES;
/* non-null if printing EPS for Java Plugin */
private EPSPrinter epsPrinter = null;
@ -796,6 +792,15 @@ public class PSPrinterJob extends RasterPrinterJob {
}
}
private String getCoordPrep() {
return " 0 exch translate "
+ "1 -1 scale"
+ "[72 " + getXRes() + " div "
+ "0 0 "
+ "72 " + getYRes() + " div "
+ "0 0]concat";
}
/**
* The RasterPrintJob super class calls this method
* at the start of each page.
@ -852,7 +857,7 @@ public class PSPrinterJob extends RasterPrinterJob {
mPSStream.println(" >> setpagedevice");
}
mPSStream.println(PAGE_SAVE);
mPSStream.println(paperHeight + COORD_PREP);
mPSStream.println(paperHeight + getCoordPrep());
}
/**
@ -1493,14 +1498,22 @@ public class PSPrinterJob extends RasterPrinterJob {
* to be rendered.
*/
protected double getXRes() {
return PS_XRES;
return xres;
}
/**
* Return the y resolution of the coordinates
* to be rendered.
*/
protected double getYRes() {
return PS_YRES;
return yres;
}
/**
* Set the resolution at which to print.
*/
protected void setXYRes(double x, double y) {
xres = x;
yres = y;
}
/**

@ -72,6 +72,7 @@ import javax.print.attribute.Attribute;
import javax.print.attribute.AttributeSet;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.print.attribute.ResolutionSyntax;
import javax.print.attribute.Size2DSyntax;
import javax.print.attribute.standard.Chromaticity;
import javax.print.attribute.standard.Copies;
@ -86,6 +87,7 @@ import javax.print.attribute.standard.MediaSize;
import javax.print.attribute.standard.MediaSizeName;
import javax.print.attribute.standard.OrientationRequested;
import javax.print.attribute.standard.PageRanges;
import javax.print.attribute.standard.PrinterResolution;
import javax.print.attribute.standard.PrinterState;
import javax.print.attribute.standard.PrinterStateReason;
import javax.print.attribute.standard.PrinterStateReasons;
@ -283,6 +285,7 @@ public abstract class RasterPrinterJob extends PrinterJob {
private String jobNameAttr;
private String userNameAttr;
private PageRanges pageRangesAttr;
protected PrinterResolution printerResAttr;
protected Sides sidesAttr;
protected String destinationAttr;
protected boolean noJobSheet = false;
@ -1064,6 +1067,14 @@ public abstract class RasterPrinterJob extends PrinterJob {
attrset));
}
/**
* Set the device resolution.
* Overridden and used only by the postscript code.
* Windows code pulls the information from the attribute set itself.
*/
protected void setXYRes(double x, double y) {
}
/* subclasses may need to pull extra information out of the attribute set
* They can override this method & call super.setAttributes()
*/
@ -1072,6 +1083,7 @@ public abstract class RasterPrinterJob extends PrinterJob {
/* reset all values to defaults */
setCollated(false);
sidesAttr = null;
printerResAttr = null;
pageRangesAttr = null;
copiesAttr = 0;
jobNameAttr = null;
@ -1117,6 +1129,18 @@ public abstract class RasterPrinterJob extends PrinterJob {
sidesAttr = Sides.ONE_SIDED;
}
printerResAttr = (PrinterResolution)attributes.get(PrinterResolution.class);
if (service.isAttributeCategorySupported(PrinterResolution.class)) {
if (!isSupportedValue(printerResAttr, attributes)) {
printerResAttr = (PrinterResolution)
service.getDefaultAttributeValue(PrinterResolution.class);
}
double xr =
printerResAttr.getCrossFeedResolution(ResolutionSyntax.DPI);
double yr = printerResAttr.getFeedResolution(ResolutionSyntax.DPI);
setXYRes(xr, yr);
}
pageRangesAttr = (PageRanges)attributes.get(PageRanges.class);
if (!isSupportedValue(pageRangesAttr, attributes)) {
pageRangesAttr = null;

@ -39,6 +39,7 @@ import javax.print.attribute.standard.MediaSizeName;
import javax.print.attribute.standard.MediaSize;
import javax.print.attribute.standard.MediaTray;
import javax.print.attribute.standard.MediaPrintableArea;
import javax.print.attribute.standard.PrinterResolution;
import javax.print.attribute.Size2DSyntax;
import javax.print.attribute.Attribute;
import javax.print.attribute.EnumSyntax;
@ -57,6 +58,8 @@ public class CUPSPrinter {
// CUPS does not support multi-threading.
private static synchronized native String[] getMedia(String printer);
private static synchronized native float[] getPageSizes(String printer);
private static synchronized native void
getResolutions(String printer, ArrayList<Integer> resolutionList);
//public static boolean useIPPMedia = false; will be used later
private MediaPrintableArea[] cupsMediaPrintables;
@ -68,6 +71,7 @@ public class CUPSPrinter {
public int nTrays = 0;
private String[] media;
private float[] pageSizes;
int[] resolutionsArray;
private String printer;
private static boolean libFound;
@ -119,6 +123,12 @@ public class CUPSPrinter {
nTrays = media.length/2-nPageSizes;
assert (nTrays >= 0);
}
ArrayList<Integer> resolutionList = new ArrayList<>();
getResolutions(printer, resolutionList);
resolutionsArray = new int[resolutionList.size()];
for (int i=0; i < resolutionList.size(); i++) {
resolutionsArray[i] = resolutionList.get(i);
}
}
}
@ -160,6 +170,12 @@ public class CUPSPrinter {
return cupsMediaTrays;
}
/**
* return the raw packed array of supported printer resolutions.
*/
int[] getRawResolutions() {
return resolutionsArray;
}
/**
* Initialize media by translating PPD info to PrintService attributes.

@ -96,6 +96,8 @@ public class IPPPrintService implements PrintService, SunPrinterJobService {
private MediaSizeName[] mediaSizeNames;
private CustomMediaSizeName[] customMediaSizeNames;
private int defaultMediaIndex;
private int[] rawResolutions = null;
private PrinterResolution[] printerResolutions = null;
private boolean isCupsPrinter;
private boolean init;
private Boolean isPS;
@ -414,6 +416,7 @@ public class IPPPrintService implements PrintService, SunPrinterJobService {
mediaTrays = cps.getMediaTrays();
customMediaSizeNames = cps.getCustomMediaSizeNames();
defaultMediaIndex = cps.getDefaultMediaIndex();
rawResolutions = cps.getRawResolutions();
urlConnection.disconnect();
init = true;
return;
@ -765,6 +768,15 @@ public class IPPPrintService implements PrintService, SunPrinterJobService {
return sidesSup;
}
}
} else if (category == PrinterResolution.class) {
PrinterResolution[] supportedRes = getPrintResolutions();
if (supportedRes == null) {
return null;
}
PrinterResolution []arr =
new PrinterResolution[supportedRes.length];
System.arraycopy(supportedRes, 0, arr, 0, supportedRes.length);
return arr;
}
return null;
@ -1043,6 +1055,14 @@ public class IPPPrintService implements PrintService, SunPrinterJobService {
if (getAttMap != null && getAttMap.containsKey("color-supported")) {
catList.add(Chromaticity.class);
}
// CUPS does not report printer resolution via IPP but it
// may be gleaned from the PPD.
PrinterResolution[] supportedRes = getPrintResolutions();
if (supportedRes != null && (supportedRes.length > 0)) {
catList.add(PrinterResolution.class);
}
supportedCats = new Class<?>[catList.size()];
catList.toArray(supportedCats);
return supportedCats;
@ -1362,6 +1382,10 @@ public class IPPPrintService implements PrintService, SunPrinterJobService {
}
}
return false;
} if (attr.getCategory() == PrinterResolution.class) {
if (attr instanceof PrinterResolution) {
return isSupportedResolution((PrinterResolution)attr);
}
}
return true;
}
@ -1523,11 +1547,48 @@ public class IPPPrintService implements PrintService, SunPrinterJobService {
}
}
return Sides.ONE_SIDED;
} else if (category == PrinterResolution.class) {
PrinterResolution[] supportedRes = getPrintResolutions();
if ((supportedRes != null) && (supportedRes.length > 0)) {
return supportedRes[0];
} else {
return new PrinterResolution(300, 300, PrinterResolution.DPI);
}
}
return null;
}
private PrinterResolution[] getPrintResolutions() {
if (printerResolutions == null) {
if (rawResolutions == null) {
printerResolutions = new PrinterResolution[0];
} else {
int numRes = rawResolutions.length / 2;
PrinterResolution[] pres = new PrinterResolution[numRes];
for (int i=0; i < numRes; i++) {
pres[i] = new PrinterResolution(rawResolutions[i*2],
rawResolutions[i*2+1],
PrinterResolution.DPI);
}
printerResolutions = pres;
}
}
return printerResolutions;
}
private boolean isSupportedResolution(PrinterResolution res) {
PrinterResolution[] supportedRes = getPrintResolutions();
if (supportedRes != null) {
for (int i=0; i<supportedRes.length; i++) {
if (res.equals(supportedRes[i])) {
return true;
}
}
}
return false;
}
public ServiceUIFactory getServiceUIFactory() {
return null;
}

@ -394,3 +394,112 @@ Java_sun_print_CUPSPrinter_getPageSizes(JNIEnv *env,
unlink(filename);
return sizeArray;
}
/*
* Populates the supplied ArrayList<Integer> with resolutions.
* The first pair of elements will be the default resolution.
* If resolution isn't supported the list will be empty.
* If needed we can add a 2nd ArrayList<String> which would
* be populated with the corresponding UI name.
* PPD specifies the syntax for resolution as either "Ndpi" or "MxNdpi",
* eg 300dpi or 600x600dpi. The former is a shorthand where xres==yres.
* We will always expand to the latter as we use a single array list.
* Note: getMedia() and getPageSizes() both open the ppd file
* This is not going to scale forever so if we add anymore we
* should look to consolidate this.
*/
JNIEXPORT void JNICALL
Java_sun_print_CUPSPrinter_getResolutions(JNIEnv *env,
jobject printObj,
jstring printer,
jobject arrayList)
{
ppd_file_t *ppd = NULL;
ppd_option_t *resolution;
int defx = 0, defy = 0;
int resx = 0, resy = 0;
jclass intCls, cls;
jmethodID intCtr, arrListAddMID;
int i;
intCls = (*env)->FindClass(env, "java/lang/Integer");
CHECK_NULL(intCls);
intCtr = (*env)->GetMethodID(env, intCls, "<init>", "(I)V");
CHECK_NULL(intCtr);
cls = (*env)->FindClass(env, "java/util/ArrayList");
CHECK_NULL(cls);
arrListAddMID =
(*env)->GetMethodID(env, cls, "add", "(Ljava/lang/Object;)Z");
CHECK_NULL(arrListAddMID);
const char *name = (*env)->GetStringUTFChars(env, printer, NULL);
if (name == NULL) {
(*env)->ExceptionClear(env);
JNU_ThrowOutOfMemoryError(env, "Could not create printer name");
}
const char *filename;
// NOTE: cupsGetPPD returns a pointer to a filename of a temporary file.
// unlink() must be called to remove the file after using it.
filename = j2d_cupsGetPPD(name);
(*env)->ReleaseStringUTFChars(env, printer, name);
CHECK_NULL(filename);
if ((ppd = j2d_ppdOpenFile(filename)) == NULL) {
unlink(filename);
DPRINTF("unable to open PPD %s\n", filename)
}
resolution = j2d_ppdFindOption(ppd, "Resolution");
if (resolution != NULL) {
int matches = sscanf(resolution->defchoice, "%dx%ddpi", &defx, &defy);
if (matches == 2) {
if (defx <= 0 || defy <= 0) {
defx = 0;
defy = 0;
}
} else {
matches = sscanf(resolution->defchoice, "%ddpi", &defx);
if (matches == 1) {
if (defx <= 0) {
defx = 0;
} else {
defy = defx;
}
}
}
if (defx > 0) {
jobject rxObj = (*env)->NewObject(env, intCls, intCtr, defx);
jobject ryObj = (*env)->NewObject(env, intCls, intCtr, defy);
(*env)->CallBooleanMethod(env, arrayList, arrListAddMID, rxObj);
(*env)->CallBooleanMethod(env, arrayList, arrListAddMID, ryObj);
}
for (i = 0; i < resolution->num_choices; i++) {
char *resStr = resolution->choices[i].choice;
int matches = sscanf(resStr, "%dx%ddpi", &resx, &resy);
if (matches == 2) {
if (resx <= 0 || resy <= 0) {
resx = 0;
resy = 0;
}
} else {
matches = sscanf(resStr, "%ddpi", &resx);
if (matches == 1) {
if (resx <= 0) {
resx = 0;
} else {
resy = resx;
}
}
}
if (resx > 0 && (resx != defx || resy != defy )) {
jobject rxObj = (*env)->NewObject(env, intCls, intCtr, resx);
jobject ryObj = (*env)->NewObject(env, intCls, intCtr, resy);
(*env)->CallBooleanMethod(env, arrayList, arrListAddMID, rxObj);
(*env)->CallBooleanMethod(env, arrayList, arrListAddMID, ryObj);
}
}
}
j2d_ppdClose(ppd);
unlink(filename);
}

@ -0,0 +1,58 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 8048328
* @summary CUPS Printing does not report supported printer resolutions.
* @run main PrintResAttr
*/
/*
* Since there is no guarantee you have any printers that support
* resolution this test can't verify that resolution is being
* reported when supported. But when they are it should test that
* the code behaves reasonably.
*/
import javax.print.*;
import javax.print.attribute.*;
import javax.print.attribute.standard.*;
public class PrintResAttr {
public static void main(String args[]) throws Exception {
PrintService[] services =
PrintServiceLookup.lookupPrintServices(null,null);
for (int i=0; i<services.length; i++) {
if (services[i].isAttributeCategorySupported(PrinterResolution.class)) {
System.out.println("Testing " + services[i]);
PrinterResolution[] res = (PrinterResolution[])
services[i].getSupportedAttributeValues(PrinterResolution.class,
null,null);
System.out.println("# supp res= " + res.length);
for (int r=0;r<res.length;r++) System.out.println(res[r]);
}
}
}
}