1 /* @test
   2    @bug 4328745 5090704
   3    @summary exercise getLayoutFlags, getGlyphCharIndex, getGlyphCharIndices
   4  */
   5 
   6 import java.awt.*;
   7 import java.awt.event.*;
   8 import java.awt.font.*;
   9 import java.awt.geom.*;
  10 
  11 public class TestLayoutFlags {
  12 
  13     static public void main(String[] args) {
  14         new TestLayoutFlags().runTest();
  15     }
  16 
  17     void runTest() {
  18 
  19         Font font = new Font("Lucida Sans", Font.PLAIN, 24);
  20 
  21         String latin1 = "This is a latin1 string"; // none
  22         String hebrew = "\u05d0\u05d1\u05d2\u05d3"; // rtl
  23         String arabic = "\u0646\u0644\u0622\u0646"; // rtl + mc/g
  24         String hindi = "\u0939\u093f\u0923\u094d\u0921\u0940"; // ltr + reorder
  25         //      String tamil = "\u0b9c\u0bcb"; // ltr + mg/c + split
  26 
  27         FontRenderContext frc = new FontRenderContext(null, true, true);
  28 
  29         // get glyph char indices needs to initializes layoutFlags before use (5090704)
  30         {
  31           GlyphVector gv = font.createGlyphVector(frc, "abcde");
  32           int ix = gv.getGlyphCharIndex(0);
  33           if (ix != 0) {
  34             throw new Error("glyph 0 incorrectly mapped to char " + ix);
  35           }
  36           int[] ixs = gv.getGlyphCharIndices(0, gv.getNumGlyphs(), null);
  37           for (int i = 0; i < ixs.length; ++i) {
  38             if (ixs[i] != i) {
  39               throw new Error("glyph " + i + " incorrectly mapped to char " + ixs[i]);
  40             }
  41           }
  42         }
  43 
  44         GlyphVector latinGV = makeGlyphVector("Lucida Sans", frc, latin1, false, 1 /* ScriptRun.LATIN */);
  45         GlyphVector hebrewGV = makeGlyphVector("Lucida Sans", frc, hebrew, true, 5 /* ScriptRun.HEBREW */);
  46         GlyphVector arabicGV = makeGlyphVector("Lucida Sans", frc, arabic, true, 6 /* ScriptRun.ARABIC */);
  47         GlyphVector hindiGV = makeGlyphVector("Lucida Sans", frc, hindi, false, 7 /* ScriptRun.DEVANAGARI */);
  48         //      GlyphVector tamilGV = makeGlyphVector("Devanagari MT for IBM", frc, tamil, false, 12 /* ScriptRun.TAMIL */);
  49 
  50         GlyphVector latinPos = font.createGlyphVector(frc, latin1);
  51         Point2D pt = latinPos.getGlyphPosition(0);
  52         pt.setLocation(pt.getX(), pt.getY() + 1.0);
  53         latinPos.setGlyphPosition(0, pt);
  54 
  55         GlyphVector latinTrans = font.createGlyphVector(frc, latin1);
  56         latinTrans.setGlyphTransform(0, AffineTransform.getRotateInstance(.15));
  57 
  58         test("latin", latinGV, GlyphVector.FLAG_HAS_POSITION_ADJUSTMENTS);
  59         test("hebrew", hebrewGV, GlyphVector.FLAG_RUN_RTL |
  60              GlyphVector.FLAG_HAS_POSITION_ADJUSTMENTS);
  61         test("arabic", arabicGV, GlyphVector.FLAG_RUN_RTL |
  62              GlyphVector.FLAG_HAS_POSITION_ADJUSTMENTS);
  63         test("hindi", hindiGV, GlyphVector.FLAG_COMPLEX_GLYPHS |
  64              GlyphVector.FLAG_HAS_POSITION_ADJUSTMENTS);
  65         //      test("tamil", tamilGV, GlyphVector.FLAG_COMPLEX_GLYPHS);
  66         test("pos", latinPos, GlyphVector.FLAG_HAS_POSITION_ADJUSTMENTS);
  67         test("trans", latinTrans, GlyphVector.FLAG_HAS_TRANSFORMS);
  68     }
  69 
  70     GlyphVector makeGlyphVector(String fontname, FontRenderContext frc, String text, boolean rtl, int script) {
  71         Font font = new Font(fontname, Font.PLAIN, 14);
  72         System.out.println("asking for " + fontname + " and got " + font.getFontName());
  73         int flags = rtl ? 1 : 0;
  74         return font.layoutGlyphVector(frc, text.toCharArray(), 0, text.length(), flags);
  75     }
  76 
  77     void test(String name, GlyphVector gv, int expectedFlags) {
  78         expectedFlags &= gv.FLAG_MASK;
  79         int computedFlags = computeFlags(gv) & gv.FLAG_MASK;
  80         int actualFlags = gv.getLayoutFlags() & gv.FLAG_MASK;
  81 
  82         System.out.println("\n*** " + name + " ***");
  83         System.out.println(" test flags");
  84         System.out.print("expected ");
  85         printFlags(expectedFlags);
  86         System.out.print("computed ");
  87         printFlags(computedFlags);
  88         System.out.print("  actual ");
  89         printFlags(actualFlags);
  90 
  91         if (expectedFlags != actualFlags) {
  92             throw new Error("layout flags in test: " + name +
  93                             " expected: " + Integer.toHexString(expectedFlags) +
  94                             " but got: " + Integer.toHexString(actualFlags));
  95         }
  96     }
  97 
  98     static public void printFlags(int flags) {
  99         System.out.print("flags:");
 100         if ((flags & GlyphVector.FLAG_HAS_POSITION_ADJUSTMENTS) != 0) {
 101             System.out.print(" pos");
 102         }
 103         if ((flags & GlyphVector.FLAG_HAS_TRANSFORMS) != 0) {
 104             System.out.print(" trans");
 105         }
 106         if ((flags & GlyphVector.FLAG_RUN_RTL) != 0) {
 107             System.out.print(" rtl");
 108         }
 109         if ((flags & GlyphVector.FLAG_COMPLEX_GLYPHS) != 0) {
 110             System.out.print(" complex");
 111         }
 112         if ((flags & GlyphVector.FLAG_MASK) == 0) {
 113             System.out.print(" none");
 114         }
 115         System.out.println();
 116     }
 117 
 118     int computeFlags(GlyphVector gv) {
 119         validateCharIndexMethods(gv);
 120 
 121         int result = 0;
 122         if (glyphsAreRTL(gv)) {
 123             result |= GlyphVector.FLAG_RUN_RTL;
 124         }
 125         if (hasComplexGlyphs(gv)) {
 126             result |= GlyphVector.FLAG_COMPLEX_GLYPHS;
 127         }
 128 
 129         return result;
 130     }
 131 
 132     /**
 133      * throw an exception if getGlyphCharIndices returns a different result than
 134      * you get from iterating through getGlyphCharIndex one at a time.
 135      */
 136     void validateCharIndexMethods(GlyphVector gv) {
 137         int[] indices = gv.getGlyphCharIndices(0, gv.getNumGlyphs(), null);
 138         for (int i = 0; i < gv.getNumGlyphs(); ++i) {
 139             if (gv.getGlyphCharIndex(i) != indices[i]) {
 140                 throw new Error("glyph index mismatch at " + i);
 141             }
 142         }
 143     }
 144 
 145     /**
 146      * Return true if the glyph indices are pure ltr
 147      */
 148     boolean glyphsAreLTR(GlyphVector gv) {
 149         int[] indices = gv.getGlyphCharIndices(0, gv.getNumGlyphs(), null);
 150         for (int i = 0; i < indices.length; ++i) {
 151             if (indices[i] != i) {
 152                 return false;
 153             }
 154         }
 155         return true;
 156     }
 157 
 158     /**
 159      * Return true if the glyph indices are pure rtl
 160      */
 161     boolean glyphsAreRTL(GlyphVector gv) {
 162         int[] indices = gv.getGlyphCharIndices(0, gv.getNumGlyphs(), null);
 163         for (int i = 0; i < indices.length; ++i) {
 164             if (indices[i] != indices.length - i - 1) {
 165                 return false;
 166             }
 167         }
 168         return true;
 169     }
 170 
 171     /**
 172      * Return true if there is a local reordering (the run is not ltr or rtl).
 173      * !!! We can't have mixed bidi runs in the glyphs.
 174      */
 175     boolean hasComplexGlyphs(GlyphVector gv) {
 176         return !glyphsAreLTR(gv) && !glyphsAreRTL(gv);
 177     }
 178 }
 179 
 180 /*
 181 rect getPixelBounds(frc, x, y)
 182 rect getGlyphPixelBounds(frc, int, x, y)
 183 getGlyphOutline(int index, x, y)
 184 getGlyphInfo()
 185 */