001: /*
002: * Copyright 2002 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.inputmethods.internal.thaiim;
027:
028: import java.awt.im.InputMethodRequests;
029:
030: public class ThaiRules {
031:
032: public static final char BASE = 0x0e00;
033:
034: public static final byte NON = 0;
035: public static final byte CONS = 1;
036: public static final byte LV = 2;
037: public static final byte FV1 = 3;
038: public static final byte FV2 = 4;
039: public static final byte FV3 = 5;
040: public static final byte FV4 = 6;
041: /* Note that FV4 is added. It is not in WTT.
042: * We need it for SARA AM since it has a
043: * weired characteristic to share the same
044: * cell with whatever consonant preceeds it.
045: */
046: public static final byte BV1 = 7;
047: public static final byte BV2 = 8;
048: public static final byte BD = 9;
049: public static final byte TONE = 10;
050: public static final byte AD1 = 11;
051: public static final byte AD2 = 12;
052: public static final byte AD3 = 13;
053: public static final byte AV1 = 14;
054: public static final byte AV2 = 15;
055: public static final byte AV3 = 16;
056:
057: /**
058: * Constants for validity checking and auto correction
059: */
060: public static final byte STRICT = 0;
061: public static final byte LOOSE = 1;
062: public static final byte NOREPLACE = 2;
063:
064: public static final byte[] CHARTYPE = {
065: /* 0e00 UNUSED */NON,
066: /* THAI CHARACTER KO KAI */CONS,
067: /* THAI CHARACTER KHO KHAI */CONS,
068: /* THAI CHARACTER KHO KHUAT */CONS,
069: /* THAI CHARACTER KHO KHWAI */CONS,
070: /* THAI CHARACTER KHO KHON */CONS,
071: /* THAI CHARACTER KHO RAKHANG */CONS,
072: /* THAI CHARACTER NGO NGU */CONS,
073: /* THAI CHARACTER CHO CHAN */CONS,
074: /* THAI CHARACTER CHO CHING */CONS,
075: /* THAI CHARACTER CHO CHANG */CONS,
076: /* THAI CHARACTER SO SO */CONS,
077: /* THAI CHARACTER CHO CHOE */CONS,
078: /* THAI CHARACTER YO YING */CONS,
079: /* THAI CHARACTER DO CHADA */CONS,
080: /* THAI CHARACTER TO PATAK */CONS,
081: /* THAI CHARACTER THO THAN */CONS,
082: /* THAI CHARACTER THO NANGMONTHO */CONS,
083: /* THAI CHARACTER THO PHUTHAO */CONS,
084: /* THAI CHARACTER NO NEN */CONS,
085: /* THAI CHARACTER DO DEK */CONS,
086: /* THAI CHARACTER TO TAO */CONS,
087: /* THAI CHARACTER THO THUNG */CONS,
088: /* THAI CHARACTER THO THAHAN */CONS,
089: /* THAI CHARACTER THO THONG */CONS,
090: /* THAI CHARACTER NO NU */CONS,
091: /* THAI CHARACTER BO BAIMAI */CONS,
092: /* THAI CHARACTER PO PLA */CONS,
093: /* THAI CHARACTER PHO PHUNG */CONS,
094: /* THAI CHARACTER FO FA */CONS,
095: /* THAI CHARACTER PHO PHAN */CONS,
096: /* THAI CHARACTER FO FAN */CONS,
097: /* THAI CHARACTER PHO SAMPHAO */CONS,
098: /* THAI CHARACTER MO MA */CONS,
099: /* THAI CHARACTER YO YAK */CONS,
100: /* THAI CHARACTER RO RUA */CONS,
101: /* THAI CHARACTER RU */FV3,
102: /* THAI CHARACTER LO LING */CONS,
103: /* THAI CHARACTER LU */FV3,
104: /* THAI CHARACTER WO WAEN */CONS,
105: /* THAI CHARACTER SO SALA */CONS,
106: /* THAI CHARACTER SO RUSI */CONS,
107: /* THAI CHARACTER SO SUA */CONS,
108: /* THAI CHARACTER HO HIP */CONS,
109: /* THAI CHARACTER LO CHULA */CONS,
110: /* THAI CHARACTER O ANG */CONS,
111: /* THAI CHARACTER HO NOKHUK */CONS,
112: /* THAI CHARACTER PAIYANNOI */NON,
113: /* THAI CHARACTER SARA A */FV1,
114: /* THAI CHARACTER MAI HAN-AKAT */AV2,
115: /* THAI CHARACTER SARA AA */FV1,
116: /* THAI CHARACTER SARA AM */FV4,
117: /* THAI CHARACTER SARA I */AV1,
118: /* THAI CHARACTER SARA II */AV3,
119: /* THAI CHARACTER SARA UE */AV2,
120: /* THAI CHARACTER SARA UEE */AV3,
121: /* THAI CHARACTER SARA U */BV1,
122: /* THAI CHARACTER SARA UU */BV2,
123: /* THAI CHARACTER PHINTHU */BD,
124: /* 0e3b UNUSED */NON,
125: /* 0e3c UNUSED */NON,
126: /* 0e3d UNUSED */NON,
127: /* 0e3e UNUSED */NON,
128: /* THAI CURRENCY SYMBOL BAHT */NON,
129: /* THAI CHARACTER SARA E */LV,
130: /* THAI CHARACTER SARA AE */LV,
131: /* THAI CHARACTER SARA O */LV,
132: /* THAI CHARACTER SARA AI MAIMUAN */LV,
133: /* THAI CHARACTER SARA AI MAIMALAI */LV,
134: /* THAI CHARACTER LAKKHANGYAO */FV2,
135: /* THAI CHARACTER MAIYAMOK */NON,
136: /* THAI CHARACTER MAITAIKHU */AD2,
137: /* THAI CHARACTER MAI EK */TONE,
138: /* THAI CHARACTER MAI THO */TONE,
139: /* THAI CHARACTER MAI TRI */TONE,
140: /* THAI CHARACTER MAI CHATTAWA */TONE,
141: /* THAI CHARACTER THANTHAKHAT */AD1,
142: /* THAI CHARACTER NIKHAHIT */AD3,
143: /* THAI CHARACTER YAMAKKAN */AD3,
144: /* THAI CHARACTER FONGMAN */NON,
145: /* THAI DIGIT ZERO */NON,
146: /* THAI DIGIT ONE */NON,
147: /* THAI DIGIT TWO */NON,
148: /* THAI DIGIT THREE */NON,
149: /* THAI DIGIT FOUR */NON,
150: /* THAI DIGIT FIVE */NON,
151: /* THAI DIGIT SIX */NON,
152: /* THAI DIGIT SEVEN */NON,
153: /* THAI DIGIT EIGHT */NON,
154: /* THAI DIGIT NINE */NON,
155: /* THAI CHARACTER ANGKHANKHU */NON,
156: /* THAI CHARACTER KHOMUT */NON };
157:
158: private InputMethodRequests requests;
159:
160: ThaiRules(InputMethodRequests requests) {
161: this .requests = requests;
162: }
163:
164: public static byte getCharType(char c) {
165: byte cType;
166: int ci = ((int) c) - (int) BASE;
167: if (ci < 0 || ci >= CHARTYPE.length)
168: cType = NON;
169: else
170: cType = CHARTYPE[ci];
171: return cType;
172: }
173:
174: private static boolean isValid(char c1, char c2, int[] validityArray) {
175: return ((validityArray[getCharType(c1)] & (1 << getCharType(c2))) != 0);
176: }
177:
178: /**
179: * VALIDITY is a bit matrix defining whether one
180: * character is allowed to be typed in after the
181: * previous one (array index). Determining the
182: * validity is done by bit-anding the 2nd char
183: * type's mask (obtained by 1 << chartype) with
184: * the array element indexed by the first char
185: * type. If the result is non-zero, the 2nd
186: * character is allowed to follow the first.
187: */
188:
189: /* Please note that the bits in the comment below
190: * are displayed least significant bit first.
191: * The actual value reflexs this representation
192: * when the bits are swapped.
193: */
194:
195: private static final int[] INPUTVALIDITY = {
196: /* NON 1110 010 0 0000 0000 0 */0x00027,
197: /* CONS 1111 111 1 1111 1111 1 */0x1ffff,
198: /* LV 0100 000 0 0000 0000 0 */0x00002,
199: /* FV1 1110 010 0 0000 0000 0 */0x00027,
200: /* FV2 1110 010 0 0000 0000 0 */0x00027,
201: /* FV3 1110 110 0 0000 0000 0 */0x00037,
202: /* FV4 1110 010 0 0000 0000 0 */0x00027,
203: /* BV1 1110 010 0 0011 0000 0 */0x00c27,
204: /* BV2 1110 010 0 0010 0000 0 */0x00427,
205: /* BD 1110 010 0 0000 0000 0 */0x00027,
206: /* TONE 1111 011 0 0000 0000 0 */0x0006f,
207: /* AD1 1110 010 0 0000 0000 0 */0x00027,
208: /* AD2 1110 010 0 0000 0000 0 */0x00027,
209: /* AD3 1110 010 0 0000 0000 0 */0x00027,
210: /* AV1 1110 010 0 0011 0000 0 */0x00c27,
211: /* AV2 1110 010 0 0010 0000 0 */0x00427,
212: /* AV3 1110 010 0 0010 0100 0 */0x02427 };
213:
214: private static final int[] COMPOSABLE = {
215: /* NON 0000 000 0 0000 0000 0 */0x00000,
216: /* CONS 0000 001 1 1111 1111 1 */0x1ffc0,
217: /* LV 0000 000 0 0000 0000 0 */0x00000,
218: /* FV1 0000 000 0 0000 0000 0 */0x00000,
219: /* FV2 0000 000 0 0000 0000 0 */0x00000,
220: /* FV3 0000 000 0 0000 0000 0 */0x00000,
221: /* FV4 0000 000 0 0000 0000 0 */0x00000,
222: /* BV1 0000 000 0 0011 0000 0 */0x00c00,
223: /* BV2 0000 000 0 0010 0000 0 */0x00400,
224: /* BD 0000 000 0 0000 0000 0 */0x00000,
225: /* TONE 0000 001 0 0000 0000 0 */0x00040,
226: /* AD1 0000 000 0 0000 0000 0 */0x00000,
227: /* AD2 0000 000 0 0000 0000 0 */0x00000,
228: /* AD3 0000 000 0 0000 0000 0 */0x00000,
229: /* AV1 0000 000 0 0011 0000 0 */0x00c00,
230: /* AV2 0000 000 0 0010 0000 0 */0x00400,
231: /* AV3 0000 000 0 0010 0100 0 */0x02400 };
232:
233: private static final int[] REPLACABLE = {
234: /* NON 0000 000 0 0000 0000 0 */0x00000,
235: /* CONS 0000 000 0 0000 0000 0 */0x00000,
236: /* LV 0000 000 0 0000 0000 0 */0x00000,
237: /* FV1 0000 000 0 0000 0000 0 */0x00000,
238: /* FV2 0000 000 0 0000 0000 0 */0x00000,
239: /* FV3 0000 000 0 0000 0000 0 */0x00000,
240: /* FV4 0000 001 1 1001 1111 1 */0x1f9c0,
241: /* BV1 0000 001 1 1100 1111 1 */0x1f3c0,
242: /* BV2 0000 001 1 1101 1111 1 */0x1fbc0,
243: /* BD 0000 001 1 1111 1111 1 */0x1ffc0,
244: /* TONE 0000 000 0 0111 1100 0 */0x03e00,
245: /* AD1 0000 001 0 1111 1101 1 */0x1bf40,
246: /* AD2 0000 001 1 1111 1111 1 */0x1ffc0,
247: /* AD3 0000 001 1 1111 1111 0 */0x0ffc0,
248: /* AV1 0000 001 1 1100 1111 1 */0x1f3c0,
249: /* AV2 0000 001 1 1101 1111 1 */0x1fbc0,
250: /* AV3 0000 001 1 1101 1011 1 */0x1dbc0 };
251:
252: private static final int[] SWAPPABLE = {
253: /* NON 0000 000 0 0000 0000 0 */0x00000,
254: /* CONS 0000 000 0 0000 0000 0 */0x00000,
255: /* LV 0000 000 0 0000 0000 0 */0x00000,
256: /* FV1 0000 000 0 0000 0000 0 */0x00000,
257: /* FV2 0000 000 0 0000 0000 0 */0x00000,
258: /* FV3 0000 000 0 0000 0000 0 */0x00000,
259: /* FV4 0000 000 0 0010 0000 0 */0x00400,
260: /* BV1 0000 000 0 0000 0000 0 */0x00000,
261: /* BV2 0000 000 0 0000 0000 0 */0x00000,
262: /* BD 0000 000 0 0000 0000 0 */0x00000,
263: /* TONE 0000 000 1 1000 0011 1 */0x1c180,
264: /* AD1 0000 000 1 0000 0010 0 */0x04080,
265: /* AD2 0000 000 0 0000 0000 0 */0x00000,
266: /* AD3 0000 000 0 0000 0000 1 */0x10000,
267: /* AV1 0000 000 0 0000 0000 0 */0x00000,
268: /* AV2 0000 000 0 0000 0000 0 */0x00000,
269: /* AV3 0000 000 0 0000 0000 0 */0x00000 };
270:
271: public static boolean isInputValid(char c1, char c2) {
272: return isValid(c1, c2, INPUTVALIDITY);
273: }
274:
275: public static boolean isComposable(char c1, char c2) {
276: return isValid(c1, c2, COMPOSABLE);
277: }
278:
279: public static boolean isSwappable(char c1, char c2) {
280: return isValid(c1, c2, SWAPPABLE);
281: }
282:
283: public static boolean isReplacable(char c1, char c2) {
284: return isValid(c1, c2, REPLACABLE);
285: }
286:
287: public static boolean isForward(char c) {
288: return (getCharType(c) < FV4);
289: }
290:
291: public static boolean isDead(char c) {
292: return (getCharType(c) > FV3);
293: }
294:
295: public boolean isInputValid(char current) {
296: int offset = requests.getInsertPositionOffset();
297: if (offset == 0) {
298: byte charType = getCharType(current);
299: return ((charType < FV1) || (charType == FV3));
300: } else {
301: char prev = requests.getCommittedText(offset - 1, offset,
302: null).first();
303:
304: if (isForward(current)) {
305: if (isInputValid(prev, current)) {
306: if (getCharType(prev) == TONE
307: && getCharType(current) == FV1) {
308: if (offset == 1) {
309: return true;
310: } else {
311: char pprev = requests.getCommittedText(
312: offset - 2, offset - 1, null)
313: .first();
314: return isInputValid(pprev, current);
315: }
316: } else {
317: return true;
318: }
319: } else if (prev == '\u0e32' && // SARA AA
320: current == '\u0e30') { // SARA A
321: return true;
322: } else if (prev == '\u0e4d' && // NIKAHIT
323: current == '\u0e32') { // SARA AA
324: // Special compose to SARA AM
325: return true;
326: } else {
327: return false;
328: }
329: } else {
330: if (isInputValid(prev, current)) {
331: if (getCharType(prev) == TONE
332: && getCharType(current) == FV4) {
333: return (offset != 1);
334: } else {
335: return true;
336: }
337: } else {
338: return false;
339: }
340: }
341: }
342: }
343: }
|