/* * Copyright 1999 Computing Research Labs, New Mexico State University * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * $Id: CURender.java,v 1.8 1999/11/02 22:36:11 mleisher Exp $ */ /************************************************************************ * * This module handles the special processing needed to render text with * the ClearlyU PCF font. * ************************************************************************/ package pcffont; import java.io.*; import java.net.*; import pcffont.PCFFont; import pcffont.PCFMetrics; import pcffont.PCFRenderRun; import pcffont.UCData; public class CURender { private static char[] hdigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; private static String hexit(int n) { StringBuffer b = new StringBuffer(); b.append("0x"); if (n == 0) b.append("0000"); else { while (n > 0) { b.insert(2, hdigits[n & 0xf]); n >>= 4; } } return b.toString(); } public static boolean debug = false; // // This table returns the Devanagari dependent vowel for an independent. // // v = dev_i2d[code - 0x900]; // private static char dev_i2d[] = { 0x0900, 0x0901, 0x0902, 0x0903, 0x0904, 0x0905, 0x093E, 0x093F, 0x0940, 0x0941, 0x0942, 0x0943, 0x0962, 0x0945, 0x0946, 0x0947, 0x0948, 0x0949, 0x094A, 0x094B, 0x094C, 0x0915, 0x0916, 0x0917, 0x0918, 0x0919, 0x091A, 0x091B, 0x091C, 0x091D, 0x091E, 0x091F, 0x0920, 0x0921, 0x0922, 0x0923, 0x0924, 0x0925, 0x0926, 0x0927, 0x0928, 0x0929, 0x092A, 0x092B, 0x092C, 0x092D, 0x092E, 0x092F, 0x0930, 0x0931, 0x0932, 0x0933, 0x0934, 0x0935, 0x0936, 0x0937, 0x0938, 0x0939, 0x093A, 0x093B, 0x093C, 0x093D, 0x093E, 0x093F, 0x0940, 0x0941, 0x0942, 0x0943, 0x0944, 0x0945, 0x0946, 0x0947, 0x0948, 0x0949, 0x094A, 0x094B, 0x094C, 0x094D, 0x094E, 0x094F, 0x0950, 0x0951, 0x0952, 0x0953, 0x0954, 0x0955, 0x0956, 0x0957, 0x0958, 0x0959, 0x095A, 0x095B, 0x095C, 0x095D, 0x095E, 0x095F, 0x0944, 0x0963, 0x0962, 0x0963, 0x0964, 0x0965, 0x0966, 0x0967, 0x0968, 0x0969, 0x096A, 0x096B, 0x096C, 0x096D, 0x096E, 0x096F, 0x0970, 0x0971, 0x0972, 0x0973, 0x0974, 0x0975, 0x0976, 0x0977, 0x0978, 0x0979, 0x097A, 0x097B, 0x097C, 0x097D, 0x097E, 0x097F, }; // // This table returns the Devanagari independent vowel for a dependent. // // v = dev_d2i[code - 0x900]; // private static char dev_d2i[] = { 0x0900, 0x0901, 0x0902, 0x0903, 0x0904, 0x0905, 0x0906, 0x0907, 0x0908, 0x0909, 0x090A, 0x090B, 0x090C, 0x090D, 0x090E, 0x090F, 0x0910, 0x0911, 0x0912, 0x0913, 0x0914, 0x0915, 0x0916, 0x0917, 0x0918, 0x0919, 0x091A, 0x091B, 0x091C, 0x091D, 0x091E, 0x091F, 0x0920, 0x0921, 0x0922, 0x0923, 0x0924, 0x0925, 0x0926, 0x0927, 0x0928, 0x0929, 0x092A, 0x092B, 0x092C, 0x092D, 0x092E, 0x092F, 0x0930, 0x0931, 0x0932, 0x0933, 0x0934, 0x0935, 0x0936, 0x0937, 0x0938, 0x0939, 0x093A, 0x093B, 0x093C, 0x093D, 0x0906, 0x0907, 0x0908, 0x0909, 0x090A, 0x090B, 0x0960, 0x090D, 0x090E, 0x090F, 0x0910, 0x0911, 0x0912, 0x0913, 0x0914, 0x094D, 0x094E, 0x094F, 0x0950, 0x0951, 0x0952, 0x0953, 0x0954, 0x0955, 0x0956, 0x0957, 0x0958, 0x0959, 0x095A, 0x095B, 0x095C, 0x095D, 0x095E, 0x095F, 0x0960, 0x0961, 0x090C, 0x0961, 0x0964, 0x0965, 0x0966, 0x0967, 0x0968, 0x0969, 0x096A, 0x096B, 0x096C, 0x096D, 0x096E, 0x096F, 0x0970, 0x0971, 0x0972, 0x0973, 0x0974, 0x0975, 0x0976, 0x0977, 0x0978, 0x0979, 0x097A, 0x097B, 0x097C, 0x097D, 0x097E, 0x097F, }; // // This array provides a fast way of determining which characters // are independent vowels. 0x900 must be subtracted first. // private static char dev_indepv[] = { 0xFFE0, 0x001F, 0x0000, 0x0000, 0x0000, 0x0000, 0x0003, 0x0000, }; // // This array provides a fast way of determining which characters // are dependent vowels. 0x900 must be subtracted first. // private static char dev_depv[] = { 0x0000, 0x0000, 0x0000, 0xC000, 0x1FFF, 0x0000, 0x000C, 0x0000, }; private static boolean IsDevIndepV(char code) { return (0x900 <= code && code <= 0x97f && ((dev_indepv[(code-0x900)>>4] & (1<<((code-0x900)&15))) != 0)); } private static boolean IsDevDepV(char code) { return (0x900 <= code && code <= 0x97f && ((dev_depv[(code-0x900)>>4] & (1<<((code-0x900)&15))) != 0)); } private static boolean IsDevVowel(char code) { return (IsDevIndepV(code) || IsDevDepV(code)); } private static boolean IsDevConsonant(char code) { return ((0x915 <= code && code <= 0x939) || (0x958 <= code && code <= 0x95f)); } /****************************************************************** * * Symmetric characters that need to be swapped during right-to-left * processing. * ******************************************************************/ private static char symmetric_pairs[] = { 0x0028, 0x0029, 0x0029, 0x0028, 0x003c, 0x003e, 0x003e, 0x003c, 0x005b, 0x005d, 0x005d, 0x005b, 0x007b, 0x007d, 0x007d, 0x007b, 0x2045, 0x2046, 0x2046, 0x2045, 0x207d, 0x207e, 0x207e, 0x207d, 0x208d, 0x208e, 0x208e, 0x208d, 0x3008, 0x3009, 0x3009, 0x3008, 0x300a, 0x300b, 0x300b, 0x300a, 0x300c, 0x300d, 0x300d, 0x300c, 0x300e, 0x300f, 0x300f, 0x300e, 0x3010, 0x3011, 0x3011, 0x3010, 0x3014, 0x3015, 0x3015, 0x3014, 0x3016, 0x3017, 0x3017, 0x3016, 0x3018, 0x3019, 0x3019, 0x3018, 0x301a, 0x301b, 0x301b, 0x301a, }; private static char symmetricPair(char c) { for (int i = 0; i < symmetric_pairs.length; i += 2) { if (symmetric_pairs[i] == c) return symmetric_pairs[i + 1]; } return c; } /****************************************************************** * * Positioning info for non-spacing characters. * ******************************************************************/ private static final char TOP = 0x01; private static final char BOTTOM = 0x02; private static final char LEFT = 0x04; private static final char RIGHT = 0x08; private static final char CENTER = 0x10; private static final char DOUBLE = 0x20; private static char[] nstable = { 0x0300, TOP|CENTER, 0x0301, TOP|CENTER, 0x0302, TOP|CENTER, 0x0303, TOP|CENTER, 0x0304, TOP|CENTER, 0x0305, TOP|CENTER, 0x0306, TOP|CENTER, 0x0307, TOP|CENTER, 0x0308, TOP|CENTER, 0x0309, TOP|CENTER, 0x030A, TOP|CENTER, 0x030B, TOP|CENTER, 0x030C, TOP|CENTER, 0x030D, TOP|CENTER, 0x030E, TOP|CENTER, 0x030F, TOP|CENTER, 0x0310, TOP|CENTER, 0x0311, TOP|CENTER, 0x0312, TOP|CENTER, 0x0313, TOP|CENTER, 0x0314, TOP|CENTER, 0x0315, TOP|RIGHT, 0x0316, BOTTOM|CENTER, 0x0317, BOTTOM|CENTER, 0x0318, BOTTOM|CENTER, 0x0319, BOTTOM|CENTER, 0x031A, TOP|RIGHT, 0x031B, TOP|RIGHT, 0x031C, BOTTOM|CENTER, 0x031D, BOTTOM|CENTER, 0x031E, BOTTOM|CENTER, 0x031F, BOTTOM|CENTER, 0x0320, BOTTOM|CENTER, 0x0321, BOTTOM|RIGHT, 0x0322, BOTTOM|RIGHT, 0x0323, BOTTOM|CENTER, 0x0324, BOTTOM|CENTER, 0x0325, BOTTOM|CENTER, 0x0326, BOTTOM|CENTER, 0x0327, BOTTOM|CENTER, 0x0328, BOTTOM|CENTER, 0x0329, BOTTOM|CENTER, 0x032A, BOTTOM|CENTER, 0x032B, BOTTOM|CENTER, 0x032C, BOTTOM|CENTER, 0x032D, BOTTOM|CENTER, 0x032E, BOTTOM|CENTER, 0x032F, BOTTOM|CENTER, 0x0330, BOTTOM|CENTER, 0x0331, BOTTOM|CENTER, 0x0332, BOTTOM|CENTER, 0x0333, BOTTOM|CENTER, 0x0334, CENTER, 0x0335, CENTER, 0x0336, CENTER, 0x0337, CENTER, 0x0338, CENTER, 0x0339, BOTTOM|CENTER, 0x033A, BOTTOM|CENTER, 0x033B, BOTTOM|CENTER, 0x033C, BOTTOM|CENTER, 0x033D, TOP|CENTER, 0x033E, TOP|CENTER, 0x033F, TOP|CENTER, 0x0340, TOP|CENTER, 0x0341, TOP|CENTER, 0x0342, TOP|CENTER, 0x0343, TOP|CENTER, 0x0344, TOP|CENTER, 0x0345, BOTTOM|CENTER, 0x0346, TOP|CENTER, 0x0347, BOTTOM|CENTER, 0x0348, BOTTOM|CENTER, 0x0349, BOTTOM|CENTER, 0x034A, TOP|CENTER, 0x034B, TOP|CENTER, 0x034C, TOP|CENTER, 0x034D, BOTTOM|CENTER, 0x034E, BOTTOM|CENTER, 0x0360, DOUBLE, 0x0361, DOUBLE, 0x0362, DOUBLE, 0x0483, TOP|CENTER, 0x0484, TOP|CENTER, 0x0485, TOP|CENTER, 0x0486, TOP|CENTER, 0x055B, TOP|CENTER, 0x055C, TOP|CENTER, 0x055E, TOP|CENTER, 0x0591, BOTTOM|CENTER, 0x0592, TOP|CENTER, 0x0593, TOP|CENTER, 0x0594, TOP|CENTER, 0x0595, TOP|CENTER, 0x0596, BOTTOM|CENTER, 0x0597, TOP|CENTER, 0x0598, TOP|CENTER, 0x0599, TOP|LEFT, 0x059A, BOTTOM|RIGHT, 0x059B, BOTTOM|CENTER, 0x059C, TOP|CENTER, 0x059D, TOP|RIGHT, 0x059E, TOP|CENTER, 0x059F, TOP|CENTER, 0x05A0, TOP|RIGHT, 0x05A1, TOP|LEFT, 0x05A3, BOTTOM|CENTER, 0x05A4, BOTTOM|CENTER, 0x05A5, BOTTOM|CENTER, 0x05A6, BOTTOM|CENTER, 0x05A7, BOTTOM|CENTER, 0x05A8, TOP|CENTER, 0x05A9, TOP|LEFT, 0x05AA, BOTTOM|CENTER, 0x05AB, TOP|CENTER, 0x05AC, TOP|CENTER, 0x05AD, BOTTOM|RIGHT, 0x05AE, TOP|LEFT, 0x05AF, TOP|CENTER, 0x05B0, BOTTOM|CENTER, 0x05B1, BOTTOM|CENTER, 0x05B2, BOTTOM|CENTER, 0x05B3, BOTTOM|CENTER, 0x05B4, BOTTOM|CENTER, 0x05B5, BOTTOM|CENTER, 0x05B6, BOTTOM|CENTER, 0x05B7, BOTTOM|CENTER, 0x05B8, BOTTOM|CENTER, 0x05B9, TOP|LEFT, 0x05BB, BOTTOM|CENTER, 0x05BC, CENTER, 0x05BD, BOTTOM|CENTER, 0x05BF, TOP|CENTER, 0x05C1, TOP|RIGHT, 0x05C2, TOP|LEFT, 0x05C4, TOP|CENTER, 0x064B, TOP|CENTER, 0x064C, TOP|CENTER, 0x064D, BOTTOM|CENTER, 0x064E, TOP|CENTER, 0x064F, TOP|CENTER, 0x0650, BOTTOM|CENTER, 0x0651, TOP|CENTER, 0x0652, TOP|CENTER, 0x0653, TOP|CENTER, 0x0654, TOP|CENTER, 0x0655, BOTTOM|CENTER, 0x0670, TOP|LEFT, 0x06D6, TOP|CENTER, 0x06D7, TOP|CENTER, 0x06D8, TOP|CENTER, 0x06D9, TOP|CENTER, 0x06DA, TOP|CENTER, 0x06DB, TOP|CENTER, 0x06DC, TOP|CENTER, 0x06DD, CENTER, 0x06DE, CENTER, 0x06DF, TOP|CENTER, 0x06E0, TOP|CENTER, 0x06E1, TOP|CENTER, 0x06E2, TOP|CENTER, 0x06E3, TOP|CENTER, 0x06E4, TOP|CENTER, 0x06E7, TOP|CENTER, 0x06E8, TOP|CENTER, 0x06EA, BOTTOM|CENTER, 0x06EB, TOP|CENTER, 0x06EC, TOP|CENTER, 0x06ED, BOTTOM|CENTER, 0x0711, TOP|CENTER, 0x0730, TOP|CENTER, 0x0731, BOTTOM|CENTER, 0x0732, CENTER, 0x0733, TOP|CENTER, 0x0734, BOTTOM|CENTER, 0x0735, TOP|CENTER, 0x0736, TOP|CENTER, 0x0737, BOTTOM|CENTER, 0x0738, BOTTOM|CENTER, 0x0739, BOTTOM|CENTER, 0x073A, TOP|CENTER, 0x073B, BOTTOM|CENTER, 0x073C, BOTTOM|CENTER, 0x073D, TOP|CENTER, 0x073E, BOTTOM|CENTER, 0x073F, TOP|CENTER, 0x0740, TOP|CENTER, 0x0741, TOP|CENTER, 0x0742, BOTTOM|CENTER, 0x0743, TOP|CENTER, 0x0744, BOTTOM|CENTER, 0x0745, TOP|CENTER, 0x0746, BOTTOM|CENTER, 0x0747, TOP|CENTER, 0x0748, BOTTOM|CENTER, 0x0749, TOP|CENTER, 0x074A, TOP|CENTER, 0x07A6, TOP|CENTER, 0x07A7, TOP|CENTER, 0x07A8, BOTTOM|CENTER, 0x07A9, BOTTOM|CENTER, 0x07AA, TOP|CENTER, 0x07AB, TOP|CENTER, 0x07AC, TOP|CENTER, 0x07AD, TOP|CENTER, 0x07AE, TOP|CENTER, 0x07AF, TOP|CENTER, 0x07B0, TOP|CENTER, 0x0901, TOP|CENTER, 0x0902, TOP|RIGHT, 0x093C, BOTTOM|CENTER, 0x0941, BOTTOM|CENTER, 0x0942, BOTTOM|CENTER, 0x0943, BOTTOM|CENTER, 0x0944, BOTTOM|CENTER, 0x0945, TOP|CENTER, 0x0946, TOP|CENTER, 0x0947, TOP|CENTER, 0x0948, TOP|CENTER, 0x094D, BOTTOM|CENTER, 0x0951, TOP|CENTER, 0x0952, BOTTOM|CENTER, 0x0953, TOP|CENTER, 0x0954, TOP|CENTER, 0x0962, BOTTOM|CENTER, 0x0963, BOTTOM|CENTER, 0x0981, TOP|CENTER, 0x09BC, BOTTOM|CENTER, 0x09C1, BOTTOM|CENTER, 0x09C2, BOTTOM|CENTER, 0x09C3, BOTTOM|CENTER, 0x09C4, BOTTOM|CENTER, 0x09CD, BOTTOM|CENTER, 0x09E2, BOTTOM|CENTER, 0x09E3, BOTTOM|CENTER, 0x0A02, TOP|CENTER, 0x0A3C, BOTTOM|CENTER, 0x0A41, BOTTOM|CENTER, 0x0A42, BOTTOM|CENTER, 0x0A47, TOP|CENTER, 0x0A48, TOP|CENTER, 0x0A4B, TOP|LEFT, 0x0A4C, TOP|LEFT, 0x0A4D, BOTTOM|CENTER, 0x0A70, TOP|CENTER, 0x0A71, TOP|CENTER, 0x0A81, TOP|CENTER, 0x0A82, TOP|CENTER, 0x0ABC, BOTTOM|CENTER, 0x0AC1, BOTTOM|CENTER, 0x0AC2, BOTTOM|CENTER, 0x0AC3, BOTTOM|CENTER, 0x0AC4, BOTTOM|CENTER, 0x0AC5, TOP|CENTER, 0x0AC7, TOP|CENTER, 0x0AC8, TOP|CENTER, 0x0ACD, BOTTOM|CENTER, 0x0B01, TOP|CENTER, 0x0B3C, BOTTOM|CENTER, 0x0B3F, TOP|CENTER, 0x0B41, BOTTOM|CENTER, 0x0B42, BOTTOM|CENTER, 0x0B43, BOTTOM|CENTER, 0x0B4D, BOTTOM|CENTER, 0x0B56, TOP|LEFT, 0x0B82, TOP|CENTER, 0x0BC0, TOP|CENTER, 0x0BCD, BOTTOM|CENTER, 0x0C3E, TOP|RIGHT, 0x0C3F, TOP|RIGHT, 0x0C40, TOP|RIGHT, 0x0C46, TOP|CENTER, 0x0C47, TOP|CENTER, 0x0C48, CENTER, 0x0C4A, TOP|CENTER, 0x0C4B, TOP|CENTER, 0x0C4C, TOP|CENTER, 0x0C4D, TOP|CENTER, 0x0C55, TOP|RIGHT, 0x0C56, BOTTOM|CENTER, 0x0CBF, TOP|CENTER, 0x0CC6, TOP|CENTER, 0x0CCC, TOP|CENTER, 0x0CCD, TOP|CENTER, 0x0D41, BOTTOM|RIGHT, 0x0D42, BOTTOM|RIGHT, 0x0D43, BOTTOM|RIGHT, 0x0D4D, TOP|RIGHT, 0x0DCA, TOP|RIGHT, 0x0DD2, TOP|CENTER, 0x0DD3, TOP|CENTER, 0x0DD4, BOTTOM|CENTER, 0x0DD6, BOTTOM|CENTER, 0x0E31, TOP|RIGHT, 0x0E34, TOP|CENTER, 0x0E35, TOP|CENTER, 0x0E36, TOP|CENTER, 0x0E37, TOP|CENTER, 0x0E38, BOTTOM|RIGHT, 0x0E39, BOTTOM|RIGHT, 0x0E3A, BOTTOM|RIGHT, 0x0E47, TOP|RIGHT, 0x0E48, TOP|RIGHT, 0x0E49, TOP|RIGHT, 0x0E4A, TOP|RIGHT, 0x0E4B, TOP|RIGHT, 0x0E4C, TOP|RIGHT, 0x0E4D, TOP|RIGHT, 0x0E4E, TOP|RIGHT, 0x0EB1, TOP|RIGHT, 0x0EB4, TOP|CENTER, 0x0EB5, TOP|CENTER, 0x0EB6, TOP|CENTER, 0x0EB7, TOP|CENTER, 0x0EB8, BOTTOM|RIGHT, 0x0EB9, BOTTOM|RIGHT, 0x0EBB, TOP|RIGHT, 0x0EBC, BOTTOM|RIGHT, 0x0EC8, TOP|RIGHT, 0x0EC9, TOP|RIGHT, 0x0ECA, TOP|RIGHT, 0x0ECB, TOP|RIGHT, 0x0ECC, TOP|RIGHT, 0x0ECD, TOP|RIGHT, 0x0F18, BOTTOM|RIGHT, 0x0F19, BOTTOM|CENTER, 0x0F35, BOTTOM|CENTER, 0x0F37, BOTTOM|CENTER, 0x0F39, TOP|RIGHT, 0x0F71, BOTTOM|CENTER, 0x0F72, TOP|CENTER, 0x0F73, CENTER, 0x0F74, BOTTOM|CENTER, 0x0F75, BOTTOM|CENTER, 0x0F76, CENTER, 0x0F77, CENTER, 0x0F78, CENTER, 0x0F79, CENTER, 0x0F7A, TOP|CENTER, 0x0F7B, TOP|CENTER, 0x0F7C, TOP|CENTER, 0x0F7D, TOP|CENTER, 0x0F7E, TOP|CENTER, 0x0F80, TOP|CENTER, 0x0F81, CENTER, 0x0F82, TOP|CENTER, 0x0F83, TOP|CENTER, 0x0F84, BOTTOM|CENTER, 0x0F86, TOP|CENTER, 0x0F87, TOP|CENTER, 0x0F90, BOTTOM|CENTER, 0x0F91, BOTTOM|CENTER, 0x0F92, BOTTOM|CENTER, 0x0F93, BOTTOM|CENTER, 0x0F94, BOTTOM|CENTER, 0x0F95, BOTTOM|CENTER, 0x0F96, BOTTOM|CENTER, 0x0F97, BOTTOM|CENTER, 0x0F99, BOTTOM|CENTER, 0x0F9A, BOTTOM|CENTER, 0x0F9B, BOTTOM|CENTER, 0x0F9C, BOTTOM|CENTER, 0x0F9D, BOTTOM|CENTER, 0x0F9E, BOTTOM|CENTER, 0x0F9F, BOTTOM|CENTER, 0x0FA0, BOTTOM|CENTER, 0x0FA1, BOTTOM|CENTER, 0x0FA2, BOTTOM|CENTER, 0x0FA3, BOTTOM|CENTER, 0x0FA4, BOTTOM|CENTER, 0x0FA5, BOTTOM|CENTER, 0x0FA6, BOTTOM|CENTER, 0x0FA7, BOTTOM|CENTER, 0x0FA8, BOTTOM|CENTER, 0x0FA9, BOTTOM|CENTER, 0x0FAA, BOTTOM|CENTER, 0x0FAB, BOTTOM|CENTER, 0x0FAC, BOTTOM|CENTER, 0x0FAD, BOTTOM|CENTER, 0x0FAE, BOTTOM|CENTER, 0x0FAF, BOTTOM|CENTER, 0x0FB0, BOTTOM|CENTER, 0x0FB1, BOTTOM|CENTER, 0x0FB2, BOTTOM|CENTER, 0x0FB3, BOTTOM|CENTER, 0x0FB4, BOTTOM|CENTER, 0x0FB5, BOTTOM|CENTER, 0x0FB6, BOTTOM|CENTER, 0x0FB7, BOTTOM|CENTER, 0x0FB8, BOTTOM|CENTER, 0x0FB9, BOTTOM|CENTER, 0x0FBA, BOTTOM|CENTER, 0x0FBB, BOTTOM|CENTER, 0x0FBC, BOTTOM|CENTER, 0x0FC6, BOTTOM|CENTER, 0x102D, TOP|CENTER, 0x102E, TOP|CENTER, 0x102F, BOTTOM|CENTER, 0x1030, BOTTOM|CENTER, 0x1032, TOP|CENTER, 0x1036, TOP|CENTER, 0x1037, BOTTOM|CENTER, 0x1039, TOP|CENTER, 0x1058, BOTTOM|CENTER, 0x1059, BOTTOM|CENTER, 0x17B7, TOP|CENTER, 0x17B8, TOP|CENTER, 0x17B9, TOP|CENTER, 0x17BA, TOP|CENTER, 0x17BB, BOTTOM|CENTER, 0x17BC, BOTTOM|CENTER, 0x17BD, BOTTOM|CENTER, 0x17C6, TOP|CENTER, 0x17C9, TOP|CENTER, 0x17CA, TOP|CENTER, 0x17CB, TOP|CENTER, 0x17CC, TOP|CENTER, 0x17CD, TOP|CENTER, 0x17CE, TOP|CENTER, 0x17CF, TOP|CENTER, 0x17D0, TOP|RIGHT, 0x17D1, TOP|CENTER, 0x17D2, BOTTOM|CENTER, 0x17D3, TOP|CENTER, 0x18A9, BOTTOM|LEFT, 0x20D0, TOP|CENTER, 0x20D1, TOP|CENTER, 0x20D2, CENTER, 0x20D3, CENTER, 0x20D4, TOP|CENTER, 0x20D5, TOP|CENTER, 0x20D6, TOP|CENTER, 0x20D7, TOP|CENTER, 0x20D8, CENTER, 0x20D9, CENTER, 0x20DA, CENTER, 0x20DB, CENTER, 0x20DC, CENTER, 0x20DD, CENTER, 0x20DE, CENTER, 0x20DF, CENTER, 0x20E0, CENTER, 0x20E1, CENTER, 0x302A, BOTTOM|LEFT, 0x302B, TOP|LEFT, 0x302C, TOP|RIGHT, 0x302D, BOTTOM|RIGHT, 0x302E, CENTER|LEFT, 0x302F, CENTER|LEFT, 0x3099, TOP|RIGHT, 0x309A, TOP|RIGHT, 0xE97B, TOP|CENTER, 0xE97E, TOP|CENTER, 0xE97F, BOTTOM|CENTER, 0xF209, TOP|CENTER, 0xFB1E, TOP|CENTER, 0xFE20, TOP|RIGHT, 0xFE21, TOP|LEFT, 0xFE22, TOP|RIGHT, 0xFE23, TOP|LEFT, }; private static char nonSpacingPosition(char c) { int l, r, m; l = 0; r = nstable.length - 2; while (l <= r) { m = (l + r) >> 1; m -= (m & 1); if (c > nstable[m]) l = m + 2; else if (c < nstable[m]) r = m - 2; else return nstable[m + 1]; } return 0x00; } private static char[] aca_trie = { 0x0000, 0x0000, 0x0198, 0x0000, 0x0672, 0x0000, 0x0000, 0x0008, 0x0673, 0x0004, 0x0000, 0x000C, 0x0675, 0x0008, 0x0000, 0x0010, 0x0676, 0x000C, 0x0000, 0x0140, 0x0678, 0x0010, 0x0000, 0x00F8, 0x067C, 0x0014, 0x0000, 0x001C, 0x067D, 0x0018, 0x0000, 0x00E8, 0x0681, 0x001C, 0x0000, 0x0024, 0x0682, 0x0020, 0x0000, 0x0108, 0x0685, 0x0024, 0x0000, 0x010C, 0x0689, 0x0028, 0x0000, 0x0030, 0x068A, 0x002C, 0x0000, 0x0034, 0x068B, 0x0030, 0x0000, 0x0118, 0x068F, 0x0034, 0x0000, 0x003C, 0x0690, 0x0038, 0x0000, 0x0128, 0x0692, 0x003C, 0x0000, 0x0044, 0x0693, 0x0040, 0x0000, 0x0048, 0x0694, 0x0044, 0x0000, 0x004C, 0x0695, 0x0048, 0x0000, 0x0050, 0x0696, 0x004C, 0x0000, 0x0054, 0x0697, 0x0050, 0x0000, 0x0124, 0x0699, 0x0054, 0x0000, 0x005C, 0x069A, 0x0058, 0x0000, 0x0060, 0x069B, 0x005C, 0x0000, 0x0064, 0x069C, 0x0060, 0x0000, 0x0068, 0x069D, 0x0064, 0x0000, 0x006C, 0x069E, 0x0068, 0x0000, 0x0070, 0x069F, 0x006C, 0x0000, 0x0074, 0x06A0, 0x0070, 0x0000, 0x0078, 0x06A1, 0x0074, 0x0000, 0x007C, 0x06A2, 0x0078, 0x0000, 0x0080, 0x06A3, 0x007C, 0x0000, 0x00FC, 0x06A5, 0x0080, 0x0000, 0x0100, 0x06A7, 0x0084, 0x0000, 0x008C, 0x06A8, 0x0088, 0x0000, 0x012C, 0x06AA, 0x008C, 0x0000, 0x0094, 0x06AB, 0x0090, 0x0000, 0x0098, 0x06AC, 0x0094, 0x0000, 0x0164, 0x06AE, 0x0098, 0x0000, 0x0130, 0x06B0, 0x009C, 0x0000, 0x0138, 0x06B2, 0x00A0, 0x0000, 0x0134, 0x06B4, 0x00A4, 0x0000, 0x00AC, 0x06B5, 0x00A8, 0x0144, 0x00B0, 0x06B6, 0x00AC, 0x0148, 0x00B4, 0x06B7, 0x00B0, 0x014C, 0x013C, 0x06BC, 0x00B4, 0x0000, 0x00BC, 0x06BD, 0x00B8, 0x0000, 0x0158, 0x06C0, 0x00BC, 0x0000, 0x0154, 0x06C2, 0x00C0, 0x0000, 0x00C8, 0x06C3, 0x00C4, 0x0000, 0x00CC, 0x06C4, 0x00C8, 0x0000, 0x0178, 0x06CA, 0x00CC, 0x0000, 0x0174, 0x06CD, 0x00D0, 0x0000, 0x00D8, 0x06CE, 0x00D4, 0x0000, 0x0180, 0x06D1, 0x00D8, 0x0000, 0x015C, 0x0671, 0x00DC, 0x0000, 0x0004, 0x067B, 0x00E0, 0x0000, 0x0018, 0x067E, 0x00E4, 0x0000, 0x00F4, 0x0680, 0x00E8, 0x0000, 0x0020, 0x067A, 0x00EC, 0x0000, 0x00E4, 0x067F, 0x00F0, 0x0000, 0x00EC, 0x0679, 0x00F4, 0x0000, 0x00F0, 0x06A4, 0x00F8, 0x0000, 0x0084, 0x06A6, 0x00FC, 0x0000, 0x0088, 0x0684, 0x0100, 0x0000, 0x0028, 0x0683, 0x0104, 0x0000, 0x0104, 0x0686, 0x0108, 0x0000, 0x0110, 0x0687, 0x010C, 0x0000, 0x0120, 0x068D, 0x0110, 0x0000, 0x011C, 0x068C, 0x0114, 0x0000, 0x0114, 0x068E, 0x0118, 0x0000, 0x0038, 0x0688, 0x011C, 0x0000, 0x002C, 0x0698, 0x0120, 0x0000, 0x0058, 0x0691, 0x0124, 0x0000, 0x0040, 0x06A9, 0x0128, 0x0000, 0x0090, 0x06AF, 0x012C, 0x0000, 0x00A0, 0x06B3, 0x0130, 0x0000, 0x00A8, 0x06B1, 0x0134, 0x0000, 0x00A4, 0x06BA, 0x0138, 0x0000, 0x0150, 0x0677, 0x013C, 0x0000, 0x0014, 0x0627, 0x0140, 0x0000, 0x0000, 0x0627, 0x0144, 0x0000, 0x0000, 0x0627, 0x0148, 0x0000, 0x0000, 0x06BB, 0x014C, 0x0000, 0x00B8, 0x06C1, 0x0150, 0x0000, 0x00C4, 0x06BE, 0x0154, 0x0000, 0x00C0, 0x06D2, 0x0158, 0x0000, 0x0160, 0x06D3, 0x015C, 0x0000, 0x0000, 0x06AD, 0x0160, 0x0000, 0x009C, 0x06C7, 0x0164, 0x0000, 0x0170, 0x06C6, 0x0168, 0x0000, 0x0168, 0x06C8, 0x016C, 0x0000, 0x017C, 0x06CB, 0x0170, 0x0000, 0x0184, 0x06C5, 0x0174, 0x0000, 0x016C, 0x06C9, 0x0178, 0x0000, 0x00D0, 0x06D0, 0x017C, 0x0000, 0x00DC, 0x06CC, 0x0180, 0x01D4, 0x00D4, 0x0627, 0x01C4, 0x018C, 0x01D8, 0x0644, 0xFFFF, 0x0190, 0x0000, 0x0644, 0xFFFF, 0x0194, 0x0000, 0x0647, 0x0184, 0x0000, 0x0000, 0x0020, 0xFFFF, 0x019C, 0x01BC, 0x064B, 0x0188, 0x0000, 0x01A0, 0x064C, 0x018C, 0x0000, 0x01A4, 0x064D, 0x0190, 0x0000, 0x01A8, 0x064E, 0x0194, 0x0000, 0x01AC, 0x064F, 0x0198, 0x0000, 0x01B0, 0x0650, 0x019C, 0x0000, 0x01B4, 0x0651, 0x01A0, 0x0000, 0x01B8, 0x0652, 0x01A4, 0x0000, 0x0000, 0x0621, 0x01A8, 0x0000, 0x01C0, 0x0622, 0x01AC, 0x0000, 0x01C4, 0x0623, 0x01B0, 0x0000, 0x01C8, 0x0624, 0x01B4, 0x0000, 0x01CC, 0x0625, 0x01B8, 0x0000, 0x01D0, 0x0626, 0x01BC, 0x0000, 0x0188, 0x0621, 0x01C0, 0x0000, 0x0000, 0x0628, 0x01C8, 0x0000, 0x01DC, 0x0629, 0x01CC, 0x0000, 0x01E0, 0x062A, 0x01D0, 0x0000, 0x01E4, 0x062B, 0x01D4, 0x0000, 0x01E8, 0x062C, 0x01D8, 0x0000, 0x01EC, 0x062D, 0x01DC, 0x0000, 0x01F0, 0x062E, 0x01E0, 0x0000, 0x01F4, 0x062F, 0x01E4, 0x0000, 0x01F8, 0x0630, 0x01E8, 0x0000, 0x01FC, 0x0631, 0x01EC, 0x0000, 0x0200, 0x0632, 0x01F0, 0x0000, 0x0204, 0x0633, 0x01F4, 0x0000, 0x0208, 0x0634, 0x01F8, 0x0000, 0x020C, 0x0635, 0x01FC, 0x0000, 0x0210, 0x0636, 0x0200, 0x0000, 0x0214, 0x0637, 0x0204, 0x0000, 0x0218, 0x0638, 0x0208, 0x0000, 0x021C, 0x0639, 0x020C, 0x0000, 0x0220, 0x063A, 0x0210, 0x0000, 0x0224, 0x0641, 0x0214, 0x0000, 0x0228, 0x0642, 0x0218, 0x0000, 0x022C, 0x0643, 0x021C, 0x0000, 0x0230, 0x0644, 0x0220, 0x024C, 0x0234, 0x0645, 0x0224, 0x0000, 0x0238, 0x0646, 0x0228, 0x0000, 0x023C, 0x0647, 0x022C, 0x0000, 0x0240, 0x0648, 0x0230, 0x0000, 0x0244, 0x0649, 0x0234, 0x0000, 0x0248, 0x064A, 0x0238, 0x0000, 0x00E0, 0x0622, 0x023C, 0x0000, 0x0250, 0x0623, 0x0240, 0x0000, 0x0254, 0x0625, 0x0244, 0x0000, 0x0258, 0x0627, 0x0248, 0x0000, 0x0000, }; private static int[] aca_forms = { 0x0000E600, 0x0000E601, 0x00000000, 0x00000000, 0x0000E602, 0x0000E603, 0x00000000, 0x00000000, 0x0000E604, 0x0000E605, 0x00000000, 0x00000000, 0x0000E606, 0x0000E607, 0x00000000, 0x00000000, 0x0000E608, 0x00000509, 0x00000000, 0x00000066, 0x00000672, 0x00020000, 0x00040673, 0x00030000, 0x00080675, 0x00040000, 0x000C0676, 0x00500000, 0x00100678, 0x003E0000, 0x0014067C, 0x00070000, 0x0018067D, 0x003A0000, 0x001C0681, 0x00090000, 0x00200682, 0x00420000, 0x00240685, 0x00430000, 0x00280689, 0x000C0000, 0x002C068A, 0x000D0000, 0x0030068B, 0x00460000, 0x0034068F, 0x000F0000, 0x00380690, 0x004A0000, 0x003C0692, 0x00110000, 0x00400693, 0x00120000, 0x00440694, 0x00130000, 0x00480695, 0x00140000, 0x004C0696, 0x00150000, 0x00500697, 0x00490000, 0x00540699, 0x00170000, 0x0058069A, 0x00180000, 0x005C069B, 0x00190000, 0x0060069C, 0x001A0000, 0x0064069D, 0x001B0000, 0x0068069E, 0x001C0000, 0x006C069F, 0x001D0000, 0x007006A0, 0x001E0000, 0x007406A1, 0x001F0000, 0x007806A2, 0x00200000, 0x007C06A3, 0x003F0000, 0x008006A5, 0x00400000, 0x008406A7, 0x00230000, 0x008806A8, 0x004B0000, 0x008C06AA, 0x00250000, 0x009006AB, 0x00260000, 0x009406AC, 0x00590000, 0x009806AE, 0x004C0000, 0x009C06B0, 0x004E0000, 0x00A006B2, 0x004D0000, 0x00A406B4, 0x002B0000, 0x00A806B5, 0x002C0051, 0x00AC06B6, 0x002D0052, 0x00B006B7, 0x004F0053, 0x00B406BC, 0x002F0000, 0x00B806BD, 0x00560000, 0x00BC06C0, 0x00550000, 0x00C006C2, 0x00320000, 0x00C406C3, 0x00330000, 0x00C806C4, 0x005E0000, 0x00CC06CA, 0x005D0000, 0x00D006CD, 0x00360000, 0x00D406CE, 0x00600000, 0x00D806D1, 0x00570000, 0x00DC0671, 0x00010000, 0x00E0067B, 0x00060000, 0x00E4067E, 0x003D0000, 0x00E80680, 0x00080000, 0x00EC067A, 0x00390000, 0x00F0067F, 0x003B0000, 0x00F40679, 0x003C0000, 0x00F806A4, 0x00210000, 0x00FC06A6, 0x00220000, 0x01000684, 0x000A0000, 0x01040683, 0x00410000, 0x01080686, 0x00440000, 0x010C0687, 0x00480000, 0x0110068D, 0x00470000, 0x0114068C, 0x00450000, 0x0118068E, 0x000E0000, 0x011C0688, 0x000B0000, 0x01200698, 0x00160000, 0x01240691, 0x00100000, 0x012806A9, 0x00240000, 0x012C06AF, 0x00280000, 0x013006B3, 0x002A0000, 0x013406B1, 0x00290000, 0x013806BA, 0x00540000, 0x013C0677, 0x00050000, 0x01400627, 0x00000000, 0x01440627, 0x00000000, 0x01480627, 0x00000000, 0x014C06BB, 0x002E0000, 0x015006C1, 0x00310000, 0x015406BE, 0x00300000, 0x015806D2, 0x00580000, 0x015C06D3, 0x00000000, 0x016006AD, 0x00270000, 0x016406C7, 0x005C0000, 0x016806C6, 0x005A0000, 0x016C06C8, 0x005F0000, 0x017006CB, 0x00610000, 0x017406C5, 0x005B0000, 0x017806C9, 0x00340000, 0x017C06D0, 0x00370000, 0x018006CC, 0x00350075, 0x01C40627, 0x00760063, 0xFFFF0644, 0x00000064, 0xFFFF0644, 0x00000065, 0x01840647, 0x00000000, 0xFFFF0020, 0x006F0067, 0x0188064B, 0x00680000, 0x018C064C, 0x00690000, 0x0190064D, 0x006A0000, 0x0194064E, 0x006B0000, 0x0198064F, 0x006C0000, 0x019C0650, 0x006D0000, 0x01A00651, 0x006E0000, 0x01A40652, 0x00000000, 0x01A80621, 0x00700000, 0x01AC0622, 0x00710000, 0x01B00623, 0x00720000, 0x01B40624, 0x00730000, 0x01B80625, 0x00740000, 0x01BC0626, 0x00620000, 0x01C00621, 0x00000000, 0x01C80628, 0x00770000, 0x01CC0629, 0x00780000, 0x01D0062A, 0x00790000, 0x01D4062B, 0x007A0000, 0x01D8062C, 0x007B0000, 0x01DC062D, 0x007C0000, 0x01E0062E, 0x007D0000, 0x01E4062F, 0x007E0000, 0x01E80630, 0x007F0000, 0x01EC0631, 0x00800000, 0x01F00632, 0x00810000, 0x01F40633, 0x00820000, 0x01F80634, 0x00830000, 0x01FC0635, 0x00840000, 0x02000636, 0x00850000, 0x02040637, 0x00860000, 0x02080638, 0x00870000, 0x020C0639, 0x00880000, 0x0210063A, 0x00890000, 0x02140641, 0x008A0000, 0x02180642, 0x008B0000, 0x021C0643, 0x008C0000, 0x02200644, 0x008D0093, 0x02240645, 0x008E0000, 0x02280646, 0x008F0000, 0x022C0647, 0x00900000, 0x02300648, 0x00910000, 0x02340649, 0x00920000, 0x0238064A, 0x00380000, 0x023C0622, 0x00940000, 0x02400623, 0x00950000, 0x02440625, 0x00960000, 0x02480627, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000FBA8, 0x00000741, 0x0000FBAA, 0x0000FBAB, 0x0000FBAC, 0x0000FBAD, 0x0000FBAE, 0x0000FBAF, 0x00000000, 0x00000000, 0x0000FBB0, 0x0000FBB1, 0x00000000, 0x00000000, 0x0000FBD3, 0x0000FBD4, 0x0000FBD5, 0x0000FBD6, 0x0000FBD7, 0x0000FBD8, 0x00000000, 0x00000000, 0x0000FBD9, 0x0000FBDA, 0x00000000, 0x00000000, 0x0000FBDB, 0x0000FBDC, 0x00000000, 0x00000000, 0x0000FBDE, 0x0000FBDF, 0x00000000, 0x00000000, 0x0000FBE0, 0x0000FBE1, 0x00000000, 0x00000000, 0x0000FBE2, 0x0000FBE3, 0x00000000, 0x00000000, 0x0000FBE4, 0x0000FBE5, 0x0000FBE6, 0x0000FBE7, 0x0000FBFC, 0x0000FBFD, 0x0000FBFE, 0x0000FBFF, 0x0000FDF2, 0x00000000, 0x00000000, 0x00000000, 0x0000FE70, 0x00000000, 0x00000000, 0x00000000, 0x0000FE72, 0x00000000, 0x00000000, 0x00000000, 0x0000FE74, 0x00000000, 0x00000000, 0x00000000, 0x0000FE76, 0x00000000, 0x00000000, 0x00000000, 0x0000FE78, 0x00000000, 0x00000000, 0x00000000, 0x0000FE7A, 0x00000000, 0x00000000, 0x00000000, 0x0000FE7C, 0x00000000, 0x00000000, 0x00000000, 0x0000FE7E, 0x00000000, 0x00000000, 0x00000000, 0x0000FE80, 0x00000000, 0x00000000, 0x00000000, 0x0000FE81, 0x0000FE82, 0x00000000, 0x00000000, 0x0000FE83, 0x0000FE84, 0x00000000, 0x00000000, 0x0000FE85, 0x0000FE86, 0x00000000, 0x00000000, 0x0000FE87, 0x0000FE88, 0x00000000, 0x00000000, 0x0000FE89, 0x0000FE8A, 0x0000FE8B, 0x0000FE8C, 0x0000FE89, 0x0000FE8A, 0x0000FE8B, 0x0000FE8C, 0x0000FE8D, 0x0000FE8E, 0x00000000, 0x00000000, 0x0000FE8F, 0x0000FE90, 0x0000FE91, 0x0000FE92, 0x0000FE93, 0x0000FE94, 0x00000000, 0x00000000, 0x0000FE95, 0x0000FE96, 0x0000FE97, 0x0000FE98, 0x0000FE99, 0x0000FE9A, 0x0000FE9B, 0x0000FE9C, 0x0000FE9D, 0x0000FE9E, 0x0000FE9F, 0x0000FEA0, 0x0000FEA1, 0x0000FEA2, 0x0000FEA3, 0x0000FEA4, 0x0000FEA5, 0x0000FEA6, 0x0000FEA7, 0x0000FEA8, 0x0000FEA9, 0x0000FEAA, 0x00000000, 0x00000000, 0x0000FEAB, 0x0000FEAC, 0x00000000, 0x00000000, 0x0000FEAD, 0x0000FEAE, 0x00000000, 0x00000000, 0x0000FEAF, 0x0000FEB0, 0x00000000, 0x00000000, 0x0000FEB1, 0x0000FEB2, 0x0000FEB3, 0x0000FEB4, 0x0000FEB5, 0x0000FEB6, 0x0000FEB7, 0x0000FEB8, 0x0000FEB9, 0x0000FEBA, 0x0000FEBB, 0x0000FEBC, 0x0000FEBD, 0x0000FEBE, 0x0000FEBF, 0x0000FEC0, 0x0000FEC1, 0x0000FEC2, 0x0000FEC3, 0x0000FEC4, 0x0000FEC5, 0x0000FEC6, 0x0000FEC7, 0x0000FEC8, 0x0000FEC9, 0x0000FECA, 0x0000FECB, 0x0000FECC, 0x0000FECD, 0x0000FECE, 0x0000FECF, 0x0000FED0, 0x0000FED1, 0x0000FED2, 0x0000FED3, 0x0000FED4, 0x0000FED5, 0x0000FED6, 0x0000FED7, 0x0000FED8, 0x0000FED9, 0x0000FEDA, 0x0000FEDB, 0x0000FEDC, 0x0000FEDD, 0x0000FEDE, 0x0000FEDF, 0x0000FEE0, 0x0000FEE1, 0x0000FEE2, 0x0000FEE3, 0x0000FEE4, 0x0000FEE5, 0x0000FEE6, 0x0000FEE7, 0x0000FEE8, 0x0000FEE9, 0x0000FEEA, 0x0000FEEB, 0x0000FEEC, 0x0000FEED, 0x0000FEEE, 0x00000000, 0x00000000, 0x0000FEEF, 0x0000FEF0, 0x00000000, 0x00000000, 0x0000FEF1, 0x0000FEF2, 0x0000FEF3, 0x0000FEF4, 0x0000FEF5, 0x0000FEF6, 0x00000000, 0x00000000, 0x0000FEF7, 0x0000FEF8, 0x00000000, 0x00000000, 0x0000FEF9, 0x0000FEFA, 0x00000000, 0x00000000, 0x0000FEFB, 0x0000FEFC, 0x00000000, 0x00000000, }; // // Flags used to indicate which scripts need special rendering. // private final static int CU_RENDER_ARABIC = 0x01; private final static int CU_RENDER_DEVANAGARI = 0x02; private final static int CU_RENDER_GREEK = 0x04; private final static int CU_RENDER_HEBREW = 0x08; private final static int ARABIC_ISOLATED = 0; private final static int ARABIC_FINAL = 1; private final static int ARABIC_INITIAL = 2; private final static int ARABIC_MEDIAL = 3; private static void findArabicForms(char[] visual, int start, int end, int[] count) { int i, code; char t, c; i = start; t = aca_trie[2]; while (i < end) { c = visual[i]; for (; t != 0 && aca_trie[t] != c; t = aca_trie[t + 3]) ; if (t == 0) return; else if (aca_trie[t + 1] != '\uffff') { count[0] = (i - start) + 1; count[1] = (int) aca_trie[t + 1]; } t = aca_trie[t + 2]; i++; } } // // The first rendering pass is made with the Arabic renderer which will // detect whether any of the other rendering routines needs to be called. // private static void renderArabicBlock(PCFRenderRun run) { int i, j, state, vstate, lpos, lcoff, comp[] = {0, 0}; for (i = 0; i < run.visual_used; i++) { // // Skip all the non-Arabic Block characters. // while (i < run.visual_used && (run.visual[i] < 0x600 || run.visual[i] > 0x6ff || !UCData.ucisalpha(run.visual[i]))) i++; // // Deal with the Arabic Block characters. // lpos = lcoff = -1; state = ARABIC_ISOLATED; while (i < run.visual_used && ((run.visual[i] >= 0x600 && run.visual[i] <= 0x6ff) || run.visual[i] == 0x200d)) { // // Look up the next Arabic Block composition. // comp[0] = comp[1] = -1; findArabicForms(run.visual, i, run.visual_used, comp); if (comp[0] > 1) { // // Need to shift everything from the next character to the // end down to account for a composition of more than one // character. // for (j = i + 1; j < run.visual_used - 1; j++) { run.positions[j] = run.positions[j + (comp[0] - 1)]; run.visual[j] = run.visual[j + (comp[0] - 1)]; run.nonspacing[j] = run.nonspacing[j + (comp[0] - 1)]; } // // Adjust the end of the visual array to account for the // characters used in the composition. // run.visual_used -= (comp[0] - 1); } if (run.visual[i] != 0x621 && (run.visual[i] == 0x200d || comp[0] > 0)) { // // Now select the shape according to the state. // if (state == ARABIC_INITIAL) { // // Change the last glyph to initial and shift to // final state. // if (lpos > -1) { vstate = state; if (aca_forms[lcoff + vstate] == 0) vstate -= 2; run.visual[lpos] = (char) (aca_forms[lcoff + vstate] & 0xffff); } state = ARABIC_FINAL; } else if (state == ARABIC_FINAL) { if (lpos > -1) { vstate = ARABIC_MEDIAL; if (aca_forms[lcoff + vstate] == 0) vstate -= 2; run.visual[lpos] = (char) (aca_forms[lcoff + vstate] & 0xffff); } } } if (comp[0] > 0) { vstate = state; if (aca_forms[comp[1] + vstate] == 0) vstate -= 2; run.visual[i] = (char) (aca_forms[comp[1] + vstate] & 0xffff); // // Handle the special case of hamzah on the line. // if (run.visual[i] == 0) run.visual[i] = (char) (aca_forms[comp[1]] & 0xffff); } if (comp[0] > 0 && aca_forms[comp[1] + ARABIC_MEDIAL] == 0) state = ARABIC_ISOLATED; else if (state == ARABIC_ISOLATED) state = ARABIC_INITIAL; lpos = i; lcoff = comp[1]; i++; // // Skip the TATWEEL and non-spacing characters. // while (i < run.visual_used && (run.visual[i] == 0x640 || run.nonspacing[i])) i++; } } } private static void renderDevanagariBlock(PCFRenderRun run) { int i, j, cluster_start, vu, lc; char tmp, tmpp; cluster_start = lc = -1; for (i = vu = 0; i < run.visual_used; vu++, i++) { // // Skip over all characters that are not from the Devanagari // block. Keep the ZERO WIDTH JOINER so it can be handled. // if (i < run.visual_used && run.visual[i] != 0x200D && (run.visual[i] < 0x900 || run.visual[i] > 0x97f)) { run.nonspacing[vu] = run.nonspacing[i]; run.positions[vu] = run.positions[i]; run.visual[vu] = run.visual[i]; cluster_start = lc = -1; continue; } run.visual[vu] = run.visual[i]; run.positions[vu] = run.positions[i]; run.nonspacing[vu] = run.nonspacing[i]; if (IsDevConsonant(run.visual[vu]) || run.visual[i] == 0x200D) { if (cluster_start == -1) // // Mark the beginning of the akshara. // cluster_start = vu; // // Set the marker to the last actual consonant. This may // need to be moved farther down later, but is only used // in the vowel section at the moment. // if (run.visual[vu] != 0x200D) lc = vu; // // First, check for consonant ligatures. // if (vu - cluster_start >= 2 && run.visual[vu - 1] == 0x094D) { tmp = 0; if (run.visual[vu - 2] == 0x915 && run.visual[vu] == 0x937) run.visual[vu - 2] = tmp = 0xe900; else if (run.visual[vu - 2] == 0x91C && run.visual[vu] == 0x91E) run.visual[vu - 2] = tmp = 0xe901; else if (run.visual[vu - 2] == 0x924 && run.visual[vu] == 0x924) run.visual[vu - 2] = tmp = 0xe902; else if (run.visual[vu - 2] == 0x924 && run.visual[vu] == 0x930) run.visual[vu - 2] = tmp = 0xe903; else if (run.visual[vu - 2] == 0x936 && run.visual[vu] == 0x91B) run.visual[vu - 2] = tmp = 0xe904; else if (run.visual[vu - 2] == 0x936 && run.visual[vu] == 0x930) run.visual[vu - 2] = tmp = 0xe905; else if (run.visual[vu - 2] == 0x936 && run.visual[vu] == 0x935) run.visual[vu - 2] = tmp = 0xe906; else if (run.visual[vu - 2] == 0x915 && run.visual[vu] == 0x915) run.visual[vu - 2] = tmp = 0xe940; else if (run.visual[vu - 2] == 0x915 && run.visual[vu] == 0x924) run.visual[vu - 2] = tmp = 0xe941; else if (run.visual[vu - 2] == 0x926 && run.visual[vu] == 0x918) run.visual[vu - 2] = tmp = 0xe947; else if (run.visual[vu - 2] == 0x926 && run.visual[vu] == 0x927) run.visual[vu - 2] = tmp = 0xe949; else if (run.visual[vu - 2] == 0x926 && run.visual[vu] == 0x92F) run.visual[vu - 2] = tmp = 0xe94d; else if (run.visual[vu - 2] == 0x926 && run.visual[vu] == 0x935) run.visual[vu - 2] = tmp = 0xe94e; else if (run.visual[vu - 2] == 0x91f && run.visual[vu] == 0x91f) run.visual[vu - 2] = tmp = 0xe94f; else if (run.visual[vu - 2] == 0x91f && run.visual[vu] == 0x920) run.visual[vu - 2] = tmp = 0xe950; else if (run.visual[vu - 2] == 0x921 && run.visual[vu] == 0x917) run.visual[vu - 2] = tmp = 0xe952; else if (run.visual[vu - 2] == 0x928 && run.visual[vu] == 0x928) run.visual[vu - 2] = tmp = 0xe955; if (tmp != 0) // // A ligature was formed, so account for the combining // of two characters and removal of the VIRAMA. // vu -= 2; // // Check for a final RA which will change to a // subjoined form and ligate with certain characters. // tmp = 0; if (vu - cluster_start >= 2 && run.visual[vu] == 0x930 && (i + 1 == run.visual_used || (i + 1 < run.visual_used && !(IsDevConsonant(run.visual[i + 1]) || run.visual[i + 1] == 0x094D)))) { switch (run.visual[vu - 2]) { case 0x0915: tmp = run.visual[vu - 2] = 0xE907; break; case 0x091C: tmp = run.visual[vu - 2] = 0xE908; break; case 0x092A: tmp = run.visual[vu - 2] = 0xE90C; break; case 0x092B: tmp = run.visual[vu - 2] = 0xE90A; break; case 0x0938: tmp = run.visual[vu - 2] = 0xE90D; break; case 0x095B: tmp = run.visual[vu - 2] = 0xE909; break; case 0x095E: tmp = run.visual[vu - 2] = 0xE90B; break; default: run.visual[vu - 1] = 0xE97F; run.nonspacing[vu - 1] = true; } if (tmp == 0) // // Adjust the count to reflect the preceding VIRAMA // replaced by the subjoined form of RA. // vu--; else // // Adjust the count to reflect the preceding VIRAMA // removed and the preceding consonant ligating with // the subjoined form of RA. // vu -= 2; } // // If this consonant is not the first and the last // character is a VIRAMA, do two things: // // 1. If the preceding consonant was a RA, change // it to the non-spacing REPHA form and exchange it // with the current consonant. // 2. Change the last consonant to the half-consonant // form. // if (vu - cluster_start >= 2 && run.visual[vu - 1] == 0x094D) { if (run.visual[vu - 2] == 0x0930) { // // The consonant was preceded by a RA. // tmp = run.visual[vu - 2]; tmpp = run.positions[vu - 2]; run.visual[vu - 2] = run.visual[vu]; run.positions[vu - 2] = run.positions[vu]; run.nonspacing[vu - 2] = false; // // Decrement to account for the preceding VIRAMA. // vu--; // // Change the RA to the non-spacing REPHA form. // run.visual[vu] = 0xE97E; run.positions[vu] = tmpp; run.nonspacing[vu] = true; } else { // // Convert the preceding consonant to its // half-consonant form. // if (run.visual[vu - 2] >= 0xE900 && run.visual[vu - 2] <= 0xE906) // // This is a consonant ligature with a // half-consonant form. A fixed offset reaches // the appropriate glyphs. // run.visual[vu - 2] += 0x70; else if (run.visual[vu - 2] == 0x0931) // // Change the RAA to the half-consonant form of // the eyelash RA. // run.visual[vu - 2] = 0xE97D; else // // A fixed offset gets the single half-consonant // forms. // run.visual[vu - 2] += 0xE000; // // Shift backward by one to remove the preceding // VIRAMA. // run.visual[vu - 1] = run.visual[vu]; run.positions[vu - 1] = run.positions[vu]; run.nonspacing[vu - 1] = run.nonspacing[vu]; // // Decrement to account for the preceding VIRAMA. // vu--; } } } } else if (IsDevVowel(run.visual[vu])) { // // First, determine if the vowel should be in dependent or // independent form. // if (cluster_start == -1) cluster_start = vu; if (vu > cluster_start) { // // A dependent form is needed except in one rare case: // where a RA followed by VIRAMA is the only consonant // preceding the vowel. In that case, the vowel becomes // independent and the RA is changed to a non-spacing // REPHA form. // if (vu - cluster_start == 2 && run.visual[vu - 1] == 0x094D && run.visual[vu - 2] == 0x0930) { // // Change to the independent form. // run.visual[vu] = dev_d2i[run.visual[vu] - 0x900]; // // Save the RA or RAA and its position. // tmp = run.visual[vu - 2]; tmpp = run.positions[vu - 2]; // // Move the vowel backward. // run.visual[vu - 2] = run.visual[vu]; run.positions[vu - 2] = run.positions[vu]; run.nonspacing[vu - 2] = run.nonspacing[vu]; // // Decrement to account for the VIRAMA. // vu--; // // Add the REPHA form after the vowel. // run.visual[vu] = 0xE97E; run.positions[vu] = tmpp; run.nonspacing[vu] = true; } else { // // Change to the dependent form. // run.visual[vu] = dev_i2d[run.visual[vu] - 0x900]; run.nonspacing[vu] = UCData.ucisnonspacing(run.visual[vu]); // // If this happens to be U or UU, and the preceding // character happens to be a RA, change to use the // special ligatures. // if (lc > -1) { if (run.visual[lc] == 0x0930) { tmp = 0; switch (run.visual[vu]) { case 0x0941: tmp = run.visual[lc] = 0xE90E; break; case 0x0942: tmp = run.visual[lc] = 0xE90F; break; } if (tmp != 0) // // Adjust to take into account the ligature // of RA and U or UU. // vu--; } } } // // Shift the dependent vowel form of I to the beginning // of the cluster. // if (run.visual[vu] == 0x093F) { if (cluster_start == -1) cluster_start = vu - 1; // // Adjust the beginning of the cluster so the // dependent I appears before a spacing character that // is not a control. // for (; cluster_start > 0 && (UCData.uciscntrl(run.visual[cluster_start]) || UCData.ucisnonspacing(run.visual[cluster_start])|| UCData.ucisspace(run.visual[cluster_start])); cluster_start--) ; tmp = run.positions[vu]; for (j = vu; cluster_start >= 0 && j > cluster_start; j--) { run.visual[j] = run.visual[j - 1]; run.positions[j] = run.positions[j - 1]; run.nonspacing[j] = run.nonspacing[j - 1]; } if (cluster_start >= 0) { run.visual[cluster_start] = 0x093F; run.positions[cluster_start] = tmp; run.nonspacing[cluster_start] = false; } } } else // // Convert to the independent form. // run.visual[vu] = dev_d2i[run.visual[vu] - 0x900]; // // Reset the cluster start indicator and the last consonant // marker. // cluster_start = lc = -1; } else if (run.visual[vu] != 0x093C && run.visual[vu] != 0x0902 && run.visual[vu] != 0x094D && run.visual[vu] != 0x200D) // // Reset the cluster start indicator and the last consonant // marker. // cluster_start = lc = -1; } run.visual_used = vu; } private static void renderGreekBlock(PCFRenderRun run) { int i; char lc, c; for (lc = 0, i = 0; i < run.visual_used; i++) { if (((lc >= 0x370 && lc <= 0x3ff) || (lc >= 0x1f00 && lc <= 0x1fff)) && run.visual[i] == 0x3c3) { c = (i + 1 < run.visual_used) ? run.visual[i + 1] : 0; if (c == 0 || !(c == 0x200d || (c >= 0x370 && c <= 0x3ff) || (c >= 0x1f00 && c <= 0x1fff))) // // Change to the final form of the Sigma. // run.visual[i]--; } lc = run.visual[i]; } } private static void renderHebrewBlock(PCFRenderRun run) { int i; char lc, c; for (lc = 0, i = 0; i < run.visual_used; i++) { if (((lc >= 0x590 && lc <= 0x5ff) || (lc >= 0xfb20 && lc <= 0xfb4f) || lc == 0xe5da) && (run.visual[i] == 0x5db || run.visual[i] == 0x5de || run.visual[i] == 0x5e0 || run.visual[i] == 0x5e4 || run.visual[i] == 0x5e6)) { c = (i + 1 < run.visual_used) ? run.visual[i + 1] : 0; if (c == 0 || !((c >= 0x590 && c <= 0x5ff) || (c >= 0xfb20 && c <= 0xfb4f) || c == 0xe5da || c == 0x200d)) // // Change to the final form of the letter. // run.visual[i]--; } lc = run.visual[i]; } } /** * Primary function for rendering with fonts arranged in the ClearlyU * Unicode format. *

* @param font A bitmap PCF font. *

* @param rs The reordered string that needs to be rendered for this font. *

* @param showControls A boolean indicating whether certain control * characters should be displayed when the string is * rendered. *

* @see pcffont.PCFRenderRun */ public static void renderForFont(PCFUnicodeFont font, PCFRenderString rs, boolean showControls) { int i, flags = 0, cw, comp[] = {0, 0}; int lsb, rsb, as, ds, wd; boolean ns; char c, pos; PCFRenderRun run; PCFMetrics metrics, gm; metrics = rs.metrics; for (run = rs.visual_first; run != null; run = run.visual_next) { // // First, run through and do the compositions that are generated // from the Unicode Character Database. // for (flags = 0, i = run.start; i < run.end; ) { c = run.source.charAt(i); // // Check for Devanagari, Greek, and Hebrew Block characters // that might indicate some rendering needs to be done. // if ((flags & CU_RENDER_ARABIC) == 0 && c >= 0x600 && c <= 0x6ff && UCData.ucisalpha((int) c)) flags |= CU_RENDER_ARABIC; else if ((flags & CU_RENDER_DEVANAGARI) == 0 && c >= 0x900 && c <= 0x97f) flags |= CU_RENDER_DEVANAGARI; else if ((flags & CU_RENDER_GREEK) == 0 && c == 0x3c3) flags |= CU_RENDER_GREEK; else if ((flags & CU_RENDER_HEBREW) == 0 && (c == 0x5db || c == 0x5de || c == 0x5e0 || c == 0x5e4 || c == 0x5e6)) flags |= CU_RENDER_HEBREW; comp[0] = 1; comp[1] = run.source.charAt(i); UCData.ucrcmp_compose(run.source, i, run.end, comp); ns = UCData.ucisnonspacing(comp[1]); // // If the very first character of the run happens to be a // non-spacing character, then insert a dotted circle to make // it clear it is a stand-alone character. // // NOTE: This can mess up space allocation for a run. This // test should actually be done when the run is allocated. // if (i == run.start && ns) { run.positions[run.visual_used] = (char) (i - run.start); run.nonspacing[run.visual_used] = false; run.visual[run.visual_used++] = 0x25cc; } // // Swap the mirroring characters for RTL runs so they appear // correctly when displayed. // if (run.direction == PCFRenderRun.RIGHT_TO_LEFT && (UCData.ucissymmetric(comp[1]) || comp[1] == 0x003C || comp[1] == 0x003E)) comp[1] = (int) symmetricPair((char) comp[1]); run.positions[run.visual_used] = (char) (i - run.start); run.nonspacing[run.visual_used] = ns; run.visual[run.visual_used++] = (char) comp[1]; i += comp[0]; } // // Do the script-specific rendering. // if ((flags & CU_RENDER_ARABIC) != 0) renderArabicBlock(run); if ((flags & CU_RENDER_DEVANAGARI) != 0) renderDevanagariBlock(run); if ((flags & CU_RENDER_GREEK) != 0) renderGreekBlock(run); if ((flags & CU_RENDER_HEBREW) != 0) renderHebrewBlock(run); // // Strip the controls in the 0x2000-0x206f block if indicated. // TEMPORARY: When controls should be shown, only show those // that appear at the beginning of a run. Remove the rest. // This will break if there is some combination of controls // that should be shown, which is unlikely. // wd = (showControls) ? 1 : 0; for (lsb = rsb = wd; lsb < run.visual_used; lsb++) { c = run.visual[lsb]; if ((0x200c <= c && c <= 0x200f) || (0x202a <= c && c <= 0x202e) || (0x206a <= c && c <= 0x206f)) continue; run.positions[rsb] = run.positions[lsb]; run.nonspacing[rsb] = run.nonspacing[lsb]; run.visual[rsb++] = run.visual[lsb]; } run.visual_used = rsb; // // Reverse right-to-left runs. // if (run.direction == PCFRenderRun.RIGHT_TO_LEFT) { for (lsb = 0, rsb = run.visual_used - 1; rsb > lsb; rsb--, lsb++) { c = run.visual[lsb]; run.visual[lsb] = run.visual[rsb]; run.visual[rsb] = c; c = run.positions[lsb]; run.positions[lsb] = run.positions[rsb]; run.positions[rsb] = c; ns = run.nonspacing[lsb]; run.nonspacing[lsb] = run.nonspacing[rsb]; run.nonspacing[rsb] = ns; } // // Do another pass to rearrange the non-spacing glyphs so they // follow their spacing glyph. // for (lsb = 0; lsb < run.visual_used; lsb++) { if (run.nonspacing[lsb]) { for (rsb = lsb + 1; rsb < run.visual_used && run.nonspacing[rsb]; rsb++); for (; rsb < run.visual_used && rsb > lsb; rsb--, lsb++) { c = run.visual[lsb]; run.visual[lsb] = run.visual[rsb]; run.visual[rsb] = c; ns = run.nonspacing[lsb]; run.nonspacing[lsb] = run.nonspacing[rsb]; run.nonspacing[rsb] = ns; } } } } // // Now generate the metrics based on the font passed. // lsb = rsb = as = ds = wd = 0; for (i = 0; i < run.visual_used; i++) { // // Skip zero-width spaces. Change later to allow optional // control of displaying these characters in the string. // if (run.visual[i] == 0x200b || run.visual[i] == 0xfeff) continue; if (run.visual[i] <= 0x1f && run.visual[i] != 0x9) // // Change the C0 control characters to their pictures and // assume that the other control characters have a glyph. // run.visual[i] += 0x2400; gm = font.glyphMetrics(run.visual[i]); if (run.nonspacing[i]) { cw = wd - font.getCharSpacing(); // // Position the non-spacing depending on the positioning // table above. This provides a rough estimate as to // where the glyph is supposed to go. // pos = nonSpacingPosition(run.visual[i]); // // Do the horizontal positioning. // if ((pos & LEFT) != 0) { run.offsets[run.offsets_used] = (short) -(cw + ((gm.rightSideBearing - gm.leftSideBearing)>>1)); flags = (gm.rightSideBearing - gm.leftSideBearing)>> 1; if (-flags < lsb) lsb = -(flags + 1); } else if ((pos & CENTER) != 0) { run.offsets[run.offsets_used] = (short) -((cw >> 1) + ((gm.rightSideBearing - gm.leftSideBearing)>>1)); if (gm.rightSideBearing > rsb) rsb = gm.rightSideBearing; if (gm.leftSideBearing < lsb) lsb = gm.leftSideBearing; } else if ((pos & RIGHT) != 0) { run.offsets[run.offsets_used] = (short) -((gm.rightSideBearing - gm.leftSideBearing) >> 1); flags = (gm.rightSideBearing - gm.leftSideBearing)>> 1; if (flags == 0) flags = gm.rightSideBearing - gm.leftSideBearing; if (cw + flags > rsb) rsb = cw + flags + 1; } else if ((pos & DOUBLE) != 0) { run.offsets[run.offsets_used] = (short) -((cw >> 1) + gm.leftSideBearing); flags = (cw >> 1) + gm.leftSideBearing; if (flags > rsb) rsb = flags + 1; } // // Do the vertical positioning. // if ((pos & TOP) != 0) { run.offsets[run.offsets_used + 1] = (short) (as + gm.ascent + gm.descent + 1); as += gm.ascent + gm.descent + 1; } else if ((pos & BOTTOM) != 0) { run.offsets[run.offsets_used + 1] = (short) -(ds + 1); ds += gm.ascent + gm.descent + 1; } else if ((pos & CENTER) != 0) { run.offsets[run.offsets_used + 1] = (short) ((as + ds) >> 1); } run.offsets_used += 2; } else { if (as > metrics.ascent) metrics.ascent = as; if (ds > metrics.descent) metrics.descent = ds; if (metrics.characterWidth + lsb < metrics.leftSideBearing) metrics.leftSideBearing = metrics.characterWidth + lsb; if (metrics.characterWidth+rsb > metrics.rightSideBearing) metrics.rightSideBearing = metrics.characterWidth + rsb; metrics.characterWidth += wd; if (wd > 0) metrics.characterWidth += font.getCharSpacing(); if (run.visual[i] == 0x0009) { // // Change this later to calculate based on preceding // tab stops. // rsb = wd = 10; lsb = as = ds = 0; } else { rsb = gm.rightSideBearing; lsb = gm.leftSideBearing; wd = gm.characterWidth; as = gm.ascent; ds = gm.descent; // // Take care of spaces kept as metrics only and do not // have a bitmap. // if (wd > 0 && rsb == 0) rsb = wd; } // // This marks the beginning and ending positions of the // glyph for purposes of cursor motion. // run.offsets[run.offsets_used++] = (short) metrics.characterWidth; run.offsets[run.offsets_used++] = (short) (metrics.characterWidth + wd); } } // // // Capture the last spacing glyph seen. // if (as > metrics.ascent) metrics.ascent = as; if (ds > metrics.descent) metrics.descent = ds; if (metrics.characterWidth + lsb < metrics.leftSideBearing) metrics.leftSideBearing = metrics.characterWidth + lsb; if (metrics.characterWidth + rsb > metrics.rightSideBearing) metrics.rightSideBearing = metrics.characterWidth + rsb; metrics.characterWidth += wd; } } }