Skip to content

Commit e9370a1

Browse files
author
Alexander Scherbatiy
committed
8265761: Font with missed font family name is not properly printed on Windows
Reviewed-by: serb, prr
1 parent 3554dc2 commit e9370a1

File tree

3 files changed

+293
-0
lines changed

3 files changed

+293
-0
lines changed

src/java.desktop/windows/classes/sun/awt/windows/WPrinterJob.java

+4
Original file line numberDiff line numberDiff line change
@@ -1157,6 +1157,10 @@ protected boolean selectStylePen(int cap, int join, float width,
11571157
protected boolean setFont(String family, float size, int style,
11581158
int rotation, float awScale) {
11591159

1160+
if (family.isEmpty()) {
1161+
return false;
1162+
}
1163+
11601164
boolean didSetFont = true;
11611165

11621166
if (!family.equals(mLastFontFamily) ||
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,289 @@
1+
/*
2+
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
3+
* Copyright (c) 2021, BELLSOFT. All rights reserved.
4+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5+
*
6+
* This code is free software; you can redistribute it and/or modify it
7+
* under the terms of the GNU General Public License version 2 only, as
8+
* published by the Free Software Foundation.
9+
*
10+
* This code is distributed in the hope that it will be useful, but WITHOUT
11+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13+
* version 2 for more details (a copy is included in the LICENSE file that
14+
* accompanied this code).
15+
*
16+
* You should have received a copy of the GNU General Public License version
17+
* 2 along with this work; if not, write to the Free Software Foundation,
18+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19+
*
20+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21+
* or visit www.oracle.com if you need additional information or have any
22+
* questions.
23+
*/
24+
25+
/**
26+
* @test
27+
* @bug 8265761
28+
* @requires (os.family == "windows")
29+
* @summary Font with missed font family name is not properly printed on Windows
30+
* @run main/othervm/manual PrintFontWithMissedFontFamilyTest
31+
*/
32+
33+
import javax.print.PrintServiceLookup;
34+
import javax.swing.*;
35+
import java.awt.*;
36+
import java.awt.event.WindowAdapter;
37+
import java.awt.event.WindowEvent;
38+
import java.awt.font.FontRenderContext;
39+
import java.awt.font.GlyphVector;
40+
import java.awt.geom.AffineTransform;
41+
import java.awt.print.PageFormat;
42+
import java.awt.print.Printable;
43+
import java.awt.print.PrinterException;
44+
import java.awt.print.PrinterJob;
45+
import java.io.File;
46+
import java.io.IOException;
47+
import java.util.concurrent.CountDownLatch;
48+
import java.util.concurrent.TimeUnit;
49+
50+
public class PrintFontWithMissedFontFamilyTest {
51+
52+
private static final String DESCRIPTION =
53+
" 1. Setup 'Microsoft Print to PDF' printer on Windows.\n" +
54+
" 2. Press Print button to print a text with a custom font to PDF.\n" +
55+
" 3. Choose 'Microsoft Print to PDF' on the print dialog and press OK.\n" +
56+
" 4. Open the PDF file.\n" +
57+
" Three lines with text ABCDEF and the same custom font should be printed.\n" +
58+
" 5. Compare the text from the pdf with three strings drawn on the right pane.\n" +
59+
" The pdf and the pane text should have the same font.\n" +
60+
" 6. If so, press PASS button, otherwise press FAIL button.\n";
61+
62+
private static final CountDownLatch testEndedSignal = new CountDownLatch(1);
63+
private static final int testTimeout = 300000;
64+
private static volatile String testFailureMsg;
65+
private static volatile boolean testPassed;
66+
private static volatile boolean testFinished;
67+
private static final float FONT_SIZE = 32.0f;
68+
private static final String TEXT = "ABCDEF";
69+
private static final String FONT_FILE = "SampleFontMissedFontFamily.ttf";
70+
private static Font customFont;
71+
72+
public static void main(String[] args) throws Exception {
73+
74+
SwingUtilities.invokeLater(() -> createAndShowTestDialog());
75+
76+
try {
77+
if (!testEndedSignal.await(testTimeout, TimeUnit.MILLISECONDS)) {
78+
throw new RuntimeException(String.format(
79+
"Test timeout '%d ms' elapsed.", testTimeout));
80+
}
81+
if (!testPassed) {
82+
String failureMsg = testFailureMsg;
83+
if ((failureMsg != null) && (!failureMsg.trim().isEmpty())) {
84+
throw new RuntimeException(failureMsg);
85+
} else {
86+
throw new RuntimeException("Test failed.");
87+
}
88+
}
89+
} catch (InterruptedException ie) {
90+
throw new RuntimeException(ie);
91+
} finally {
92+
testFinished = true;
93+
}
94+
}
95+
96+
private static void pass() {
97+
testPassed = true;
98+
testEndedSignal.countDown();
99+
}
100+
101+
private static void fail(String failureMsg) {
102+
testFailureMsg = failureMsg;
103+
testPassed = false;
104+
testEndedSignal.countDown();
105+
}
106+
107+
private static String convertMillisToTimeStr(int millis) {
108+
if (millis < 0) {
109+
return "00:00:00";
110+
}
111+
int hours = millis / 3600000;
112+
int minutes = (millis - hours * 3600000) / 60000;
113+
int seconds = (millis - hours * 3600000 - minutes * 60000) / 1000;
114+
return String.format("%02d:%02d:%02d", hours, minutes, seconds);
115+
}
116+
117+
private static void createAndShowTestDialog() {
118+
119+
final JDialog dialog = new JDialog();
120+
dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
121+
dialog.addWindowListener(new WindowAdapter() {
122+
@Override
123+
public void windowClosing(WindowEvent e) {
124+
dialog.dispose();
125+
fail("Main dialog was closed.");
126+
}
127+
});
128+
129+
final JLabel testTimeoutLabel = new JLabel(String.format(
130+
"Test timeout: %s", convertMillisToTimeStr(testTimeout)));
131+
final long startTime = System.currentTimeMillis();
132+
final Timer timer = new Timer(0, null);
133+
timer.setDelay(1000);
134+
timer.addActionListener((e) -> {
135+
int leftTime = testTimeout - (int) (System.currentTimeMillis() - startTime);
136+
if ((leftTime < 0) || testFinished) {
137+
timer.stop();
138+
dialog.dispose();
139+
}
140+
testTimeoutLabel.setText(String.format(
141+
"Test timeout: %s", convertMillisToTimeStr(leftTime)));
142+
});
143+
timer.start();
144+
145+
JTextArea textArea = new JTextArea(DESCRIPTION);
146+
textArea.setEditable(false);
147+
148+
final JButton testButton = new JButton("Print");
149+
final JButton passButton = new JButton("PASS");
150+
final JButton failButton = new JButton("FAIL");
151+
152+
testButton.addActionListener((e) -> {
153+
testButton.setEnabled(false);
154+
new Thread(() -> {
155+
try {
156+
doTest();
157+
158+
SwingUtilities.invokeLater(() -> {
159+
passButton.setEnabled(true);
160+
failButton.setEnabled(true);
161+
});
162+
} catch (Throwable t) {
163+
t.printStackTrace();
164+
dialog.dispose();
165+
fail("Exception occurred in a thread executing the test.");
166+
}
167+
}).start();
168+
});
169+
passButton.setEnabled(false);
170+
passButton.addActionListener((e) -> {
171+
dialog.dispose();
172+
pass();
173+
});
174+
failButton.setEnabled(false);
175+
failButton.addActionListener((e) -> {
176+
dialog.dispose();
177+
fail("TitledBorder label is cut off");
178+
});
179+
180+
try {
181+
File dir = new File(System.getProperty("test.src", "."));
182+
File customFontFile = new File(dir, FONT_FILE);
183+
customFont = Font.createFont(Font.TRUETYPE_FONT, customFontFile);
184+
customFont = customFont.deriveFont(FONT_SIZE);
185+
} catch(Exception e) {
186+
fail("Unable to load the custom font: " + e);
187+
}
188+
189+
JPanel mainPanel = new JPanel(new BorderLayout());
190+
JPanel textPanel = new JPanel() {
191+
@Override
192+
public void paint(Graphics g) {
193+
super.paint(g);
194+
drawText((Graphics2D) g, customFont, TEXT);
195+
}
196+
};
197+
198+
textPanel.setPreferredSize(new Dimension(300, 300));
199+
200+
JPanel labelPanel = new JPanel(new FlowLayout());
201+
labelPanel.add(testTimeoutLabel);
202+
mainPanel.add(labelPanel, BorderLayout.NORTH);
203+
mainPanel.add(textPanel, BorderLayout.EAST);
204+
mainPanel.add(textArea, BorderLayout.CENTER);
205+
JPanel buttonPanel = new JPanel(new FlowLayout());
206+
buttonPanel.add(testButton);
207+
buttonPanel.add(passButton);
208+
buttonPanel.add(failButton);
209+
mainPanel.add(buttonPanel, BorderLayout.SOUTH);
210+
dialog.add(mainPanel);
211+
212+
dialog.pack();
213+
dialog.setVisible(true);
214+
}
215+
216+
private static void doTest() throws Exception {
217+
SwingUtilities.invokeAndWait(() -> {
218+
try {
219+
new TestPrintable();
220+
} catch (PrinterException e) {
221+
throw new RuntimeException(e);
222+
}
223+
});
224+
}
225+
226+
private static void drawText(Graphics2D g, Font font, String text) {
227+
228+
Font prevFont = g.getFont();
229+
g.setFont(font);
230+
FontRenderContext frc = new FontRenderContext(new AffineTransform(), false, true);
231+
232+
Rectangle clip = g.getClipBounds();
233+
int cx = (int) clip.getCenterX();
234+
int cy = (int) (0.5 * clip.getCenterY());
235+
236+
FontMetrics metrics = g.getFontMetrics();
237+
int w = metrics.stringWidth(text);
238+
int h = metrics.getHeight();
239+
240+
int x = cx - w / 2;
241+
int y = cy - h / 4;
242+
243+
g.drawString(text, x, y);
244+
245+
GlyphVector gv = font.createGlyphVector(frc, text);
246+
g.drawGlyphVector(gv, x, y + h);
247+
248+
gv = font.deriveFont(1.0f).createGlyphVector(frc, text);
249+
int fontSize = font.getSize();
250+
251+
AffineTransform scale = AffineTransform.getScaleInstance(fontSize, fontSize);
252+
for (int i = 0; i < gv.getNumGlyphs(); i++) {
253+
gv.setGlyphTransform(i, scale);
254+
}
255+
256+
g.drawGlyphVector(gv, x, y + 2 * h);
257+
258+
g.setFont(prevFont);
259+
}
260+
261+
private static class TestPrintable implements Printable {
262+
263+
TestPrintable() throws PrinterException {
264+
PrinterJob job = PrinterJob.getPrinterJob();
265+
job.setPrintService(PrintServiceLookup.lookupDefaultPrintService());
266+
job.setPrintable(this);
267+
268+
if (job.printDialog()) {
269+
job.print();
270+
} else {
271+
throw new RuntimeException("Printing was canceled!");
272+
}
273+
}
274+
275+
void paint(Graphics2D g) {
276+
drawText(g, customFont, TEXT);
277+
}
278+
279+
@Override
280+
public int print(Graphics graphics, PageFormat pageFormat, int index) {
281+
if (index == 0) {
282+
paint((Graphics2D) graphics);
283+
return PAGE_EXISTS;
284+
} else {
285+
return NO_SUCH_PAGE;
286+
}
287+
}
288+
}
289+
}
Binary file not shown.

0 commit comments

Comments
 (0)