blob: 80da2a93fe656a5933150d661d678f32cf30b427 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2003-2005 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.font;
27
28import java.awt.FontFormatException;
29import java.awt.font.FontRenderContext;
30import java.awt.geom.GeneralPath;
31import java.awt.geom.Rectangle2D;
32import java.util.HashMap;
33import java.util.Locale;
34import java.nio.charset.*;
35import java.nio.CharBuffer;
36import java.nio.ByteBuffer;
37
38class XMap {
39
40 private static HashMap xMappers = new HashMap();
41
42 /* ConvertedGlyphs has unicode code points as indexes and values
43 * are platform-encoded multi-bytes chars packed into java chars.
44 * These platform-encoded characters are equated to glyph ids, although
45 * that's not strictly true, as X11 only supports using chars.
46 * The assumption carried over from the native implementation that
47 * a char is big enough to hold an X11 glyph id (ie platform char).
48 */
49 char[] convertedGlyphs;
50
51 static synchronized XMap getXMapper(String encoding) {
52 XMap mapper = (XMap)xMappers.get(encoding);
53 if (mapper == null) {
54 mapper = getXMapperInternal(encoding);
55 xMappers.put(encoding, mapper);
56 }
57 return mapper;
58 }
59
60 static final int SINGLE_BYTE = 1;
61 static final int DOUBLE_BYTE = 2;
62
63 private static XMap getXMapperInternal(String encoding) {
64
65 String jclass = null;
66 int nBytes = SINGLE_BYTE;
67 int maxU = 0xffff;
68 int minU = 0;
69 boolean addAscii = false;
70 boolean lowPartOnly = false;
71 if (encoding.equals("dingbats")) {
72 jclass = "sun.awt.motif.X11Dingbats";
73 minU = 0x2701;
74 maxU = 0x27be;
75 } else if (encoding.equals("symbol")){
76 jclass = "sun.awt.Symbol";
77 minU = 0x0391;
78 maxU = 0x22ef;
79 } else if (encoding.equals("iso8859-1")) {
80 maxU = 0xff;
81 } else if (encoding.equals("iso8859-2")) {
82 jclass = "ISO8859_2";
83 } else if (encoding.equals("jisx0208.1983-0")) {
84 jclass = "sun.awt.motif.X11JIS0208";
85 nBytes = DOUBLE_BYTE;
86 } else if (encoding.equals("jisx0201.1976-0")) {
87 jclass = "sun.awt.motif.X11JIS0201";
88 // this is mapping the latin supplement range 128->255 which
89 // doesn't exist in JIS0201. This needs examination.
90 // it was also overwriting a couple of the mappings of
91 // 7E and A5 which in JIS201 are different chars than in
92 // Latin 1. I have revised AddAscii to not overwrite chars
93 // which are already converted.
94 addAscii = true;
95 lowPartOnly = true;
96 } else if (encoding.equals("jisx0212.1990-0")) {
97 jclass = "sun.awt.motif.X11JIS0212";
98 nBytes = DOUBLE_BYTE;
99 } 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, lowPartOnly);
163 }
164
165 private static final char SURR_MIN = '\uD800';
166 private static final char SURR_MAX = '\uDFFF';
167
168 private XMap(String className, int minU, int maxU, int nBytes,
169 boolean addAscii, boolean lowPartOnly) {
170
171 CharsetEncoder enc = null;
172 if (className != null) {
173 try {
174 if (className.startsWith("sun.awt")) {
175 enc = ((Charset)Class.forName(className).newInstance()).newEncoder();
176 } else {
177 enc = Charset.forName(className).newEncoder();
178 }
179 } catch (Exception x) {x.printStackTrace();}
180 }
181 if (enc == null) {
182 convertedGlyphs = new char[256];
183 for (int i=0; i<256; i++) {
184 convertedGlyphs[i] = (char)i;
185 }
186 return;
187 } else {
188 /* chars is set to the unicode values to convert,
189 * bytes is where the X11 character codes will be output.
190 * Finally we pack the byte pairs into chars.
191 */
192 int count = maxU - minU + 1;
193 byte[] bytes = new byte[count*nBytes];
194 char[] chars = new char[count];
195 for (int i=0; i<count; i++) {
196 chars[i] = (char)(minU+i);
197 }
198 int startCharIndex = 0;
199 /* For multi-byte encodings, single byte chars should be skipped */
200 if (nBytes > SINGLE_BYTE && minU < 256) {
201 startCharIndex = 256-minU;
202 }
203 byte[] rbytes = new byte[nBytes];
204 try {
205 int cbLen = 0;
206 int bbLen = 0;
207 // Since we dont support surrogates in any X11 encoding, skip
208 // the surrogate area, otherwise the sequence of "Oxdbff0xdc00"
209 // will accidently cause the surrogate-aware nio charset to treat
210 // them as a legal pair and then undesirablly skip 2 "chars"
211 // for one "unmappable character"
212 if (startCharIndex < SURR_MIN && startCharIndex + count >SURR_MAX) {
213 cbLen = SURR_MIN - startCharIndex;
214 bbLen = cbLen * nBytes;
215 enc.onMalformedInput(CodingErrorAction.REPLACE)
216 .onUnmappableCharacter(CodingErrorAction.REPLACE)
217 .replaceWith(rbytes)
218 .encode(CharBuffer.wrap(chars, startCharIndex, cbLen),
219 ByteBuffer.wrap(bytes, startCharIndex * nBytes, bbLen),
220 true);
221 startCharIndex = SURR_MAX + 1;
222 }
223 cbLen = count - startCharIndex;
224 bbLen = cbLen * nBytes;
225 enc.onMalformedInput(CodingErrorAction.REPLACE)
226 .onUnmappableCharacter(CodingErrorAction.REPLACE)
227 .replaceWith(rbytes)
228 .encode(CharBuffer.wrap(chars, startCharIndex, cbLen),
229 ByteBuffer.wrap(bytes, startCharIndex * nBytes, bbLen),
230 true);
231 } catch (Exception e) { e.printStackTrace();}
232
233 convertedGlyphs = new char[65536];
234 for (int i=0; i<count; i++) {
235 if (nBytes == 1) {
236 convertedGlyphs[i+minU] = (char)(bytes[i]&0xff);
237 } else {
238 convertedGlyphs[i+minU] =
239 (char)(((bytes[i*2]&0xff) << 8) + (bytes[i*2+1]&0xff));
240 }
241 }
242 }
243
244 int max = (lowPartOnly) ? 128 : 256;
245 if (addAscii && convertedGlyphs.length >= 256) {
246 for (int i=0;i<max;i++) {
247 if (convertedGlyphs[i] == 0) {
248 convertedGlyphs[i] = (char)i;
249 }
250 }
251 }
252 }
253}