1 /* 2 * Copyright (c) 2004, 2015, 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 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 main(String[] args)37 static public void main(String[] args) { 38 new TestLayoutFlags().runTest(); 39 } 40 runTest()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_RUN_RTL | 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 makeGlyphVector(String fontname, FontRenderContext frc, String text, boolean rtl, int script)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 test(String name, GlyphVector gv, int expectedFlags)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 printFlags(int flags)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 computeFlags(GlyphVector gv)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 */ validateCharIndexMethods(GlyphVector gv)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 */ glyphsAreLTR(GlyphVector gv)172 boolean glyphsAreLTR(GlyphVector gv) { 173 int[] indices = gv.getGlyphCharIndices(0, gv.getNumGlyphs(), null); 174 for (int i = 0; i < indices.length; ++i) { 175 if (indices[i] != i) { 176 return false; 177 } 178 } 179 return true; 180 } 181 182 /** 183 * Return true if the glyph indices are pure rtl 184 */ glyphsAreRTL(GlyphVector gv)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 */ hasComplexGlyphs(GlyphVector gv)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 */ 210