# HG changeset patch # User prr # Date 1405102379 25200 # Node ID 21b78da4b2df832c790cb2166dd28bda205ab5b8 # Parent 07cae3ef5f5707dfad418fcaa04a75b88f9d36ef 8048328: CUPS Printing does not report supported printer resolutions. Reviewed-by: bae, jgodinez diff -r 07cae3ef5f57 -r 21b78da4b2df jdk/make/mapfiles/libawt/mapfile-mawt-vers --- a/jdk/make/mapfiles/libawt/mapfile-mawt-vers Fri Jul 11 18:46:47 2014 +0400 +++ b/jdk/make/mapfiles/libawt/mapfile-mawt-vers Fri Jul 11 11:12:59 2014 -0700 @@ -204,6 +204,7 @@ 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; diff -r 07cae3ef5f57 -r 21b78da4b2df jdk/make/mapfiles/libawt_headless/mapfile-vers --- a/jdk/make/mapfiles/libawt_headless/mapfile-vers Fri Jul 11 18:46:47 2014 +0400 +++ b/jdk/make/mapfiles/libawt_headless/mapfile-vers Fri Jul 11 11:12:59 2014 -0700 @@ -76,6 +76,7 @@ Java_sun_print_CUPSPrinter_canConnect; Java_sun_print_CUPSPrinter_getMedia; Java_sun_print_CUPSPrinter_getPageSizes; + Java_sun_print_CUPSPrinter_getResolutions; # libfontmanager entry points AWTIsHeadless; diff -r 07cae3ef5f57 -r 21b78da4b2df jdk/make/mapfiles/libawt_xawt/mapfile-vers --- a/jdk/make/mapfiles/libawt_xawt/mapfile-vers Fri Jul 11 18:46:47 2014 +0400 +++ b/jdk/make/mapfiles/libawt_xawt/mapfile-vers Fri Jul 11 11:12:59 2014 -0700 @@ -442,6 +442,7 @@ Java_sun_print_CUPSPrinter_canConnect; Java_sun_print_CUPSPrinter_getMedia; Java_sun_print_CUPSPrinter_getPageSizes; + Java_sun_print_CUPSPrinter_getResolutions; awt_GetDrawingSurface; awt_FreeDrawingSurface; diff -r 07cae3ef5f57 -r 21b78da4b2df jdk/src/share/classes/sun/print/PSPrinterJob.java --- a/jdk/src/share/classes/sun/print/PSPrinterJob.java Fri Jul 11 18:46:47 2014 +0400 +++ b/jdk/src/share/classes/sun/print/PSPrinterJob.java Fri Jul 11 11:12:59 2014 -0700 @@ -168,13 +168,6 @@ 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 @@ 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 @@ } } + 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 @@ mPSStream.println(" >> setpagedevice"); } mPSStream.println(PAGE_SAVE); - mPSStream.println(paperHeight + COORD_PREP); + mPSStream.println(paperHeight + getCoordPrep()); } /** @@ -1493,14 +1498,22 @@ * 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; } /** diff -r 07cae3ef5f57 -r 21b78da4b2df jdk/src/share/classes/sun/print/RasterPrinterJob.java --- a/jdk/src/share/classes/sun/print/RasterPrinterJob.java Fri Jul 11 18:46:47 2014 +0400 +++ b/jdk/src/share/classes/sun/print/RasterPrinterJob.java Fri Jul 11 11:12:59 2014 -0700 @@ -72,6 +72,7 @@ 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.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 @@ 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 @@ 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 @@ /* reset all values to defaults */ setCollated(false); sidesAttr = null; + printerResAttr = null; pageRangesAttr = null; copiesAttr = 0; jobNameAttr = null; @@ -1117,6 +1129,18 @@ 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; diff -r 07cae3ef5f57 -r 21b78da4b2df jdk/src/solaris/classes/sun/print/CUPSPrinter.java --- a/jdk/src/solaris/classes/sun/print/CUPSPrinter.java Fri Jul 11 18:46:47 2014 +0400 +++ b/jdk/src/solaris/classes/sun/print/CUPSPrinter.java Fri Jul 11 11:12:59 2014 -0700 @@ -39,6 +39,7 @@ 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 @@ // 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 resolutionList); //public static boolean useIPPMedia = false; will be used later private MediaPrintableArea[] cupsMediaPrintables; @@ -68,6 +71,7 @@ public int nTrays = 0; private String[] media; private float[] pageSizes; + int[] resolutionsArray; private String printer; private static boolean libFound; @@ -119,6 +123,12 @@ nTrays = media.length/2-nPageSizes; assert (nTrays >= 0); } + ArrayList 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 @@ return cupsMediaTrays; } + /** + * return the raw packed array of supported printer resolutions. + */ + int[] getRawResolutions() { + return resolutionsArray; + } /** * Initialize media by translating PPD info to PrintService attributes. diff -r 07cae3ef5f57 -r 21b78da4b2df jdk/src/solaris/classes/sun/print/IPPPrintService.java --- a/jdk/src/solaris/classes/sun/print/IPPPrintService.java Fri Jul 11 18:46:47 2014 +0400 +++ b/jdk/src/solaris/classes/sun/print/IPPPrintService.java Fri Jul 11 11:12:59 2014 -0700 @@ -96,6 +96,8 @@ 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 @@ mediaTrays = cps.getMediaTrays(); customMediaSizeNames = cps.getCustomMediaSizeNames(); defaultMediaIndex = cps.getDefaultMediaIndex(); + rawResolutions = cps.getRawResolutions(); urlConnection.disconnect(); init = true; return; @@ -765,6 +768,15 @@ 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 @@ 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 @@ } } return false; + } if (attr.getCategory() == PrinterResolution.class) { + if (attr instanceof PrinterResolution) { + return isSupportedResolution((PrinterResolution)attr); + } } return true; } @@ -1523,11 +1547,48 @@ } } 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 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 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, "", "(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); +} diff -r 07cae3ef5f57 -r 21b78da4b2df jdk/test/javax/print/attribute/PrintResAttr.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/print/attribute/PrintResAttr.java Fri Jul 11 11:12:59 2014 -0700 @@ -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