java-topology/test/jdk/javax/print/PrintablePrintDPI.java
russell@unturf.com 0a580b313d undefect. CWE-407 — 63 sites patched across 27 ecosystems
Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com

Patches, unit tests, benchmarks, whitepaper, and outreach briefs.
Public domain — no copyright claimed. Use freely.
2026-03-26 17:11:57 -04:00

302 lines
12 KiB
Java

/*
* 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.
*
* 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.
*/
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.print.attribute.ResolutionSyntax;
import javax.print.attribute.standard.OrientationRequested;
import javax.print.attribute.standard.PrinterResolution;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.ListCellRenderer;
import javax.swing.border.EmptyBorder;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.GeneralPath;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
/*
* @test
* @bug 8251928 8375221
* @key printer
* @summary Printable.print method should reflect printer's DPI
* @library /java/awt/regtesthelpers
* @requires os.family == "mac"
* @build PassFailJFrame
* @run main/manual PrintablePrintDPI
*/
public class PrintablePrintDPI implements Printable {
private static final double PAPER_DPI = 72.0;
private static final int DEFAULT_DOCUMENT_DPI = 300;
private static final int UNITS = ResolutionSyntax.DPI;
private static final String INSTRUCTIONS = """
This test checks document DPI.
To be able to run this test it is required to have a
printer configured in your user environment.
Test's steps:
- Choose a printer.
- Choose a printer resolution.
- Press 'Print' button.
Visual inspection of the printed pages is needed.
A passing test will print chosen DPI on the printed page,
2 vertical and 2 horizontal lines.
""";
private final PrintService printService;
private final PrinterResolution printerResolution;
public static void main(String[] args) throws Exception {
PrintService[] availablePrintServices = PrintServiceLookup.lookupPrintServices(null, null);
if (availablePrintServices.length == 0) {
System.out.println("Available print services not found");
return;
}
PassFailJFrame.builder()
.instructions(INSTRUCTIONS)
.testTimeOut(300)
.title("Document DPI test")
.testUI(createTestWindow(availablePrintServices))
.build()
.awaitAndCheck();
}
private static Window createTestWindow(final PrintService[] availablePrintServices) {
final Window frame = new JFrame("Choose service to test");
JPanel pnlMain = new JPanel();
pnlMain.setBorder(new EmptyBorder(5, 5, 5, 5));
pnlMain.setLayout(new GridLayout(3, 1, 5, 5));
JLabel lblServices = new JLabel("Available services");
JLabel lblResolutions = new JLabel("Available resolutions");
JButton btnPrint = new JButton("Print");
btnPrint.setEnabled(false);
JComboBox<PrinterResolution> cbResolutions = new JComboBox<>();
cbResolutions.setRenderer(new ListCellRenderer<PrinterResolution>() {
@Override
public Component getListCellRendererComponent(JList<? extends PrinterResolution> list,
PrinterResolution value,
int index, boolean isSelected, boolean cellHasFocus) {
String str = value == null ? "" :
String.format("%dx%d DPI",
value.getCrossFeedResolution(UNITS), value.getFeedResolution(UNITS));
return new JLabel(str);
}
});
cbResolutions.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
btnPrint.setEnabled(cbResolutions.getSelectedItem() != null);
}
});
JComboBox<PrintService> cbServices = new JComboBox<>();
cbServices.setRenderer(new ListCellRenderer<PrintService>() {
@Override
public Component getListCellRendererComponent(JList<? extends PrintService> list, PrintService value,
int index, boolean isSelected, boolean cellHasFocus) {
return new JLabel(value == null ? "" : value.getName());
}
});
cbServices.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
PrintService ps = (PrintService) cbServices.getSelectedItem();
cbResolutions.removeAllItems();
btnPrint.setEnabled(ps != null);
if (ps != null) {
PrinterResolution[] supportedResolutions = (PrinterResolution[])ps
.getSupportedAttributeValues(PrinterResolution.class, null, null);
if (supportedResolutions == null || supportedResolutions.length == 0) {
cbResolutions.addItem(new PrinterResolution(DEFAULT_DOCUMENT_DPI, DEFAULT_DOCUMENT_DPI, UNITS));
} else {
for (PrinterResolution pr : supportedResolutions) {
cbResolutions.addItem(pr);
}
}
}
}
});
for (PrintService ps : availablePrintServices) {
cbServices.addItem(ps);
}
lblServices.setLabelFor(cbServices);
btnPrint.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
PrintService printService = (PrintService) cbServices.getSelectedItem();
PrinterResolution resolution = (PrinterResolution) cbResolutions.getSelectedItem();
if (printService != null && resolution != null) {
cbServices.setEnabled(false);
cbResolutions.setEnabled(false);
btnPrint.setEnabled(false);
frame.setVisible(false);
new PrintablePrintDPI(printService, resolution).test();
}
}
});
pnlMain.add(lblServices);
pnlMain.add(cbServices);
pnlMain.add(lblResolutions);
pnlMain.add(cbResolutions);
pnlMain.add(btnPrint);
frame.add(pnlMain);
frame.pack();
return frame;
}
private PrintablePrintDPI(PrintService printService, PrinterResolution printerResolution) {
this.printService = printService;
this.printerResolution = printerResolution;
}
private void test() {
System.out.printf("Perform test using %s and %dx%d DPI\n",
printService.getName(),
printerResolution.getCrossFeedResolution(UNITS),
printerResolution.getFeedResolution(UNITS));
PrinterJob job = PrinterJob.getPrinterJob();
try {
PrintRequestAttributeSet attributeSet = new HashPrintRequestAttributeSet();
attributeSet.add(printerResolution);
attributeSet.add(OrientationRequested.PORTRAIT);
job.setPrintService(printService);
job.setPrintable(this);
if (job.printDialog(attributeSet)) {
job.print(attributeSet);
}
} catch (PrinterException ex) {
throw new RuntimeException(ex);
}
}
@Override
public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
if (pageIndex > 0) {
return NO_SUCH_PAGE;
}
final int[] deviceRes = printerResolution.getResolution(ResolutionSyntax.DPI);
Graphics2D g2 = (Graphics2D)graphics;
double hRes = g2.getTransform().getScaleX() * PAPER_DPI;
double vRes = g2.getTransform().getScaleY() * PAPER_DPI;
// Horizontal and vertical document resolution
g2.drawLine((int)pageFormat.getImageableX() + 5, (int)pageFormat.getImageableY() + 5,
(int)pageFormat.getImageableX() + 50, (int)pageFormat.getImageableY() + 5);
g2.drawString(Integer.toString((int)hRes),
(int)pageFormat.getImageableX() + 60,
(int)pageFormat.getImageableY() + 5 + g2.getFontMetrics().getHeight() / 2);
g2.drawLine((int)pageFormat.getImageableX() + 5, (int)pageFormat.getImageableY() + 5,
(int)pageFormat.getImageableX() + 5, (int)pageFormat.getImageableY() + 50);
g2.drawString(Integer.toString((int)vRes),
(int)pageFormat.getImageableX() + 5, (int)pageFormat.getImageableY() + 60);
String msg = String.format(
"Expected DPI: %dx%d, actual: %dx%d.\n",
deviceRes[0], deviceRes[1], (int)hRes, (int)vRes);
System.out.println(msg);
int msgX = (int)pageFormat.getImageableX() +
g2.getFontMetrics().stringWidth(Integer.toString((int)vRes)) + 20;
int msgY = (int)pageFormat.getImageableY() +
g2.getFontMetrics().getHeight() + 20;
g2.drawString(msg, msgX, msgY);
msgY += 20;
g2.drawString("ScaleX: " + g2.getTransform().getScaleX(), msgX, msgY);
msgY += 20;
g2.drawString("ScaleY: " + g2.getTransform().getScaleY(), msgX, msgY);
final float lineWidth = 0.2f;
double pageWidth = pageFormat.getWidth();
double xLeft = pageWidth / 10;
double yBase = pageFormat.getHeight() / 2;
double xBase = pageFormat.getWidth() / 2;
double yTop = yBase + 40;
double yBottom = pageFormat.getHeight() - pageFormat.getHeight() / 10;
g2.setStroke(new BasicStroke(lineWidth));
double xRight = pageWidth - xLeft;
g2.drawLine((int) xLeft, (int) yBase + 80,
(int) (xRight),(int) yBase + 80);
g2.drawLine((int) xBase, (int) yTop,
(int) (xBase),(int) yBottom);
GeneralPath line = new GeneralPath();
double halfLineWidth = lineWidth / 2.0f;
double yLine = yBase + 100;
double xLine = xBase + 20;
line.moveTo(xLeft, yLine);
line.lineTo(xLeft, yLine - halfLineWidth);
line.lineTo(xLine - halfLineWidth, yLine - halfLineWidth);
line.lineTo(xLine - halfLineWidth, yTop);
line.lineTo(xLine + halfLineWidth, yTop);
line.lineTo(xLine + halfLineWidth, yLine - halfLineWidth);
line.lineTo(xRight, yLine - halfLineWidth);
line.lineTo(xRight, yLine + halfLineWidth);
line.lineTo(xLine + halfLineWidth, yLine + halfLineWidth);
line.lineTo(xLine + halfLineWidth, yBottom);
line.lineTo(xLine - halfLineWidth, yBottom);
line.lineTo(xLine - halfLineWidth, yLine + halfLineWidth);
line.lineTo(xLeft, yLine + halfLineWidth );
line.closePath();
g2.clip(line);
g2.setColor(Color.RED);
line.reset();
line.moveTo(xLeft, yLine);
line.lineTo(xRight, yLine);
g2.draw(line);
line.reset();
line.moveTo(xBase + 20, yTop);
line.lineTo(xBase + 20, yBottom);
g2.draw(line);
return PAGE_EXISTS;
}
}