Skip to content

Commit 38c5194

Browse files
committed
8340560: Open Source several AWT/2D font and rendering tests
Backport-of: ade17ecb6cb5125d048401a878b557e5afefc08c
1 parent 20d5609 commit 38c5194

File tree

4 files changed

+578
-0
lines changed

4 files changed

+578
-0
lines changed
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
/*
2+
* Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
/*
25+
* @test
26+
* @bug 4286726
27+
* @summary Java2D raster printing: large text may overflow glyph cache.
28+
* Draw a large glyphvector, the 'A' glyph should appear and not get flushed.
29+
*/
30+
31+
import java.awt.Color;
32+
import java.awt.Font;
33+
import java.awt.Graphics2D;
34+
import java.awt.RenderingHints;
35+
import java.awt.font.FontRenderContext;
36+
import java.awt.font.GlyphVector;
37+
import java.awt.geom.Point2D;
38+
import java.awt.image.BufferedImage;
39+
import java.util.HashMap;
40+
41+
/**
42+
* Draw a very large glyphvector on a surface.
43+
* If the cache was flushed the first glyph is not rendered.
44+
* Note: the implementation no longer uses glyphs for rendering large text,
45+
* but in principle the test is still useful.
46+
*/
47+
public class CacheFlushTest {
48+
49+
static final int WIDTH = 400, HEIGHT = 600;
50+
static final int FONTSIZE = 250;
51+
static final String TEST = "ABCDEFGHIJKLMNOP";
52+
static final HashMap<RenderingHints.Key, Object> HINTS = new HashMap<>();
53+
54+
static {
55+
HINTS.put(RenderingHints.KEY_ANTIALIASING,
56+
RenderingHints.VALUE_ANTIALIAS_ON);
57+
HINTS.put(RenderingHints.KEY_TEXT_ANTIALIASING,
58+
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
59+
HINTS.put(RenderingHints.KEY_FRACTIONALMETRICS,
60+
RenderingHints.VALUE_FRACTIONALMETRICS_ON);
61+
}
62+
63+
public static void main(String args[]) {
64+
BufferedImage bi = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
65+
66+
Graphics2D g2d = bi.createGraphics();
67+
g2d.addRenderingHints(HINTS);
68+
g2d.setColor(Color.white);
69+
g2d.fillRect(0, 0, WIDTH, HEIGHT);
70+
g2d.setColor(Color.black);
71+
72+
FontRenderContext frc = g2d.getFontRenderContext();
73+
Font font = new Font(Font.DIALOG, Font.PLAIN, 250);
74+
GlyphVector gv = font.createGlyphVector(frc, TEST);
75+
76+
/* Set the positions of all but the first glyph to be offset vertically but
77+
* FONTSIZE pixels. So if the first glyph "A" is not flushed we can tell this
78+
* by checking for non-white pixels in the range for the default y offset of 0
79+
* from the specified y location.
80+
*/
81+
Point2D.Float pt = new Point2D.Float(20f, FONTSIZE);
82+
for (int i = 1; i < gv.getNumGlyphs(); ++i) {
83+
gv.setGlyphPosition(i, pt);
84+
pt.x += 25f;
85+
pt.y = FONTSIZE;
86+
}
87+
g2d.drawGlyphVector(gv, 20, FONTSIZE);
88+
/* Now expect to find at least one black pixel in the rect (0,0) -> (WIDTH, FONTSIZE) */
89+
boolean found = false;
90+
int blackPixel = Color.black.getRGB();
91+
for (int y = 0; y < FONTSIZE; y++) {
92+
for (int x = 0; x < WIDTH; x++) {
93+
if (bi.getRGB(x, y) == blackPixel) {
94+
found = true;
95+
break;
96+
}
97+
}
98+
if (found == true) {
99+
break;
100+
}
101+
}
102+
if (!found) {
103+
throw new RuntimeException("NO BLACK PIXELS");
104+
}
105+
}
106+
}
Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
/*
2+
* Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
/*
25+
* @test
26+
* @bug 4198081
27+
* @key headful
28+
* @summary Arabic characters should appear instead of boxes and be correctly shaped.
29+
* Hebrew characters should appear instead of boxes.
30+
* Test is made headful so there's no excuse for test systems not having the fonts.
31+
*/
32+
33+
import java.awt.BorderLayout;
34+
import java.awt.Color;
35+
import java.awt.Dimension;
36+
import java.awt.EventQueue;
37+
import java.awt.Graphics;
38+
import java.awt.Graphics2D;
39+
import java.awt.GridLayout;
40+
import java.awt.Font;
41+
import java.awt.Frame;
42+
import java.awt.Panel;
43+
import java.awt.font.FontRenderContext;
44+
import java.awt.font.GlyphVector;
45+
import java.awt.geom.Rectangle2D;
46+
47+
public class TestArabicHebrew extends Panel {
48+
49+
static volatile Frame frame;
50+
static volatile Font font = new Font(Font.DIALOG, Font.PLAIN, 36);
51+
52+
static void createUI() {
53+
frame = new Frame("Test Arabic/Hebrew");
54+
frame.setLayout(new BorderLayout());
55+
TestArabicHebrew panel = new TestArabicHebrew();
56+
frame.add(panel, BorderLayout.CENTER);
57+
frame.pack();
58+
frame.setVisible(true);
59+
}
60+
61+
public static void main(String args[]) throws Exception {
62+
EventQueue.invokeAndWait(TestArabicHebrew::createUI);
63+
try {
64+
checkStrings();
65+
} finally {
66+
if (frame != null && args.length == 0) {
67+
EventQueue.invokeAndWait(frame::dispose);
68+
}
69+
}
70+
}
71+
72+
static void checkString(String script, String str) {
73+
int index = font.canDisplayUpTo(str);
74+
if (index != -1) {
75+
throw new RuntimeException("Cannot display char " + index + " for " + script);
76+
}
77+
}
78+
79+
static void checkStrings() {
80+
checkString("Arabic", arabic);
81+
checkString("Hebrew", hebrew);
82+
checkString("Latin-1 Supplement", latin1sup);
83+
}
84+
85+
// Table of arabic unicode characters - minimal support level
86+
// Includes arabic chars from basic block up to 0652 and
87+
// corresponding shaped characters from the arabic
88+
// extended-B block from fe80 to fefc (does include lam-alef
89+
// ligatures).
90+
// Does not include arabic-indic digits nor "arabic extended"
91+
// range.
92+
93+
static final String arabic =
94+
"\u060c\u061b\u061f\u0621\u0622\u0623\u0624\u0625\u0626\u0627"
95+
+ "\u0628\u0629\u062a\u062b\u062c\u062d\u062e\u062f\u0630\u0631"
96+
+ "\u0632\u0633\u0634\u0635\u0636\u0637\u0638\u0639\u063a\u0640"
97+
+ "\u0641\u0642\u0643\u0644\u0645\u0646\u0647\u0648\u0649\u064a"
98+
+ "\u064b\u064c\u064d\u064e\u064f\u0650\u0651\u0652\ufe80\ufe81"
99+
+ "\ufe82\ufe83\ufe84\ufe85\ufe86\ufe87\ufe88\ufe89\ufe8a\ufe8b"
100+
+ "\ufe8c\ufe8d\ufe8e\ufe8f\ufe90\ufe91\ufe92\ufe93\ufe94\ufe95"
101+
+ "\ufe96\ufe97\ufe98\ufe99\ufe9a\ufe9b\ufe9c\ufe9d\ufe9e\ufe9f"
102+
+ "\ufea0\ufea1\ufea2\ufea3\ufea4\ufea5\ufea6\ufea7\ufea8\ufea9"
103+
+ "\ufeaa\ufeab\ufeac\ufead\ufeae\ufeaf\ufeb0\ufeb1\ufeb2\ufeb3"
104+
+ "\ufeb4\ufeb5\ufeb6\ufeb7\ufeb8\ufeb9\ufeba\ufebb\ufebc\ufebd"
105+
+ "\ufebe\ufebf\ufec0\ufec1\ufec2\ufec3\ufec4\ufec5\ufec6\ufec7"
106+
+ "\ufec8\ufec9\ufeca\ufecb\ufecc\ufecd\ufece\ufecf\ufed0\ufed1"
107+
+ "\ufed2\ufed3\ufed4\ufed5\ufed6\ufed7\ufed8\ufed9\ufeda\ufedb"
108+
+ "\ufedc\ufedd\ufede\ufedf\ufee0\ufee1\ufee2\ufee3\ufee4\ufee5"
109+
+ "\ufee6\ufee7\ufee8\ufee9\ufeea\ufeeb\ufeec\ufeed\ufeee\ufeef"
110+
+ "\ufef0\ufef1\ufef2\ufef3\ufef4\ufef5\ufef6\ufef7\ufef8\ufef9"
111+
+ "\ufefa\ufefb\ufefc";
112+
113+
// hebrew table includes all characters in hebrew block
114+
115+
static final String hebrew =
116+
"\u0591\u0592\u0593\u0594\u0595\u0596\u0597\u0598\u0599\u059a"
117+
+ "\u059b\u059c\u059d\u059e\u059f\u05a0\u05a1\u05a3\u05a4\u05a5"
118+
+ "\u05a6\u05a7\u05a8\u05a9\u05aa\u05ab\u05ac\u05ad\u05ae\u05af"
119+
+ "\u05b0\u05b1\u05b2\u05b3\u05b4\u05b5\u05b6\u05b7\u05b8\u05b9"
120+
+ "\u05bb\u05bc\u05bd\u05be\u05bf\u05c0\u05c1\u05c2\u05c3\u05c4"
121+
+ "\u05d0\u05d1\u05d2\u05d3\u05d4\u05d5\u05d6\u05d7\u05d8\u05d9"
122+
+ "\u05da\u05db\u05dc\u05dd\u05de\u05df\u05e0\u05e1\u05e2\u05e3"
123+
+ "\u05e4\u05e5\u05e6\u05e7\u05e8\u05e9\u05ea\u05f0\u05f1\u05f2"
124+
+ "\u05f3\u05f4";
125+
126+
// latin 1 supplement table includes all non-control characters
127+
// in this range. Included because of comment in code that claims
128+
// some problems displaying this range with some SJIS fonts.
129+
130+
static final String latin1sup =
131+
"\u00a0\u00a1\u00a2\u00a3\u00a4\u00a5\u00a6\u00a7"
132+
+ "\u00a8\u00a9\u00aa\u00ab\u00ac\u00ad\u00ae\u00af\u00b0\u00b1"
133+
+ "\u00b2\u00b3\u00b4\u00b5\u00b6\u00b7\u00b8\u00b9\u00ba\u00bb"
134+
+ "\u00bc\u00bd\u00be\u00bf\u00c0\u00c1\u00c2\u00c3\u00c4\u00c5"
135+
+ "\u00c6\u00c7\u00c8\u00c9\u00ca\u00cb\u00cc\u00cd\u00ce\u00cf"
136+
+ "\u00d0\u00d1\u00d2\u00d3\u00d4\u00d5\u00d6\u00d7\u00d8\u00d9"
137+
+ "\u00da\u00db\u00dc\u00dd\u00de\u00df\u00e0\u00e1\u00e2\u00e3"
138+
+ "\u00e4\u00e5\u00e6\u00e7\u00e8\u00e9\u00ea\u00eb\u00ec\u00ed"
139+
+ "\u00ee\u00ef\u00f0\u00f1\u00f2\u00f3\u00f4\u00f5\u00f6\u00f7"
140+
+ "\u00f8\u00f9\u00fa\u00fb\u00fc\u00fd\u00fe\u00ff";
141+
142+
public TestArabicHebrew() {
143+
setLayout(new GridLayout(3, 1));
144+
145+
FontRenderContext frc = new FontRenderContext(null, false, false);
146+
add(new SubGlyphPanel("Arabic", arabic, font, frc));
147+
add(new SubGlyphPanel("Hebrew", hebrew, font, frc));
148+
add(new SubGlyphPanel("Latin-1 Supplement", latin1sup, font, frc));
149+
}
150+
151+
static class SubGlyphPanel extends Panel {
152+
String title;
153+
Dimension extent;
154+
GlyphVector[] vectors;
155+
156+
static final int kGlyphsPerLine = 20;
157+
158+
SubGlyphPanel(String title, String chars, Font font, FontRenderContext frc) {
159+
160+
this.title = title;
161+
setBackground(Color.white);
162+
163+
double width = 0;
164+
double height = 0;
165+
166+
int max = chars.length();
167+
vectors = new GlyphVector[(max + kGlyphsPerLine - 1) / kGlyphsPerLine];
168+
for (int i = 0; i < vectors.length; i++) {
169+
int start = i * 20;
170+
int limit = Math.min(max, (i + 1) * kGlyphsPerLine);
171+
String substr = "";
172+
for (int j = start; j < limit; ++j) {
173+
substr = substr.concat(chars.charAt(j) + " ");
174+
}
175+
GlyphVector gv = font.createGlyphVector(frc, substr);
176+
vectors[i] = gv;
177+
Rectangle2D bounds = gv.getLogicalBounds();
178+
179+
width = Math.max(width, bounds.getWidth());
180+
height += bounds.getHeight();
181+
}
182+
183+
extent = new Dimension((int)(width + 1), (int)(height + 1 + 30)); // room for title
184+
185+
setSize(getPreferredSize());
186+
}
187+
188+
public Dimension getPreferredSize() {
189+
return new Dimension(extent);
190+
}
191+
192+
public Dimension getMinimumSize() {
193+
return getPreferredSize();
194+
}
195+
196+
public Dimension getMaximumSize() {
197+
return getPreferredSize();
198+
}
199+
200+
public void paint(Graphics g) {
201+
Graphics2D g2d = (Graphics2D)g;
202+
203+
g.drawString(title, 10, 20);
204+
205+
float x = 10;
206+
float y = 30;
207+
for (int i = 0; i < vectors.length; ++i) {
208+
GlyphVector gv = vectors[i];
209+
Rectangle2D bounds = gv.getLogicalBounds();
210+
g2d.drawGlyphVector(gv, x, (float)(y - bounds.getY()));
211+
y += bounds.getHeight();
212+
}
213+
}
214+
}
215+
}

0 commit comments

Comments
 (0)