1 /* 2 * Copyright (c) 2003, 2014, Oracle and/or its affiliates. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.font; 27 28 import java.awt.FontFormatException; 29 import java.awt.font.FontRenderContext; 30 import java.awt.geom.GeneralPath; 31 import java.awt.geom.Rectangle2D; 32 import java.util.HashMap; 33 import java.util.Locale; 34 import java.nio.charset.*; 35 import java.nio.CharBuffer; 36 import java.nio.ByteBuffer; 37 38 class XMap { 39 40 private static HashMap<String, XMap> 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 getXMapper(String encoding)51 static synchronized XMap getXMapper(String encoding) { 52 XMap mapper = 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 getXMapperInternal(String encoding)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.font.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 = "JIS0208"; 85 nBytes = DOUBLE_BYTE; 86 } else if (encoding.equals("jisx0201.1976-0")) { 87 jclass = "JIS0201"; 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 = "JIS0212"; 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.font.X11KSC5601"; 121 nBytes = DOUBLE_BYTE; 122 } else if (encoding.equals( "ksc5601.1992-3")) { 123 jclass ="sun.font.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.font.X11CNS11643P1"; 130 nBytes = DOUBLE_BYTE; 131 } else if (encoding.equals("cns11643-2")) { 132 jclass = "sun.font.X11CNS11643P2"; 133 nBytes = DOUBLE_BYTE; 134 } else if (encoding.equals("cns11643-3")) { 135 jclass = "sun.font.X11CNS11643P3"; 136 nBytes = DOUBLE_BYTE; 137 } else if (encoding.equals("gb2312.1980-0")) { 138 jclass = "sun.font.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.font.X11GBK"; 148 nBytes = DOUBLE_BYTE; 149 } else if (encoding.indexOf("sun.unicode-0") >= 0) { 150 jclass = "sun.font.X11SunUnicode_0"; 151 nBytes = DOUBLE_BYTE; 152 } else if (encoding.indexOf("gb18030.2000-1") >= 0) { 153 jclass = "sun.font.X11GB18030_1"; 154 nBytes = DOUBLE_BYTE; 155 } else if (encoding.indexOf( "gb18030.2000-0") >= 0) { 156 jclass = "sun.font.X11GB18030_0"; 157 nBytes = DOUBLE_BYTE; 158 } else if (encoding.indexOf("hkscs") >= 0) { 159 jclass = "MS950_HKSCS_XP"; 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 XMap(String className, int minU, int maxU, int nBytes, boolean addAscii, boolean lowPartOnly)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).getDeclaredConstructor(). 176 newInstance()).newEncoder(); 177 } else { 178 enc = Charset.forName(className).newEncoder(); 179 } 180 } catch (Exception x) {x.printStackTrace();} 181 } 182 if (enc == null) { 183 convertedGlyphs = new char[256]; 184 for (int i=0; i<256; i++) { 185 convertedGlyphs[i] = (char)i; 186 } 187 return; 188 } else { 189 /* chars is set to the unicode values to convert, 190 * bytes is where the X11 character codes will be output. 191 * Finally we pack the byte pairs into chars. 192 */ 193 int count = maxU - minU + 1; 194 byte[] bytes = new byte[count*nBytes]; 195 char[] chars = new char[count]; 196 for (int i=0; i<count; i++) { 197 chars[i] = (char)(minU+i); 198 } 199 int startCharIndex = 0; 200 /* For multi-byte encodings, single byte chars should be skipped */ 201 if (nBytes > SINGLE_BYTE && minU < 256) { 202 startCharIndex = 256-minU; 203 } 204 byte[] rbytes = new byte[nBytes]; 205 try { 206 int cbLen = 0; 207 int bbLen = 0; 208 // Since we don't support surrogates in any X11 encoding, skip 209 // the surrogate area, otherwise the sequence of "Oxdbff0xdc00" 210 // will accidently cause the surrogate-aware nio charset to treat 211 // them as a legal pair and then undesirablly skip 2 "chars" 212 // for one "unmappable character" 213 if (startCharIndex < SURR_MIN && startCharIndex + count >SURR_MAX) { 214 cbLen = SURR_MIN - startCharIndex; 215 bbLen = cbLen * nBytes; 216 enc.onMalformedInput(CodingErrorAction.REPLACE) 217 .onUnmappableCharacter(CodingErrorAction.REPLACE) 218 .replaceWith(rbytes) 219 .encode(CharBuffer.wrap(chars, startCharIndex, cbLen), 220 ByteBuffer.wrap(bytes, startCharIndex * nBytes, bbLen), 221 true); 222 startCharIndex = SURR_MAX + 1; 223 } 224 cbLen = count - startCharIndex; 225 bbLen = cbLen * nBytes; 226 enc.onMalformedInput(CodingErrorAction.REPLACE) 227 .onUnmappableCharacter(CodingErrorAction.REPLACE) 228 .replaceWith(rbytes) 229 .encode(CharBuffer.wrap(chars, startCharIndex, cbLen), 230 ByteBuffer.wrap(bytes, startCharIndex * nBytes, bbLen), 231 true); 232 } catch (Exception e) { e.printStackTrace();} 233 234 convertedGlyphs = new char[65536]; 235 for (int i=0; i<count; i++) { 236 if (nBytes == 1) { 237 convertedGlyphs[i+minU] = (char)(bytes[i]&0xff); 238 } else { 239 convertedGlyphs[i+minU] = 240 (char)(((bytes[i*2]&0xff) << 8) + (bytes[i*2+1]&0xff)); 241 } 242 } 243 } 244 245 int max = (lowPartOnly) ? 128 : 256; 246 if (addAscii && convertedGlyphs.length >= 256) { 247 for (int i=0;i<max;i++) { 248 if (convertedGlyphs[i] == 0) { 249 convertedGlyphs[i] = (char)i; 250 } 251 } 252 } 253 } 254 } 255