| /* |
| * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package sun.font; |
| |
| import java.awt.FontFormatException; |
| import java.awt.font.FontRenderContext; |
| import java.awt.geom.GeneralPath; |
| import java.awt.geom.Rectangle2D; |
| import java.util.HashMap; |
| import java.util.Locale; |
| import java.nio.charset.*; |
| import java.nio.CharBuffer; |
| import java.nio.ByteBuffer; |
| |
| class XMap { |
| |
| private static HashMap xMappers = new HashMap(); |
| |
| /* ConvertedGlyphs has unicode code points as indexes and values |
| * are platform-encoded multi-bytes chars packed into java chars. |
| * These platform-encoded characters are equated to glyph ids, although |
| * that's not strictly true, as X11 only supports using chars. |
| * The assumption carried over from the native implementation that |
| * a char is big enough to hold an X11 glyph id (ie platform char). |
| */ |
| char[] convertedGlyphs; |
| |
| static synchronized XMap getXMapper(String encoding) { |
| XMap mapper = (XMap)xMappers.get(encoding); |
| if (mapper == null) { |
| mapper = getXMapperInternal(encoding); |
| xMappers.put(encoding, mapper); |
| } |
| return mapper; |
| } |
| |
| static final int SINGLE_BYTE = 1; |
| static final int DOUBLE_BYTE = 2; |
| |
| private static XMap getXMapperInternal(String encoding) { |
| |
| String jclass = null; |
| int nBytes = SINGLE_BYTE; |
| int maxU = 0xffff; |
| int minU = 0; |
| boolean addAscii = false; |
| boolean lowPartOnly = false; |
| if (encoding.equals("dingbats")) { |
| jclass = "sun.awt.motif.X11Dingbats"; |
| minU = 0x2701; |
| maxU = 0x27be; |
| } else if (encoding.equals("symbol")){ |
| jclass = "sun.awt.Symbol"; |
| minU = 0x0391; |
| maxU = 0x22ef; |
| } else if (encoding.equals("iso8859-1")) { |
| maxU = 0xff; |
| } else if (encoding.equals("iso8859-2")) { |
| jclass = "ISO8859_2"; |
| } else if (encoding.equals("jisx0208.1983-0")) { |
| jclass = "sun.awt.motif.X11JIS0208"; |
| nBytes = DOUBLE_BYTE; |
| } else if (encoding.equals("jisx0201.1976-0")) { |
| jclass = "sun.awt.motif.X11JIS0201"; |
| // this is mapping the latin supplement range 128->255 which |
| // doesn't exist in JIS0201. This needs examination. |
| // it was also overwriting a couple of the mappings of |
| // 7E and A5 which in JIS201 are different chars than in |
| // Latin 1. I have revised AddAscii to not overwrite chars |
| // which are already converted. |
| addAscii = true; |
| lowPartOnly = true; |
| } else if (encoding.equals("jisx0212.1990-0")) { |
| jclass = "sun.awt.motif.X11JIS0212"; |
| nBytes = DOUBLE_BYTE; |
| } else if (encoding.equals("iso8859-4")) { |
| jclass = "ISO8859_4"; |
| } else if (encoding.equals("iso8859-5")) { |
| jclass = "ISO8859_5"; |
| } else if (encoding.equals("koi8-r")) { |
| jclass = "KOI8_R"; |
| } else if (encoding.equals("ansi-1251")) { |
| jclass = "windows-1251"; |
| } else if (encoding.equals("iso8859-6")) { |
| jclass = "ISO8859_6"; |
| } else if (encoding.equals("iso8859-7")) { |
| jclass = "ISO8859_7"; |
| } else if (encoding.equals("iso8859-8")) { |
| jclass = "ISO8859_8"; |
| } else if (encoding.equals("iso8859-9")) { |
| jclass = "ISO8859_9"; |
| } else if (encoding.equals("iso8859-13")) { |
| jclass = "ISO8859_13"; |
| } else if (encoding.equals("iso8859-15")) { |
| jclass = "ISO8859_15"; |
| } else if (encoding.equals("ksc5601.1987-0")) { |
| jclass ="sun.awt.motif.X11KSC5601"; |
| nBytes = DOUBLE_BYTE; |
| } else if (encoding.equals( "ksc5601.1992-3")) { |
| jclass ="sun.awt.motif.X11Johab"; |
| nBytes = DOUBLE_BYTE; |
| } else if (encoding.equals( "ksc5601.1987-1")) { |
| jclass ="EUC_KR"; |
| nBytes = DOUBLE_BYTE; |
| } else if (encoding.equals( "cns11643-1")) { |
| jclass = "sun.awt.motif.X11CNS11643P1"; |
| nBytes = DOUBLE_BYTE; |
| } else if (encoding.equals("cns11643-2")) { |
| jclass = "sun.awt.motif.X11CNS11643P2"; |
| nBytes = DOUBLE_BYTE; |
| } else if (encoding.equals("cns11643-3")) { |
| jclass = "sun.awt.motif.X11CNS11643P3"; |
| nBytes = DOUBLE_BYTE; |
| } else if (encoding.equals("gb2312.1980-0")) { |
| jclass = "sun.awt.motif.X11GB2312"; |
| nBytes = DOUBLE_BYTE; |
| } else if (encoding.indexOf("big5") >= 0) { |
| jclass = "Big5"; |
| nBytes = DOUBLE_BYTE; |
| addAscii = true; |
| } else if (encoding.equals("tis620.2533-0")) { |
| jclass = "TIS620"; |
| } else if (encoding.equals("gbk-0")) { |
| jclass = "sun.awt.motif.X11GBK"; |
| nBytes = DOUBLE_BYTE; |
| } else if (encoding.indexOf("sun.unicode-0") >= 0) { |
| jclass = "sun.awt.motif.X11SunUnicode_0"; |
| nBytes = DOUBLE_BYTE; |
| } else if (encoding.indexOf("gb18030.2000-1") >= 0) { |
| jclass = "sun.awt.motif.X11GB18030_1"; |
| nBytes = DOUBLE_BYTE; |
| } else if (encoding.indexOf( "gb18030.2000-0") >= 0) { |
| jclass = "sun.awt.motif.X11GB18030_0"; |
| nBytes = DOUBLE_BYTE; |
| } else if (encoding.indexOf("hkscs") >= 0) { |
| jclass = "sun.awt.HKSCS"; |
| nBytes = DOUBLE_BYTE; |
| } |
| return new XMap(jclass, minU, maxU, nBytes, addAscii, lowPartOnly); |
| } |
| |
| private static final char SURR_MIN = '\uD800'; |
| private static final char SURR_MAX = '\uDFFF'; |
| |
| private XMap(String className, int minU, int maxU, int nBytes, |
| boolean addAscii, boolean lowPartOnly) { |
| |
| CharsetEncoder enc = null; |
| if (className != null) { |
| try { |
| if (className.startsWith("sun.awt")) { |
| enc = ((Charset)Class.forName(className).newInstance()).newEncoder(); |
| } else { |
| enc = Charset.forName(className).newEncoder(); |
| } |
| } catch (Exception x) {x.printStackTrace();} |
| } |
| if (enc == null) { |
| convertedGlyphs = new char[256]; |
| for (int i=0; i<256; i++) { |
| convertedGlyphs[i] = (char)i; |
| } |
| return; |
| } else { |
| /* chars is set to the unicode values to convert, |
| * bytes is where the X11 character codes will be output. |
| * Finally we pack the byte pairs into chars. |
| */ |
| int count = maxU - minU + 1; |
| byte[] bytes = new byte[count*nBytes]; |
| char[] chars = new char[count]; |
| for (int i=0; i<count; i++) { |
| chars[i] = (char)(minU+i); |
| } |
| int startCharIndex = 0; |
| /* For multi-byte encodings, single byte chars should be skipped */ |
| if (nBytes > SINGLE_BYTE && minU < 256) { |
| startCharIndex = 256-minU; |
| } |
| byte[] rbytes = new byte[nBytes]; |
| try { |
| int cbLen = 0; |
| int bbLen = 0; |
| // Since we dont support surrogates in any X11 encoding, skip |
| // the surrogate area, otherwise the sequence of "Oxdbff0xdc00" |
| // will accidently cause the surrogate-aware nio charset to treat |
| // them as a legal pair and then undesirablly skip 2 "chars" |
| // for one "unmappable character" |
| if (startCharIndex < SURR_MIN && startCharIndex + count >SURR_MAX) { |
| cbLen = SURR_MIN - startCharIndex; |
| bbLen = cbLen * nBytes; |
| enc.onMalformedInput(CodingErrorAction.REPLACE) |
| .onUnmappableCharacter(CodingErrorAction.REPLACE) |
| .replaceWith(rbytes) |
| .encode(CharBuffer.wrap(chars, startCharIndex, cbLen), |
| ByteBuffer.wrap(bytes, startCharIndex * nBytes, bbLen), |
| true); |
| startCharIndex = SURR_MAX + 1; |
| } |
| cbLen = count - startCharIndex; |
| bbLen = cbLen * nBytes; |
| enc.onMalformedInput(CodingErrorAction.REPLACE) |
| .onUnmappableCharacter(CodingErrorAction.REPLACE) |
| .replaceWith(rbytes) |
| .encode(CharBuffer.wrap(chars, startCharIndex, cbLen), |
| ByteBuffer.wrap(bytes, startCharIndex * nBytes, bbLen), |
| true); |
| } catch (Exception e) { e.printStackTrace();} |
| |
| convertedGlyphs = new char[65536]; |
| for (int i=0; i<count; i++) { |
| if (nBytes == 1) { |
| convertedGlyphs[i+minU] = (char)(bytes[i]&0xff); |
| } else { |
| convertedGlyphs[i+minU] = |
| (char)(((bytes[i*2]&0xff) << 8) + (bytes[i*2+1]&0xff)); |
| } |
| } |
| } |
| |
| int max = (lowPartOnly) ? 128 : 256; |
| if (addAscii && convertedGlyphs.length >= 256) { |
| for (int i=0;i<max;i++) { |
| if (convertedGlyphs[i] == 0) { |
| convertedGlyphs[i] = (char)i; |
| } |
| } |
| } |
| } |
| } |