jdk/src/java.desktop/unix/classes/sun/font/XMap.java
changeset 25859 3317bb8137f4
parent 25573 160050c1b09e
child 30456 2a753e3fc714
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.desktop/unix/classes/sun/font/XMap.java	Sun Aug 17 15:54:13 2014 +0100
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2003, 2014, 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<String, XMap> 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 = 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 don't 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;
+                }
+            }
+        }
+    }
+}