8375221: Update code to get PrinterResolution from CUPS/IPP print service

Reviewed-by: serb, psadhukhan
This commit is contained in:
Phil Race 2026-01-23 18:19:23 +00:00
parent 2c3ad0f425
commit e08fb3a914
4 changed files with 120 additions and 36 deletions

View File

@ -174,6 +174,30 @@ public final class AttributeClass {
}
/**
* Returns 3 int values.
* xres, yres, resolution as either dpi or dpcm
* The resolution is just a single byte of data.
*/
public int[] getIntResolutionValue() {
int[] res = {0, 0, 0};
byte[] bufArray = (byte[])myValue;
if (bufArray != null) {
int nBytes = 4; // 32-bit signed integer
for (int j=0; j<2; j++) { // 2 set of integers
byte[] intBytes = new byte[nBytes];
// REMIND: # bytes should be 8
for (int i=0; i< nBytes; i++) {
//+ 1 because the 1st byte is length
intBytes[i] = bufArray[i+(4*j)+1];
}
res[j] = convertToInt(intBytes);
}
res[2] = (int)bufArray[9];
}
return res;
}
/**
* Returns String value.
*/

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2026, 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
@ -141,7 +141,7 @@ public final class IPPPrintService implements PrintService, SunPrinterJobService
private MediaSizeName[] mediaSizeNames;
private CustomMediaSizeName[] customMediaSizeNames;
private int defaultMediaIndex;
private int[] rawResolutions = null;
private int[] ppdResolutions = null;
private PrinterResolution[] printerResolutions = null;
private boolean isCupsPrinter;
private boolean init;
@ -205,8 +205,7 @@ public final class IPPPrintService implements PrintService, SunPrinterJobService
OrientationRequested.PORTRAIT,
new PageRanges(1),
//PresentationDirection,
// CUPS does not supply printer-resolution attribute
//new PrinterResolution(300, 300, PrinterResolution.DPI),
new PrinterResolution(300, 300, PrinterResolution.DPI),
//PrintQuality.NORMAL,
new RequestingUserName("", Locale.getDefault()),
//SheetCollate.UNCOLLATED, //CUPS has no sheet collate?
@ -467,7 +466,9 @@ public final class IPPPrintService implements PrintService, SunPrinterJobService
: getSupportedOutputBins();
customMediaSizeNames = cps.getCustomMediaSizeNames();
defaultMediaIndex = cps.getDefaultMediaIndex();
rawResolutions = cps.getRawResolutions();
if (ppdResolutions == null) {
ppdResolutions = cps.getRawResolutions();
}
}
urlConnection.disconnect();
init = true;
@ -821,14 +822,7 @@ public final class IPPPrintService implements PrintService, SunPrinterJobService
}
}
} 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 getPrintResolutions();
} else if (category == OutputBin.class) {
return Arrays.copyOf(outputBins, outputBins.length);
}
@ -1137,8 +1131,6 @@ public final class IPPPrintService implements PrintService, SunPrinterJobService
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);
@ -1264,7 +1256,6 @@ public final class IPPPrintService implements PrintService, SunPrinterJobService
}
}
@Override
public synchronized PrintServiceAttributeSet getAttributes() {
if (!init) {
@ -1684,9 +1675,7 @@ public final class IPPPrintService implements PrintService, SunPrinterJobService
} 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 supportedRes[0];
}
} else if (category == OutputBin.class) {
if (attribClass != null) {
@ -1697,26 +1686,40 @@ public final class IPPPrintService implements PrintService, SunPrinterJobService
return null;
}
/* Called only from contexts that have called initAttributes().
* Try IPP first, and if that produces nothing, fall back to the PPD
*/
private PrinterResolution[] getPrintResolutions() {
int[] rawResolutions = null;
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;
AttributeClass attribClass = (getAttMap != null) ?
getAttMap.get("printer-resolution-supported")
: null;
if (attribClass != null) {
rawResolutions = attribClass.getIntResolutionValue();
}
if (rawResolutions == null) {
rawResolutions = ppdResolutions;
}
if (rawResolutions == null) {
rawResolutions = new int[] { 300, 300, 3 } ;
}
int numRes = rawResolutions.length / 3;
PrinterResolution[] pres = new PrinterResolution[numRes];
for (int i = 0; i < numRes; i++) {
int units = (rawResolutions[i*3+2] == 4) ? PrinterResolution.DPCM : PrinterResolution.DPI;
pres[i] = new PrinterResolution(rawResolutions[i*3],
rawResolutions[i*3+1],
units);
}
printerResolutions = pres;
}
return printerResolutions;
return printerResolutions.clone();
}
private boolean isSupportedResolution(PrinterResolution res) {
PrinterResolution[] supportedRes = getPrintResolutions();
PrinterResolution[] supportedRes =
(PrinterResolution[])getSupportedAttributeValues(PrinterResolution.class, null, null);
if (supportedRes != null) {
for (int i=0; i<supportedRes.length; i++) {
if (res.equals(supportedRes[i])) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2026, 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
@ -52,6 +52,8 @@ typedef ppd_file_t* (*fn_ppdOpenFile)(const char *);
typedef void (*fn_ppdClose)(ppd_file_t *);
typedef ppd_option_t* (*fn_ppdFindOption)(ppd_file_t *, const char *);
typedef ppd_size_t* (*fn_ppdPageSize)(ppd_file_t *, char *);
typedef ppd_attr_t* (*fn_ppdFindAttr)(ppd_file_t *, const char *name, const char *spec);
typedef ppd_attr_t* (*fn_ppdFindNextAttr)(ppd_file_t *, const char *name, const char *spec);
fn_cupsServer j2d_cupsServer;
fn_ippPort j2d_ippPort;
@ -64,6 +66,8 @@ fn_cupsFreeDests j2d_cupsFreeDests;
fn_ppdOpenFile j2d_ppdOpenFile;
fn_ppdClose j2d_ppdClose;
fn_ppdFindOption j2d_ppdFindOption;
fn_ppdFindAttr j2d_ppdFindAttr;
fn_ppdFindNextAttr j2d_ppdFindNextAttr;
fn_ppdPageSize j2d_ppdPageSize;
@ -152,6 +156,18 @@ Java_sun_print_CUPSPrinter_initIDs(JNIEnv *env,
return JNI_FALSE;
}
j2d_ppdFindAttr = (fn_ppdFindAttr)dlsym(handle, "ppdFindAttr");
if (j2d_ppdFindAttr == NULL) {
dlclose(handle);
return JNI_FALSE;
}
j2d_ppdFindNextAttr = (fn_ppdFindNextAttr)dlsym(handle, "ppdFindNextAttr");
if (j2d_ppdFindNextAttr == NULL) {
dlclose(handle);
return JNI_FALSE;
}
j2d_ppdPageSize = (fn_ppdPageSize)dlsym(handle, "ppdPageSize");
if (j2d_ppdPageSize == NULL) {
dlclose(handle);
@ -636,6 +652,9 @@ Java_sun_print_CUPSPrinter_getResolutions(JNIEnv *env,
return;
}
// IPP value of 3 means DPI, 4 means dpcm
jobject dpi = (*env)->NewObject(env, intCls, intCtr, 3);
CHECK_NULL(dpi);
// NOTE: cupsGetPPD returns a pointer to a filename of a temporary file.
// unlink() must be called to remove the file after using it.
@ -672,6 +691,7 @@ Java_sun_print_CUPSPrinter_getResolutions(JNIEnv *env,
CHECK_NULL(ryObj);
(*env)->CallBooleanMethod(env, arrayList, arrListAddMID, rxObj);
(*env)->CallBooleanMethod(env, arrayList, arrListAddMID, ryObj);
(*env)->CallBooleanMethod(env, arrayList, arrListAddMID, dpi);
}
for (i = 0; i < resolution->num_choices; i++) {
@ -700,6 +720,41 @@ Java_sun_print_CUPSPrinter_getResolutions(JNIEnv *env,
CHECK_NULL(ryObj);
(*env)->CallBooleanMethod(env, arrayList, arrListAddMID, rxObj);
(*env)->CallBooleanMethod(env, arrayList, arrListAddMID, ryObj);
(*env)->CallBooleanMethod(env, arrayList, arrListAddMID, dpi);
}
}
} else {
ppd_attr_t *defresolution = j2d_ppdFindAttr(ppd, "DefaultResolution", NULL);
if (defresolution == NULL) {
defresolution = j2d_ppdFindAttr(ppd, "Resolution", NULL);
}
if (defresolution != NULL) {
int matches = sscanf(defresolution->value, "%dx%ddpi", &defx, &defy);
if (matches == 2) {
if (defx <= 0 || defy <= 0) {
defx = 0;
defy = 0;
}
} else {
matches = sscanf(defresolution->value, "%ddpi", &defx);
if (matches == 1) {
if (defx <= 0) {
defx = 0;
} else {
defy = defx;
}
}
}
if (defx > 0) {
jobject rxObj, ryObj;
rxObj = (*env)->NewObject(env, intCls, intCtr, defx);
CHECK_NULL(rxObj);
ryObj = (*env)->NewObject(env, intCls, intCtr, defy);
CHECK_NULL(ryObj);
(*env)->CallBooleanMethod(env, arrayList, arrListAddMID, rxObj);
(*env)->CallBooleanMethod(env, arrayList, arrListAddMID, ryObj);
(*env)->CallBooleanMethod(env, arrayList, arrListAddMID, dpi);
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2025, BELLSOFT. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -54,7 +54,7 @@ import java.awt.print.PrinterJob;
/*
* @test
* @bug 8251928
* @bug 8251928 8375221
* @key printer
* @summary Printable.print method should reflect printer's DPI
* @library /java/awt/regtesthelpers
@ -201,7 +201,9 @@ public class PrintablePrintDPI implements Printable {
attributeSet.add(OrientationRequested.PORTRAIT);
job.setPrintService(printService);
job.setPrintable(this);
job.print(attributeSet);
if (job.printDialog(attributeSet)) {
job.print(attributeSet);
}
} catch (PrinterException ex) {
throw new RuntimeException(ex);
}