diff --git a/test/jdk/java/awt/font/GlyphVector/TestOutline.java b/test/jdk/java/awt/font/GlyphVector/TestOutline.java new file mode 100644 index 00000000000..cc45456b21a --- /dev/null +++ b/test/jdk/java/awt/font/GlyphVector/TestOutline.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 1999, 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.Dimension; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.font.GlyphVector; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + +import javax.swing.JPanel; + +/* + * @test + * @bug 4255072 + * @summary Display the outline of a GlyphVector that has overlapping 'O' characters in it. + * The places where the strokes of the characters cross should be filled in. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TestOutline + */ + +public final class TestOutline extends JPanel { + Shape outline; + + public static void main(String[] args) throws Exception { + final String INSTRUCTIONS = """ + Two overlapping 'O' characters should appear. Pass the test if + the places where the strokes of the characters cross is filled in. + Fail it if these places are not filled in."""; + + PassFailJFrame.builder() + .title("TestOutline Instruction") + .instructions(INSTRUCTIONS) + .columns(35) + .splitUI(TestOutline::new) + .build() + .awaitAndCheck(); + } + + @Override + public Dimension getPreferredSize() { + return new Dimension(200, 250); + } + + @Override + public void paint(Graphics g) { + Graphics2D g2d = (Graphics2D) g; + g2d.setColor(Color.WHITE); + g2d.fillRect(0, 0, getWidth(), getHeight()); + + if (outline == null) { + outline = createLayout(g2d); + } + + g2d.setColor(Color.BLACK); + g2d.fill(outline); + } + + private Shape createLayout(Graphics2D g2d) { + Font font = new Font(Font.DIALOG, Font.PLAIN, 144); + GlyphVector gv = font.createGlyphVector(g2d.getFontRenderContext(), "OO"); + gv.performDefaultLayout(); + Point2D pt = gv.getGlyphPosition(1); + double delta = -pt.getX() / 2.0; + pt.setLocation(pt.getX() + delta, pt.getY()); + gv.setGlyphPosition(1, pt); + + pt = gv.getGlyphPosition(2); + pt.setLocation(pt.getX() + delta, pt.getY()); + gv.setGlyphPosition(2, pt); + + Rectangle2D bounds = gv.getLogicalBounds(); + Rectangle d = getBounds(); + float x = (float) ((d.width - bounds.getWidth()) / 2 + bounds.getX()); + float y = (float) ((d.height - bounds.getHeight()) / 2 - bounds.getY()); + System.out.println("loc: " + x + ", " + y); + return gv.getOutline(x, y); + } +} diff --git a/test/jdk/java/awt/font/NumericShaper/ShaperTest.java b/test/jdk/java/awt/font/NumericShaper/ShaperTest.java new file mode 100644 index 00000000000..adc81cfd7e0 --- /dev/null +++ b/test/jdk/java/awt/font/NumericShaper/ShaperTest.java @@ -0,0 +1,180 @@ +/* + * 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 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(); + } + } + } +} diff --git a/test/jdk/java/awt/font/TextLayout/TestGASPHint.java b/test/jdk/java/awt/font/TextLayout/TestGASPHint.java new file mode 100644 index 00000000000..e7caeb8eabf --- /dev/null +++ b/test/jdk/java/awt/font/TextLayout/TestGASPHint.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2006, 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.Dimension; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsEnvironment; +import java.awt.RenderingHints; + +import javax.swing.JPanel; + +/* + * @test + * @bug 6320502 + * @summary Display laid out text which substitutes invisible glyphs correctly. + * @library /java/awt/regtesthelpers /test/lib + * @build PassFailJFrame jtreg.SkippedException + * @run main/manual TestGASPHint + */ + +public class TestGASPHint extends JPanel { + private static final String text = "\u0905\u0901\u0917\u094d\u0930\u0947\u091c\u093c\u0940"; + private static final Font font = getPhysicalFontForText(text, Font.PLAIN, 36); + + public static void main(String[] args) throws Exception { + if (font == null) { + throw new jtreg.SkippedException("No Devanagari font found. Test Skipped"); + } + + final String INSTRUCTIONS = """ + A short piece of Devanagari text should appear without any + artifacts. In particular there should be no "empty rectangles" + representing the missing glyph. + + If the above condition is true, press Pass, else Fail."""; + + PassFailJFrame.builder() + .title("TestGASPHint Instruction") + .instructions(INSTRUCTIONS) + .columns(32) + .splitUI(TestGASPHint::new) + .build() + .awaitAndCheck(); + } + + @Override + public Dimension getPreferredSize() { + return new Dimension(200, 200); + } + + @Override + public void paint(Graphics g) { + Graphics2D g2d = (Graphics2D) g; + + g2d.setColor(Color.WHITE); + g2d.fillRect(0, 0, getWidth(), getHeight()); + + g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_GASP); + + g2d.setFont(font); + g2d.setColor(Color.BLACK); + g2d.drawString(text, 10, 50); + } + + /* + * Searches the available system fonts for a font which can display all the + * glyphs in the input text correctly. Returns null, if not found. + */ + private static Font getPhysicalFontForText(String text, int style, int size) { + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + String[] names = ge.getAvailableFontFamilyNames(); + + for (String n : names) { + switch (n.toLowerCase()) { + case "dialog": + case "dialoginput": + case "serif": + case "sansserif": + case "monospaced": + break; + default: + Font f = new Font(n, style, size); + if (f.canDisplayUpTo(text) == -1) { + return f; + } + } + } + return null; + } +} diff --git a/test/jdk/java/awt/font/TextLayout/TestSelection.java b/test/jdk/java/awt/font/TextLayout/TestSelection.java new file mode 100644 index 00000000000..4a1a74994df --- /dev/null +++ b/test/jdk/java/awt/font/TextLayout/TestSelection.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 1999, 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.Dimension; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.font.FontRenderContext; +import java.awt.font.TextAttribute; +import java.awt.font.TextLayout; +import java.text.AttributedString; + +import javax.swing.JPanel; + +/* + * @test + * @bug 4221422 + * @summary Display several TextLayouts with various selections. + * All the selections should be between non-italic and italic text, + * and the top and bottom of the selection region should be horizontal. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TestSelection + */ + +public final class TestSelection extends JPanel { + private static final float MARGIN = 20; + + public static void main(String[] args) throws Exception { + final String INSTRUCTIONS = """ + Several TextLayouts are displayed along with selections. + The selection regions should have horizontal top and bottom segments. + + If above condition is true, press Pass else Fail."""; + + PassFailJFrame.builder() + .title("TestSelection Instruction") + .instructions(INSTRUCTIONS) + .columns(40) + .splitUI(TestSelection::new) + .build() + .awaitAndCheck(); + } + + @Override + public Dimension getPreferredSize() { + return new Dimension(300, 300); + } + + private float drawSelectionAndLayout(Graphics2D g2d, + TextLayout layout, + float y, + int selStart, + int selLimit) { + Color selectionColor = Color.PINK; + Color textColor = Color.BLACK; + + y += layout.getAscent(); + + g2d.translate(MARGIN, y); + Shape hl = layout.getLogicalHighlightShape(selStart, selLimit); + g2d.setColor(selectionColor); + g2d.fill(hl); + g2d.setColor(textColor); + layout.draw(g2d, 0, 0); + g2d.translate(-MARGIN, -y); + + y += layout.getDescent() + layout.getLeading() + 10; + return y; + } + + @Override + public void paint(Graphics g) { + String text = "Hello world"; + + Graphics2D g2d = (Graphics2D) g; + g2d.setColor(Color.WHITE); + g2d.fillRect(0, 0, getWidth(), getHeight()); + + AttributedString attrStr = new AttributedString(text); + + FontRenderContext frc = g2d.getFontRenderContext(); + + final int midPoint = text.indexOf('w'); + final int selStart = midPoint / 2; + final int selLimit = text.length() - selStart; + final Font italic = new Font(Font.SANS_SERIF, Font.ITALIC, 24); + + float y = MARGIN; + + attrStr.addAttribute(TextAttribute.FONT, italic, 0, midPoint); + TextLayout layout = new TextLayout(attrStr.getIterator(), frc); + + y = drawSelectionAndLayout(g2d, layout, y, selStart - 1, selLimit); + y = drawSelectionAndLayout(g2d, layout, y, selStart, selLimit); + y = drawSelectionAndLayout(g2d, layout, y, selStart + 1, selLimit); + + attrStr = new AttributedString(text); + attrStr.addAttribute(TextAttribute.FONT, + italic, midPoint, text.length()); + layout = new TextLayout(attrStr.getIterator(), frc); + + y = drawSelectionAndLayout(g2d, layout, y, selStart, selLimit); + + attrStr = new AttributedString(text); + attrStr.addAttribute(TextAttribute.FONT, italic, 0, midPoint); + attrStr.addAttribute(TextAttribute.SIZE, 48f, midPoint, text.length()); + layout = new TextLayout(attrStr.getIterator(), frc); + + y = drawSelectionAndLayout(g2d, layout, y, selStart, selLimit); + } +} diff --git a/test/jdk/java/awt/font/TextLayout/TestStrikethrough.java b/test/jdk/java/awt/font/TextLayout/TestStrikethrough.java new file mode 100644 index 00000000000..eff16d5aa64 --- /dev/null +++ b/test/jdk/java/awt/font/TextLayout/TestStrikethrough.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2005, 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.Dimension; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.font.FontRenderContext; +import java.awt.font.TextAttribute; +import java.awt.font.TextLayout; +import java.text.AttributedCharacterIterator; +import java.text.AttributedString; + +import javax.swing.JPanel; + +/* + * @test + * @bug 6426360 + * @summary Display a TextLayout with strikethrough at a number of + * different offsets relative to the pixel grid. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TestStrikethrough + */ + +public class TestStrikethrough extends JPanel { + + public static void main(String[] args) throws Exception { + final String INSTRUCTIONS = """ + Display text with strikethrough at a number of different positions. + + Press Fail if any line is missing a strikethrough else press Pass."""; + + PassFailJFrame.builder() + .title("TestStrikethrough Instruction") + .instructions(INSTRUCTIONS) + .columns(35) + .splitUI(TestStrikethrough::new) + .build() + .awaitAndCheck(); + } + + @Override + public Dimension getPreferredSize() { + return new Dimension(200, 120); + } + + @Override + public void paint(Graphics aContext) { + Graphics2D g2d = (Graphics2D) aContext; + + g2d.setColor(Color.WHITE); + g2d.fillRect(0, 0, getWidth(), getHeight()); + + Font font = new Font(Font.DIALOG, Font.PLAIN, 9); + FontRenderContext frc = g2d.getFontRenderContext(); + String str = "Where is the strikethrough?"; + AttributedString as = new AttributedString(str); + as.addAttribute(TextAttribute.FONT, font); + as.addAttribute(TextAttribute.STRIKETHROUGH, TextAttribute.STRIKETHROUGH_ON); + AttributedCharacterIterator aci = as.getIterator(); + TextLayout tl = new TextLayout(aci, frc); + float delta = (float) (Math.ceil(tl.getAscent() + tl.getDescent() + tl.getLeading()) + .1); + float y = delta - .1f; + g2d.setColor(Color.BLACK); + for (int i = 0; i < 11; ++i) { + tl.draw(g2d, 10f, y); + y += delta; + } + } +}