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.
180 lines
7.3 KiB
Java
180 lines
7.3 KiB
Java
/*
|
|
* Copyright (c) 2000, 2025, 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.
|
|
*/
|
|
|
|
import java.awt.Color;
|
|
import java.awt.Font;
|
|
import java.awt.Frame;
|
|
import java.awt.Graphics;
|
|
import java.awt.Graphics2D;
|
|
import java.awt.Panel;
|
|
import java.awt.font.FontRenderContext;
|
|
import java.awt.font.LineBreakMeasurer;
|
|
import java.awt.font.NumericShaper;
|
|
import java.awt.font.TextAttribute;
|
|
import java.awt.font.TextLayout;
|
|
import java.text.AttributedCharacterIterator;
|
|
import java.text.AttributedString;
|
|
import java.util.HashMap;
|
|
|
|
/*
|
|
* @test
|
|
* @bug 4210199
|
|
* @summary Draw a string with mixed ASCII digits and different scripts, applying
|
|
* different kinds of numeric shapers. Verify that the proper digits are affected.
|
|
* @library /java/awt/regtesthelpers
|
|
* @build PassFailJFrame
|
|
* @run main/manual ShaperTest
|
|
*/
|
|
|
|
public class ShaperTest extends Panel {
|
|
private static final String fontName = Font.DIALOG;
|
|
private final TextLayout[][] layouts;
|
|
private final String[] titles;
|
|
private static final String text =
|
|
"-123 (English) 456.00 (Arabic) \u0641\u0642\u0643 -789 (Thai) \u0e01\u0e33 01.23";
|
|
|
|
public static void main(String[] args) throws Exception {
|
|
final String INSTRUCTIONS = """
|
|
A line of text containing mixed numeric and other text is drawn four times
|
|
(Depending on the font/platform, some of the other text may not be visible).
|
|
|
|
There are four runs of digits, '-123' at the front of the text, '456.00' after
|
|
English text, '-789' after Arabic text, and '01.23' after Thai text.
|
|
|
|
In the first line, all four runs of digits should be present as ASCII digits.
|
|
|
|
In the second line, all four runs of digits should be Arabic digits
|
|
(they may not be visible if the font does not support Arabic).
|
|
|
|
In the third line, the initial run of digits (-123) and the one following the
|
|
Arabic text (-789) should be Arabic, while the others should be ASCII.
|
|
|
|
In the fourth line, only the digits following the Arabic text (-789) should be Arabic,
|
|
and the others should be ASCII.
|
|
|
|
Pass the test if this is true.""";
|
|
|
|
PassFailJFrame.builder()
|
|
.title("ShaperTest Instruction")
|
|
.instructions(INSTRUCTIONS)
|
|
.columns(45)
|
|
.testUI(ShaperTest::createUI)
|
|
.logArea(8)
|
|
.build()
|
|
.awaitAndCheck();
|
|
}
|
|
|
|
private static Frame createUI() {
|
|
Frame frame = new Frame("ShaperTest Test UI");
|
|
frame.add(new ShaperTest());
|
|
frame.setSize(600, 400);
|
|
return frame;
|
|
}
|
|
|
|
void dumpChars(char[] chars) {
|
|
for (int i = 0; i < chars.length; ++i) {
|
|
char c = chars[i];
|
|
if (c < 0x7f) {
|
|
System.out.print(c);
|
|
} else {
|
|
String n = Integer.toHexString(c);
|
|
n = "0000".substring(n.length()) + n;
|
|
System.out.print("0x" + n);
|
|
}
|
|
}
|
|
}
|
|
|
|
private ShaperTest() {
|
|
setBackground(Color.WHITE);
|
|
setForeground(Color.BLACK);
|
|
|
|
Font textfont = new Font(fontName, Font.PLAIN, 12);
|
|
PassFailJFrame.log("asked for: " + fontName + " and got: " + textfont.getFontName());
|
|
setFont(textfont);
|
|
|
|
Font font = new Font(fontName, Font.PLAIN, 18);
|
|
PassFailJFrame.log("asked for: " + fontName + " and got: " + font.getFontName());
|
|
|
|
FontRenderContext frc = new FontRenderContext(null, false, false);
|
|
|
|
layouts = new TextLayout[5][2];
|
|
|
|
HashMap<AttributedCharacterIterator.Attribute, Object> map = new HashMap<>();
|
|
map.put(TextAttribute.FONT, font);
|
|
layouts[0][0] = new TextLayout(text, map, frc);
|
|
AttributedCharacterIterator iter = new AttributedString(text, map).getIterator();
|
|
layouts[0][1] = new LineBreakMeasurer(iter, frc).nextLayout(Float.MAX_VALUE);
|
|
|
|
NumericShaper arabic = NumericShaper.getShaper(NumericShaper.ARABIC);
|
|
map.put(TextAttribute.NUMERIC_SHAPING, arabic);
|
|
layouts[1][0] = new TextLayout(text, map, frc);
|
|
iter = new AttributedString(text, map).getIterator();
|
|
layouts[1][1] = new LineBreakMeasurer(iter, frc).nextLayout(Float.MAX_VALUE);
|
|
|
|
NumericShaper contextualArabic = NumericShaper.getContextualShaper(NumericShaper.ARABIC, NumericShaper.ARABIC);
|
|
map.put(TextAttribute.NUMERIC_SHAPING, contextualArabic);
|
|
layouts[2][0] = new TextLayout(text, map, frc);
|
|
iter = new AttributedString(text, map).getIterator();
|
|
layouts[2][1] = new LineBreakMeasurer(iter, frc).nextLayout(Float.MAX_VALUE);
|
|
|
|
NumericShaper contextualArabicASCII = NumericShaper.getContextualShaper(NumericShaper.ARABIC);
|
|
map.put(TextAttribute.NUMERIC_SHAPING, contextualArabicASCII);
|
|
layouts[3][0] = new TextLayout(text, map, frc);
|
|
iter = new AttributedString(text, map).getIterator();
|
|
layouts[3][1] = new LineBreakMeasurer(iter, frc).nextLayout(Float.MAX_VALUE);
|
|
|
|
NumericShaper contextualAll = NumericShaper.getContextualShaper(NumericShaper.ALL_RANGES);
|
|
map.put(TextAttribute.NUMERIC_SHAPING, contextualAll);
|
|
layouts[4][0] = new TextLayout(text, map, frc);
|
|
iter = new AttributedString(text, map).getIterator();
|
|
layouts[4][1] = new LineBreakMeasurer(iter, frc).nextLayout(Float.MAX_VALUE);
|
|
|
|
titles = new String[]{
|
|
"plain -- all digits ASCII",
|
|
"Arabic -- all digits Arabic",
|
|
"contextual Arabic default Arabic -- only leading digits and digits following Arabic text are Arabic",
|
|
"contextual Arabic default ASCII -- only digits following Arabic text are Arabic",
|
|
"contextual all default ASCII -- leading digits english, others correspond to context"
|
|
};
|
|
}
|
|
|
|
@Override
|
|
public void paint(Graphics g) {
|
|
Graphics2D g2d = (Graphics2D) g;
|
|
|
|
float x = 5;
|
|
float y = 5;
|
|
|
|
for (int i = 0; i < layouts.length; ++i) {
|
|
y += 18;
|
|
g2d.drawString(titles[i], x, y);
|
|
y += 4;
|
|
|
|
for (int j = 0; j < 2; ++j) {
|
|
y += layouts[i][j].getAscent();
|
|
layouts[i][j].draw(g2d, x, y);
|
|
y += layouts[i][j].getDescent() + layouts[i][j].getLeading();
|
|
}
|
|
}
|
|
}
|
|
}
|