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