001: /*
002: * Copyright 2003-2005 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 sun.font;
027:
028: import java.awt.FontFormatException;
029: import java.awt.font.FontRenderContext;
030: import java.awt.geom.GeneralPath;
031: import java.awt.geom.Rectangle2D;
032: import java.util.HashMap;
033: import java.util.Locale;
034: import java.nio.charset.*;
035: import java.nio.CharBuffer;
036: import java.nio.ByteBuffer;
037:
038: class XMap {
039:
040: private static HashMap xMappers = new HashMap();
041:
042: /* ConvertedGlyphs has unicode code points as indexes and values
043: * are platform-encoded multi-bytes chars packed into java chars.
044: * These platform-encoded characters are equated to glyph ids, although
045: * that's not strictly true, as X11 only supports using chars.
046: * The assumption carried over from the native implementation that
047: * a char is big enough to hold an X11 glyph id (ie platform char).
048: */
049: char[] convertedGlyphs;
050:
051: static synchronized XMap getXMapper(String encoding) {
052: XMap mapper = (XMap) xMappers.get(encoding);
053: if (mapper == null) {
054: mapper = getXMapperInternal(encoding);
055: xMappers.put(encoding, mapper);
056: }
057: return mapper;
058: }
059:
060: static final int SINGLE_BYTE = 1;
061: static final int DOUBLE_BYTE = 2;
062:
063: private static XMap getXMapperInternal(String encoding) {
064:
065: String jclass = null;
066: int nBytes = SINGLE_BYTE;
067: int maxU = 0xffff;
068: int minU = 0;
069: boolean addAscii = false;
070: boolean lowPartOnly = false;
071: if (encoding.equals("dingbats")) {
072: jclass = "sun.awt.motif.X11Dingbats";
073: minU = 0x2701;
074: maxU = 0x27be;
075: } else if (encoding.equals("symbol")) {
076: jclass = "sun.awt.Symbol";
077: minU = 0x0391;
078: maxU = 0x22ef;
079: } else if (encoding.equals("iso8859-1")) {
080: maxU = 0xff;
081: } else if (encoding.equals("iso8859-2")) {
082: jclass = "ISO8859_2";
083: } else if (encoding.equals("jisx0208.1983-0")) {
084: jclass = "sun.awt.motif.X11JIS0208";
085: nBytes = DOUBLE_BYTE;
086: } else if (encoding.equals("jisx0201.1976-0")) {
087: jclass = "sun.awt.motif.X11JIS0201";
088: // this is mapping the latin supplement range 128->255 which
089: // doesn't exist in JIS0201. This needs examination.
090: // it was also overwriting a couple of the mappings of
091: // 7E and A5 which in JIS201 are different chars than in
092: // Latin 1. I have revised AddAscii to not overwrite chars
093: // which are already converted.
094: addAscii = true;
095: lowPartOnly = true;
096: } else if (encoding.equals("jisx0212.1990-0")) {
097: jclass = "sun.awt.motif.X11JIS0212";
098: nBytes = DOUBLE_BYTE;
099: } else if (encoding.equals("iso8859-4")) {
100: jclass = "ISO8859_4";
101: } else if (encoding.equals("iso8859-5")) {
102: jclass = "ISO8859_5";
103: } else if (encoding.equals("koi8-r")) {
104: jclass = "KOI8_R";
105: } else if (encoding.equals("ansi-1251")) {
106: jclass = "windows-1251";
107: } else if (encoding.equals("iso8859-6")) {
108: jclass = "ISO8859_6";
109: } else if (encoding.equals("iso8859-7")) {
110: jclass = "ISO8859_7";
111: } else if (encoding.equals("iso8859-8")) {
112: jclass = "ISO8859_8";
113: } else if (encoding.equals("iso8859-9")) {
114: jclass = "ISO8859_9";
115: } else if (encoding.equals("iso8859-13")) {
116: jclass = "ISO8859_13";
117: } else if (encoding.equals("iso8859-15")) {
118: jclass = "ISO8859_15";
119: } else if (encoding.equals("ksc5601.1987-0")) {
120: jclass = "sun.awt.motif.X11KSC5601";
121: nBytes = DOUBLE_BYTE;
122: } else if (encoding.equals("ksc5601.1992-3")) {
123: jclass = "sun.awt.motif.X11Johab";
124: nBytes = DOUBLE_BYTE;
125: } else if (encoding.equals("ksc5601.1987-1")) {
126: jclass = "EUC_KR";
127: nBytes = DOUBLE_BYTE;
128: } else if (encoding.equals("cns11643-1")) {
129: jclass = "sun.awt.motif.X11CNS11643P1";
130: nBytes = DOUBLE_BYTE;
131: } else if (encoding.equals("cns11643-2")) {
132: jclass = "sun.awt.motif.X11CNS11643P2";
133: nBytes = DOUBLE_BYTE;
134: } else if (encoding.equals("cns11643-3")) {
135: jclass = "sun.awt.motif.X11CNS11643P3";
136: nBytes = DOUBLE_BYTE;
137: } else if (encoding.equals("gb2312.1980-0")) {
138: jclass = "sun.awt.motif.X11GB2312";
139: nBytes = DOUBLE_BYTE;
140: } else if (encoding.indexOf("big5") >= 0) {
141: jclass = "Big5";
142: nBytes = DOUBLE_BYTE;
143: addAscii = true;
144: } else if (encoding.equals("tis620.2533-0")) {
145: jclass = "TIS620";
146: } else if (encoding.equals("gbk-0")) {
147: jclass = "sun.awt.motif.X11GBK";
148: nBytes = DOUBLE_BYTE;
149: } else if (encoding.indexOf("sun.unicode-0") >= 0) {
150: jclass = "sun.awt.motif.X11SunUnicode_0";
151: nBytes = DOUBLE_BYTE;
152: } else if (encoding.indexOf("gb18030.2000-1") >= 0) {
153: jclass = "sun.awt.motif.X11GB18030_1";
154: nBytes = DOUBLE_BYTE;
155: } else if (encoding.indexOf("gb18030.2000-0") >= 0) {
156: jclass = "sun.awt.motif.X11GB18030_0";
157: nBytes = DOUBLE_BYTE;
158: } else if (encoding.indexOf("hkscs") >= 0) {
159: jclass = "sun.awt.HKSCS";
160: nBytes = DOUBLE_BYTE;
161: }
162: return new XMap(jclass, minU, maxU, nBytes, addAscii,
163: lowPartOnly);
164: }
165:
166: private static final char SURR_MIN = '\uD800';
167: private static final char SURR_MAX = '\uDFFF';
168:
169: private XMap(String className, int minU, int maxU, int nBytes,
170: boolean addAscii, boolean lowPartOnly) {
171:
172: CharsetEncoder enc = null;
173: if (className != null) {
174: try {
175: if (className.startsWith("sun.awt")) {
176: enc = ((Charset) Class.forName(className)
177: .newInstance()).newEncoder();
178: } else {
179: enc = Charset.forName(className).newEncoder();
180: }
181: } catch (Exception x) {
182: x.printStackTrace();
183: }
184: }
185: if (enc == null) {
186: convertedGlyphs = new char[256];
187: for (int i = 0; i < 256; i++) {
188: convertedGlyphs[i] = (char) i;
189: }
190: return;
191: } else {
192: /* chars is set to the unicode values to convert,
193: * bytes is where the X11 character codes will be output.
194: * Finally we pack the byte pairs into chars.
195: */
196: int count = maxU - minU + 1;
197: byte[] bytes = new byte[count * nBytes];
198: char[] chars = new char[count];
199: for (int i = 0; i < count; i++) {
200: chars[i] = (char) (minU + i);
201: }
202: int startCharIndex = 0;
203: /* For multi-byte encodings, single byte chars should be skipped */
204: if (nBytes > SINGLE_BYTE && minU < 256) {
205: startCharIndex = 256 - minU;
206: }
207: byte[] rbytes = new byte[nBytes];
208: try {
209: int cbLen = 0;
210: int bbLen = 0;
211: // Since we dont support surrogates in any X11 encoding, skip
212: // the surrogate area, otherwise the sequence of "Oxdbff0xdc00"
213: // will accidently cause the surrogate-aware nio charset to treat
214: // them as a legal pair and then undesirablly skip 2 "chars"
215: // for one "unmappable character"
216: if (startCharIndex < SURR_MIN
217: && startCharIndex + count > SURR_MAX) {
218: cbLen = SURR_MIN - startCharIndex;
219: bbLen = cbLen * nBytes;
220: enc.onMalformedInput(CodingErrorAction.REPLACE)
221: .onUnmappableCharacter(
222: CodingErrorAction.REPLACE)
223: .replaceWith(rbytes).encode(
224: CharBuffer.wrap(chars,
225: startCharIndex, cbLen),
226: ByteBuffer.wrap(bytes,
227: startCharIndex * nBytes,
228: bbLen), true);
229: startCharIndex = SURR_MAX + 1;
230: }
231: cbLen = count - startCharIndex;
232: bbLen = cbLen * nBytes;
233: enc.onMalformedInput(CodingErrorAction.REPLACE)
234: .onUnmappableCharacter(
235: CodingErrorAction.REPLACE).replaceWith(
236: rbytes).encode(
237: CharBuffer.wrap(chars, startCharIndex,
238: cbLen),
239: ByteBuffer.wrap(bytes, startCharIndex
240: * nBytes, bbLen), true);
241: } catch (Exception e) {
242: e.printStackTrace();
243: }
244:
245: convertedGlyphs = new char[65536];
246: for (int i = 0; i < count; i++) {
247: if (nBytes == 1) {
248: convertedGlyphs[i + minU] = (char) (bytes[i] & 0xff);
249: } else {
250: convertedGlyphs[i + minU] = (char) (((bytes[i * 2] & 0xff) << 8) + (bytes[i * 2 + 1] & 0xff));
251: }
252: }
253: }
254:
255: int max = (lowPartOnly) ? 128 : 256;
256: if (addAscii && convertedGlyphs.length >= 256) {
257: for (int i = 0; i < max; i++) {
258: if (convertedGlyphs[i] == 0) {
259: convertedGlyphs[i] = (char) i;
260: }
261: }
262: }
263: }
264: }
|