1 /* 2 * Copyright (c) 2004, 2016, 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 4328745 5090704 8166111 27 @summary exercise getLayoutFlags, getGlyphCharIndex, getGlyphCharIndices 28 */ 29 30 import java.awt.*; 31 import java.awt.event.*; 32 import java.awt.font.*; 33 import java.awt.geom.*; 34 35 public class TestLayoutFlags { 36 37 static public void main(String[] args) { 38 new TestLayoutFlags().runTest(); 39 } 40 41 void runTest() { 42 43 Font font = new Font("Lucida Sans", Font.PLAIN, 24); 44 45 String latin1 = "This is a latin1 string"; // none 46 String hebrew = "\u05d0\u05d1\u05d2\u05d3"; // rtl 47 String arabic = "\u0646\u0644\u0622\u0646"; // rtl + mc/g 48 String hindi = "\u0939\u093f\u0923\u094d\u0921\u0940"; // ltr + reorder 49 // String tamil = "\u0b9c\u0bcb"; // ltr + mg/c + split 50 51 FontRenderContext frc = new FontRenderContext(null, true, true); 52 53 // get glyph char indices needs to initializes layoutFlags before use (5090704) 54 { 55 GlyphVector gv = font.createGlyphVector(frc, "abcde"); 56 int ix = gv.getGlyphCharIndex(0); 57 if (ix != 0) { 58 throw new Error("glyph 0 incorrectly mapped to char " + ix); 59 } 60 int[] ixs = gv.getGlyphCharIndices(0, gv.getNumGlyphs(), null); 61 for (int i = 0; i < ixs.length; ++i) { 62 if (ixs[i] != i) { 63 throw new Error("glyph " + i + " incorrectly mapped to char " + ixs[i]); 64 } 65 } 66 } 67 68 GlyphVector latinGV = makeGlyphVector("Lucida Sans", frc, latin1, false, 1 /* ScriptRun.LATIN */); 69 GlyphVector hebrewGV = makeGlyphVector("Lucida Sans", frc, hebrew, true, 5 /* ScriptRun.HEBREW */); 70 GlyphVector arabicGV = makeGlyphVector("Lucida Sans", frc, arabic, true, 6 /* ScriptRun.ARABIC */); 71 GlyphVector hindiGV = makeGlyphVector("Lucida Sans", frc, hindi, false, 7 /* ScriptRun.DEVANAGARI */); 72 // GlyphVector tamilGV = makeGlyphVector("Devanagari MT for IBM", frc, tamil, false, 12 /* ScriptRun.TAMIL */); 73 74 GlyphVector latinPos = font.createGlyphVector(frc, latin1); 75 Point2D pt = latinPos.getGlyphPosition(0); 76 pt.setLocation(pt.getX(), pt.getY() + 1.0); 77 latinPos.setGlyphPosition(0, pt); 78 79 GlyphVector latinTrans = font.createGlyphVector(frc, latin1); 80 latinTrans.setGlyphTransform(0, AffineTransform.getRotateInstance(.15)); 81 82 test("latin", latinGV, GlyphVector.FLAG_HAS_POSITION_ADJUSTMENTS); 83 test("hebrew", hebrewGV, GlyphVector.FLAG_RUN_RTL | 84 GlyphVector.FLAG_HAS_POSITION_ADJUSTMENTS); 85 test("arabic", arabicGV, GlyphVector.FLAG_COMPLEX_GLYPHS | 86 GlyphVector.FLAG_HAS_POSITION_ADJUSTMENTS); 87 test("hindi", hindiGV, GlyphVector.FLAG_COMPLEX_GLYPHS | 88 GlyphVector.FLAG_HAS_POSITION_ADJUSTMENTS); 89 // test("tamil", tamilGV, GlyphVector.FLAG_COMPLEX_GLYPHS); 90 test("pos", latinPos, GlyphVector.FLAG_HAS_POSITION_ADJUSTMENTS); 91 test("trans", latinTrans, GlyphVector.FLAG_HAS_TRANSFORMS); 92 } 93 94 GlyphVector makeGlyphVector(String fontname, FontRenderContext frc, String text, boolean rtl, int script) { 95 Font font = new Font(fontname, Font.PLAIN, 14); 96 System.out.println("asking for " + fontname + " and got " + font.getFontName()); 97 int flags = rtl ? 1 : 0; 98 return font.layoutGlyphVector(frc, text.toCharArray(), 0, text.length(), flags); 99 } 100 101 void test(String name, GlyphVector gv, int expectedFlags) { 102 expectedFlags &= gv.FLAG_MASK; 103 int computedFlags = computeFlags(gv) & gv.FLAG_MASK; 104 int actualFlags = gv.getLayoutFlags() & gv.FLAG_MASK; 105 106 System.out.println("\n*** " + name + " ***"); 107 System.out.println(" test flags"); 108 System.out.print("expected "); 109 printFlags(expectedFlags); 110 System.out.print("computed "); 111 printFlags(computedFlags); 112 System.out.print(" actual "); 113 printFlags(actualFlags); 114 115 if (expectedFlags != actualFlags) { 116 throw new Error("layout flags in test: " + name + 117 " expected: " + Integer.toHexString(expectedFlags) + 118 " but got: " + Integer.toHexString(actualFlags)); 119 } 120 } 121 122 static public void printFlags(int flags) { 123 System.out.print("flags:"); 124 if ((flags & GlyphVector.FLAG_HAS_POSITION_ADJUSTMENTS) != 0) { 125 System.out.print(" pos"); 126 } 127 if ((flags & GlyphVector.FLAG_HAS_TRANSFORMS) != 0) { 128 System.out.print(" trans"); 129 } 130 if ((flags & GlyphVector.FLAG_RUN_RTL) != 0) { 131 System.out.print(" rtl"); 132 } 133 if ((flags & GlyphVector.FLAG_COMPLEX_GLYPHS) != 0) { 134 System.out.print(" complex"); 135 } 136 if ((flags & GlyphVector.FLAG_MASK) == 0) { 137 System.out.print(" none"); 138 } 139 System.out.println(); 140 } 141 142 int computeFlags(GlyphVector gv) { 143 validateCharIndexMethods(gv); 144 145 int result = 0; 146 if (glyphsAreRTL(gv)) { 147 result |= GlyphVector.FLAG_RUN_RTL; 148 } 149 if (hasComplexGlyphs(gv)) { 150 result |= GlyphVector.FLAG_COMPLEX_GLYPHS; 151 } 152 153 return result; 154 } 155 156 /** 157 * throw an exception if getGlyphCharIndices returns a different result than 158 * you get from iterating through getGlyphCharIndex one at a time. 159 */ 160 void validateCharIndexMethods(GlyphVector gv) { 161 int[] indices = gv.getGlyphCharIndices(0, gv.getNumGlyphs(), null); 162 for (int i = 0; i < gv.getNumGlyphs(); ++i) { 163 if (gv.getGlyphCharIndex(i) != indices[i]) { 164 throw new Error("glyph index mismatch at " + i); 165 } 166 } 167 } 168 169 /** 170 * Return true if the glyph indices are pure ltr 171 */ 172 boolean glyphsAreLTR(GlyphVector gv) { 183 * Return true if the glyph indices are pure rtl 184 */ 185 boolean glyphsAreRTL(GlyphVector gv) { 186 int[] indices = gv.getGlyphCharIndices(0, gv.getNumGlyphs(), null); 187 for (int i = 0; i < indices.length; ++i) { 188 if (indices[i] != indices.length - i - 1) { 189 return false; 190 } 191 } 192 return true; 193 } 194 195 /** 196 * Return true if there is a local reordering (the run is not ltr or rtl). 197 * !!! We can't have mixed bidi runs in the glyphs. 198 */ 199 boolean hasComplexGlyphs(GlyphVector gv) { 200 return !glyphsAreLTR(gv) && !glyphsAreRTL(gv); 201 } 202 } 203 204 /* 205 rect getPixelBounds(frc, x, y) 206 rect getGlyphPixelBounds(frc, int, x, y) 207 getGlyphOutline(int index, x, y) 208 getGlyphInfo() 209 */ | 1 /* 2 * Copyright (c) 2004, 2018, 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 4328745 5090704 8166111 8176510 27 @summary exercise getLayoutFlags, getGlyphCharIndex, getGlyphCharIndices 28 */ 29 30 import java.awt.Font; 31 import static java.awt.Font.*; 32 import java.awt.GraphicsEnvironment; 33 import java.awt.font.FontRenderContext; 34 import java.awt.font.GlyphVector; 35 import static java.awt.font.GlyphVector.*; 36 import java.awt.geom.AffineTransform; 37 import java.awt.geom.Point2D; 38 39 public class TestLayoutFlags { 40 41 static public void main(String[] args) { 42 new TestLayoutFlags().runTest(); 43 } 44 45 void runTest() { 46 47 Font font = findFont("abcde"); 48 49 String latin1 = "This is a latin1 string"; // none 50 String hebrew = "\u05d0\u05d1\u05d2\u05d3"; // rtl 51 String arabic = "\u0646\u0644\u0622\u0646"; // rtl + mc/g 52 String hindi = "\u0939\u093f\u0923\u094d\u0921\u0940"; // ltr + reorder 53 String tamil = "\u0b9c\u0bcb"; // ltr + mg/c + split 54 55 FontRenderContext frc = new FontRenderContext(null, true, true); 56 57 // get glyph char indices needs to initializes layoutFlags before 58 // use (5090704) 59 { 60 GlyphVector gv = font.createGlyphVector(frc, "abcde"); 61 int ix = gv.getGlyphCharIndex(0); 62 if (ix != 0) { 63 throw new Error("glyph 0 incorrectly mapped to char " + ix); 64 } 65 int[] ixs = gv.getGlyphCharIndices(0, gv.getNumGlyphs(), null); 66 for (int i = 0; i < ixs.length; ++i) { 67 if (ixs[i] != i) { 68 throw new Error("glyph " + i + " incorrectly mapped to char " + ixs[i]); 69 } 70 } 71 } 72 73 GlyphVector latinGV = makeGlyphVector("latin", latin1, false, frc); 74 GlyphVector hebrewGV = makeGlyphVector("hebrew", hebrew, true, frc); 75 GlyphVector arabicGV = makeGlyphVector("arabic", arabic, true, frc); 76 GlyphVector hindiGV = makeGlyphVector("devanagari", hindi, false, frc); 77 GlyphVector tamilGV = makeGlyphVector("tamil", tamil, false, frc); 78 79 GlyphVector latinPos = font.createGlyphVector(frc, latin1); 80 Point2D pt = latinPos.getGlyphPosition(0); 81 pt.setLocation(pt.getX(), pt.getY() + 1.0); 82 latinPos.setGlyphPosition(0, pt); 83 84 GlyphVector latinTrans = font.createGlyphVector(frc, latin1); 85 latinTrans.setGlyphTransform(0, AffineTransform.getRotateInstance(.15)); 86 87 test("latin", latinGV, true, 0); 88 test("hebrew", hebrewGV, true, FLAG_RUN_RTL); 89 test("arabic", arabicGV, true, FLAG_COMPLEX_GLYPHS | FLAG_RUN_RTL); 90 test("hindi", hindiGV, true, FLAG_COMPLEX_GLYPHS); 91 test("tamil", tamilGV, true, FLAG_COMPLEX_GLYPHS); 92 test("pos", latinPos, true, 0); 93 test("trans", latinTrans, false, 0); 94 } 95 96 static boolean isLogicalFont(Font f) { 97 String family = f.getFamily().toLowerCase(); 98 switch (family) { 99 case "dialog": 100 case "dialoginput": 101 case "serif": 102 case "sansserif": 103 case "monospaced": return true; 104 default: return false; 105 } 106 } 107 108 Font[] allFonts = null; 109 110 Font findFont(String text) { 111 if (allFonts == null) { 112 allFonts = 113 GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts(); 114 } 115 for (Font f : allFonts) { 116 if (isLogicalFont(f)) { 117 continue; 118 } 119 if (f.canDisplayUpTo(text) == -1) { 120 return f.deriveFont(Font.PLAIN, 24); 121 } 122 } 123 return null; 124 } 125 126 GlyphVector makeGlyphVector(String script, String text, 127 boolean rtl, FontRenderContext frc) { 128 129 Font font = findFont(text); 130 if (font == null) { 131 System.out.println("No font found for script " + script); 132 return null; 133 } else { 134 System.out.println("Using " + font.getFontName() + 135 " for script " + script); 136 } 137 int flags = rtl ? LAYOUT_RIGHT_TO_LEFT : LAYOUT_LEFT_TO_RIGHT; 138 return font.layoutGlyphVector(frc, text.toCharArray(), 139 0, text.length(), flags); 140 } 141 142 void test(String name, GlyphVector gv, boolean layout, int allowedFlags) { 143 144 int iv = (layout) ? FLAG_HAS_POSITION_ADJUSTMENTS : 0; 145 146 int computedFlags = computeFlags(gv, iv) & gv.FLAG_MASK; 147 int actualFlags = gv.getLayoutFlags() & gv.FLAG_MASK; 148 149 System.out.println("\n*** " + name + " ***"); 150 System.out.println(" test flags"); 151 System.out.print("computed "); 152 printFlags(computedFlags); 153 System.out.print(" actual "); 154 printFlags(actualFlags); 155 System.out.print("allowed layout "); 156 printFlags(allowedFlags); 157 158 if (computedFlags != actualFlags) { 159 // Depending on the font, if layout is run for a RTL script 160 // you might get that flag set, or COMPLEX_GLYPHS instead. 161 boolean error = false; 162 int COMPLEX_RTL = FLAG_COMPLEX_GLYPHS | FLAG_RUN_RTL; 163 if (allowedFlags == 0) { 164 error = (allowedFlags & COMPLEX_RTL) != 0; 165 } 166 if (allowedFlags == FLAG_RUN_RTL) { 167 error = (actualFlags & FLAG_COMPLEX_GLYPHS) != 0; 168 } 169 if (allowedFlags == FLAG_COMPLEX_GLYPHS) { 170 error = (actualFlags & FLAG_RUN_RTL) != 0; 171 } 172 if (allowedFlags == COMPLEX_RTL) { 173 error = (actualFlags & COMPLEX_RTL) == 0; 174 } 175 if (error) { 176 throw new Error("layout flags in test: " + name + 177 " expected: " + Integer.toHexString(computedFlags) + 178 " but got: " + Integer.toHexString(actualFlags)); 179 } 180 } 181 } 182 183 static public void printFlags(int flags) { 184 System.out.print("flags:"); 185 if ((flags & FLAG_HAS_POSITION_ADJUSTMENTS) != 0) { 186 System.out.print(" pos"); 187 } 188 if ((flags & FLAG_HAS_TRANSFORMS) != 0) { 189 System.out.print(" trans"); 190 } 191 if ((flags & FLAG_RUN_RTL) != 0) { 192 System.out.print(" rtl"); 193 } 194 if ((flags & FLAG_COMPLEX_GLYPHS) != 0) { 195 System.out.print(" complex"); 196 } 197 if ((flags & FLAG_MASK) == 0) { 198 System.out.print(" none"); 199 } 200 System.out.println(); 201 } 202 203 int computeFlags(GlyphVector gv, int initValue) { 204 validateCharIndexMethods(gv); 205 206 int result = initValue; 207 if (glyphsAreRTL(gv)) { 208 result |= FLAG_RUN_RTL; 209 } 210 if (hasComplexGlyphs(gv)) { 211 result |= FLAG_COMPLEX_GLYPHS; 212 } 213 214 if (gv.getFont().isTransformed()) { 215 result |= FLAG_HAS_TRANSFORMS; 216 } 217 return result; 218 } 219 220 /** 221 * throw an exception if getGlyphCharIndices returns a different result than 222 * you get from iterating through getGlyphCharIndex one at a time. 223 */ 224 void validateCharIndexMethods(GlyphVector gv) { 225 int[] indices = gv.getGlyphCharIndices(0, gv.getNumGlyphs(), null); 226 for (int i = 0; i < gv.getNumGlyphs(); ++i) { 227 if (gv.getGlyphCharIndex(i) != indices[i]) { 228 throw new Error("glyph index mismatch at " + i); 229 } 230 } 231 } 232 233 /** 234 * Return true if the glyph indices are pure ltr 235 */ 236 boolean glyphsAreLTR(GlyphVector gv) { 247 * Return true if the glyph indices are pure rtl 248 */ 249 boolean glyphsAreRTL(GlyphVector gv) { 250 int[] indices = gv.getGlyphCharIndices(0, gv.getNumGlyphs(), null); 251 for (int i = 0; i < indices.length; ++i) { 252 if (indices[i] != indices.length - i - 1) { 253 return false; 254 } 255 } 256 return true; 257 } 258 259 /** 260 * Return true if there is a local reordering (the run is not ltr or rtl). 261 * !!! We can't have mixed bidi runs in the glyphs. 262 */ 263 boolean hasComplexGlyphs(GlyphVector gv) { 264 return !glyphsAreLTR(gv) && !glyphsAreRTL(gv); 265 } 266 } |