I happened to create similar patch(for SWING and JavaFX) without knowing the report below.
https://bugs.openjdk.java.net/browse/JDK-8187100

I do not know much about circumstances, because this is my first post about Java forum.
Please discard this if unnecessary.


======================================================
Difference with following patch.
http://cr.openjdk.java.net/~srl/8187100/webrev.00/

1. For Acceleration and Memory saving, load only partial format14 glyphs table.
java.desktop/share/classes/sun/font/CMap.java

+ if (numMappings[i] > 0 && (uniStart[i] == null || glyphID[i] == null)) {
+                    try {
+                        initNonDef(i);



2.  Support Mongolian and FVS  (I checked on Linux and Windows)
java.desktop/share/classes/sun/font/FontUtilities.java

+        else if (code <= 0x18af) { // 1800 - 18AF Mongolian (including FVS)
+            return true;
+        }


3.  Not implementing following

>> 3) Swing text component's DEL and BS key operations change




======================================================
This SWING patch fixes following 2 bugs.

1. To make display IVS/SVS (JDK-8187100)
Sample is kami.java and kami2.java.

java.desktop/share/classes/sun/font/CMap.java
java.desktop/share/classes/sun/font/CharToGlyphMapper.java
java.desktop/share/classes/sun/font/Font2D.java
java.desktop/share/classes/sun/font/TrueTypeGlyphMapper.java
java.desktop/share/native/libfontmanager/sunFont.c
java.desktop/share/native/libfontmanager/hb-jdk-font.cc


2. To make dislpay Mongolian and FVS
Sample is mongol.java.

java.desktop/share/classes/sun/font/FontUtilities.java



======================================================
I checked this patch on CentOS 7.5 and Windows7 x64.


I created same patch for JavaFX
 and posted to openjfx-...@openjdk.java.net.


====================
PATCH
====================
diff -r e1b3def12624 src/java.desktop/share/classes/sun/font/CMap.java
--- a/src/java.desktop/share/classes/sun/font/CMap.java Wed Jun 13 06:35:04 2018 +0200 +++ b/src/java.desktop/share/classes/sun/font/CMap.java Wed Jun 13 14:14:08 2018 +0900
@@ -129,6 +129,7 @@
     static final short MSUnicodeSurrogateEncoding = 10;

     static final char noSuchChar = (char)0xfffd;
+    static final int BYTEMASK  = 0x000000ff;
     static final int SHORTMASK = 0x0000ffff;
     static final int INTMASK   = 0xffffffff;

@@ -141,7 +142,7 @@
      */
     char[] xlat;

-    static CMap initialize(TrueTypeFont font) {
+ static CMap initialize(TrueTypeFont font, int[] offset_format, int create_cmap) {

         CMap cmap = null;

@@ -150,8 +151,15 @@
         int three0=0, three1=0, three2=0, three3=0, three4=0, three5=0,
             three6=0, three10=0;
         boolean threeStar = false;
+        boolean zeroStar = false;

         ByteBuffer cmapBuffer = font.getTableBuffer(TrueTypeFont.cmapTag);
+
+        /* create CMap14 */
+        if (create_cmap == 14 && offset_format[0] != 0) {
+            return createCMap(cmapBuffer, offset_format[0], null);
+        }
+
         int cmapTableOffset = font.getTableSize(TrueTypeFont.cmapTag);
         short numberSubTables = cmapBuffer.getShort(2);

@@ -159,7 +167,7 @@
         for (int i=0; i<numberSubTables; i++) {
             cmapBuffer.position(i * 8 + 4);
             platformID = cmapBuffer.getShort();
-            if (platformID == 3) {
+            if (platformID == 3) {  // MS
                 threeStar = true;
                 encodingID = cmapBuffer.getShort();
                 offset     = cmapBuffer.getInt();
@@ -173,6 +181,13 @@
                 case 6:  three6  = offset; break; // Johab
                 case 10: three10 = offset; break; // MS Unicode surrogates
                 }
+            } else if (platformID == 0) {  // APPLE_UNICODE
+                zeroStar = true;
+                encodingID = cmapBuffer.getShort();
+                offset     = cmapBuffer.getInt();
+                if (encodingID == 5) {
+                    offset_format[0] = offset;
+                }
             }
         }

@@ -419,6 +434,7 @@
         case 8:  return new CMapFormat8(buffer, offset, xlat);
         case 10: return new CMapFormat10(buffer, offset, xlat);
         case 12: return new CMapFormat12(buffer, offset, xlat);
+        case 14: return new CMapFormat14(buffer, offset);
default: throw new RuntimeException("Cmap format unimplemented: " +
                                             (int)buffer.getChar(offset));
         }
@@ -435,6 +451,13 @@
 */
     abstract char getGlyph(int charCode);

+    char getGlyph(int charCode, int vs) {
+        return getGlyph(charCode);
+    }
+
+    void setDefCMap(CMap defCmap) {
+    };
+
     /* Format 4 Header is
      * ushort format (off=0)
      * ushort length (off=2)
@@ -1031,6 +1054,191 @@

     }

+    // Format 14: (Table for variation selector)
+    static class CMapFormat14 extends CMap {
+
+        ByteBuffer buffer;
+        int offset;
+        int numSelector;
+        int[] varSelector;
+
+        /* default glyphs */
+        int[] defaultOff, numRanges;
+        int[][] defUniStart;
+        short[][] additionalCnt;
+
+        /* non default glyphs */
+        int[] nonDefOff, numMappings;
+        int[][] uniStart, glyphID;
+        /* e.g.
+         *  uniStart[numSelector-1] = U+e0100
+         *  uniStart[numSelector-1][numMappings-1] = U+795e
+         *  glyphID[numSelector-1][numMappings-1] = 12345
+         */
+
+        CMap defCmap;
+        void setDefCMap(CMap cmap) {
+            this.defCmap = cmap;
+        }
+
+        CMapFormat14(ByteBuffer buffer, int offset) {
+            this.buffer = buffer;
+            this.offset = offset;
+
+            buffer.position(offset+6);
+            /* get count of Variation Selector */
+            numSelector = buffer.getInt();
+
+ varSelector = new int[numSelector]; // e.g. {0xfe00, 0xe0100, 0xe0101}
+            defaultOff = new int[numSelector];
+            nonDefOff = new int[numSelector];
+
+            /* get Variation Selector and Table offset */
+            for (int i=0; i<numSelector; i++) {
+ varSelector[i] = ((buffer.getShort() & SHORTMASK)<<8) | (buffer.get() & BYTEMASK);
+                defaultOff[i] = buffer.getInt();
+                nonDefOff[i] = buffer.getInt();
+            }
+
+            numMappings = new int[numSelector];
+            uniStart = new int[numSelector][];
+            glyphID = new int[numSelector][];
+
+            /* nonDefault glyphs table, get Unicode and glyphID */
+            for (int i=0; i<numSelector; i++) {
+                if (nonDefOff[i] == 0) {
+                    numMappings[i] = 0;
+                    continue;
+                }
+                buffer.position(offset+nonDefOff[i]);
+                numMappings[i] = buffer.getInt();
+            }
+
+            numRanges = new int[numSelector];
+            defUniStart = new int[numSelector][];
+            additionalCnt = new short[numSelector][];
+
+            /* Default glyphs table, get Unicode and count */
+            for (int i=0; i<numSelector; i++) {
+                if (defaultOff[i] == 0) {
+                    numRanges[i] = 0;
+                    continue;
+                }
+                buffer.position(offset+defaultOff[i]);
+                numRanges[i] = buffer.getInt();
+            }
+        }
+
+ /* init Non Default Glyphs Table of pointed VS(e.g. fe00, e0100.) */
+        void initNonDef(int i) {
+            /* nonDefault glyphs table, get Unicode and glyphID */
+ buffer.position(offset+nonDefOff[i]+4); // +4 = skip numMappings
+            uniStart[i] = new int[numMappings[i]];
+            glyphID[i] = new int[numMappings[i]];
+
+            for (int j=0; j<numMappings[i]; j++) {
+ uniStart[i][j] = ((buffer.getShort() & SHORTMASK)<<8) | (buffer.get() & BYTEMASK);
+                glyphID[i][j] = buffer.getShort() & SHORTMASK;
+            }
+        }
+
+        void initDef(int i) {
+            buffer.position(offset+defaultOff[i]+4); // +4 = skip numRanges
+            defUniStart[i] = new int[numRanges[i]];
+            additionalCnt[i] = new short[numRanges[i]];
+
+            for (int j=0; j<numRanges[i]; j++) {
+ defUniStart[i][j] = ((buffer.getShort() & SHORTMASK)<<8) | (buffer.get() & BYTEMASK);
+                additionalCnt[i][j] = (short)(buffer.get() & BYTEMASK);
+            }
+        }
+
+        final int findMapNumber_NonDef(int charCode, int i) {
+            if (numMappings[i] > 0) {
+                int min = 0, max, mid;
+                max = numMappings[i];
+                while (min < max) {
+                    mid = (min+max) >> 1;
+                    if (charCode < uniStart[i][mid]) {
+                        max = mid;
+                    } else if (charCode > uniStart[i][mid]) {
+                        min = mid + 1;
+                    } else {
+                        return mid;
+                    }
+                }
+            }
+            return -1;
+        }
+
+        final int findRangeNumber_Def(int charCode, int i) {
+            if (numRanges[i] > 0) {
+                int min = 0, max, mid;
+                max = numRanges[i];
+                while (min < max) {
+                    mid = (min+max) >> 1;
+                    if (charCode < defUniStart[i][mid]) {
+                        max = mid;
+ } else if (charCode > defUniStart[i][mid] + additionalCnt[i][mid]) {
+                        min = mid + 1;
+                    } else {
+                        return mid;
+                    }
+                }
+            }
+            return -1;
+        }
+
+        char getGlyph(int charCode) {
+            return getGlyph(charCode, 0);
+        }
+
+        char getGlyph(int charCode, int vs) {
+            if (vs == 0) return 0;
+
+            int j;
+            for (int i=0; i<numSelector; i++) {
+                if (varSelector[i] > vs) break;
+                if (varSelector[i] != vs) continue;
+
+                /* non default glyphs table */
+ if (numMappings[i] > 0 && (uniStart[i] == null || glyphID[i] == null)) {
+                    try {
+                        initNonDef(i);
+                    } catch (Exception e) {
+                        return 0;
+                    }
+                }
+
+                /* search non default glyphs table */
+                j = findMapNumber_NonDef(charCode, i);
+                if (j != -1) {
+                    return (char)glyphID[i][j];
+                }
+
+                /* default glyphs table */
+ if (defCmap == null) break; // can't get glyphID by default glyphs table + if (numRanges[i] > 0 && (defUniStart[i] == null || additionalCnt[i] == null)) {
+                    try {
+                        initDef(i);
+                    } catch (Exception e) {
+                        return 0;
+                    }
+                }
+
+                /* search default glyphs table */
+                if (defCmap == null) break;
+                    j = findRangeNumber_Def(charCode, i);
+                if (j != -1) {
+                    return defCmap.getGlyph(charCode);
+                }
+            }
+
+            return 0;
+        }
+
+    }
+
     /* Used to substitute for bad Cmaps. */
     static class NullCMapClass extends CMap {

diff -r e1b3def12624 src/java.desktop/share/classes/sun/font/CharToGlyphMapper.java --- a/src/java.desktop/share/classes/sun/font/CharToGlyphMapper.java Wed Jun 13 06:35:04 2018 +0200 +++ b/src/java.desktop/share/classes/sun/font/CharToGlyphMapper.java Wed Jun 13 14:14:08 2018 +0900
@@ -43,6 +43,64 @@

     protected int missingGlyph = CharToGlyphMapper.UNINITIALIZED_GLYPH;

+    public static final int SVS_START = 0xFE00;  // VS1
+    public static final int SVS_END = 0xFE0F;    // VS16
+    public static final int IVS_START = 0xE0100; // VS17
+    public static final int IVS_END = 0xE01EF;   // VS256
+    public static final int FVS_START = 0x180B;  // FVS1
+    public static final int FVS_END = 0x180D;    // FVS3
+
+    /* http://www.unicode.org/versions/Unicode10.0.0/ch18.pdf */
+    public static boolean isCJK(int code) {
+        if (code >= 0x4E00 && code <= 0x9FFF) // Unified Ideographs
+            return true;
+        if (code >= 0x3400 && code <= 0x4DBF) // Extension A
+            return true;
+        if (code >= 0x20000 && code <= 0x2A6DF) // Extension B
+            return true;
+        if (code >= 0x2A700 && code <= 0x2B73F) // Extension C
+            return true;
+        if (code >= 0x2B740 && code <= 0x2B81F) // Extension D
+            return true;
+        if (code >= 0x2B820 && code <= 0x2CEAF) // Extension E
+            return true;
+        if (code >= 0x2CEB0 && code <= 0x2EBE0) // Extension F
+            return true;
+        if (code >= 0xF900 && code <= 0xFAFF) // Compatibility Ideographs
+            return true;
+ if (code >= 0x2F800 && code <= 0x2FA1F) // Compatibility Ideographs Supplement
+            return true;
+        return false;
+    }
+
+    public static boolean isVS(int code) {
+        if (isIVS(code))
+            return true;
+        if (isSVS(code))
+            return true;
+//        if (isFVS(code))
+//            return true;
+        return false;
+    }
+
+    public static boolean isSVS(int code) {
+        if (code >= SVS_START && code <= SVS_END)
+            return true;
+        return false;
+    }
+
+    public static boolean isIVS(int code) {
+        if (code >= IVS_START && code <= IVS_END)
+            return true;
+        return false;
+    }
+
+//    public static boolean isFVS(int code) {
+//        if (code >= FVS_START && code <= FVS_END)
+//            return true;
+//        return false;
+//    }
+
     public int getMissingGlyphCode() {
         return missingGlyph;
     }
@@ -62,18 +120,44 @@
     }

     public int charToGlyph(char unicode) {
-        char[] chars = new char[1];
+        return charToGlyph(unicode, 0);
+    }
+
+    public int charToGlyph(char unicode, char vs) {
+        char[] chars;
+        int count;
+        if (vs == 0) {
+            chars = new char[1];
+            count = 1;
+        } else {
+            chars = new char[2];
+            chars[1] = vs;
+            count = 2;
+        }
         int[] glyphs = new int[1];
         chars[0] = unicode;
-        charsToGlyphs(1, chars, glyphs);
+        charsToGlyphs(count, chars, glyphs);
         return glyphs[0];
     }

     public int charToGlyph(int unicode) {
-        int[] chars = new int[1];
+        return charToGlyph(unicode, 0);
+    }
+
+    public int charToGlyph(int unicode, int vs) {
+        int[] chars;
+        int count;
+        if (vs == 0) {
+            chars = new int[1];
+            count = 1;
+        } else {
+            chars = new int[2];
+            chars[1] = vs;
+            count = 2;
+        }
         int [] glyphs = new int[1];
         chars[0] = unicode;
-        charsToGlyphs(1, chars, glyphs);
+        charsToGlyphs(count, chars, glyphs);
         return glyphs[0];
     }

diff -r e1b3def12624 src/java.desktop/share/classes/sun/font/Font2D.java
--- a/src/java.desktop/share/classes/sun/font/Font2D.java Wed Jun 13 06:35:04 2018 +0200 +++ b/src/java.desktop/share/classes/sun/font/Font2D.java Wed Jun 13 14:14:08 2018 +0900
@@ -524,6 +524,10 @@
         return getMapper().charToGlyph(wchar);
     }

+    public int charToGlyph(int wchar, int vs) {
+        return getMapper().charToGlyph(wchar, vs);
+    }
+
     public int getMissingGlyphCode() {
         return getMapper().getMissingGlyphCode();
     }
diff -r e1b3def12624 src/java.desktop/share/classes/sun/font/FontUtilities.java --- a/src/java.desktop/share/classes/sun/font/FontUtilities.java Wed Jun 13 06:35:04 2018 +0200 +++ b/src/java.desktop/share/classes/sun/font/FontUtilities.java Wed Jun 13 14:14:08 2018 +0900
@@ -299,6 +299,9 @@
         else if (code <= 0x17ff) { // 1780 - 17FF Khmer
             return true;
         }
+        else if (code <= 0x18af) { // 1800 - 18AF Mongolian (including FVS)
+            return true;
+        }
         else if (code < 0x200c) {
             return false;
         }
diff -r e1b3def12624 src/java.desktop/share/classes/sun/font/TrueTypeGlyphMapper.java --- a/src/java.desktop/share/classes/sun/font/TrueTypeGlyphMapper.java Wed Jun 13 06:35:04 2018 +0200 +++ b/src/java.desktop/share/classes/sun/font/TrueTypeGlyphMapper.java Wed Jun 13 14:14:08 2018 +0900
@@ -43,11 +43,14 @@
     TrueTypeFont font;
     CMap cmap;
     int numGlyphs;
+    int offset_format[] = {0}; // offset of format14
+    CMap cmap14;

     public TrueTypeGlyphMapper(TrueTypeFont font) {
         this.font = font;
+        offset_format[0] = 0;
         try {
-            cmap = CMap.initialize(font);
+            cmap = CMap.initialize(font, offset_format, -1);
         } catch (Exception e) {
             cmap = null;
         }
@@ -68,29 +71,63 @@
         }
     }

+    public CMap createCMap14() {
+        if (cmap14 == null && offset_format[0] != 0) {
+            try {
+                cmap14 = CMap.initialize(font, offset_format, 14);
+                if (cmap14 != null) {
+                    cmap14.setDefCMap(this.cmap);
+ ByteBuffer buffer = font.getTableBuffer(TrueTypeFont.maxpTag);
+                    if (buffer != null && buffer.capacity() >= 6) {
+ numGlyphs = buffer.getChar(4); // offset 4 bytes in MAXP table.
+                    }
+                }
+            } catch (Exception e) {
+                cmap14 = null;
+            }
+            offset_format[0] = 0;
+        }
+        return cmap14;
+    }
+
     public int getNumGlyphs() {
         return numGlyphs;
     }

+    private char getGlyphFromCMAP(int charCode, int vs) {
+        char glyphCode = (char)missingGlyph;
+        if (vs == 0) {
+            try {
+                glyphCode = cmap.getGlyph(charCode);
+            } catch(Exception e) {
+                handleBadCMAP();
+                return (char) missingGlyph;
+            }
+        } else if (createCMap14() != null) {
+            try {
+                glyphCode = cmap14.getGlyph(charCode, vs);
+            } catch(Exception e) {
+                handleBadCMAP14();
+                return (char) missingGlyph;
+            }
+        }
+
+        if (glyphCode < numGlyphs ||
+            glyphCode >= FileFontStrike.INVISIBLE_GLYPHS) {
+            return glyphCode;
+        } else {
+            if (FontUtilities.isLogging()) {
+                FontUtilities.getLogger().warning
+                    (font + " out of range glyph id=" +
+                     Integer.toHexString((int)glyphCode) +
+                     " for char " + Integer.toHexString(charCode));
+            }
+            return (char)missingGlyph;
+        }
+    }
+
     private char getGlyphFromCMAP(int charCode) {
-        try {
-            char glyphCode = cmap.getGlyph(charCode);
-            if (glyphCode < numGlyphs ||
-                glyphCode >= FileFontStrike.INVISIBLE_GLYPHS) {
-                return glyphCode;
-            } else {
-                if (FontUtilities.isLogging()) {
-                    FontUtilities.getLogger().warning
-                        (font + " out of range glyph id=" +
-                         Integer.toHexString((int)glyphCode) +
-                         " for char " + Integer.toHexString(charCode));
-                }
-                return (char)missingGlyph;
-            }
-        } catch(Exception e) {
-            handleBadCMAP();
-            return (char) missingGlyph;
-        }
+        return getGlyphFromCMAP(charCode, 0);
     }

     private void handleBadCMAP() {
@@ -106,6 +143,15 @@
         cmap = CMap.theNullCmap;
     }

+    private void handleBadCMAP14() {
+        if (FontUtilities.isLogging()) {
+            FontUtilities.getLogger().severe("Null Cmap for " + font +
+                                      "substituting for this font");
+        }
+        SunFontManager.getInstance().deRegisterBadFont(font);
+        cmap14 = CMap.theNullCmap;
+    }
+
     private char remapJAChar(char unicode) {
         return (unicode == REVERSE_SOLIDUS) ? JA_YEN : unicode;
     }
@@ -114,22 +160,22 @@
         return (unicode == REVERSE_SOLIDUS) ? JA_YEN : unicode;
     }

-    public int charToGlyph(char unicode) {
+    public int charToGlyph(char unicode, char vs) {
         if (needsJAremapping) {
             unicode = remapJAChar(unicode);
         }
-        int glyph = getGlyphFromCMAP(unicode);
+        int glyph = getGlyphFromCMAP(unicode, vs);
if (font.checkUseNatives() && glyph < font.glyphToCharMap.length) {
             font.glyphToCharMap[glyph] = unicode;
         }
         return glyph;
     }

-    public int charToGlyph(int unicode) {
+    public int charToGlyph(int unicode, int vs) {
         if (needsJAremapping) {
             unicode = remapJAIntChar(unicode);
         }
-        int glyph = getGlyphFromCMAP(unicode);
+        int glyph = getGlyphFromCMAP(unicode, vs);
if (font.checkUseNatives() && glyph < font.glyphToCharMap.length) {
             font.glyphToCharMap[glyph] = (char)unicode;
         }
@@ -152,6 +198,8 @@

     public void charsToGlyphs(int count, char[] unicodes, int[] glyphs) {

+ int codeWasSurrogate = 0; // store surrogate pair to handle surrogate pair+VS
+        boolean isSurrogate = false; // set true except IVS
         for (int i=0; i<count; i++) {
             int code;
             if (needsJAremapping) {
@@ -169,13 +217,74 @@
                     code = (code - HI_SURROGATE_START) *
                         0x400 + low - LO_SURROGATE_START + 0x10000;

-                    glyphs[i] = getGlyphFromCMAP(code);
+                    if (isIVS(code) && i != 0 &&
+ ((codeWasSurrogate == 0 && isCJK((int)unicodes[i -1])) ||
+                          codeWasSurrogate != 0)) {
+                        int glyph;
+                        if (codeWasSurrogate == 0) {
+ glyph = getGlyphFromCMAP((int)unicodes[i -1], code); // IVS
+                        } else {
+ glyph = getGlyphFromCMAP(codeWasSurrogate, code); // surrogate pair+IVS
+                        }
+                        if (glyph == missingGlyph) {
+                            glyphs[i] = missingGlyph;
+                        } else {
+                            if (codeWasSurrogate == 0) {
+                                glyphs[i - 1] = glyph;
+                                glyphs[i] = INVISIBLE_GLYPH_ID;
+                            } else {
+                                glyphs[i - 2] = glyph;
+                                glyphs[i - 1] = INVISIBLE_GLYPH_ID;
+                                glyphs[i] = INVISIBLE_GLYPH_ID;
+                            }
+                        }
+                    } else { // surrogate pair, or notCJK+IVS
+                        glyphs[i] = getGlyphFromCMAP(code);
+                        if (isIVS(code) == false) {
+                            isSurrogate = true;
+                        }
+                    }
                     i += 1; // Empty glyph slot after surrogate
                     glyphs[i] = INVISIBLE_GLYPH_ID;
+
+                    if (isSurrogate == false) {
+                        codeWasSurrogate = 0;
+                    } else {
+                        codeWasSurrogate = code;
+                        isSurrogate = false;
+                    }
                     continue;
                 }
+            } else {
+                if (isSVS(code) && i != 0 &&
+ ((codeWasSurrogate == 0 && isCJK((int)unicodes[i -1])) ||
+                      codeWasSurrogate != 0)) {
+                    int glyph;
+                    if (codeWasSurrogate == 0) {
+ glyph = getGlyphFromCMAP((int)unicodes[i -1], code);
+                    } else {
+                        glyph = getGlyphFromCMAP(codeWasSurrogate, code);
+                    }
+                    if (glyph == missingGlyph) {
+                        glyphs[i] = missingGlyph;
+                    } else {
+                        if (codeWasSurrogate == 0) {
+                            glyphs[i - 1] = glyph;
+                            glyphs[i] = INVISIBLE_GLYPH_ID;
+                        } else {
+                            glyphs[i - 2] = glyph;
+                            glyphs[i - 1] = INVISIBLE_GLYPH_ID;
+                            glyphs[i] = INVISIBLE_GLYPH_ID;
+                        }
+                    }
+                } else {
+                    glyphs[i] = getGlyphFromCMAP(code);
+                }
             }
-            glyphs[i] = getGlyphFromCMAP(code);
+
+            if (isSurrogate == false) {
+                codeWasSurrogate = 0;
+            }

             if (font.checkUseNatives() &&
                 glyphs[i] < font.glyphToCharMap.length) {
@@ -192,6 +301,8 @@
      */
public boolean charsToGlyphsNS(int count, char[] unicodes, int[] glyphs) {

+ int codeWasSurrogate = 0; // store surrogate pair to handle surrogate pair+VS
+        boolean isSurrogate = false; // set true except IVS
         for (int i=0; i<count; i++) {
             int code;
             if (needsJAremapping) {
@@ -208,11 +319,71 @@
                     low <= LO_SURROGATE_END) {
                     code = (code - HI_SURROGATE_START) *
                         0x400 + low - LO_SURROGATE_START + 0x10000;
+                    if (isIVS(code) && i != 0 &&
+ ((codeWasSurrogate == 0 && isCJK((int)unicodes[i -1])) ||
+                          codeWasSurrogate != 0)) {
+                        int glyph;
+                        if (codeWasSurrogate == 0) {
+ glyph = getGlyphFromCMAP((int)unicodes[i -1], code); // IVS
+                        } else {
+ glyph = getGlyphFromCMAP(codeWasSurrogate, code); // surrogate pair+IVS
+                        }
+                        if (glyph == missingGlyph) {
+                            glyphs[i] = missingGlyph;
+                        } else {
+                            if (codeWasSurrogate == 0) {
+                                glyphs[i - 1] = glyph;
+                                glyphs[i] = INVISIBLE_GLYPH_ID;
+                            } else {
+                                glyphs[i - 2] = glyph;
+                                glyphs[i - 1] = INVISIBLE_GLYPH_ID;
+                                glyphs[i] = INVISIBLE_GLYPH_ID;
+                            }
+                        }
+                    } else { // surrogate pair, or notCJK+IVS
+                        glyphs[i] = getGlyphFromCMAP(code);
+                        if (isIVS(code) == false) {
+                            isSurrogate = true;
+                        }
+                    }
                     glyphs[i + 1] = INVISIBLE_GLYPH_ID;
+                } else { // not surrogate pair
+                    glyphs[i] = getGlyphFromCMAP(code);
+                }
+            } else { // not surrogate pair
+                if (isSVS(code) && i != 0 &&
+ ((codeWasSurrogate == 0 && isCJK((int)unicodes[i -1])) ||
+                      codeWasSurrogate != 0)) {
+                    int glyph;
+                    if (codeWasSurrogate == 0) {
+ glyph = getGlyphFromCMAP((int)unicodes[i -1], code);
+                    } else {
+                        glyph = getGlyphFromCMAP(codeWasSurrogate, code);
+                    }
+                    if (glyph == missingGlyph) {
+                        glyphs[i] = missingGlyph;
+                    } else {
+                        if (codeWasSurrogate == 0) {
+                            glyphs[i - 1] = glyph;
+                            glyphs[i] = INVISIBLE_GLYPH_ID;
+                        } else {
+                            glyphs[i - 2] = glyph;
+                            glyphs[i - 1] = INVISIBLE_GLYPH_ID;
+                            glyphs[i] = INVISIBLE_GLYPH_ID;
+                        }
+                    }
+                } else {
+                    glyphs[i] = getGlyphFromCMAP(code);
                 }
             }

-            glyphs[i] = getGlyphFromCMAP(code);
+            if (isSurrogate == false) {
+                codeWasSurrogate = 0;
+            } else {
+                codeWasSurrogate = code;
+                isSurrogate = false;
+            }
+
             if (font.checkUseNatives() &&
                 glyphs[i] < font.glyphToCharMap.length) {
                 font.glyphToCharMap[glyphs[i]] = (char)code;
diff -r e1b3def12624 src/java.desktop/share/native/libfontmanager/hb-jdk-font.cc --- a/src/java.desktop/share/native/libfontmanager/hb-jdk-font.cc Wed Jun 13 06:35:04 2018 +0200 +++ b/src/java.desktop/share/native/libfontmanager/hb-jdk-font.cc Wed Jun 13 14:14:08 2018 +0900
@@ -48,10 +48,9 @@
     JDKFontInfo *jdkFontInfo = (JDKFontInfo*)font_data;
     JNIEnv* env = jdkFontInfo->env;
     jobject font2D = jdkFontInfo->font2D;
- hb_codepoint_t u = (variation_selector==0) ? unicode : variation_selector;

     *glyph = (hb_codepoint_t)
-          env->CallIntMethod(font2D, sunFontIDs.f2dCharToGlyphMID, u);
+ env->CallIntMethod(font2D, sunFontIDs.f2dCharToGlyphMID, unicode, variation_selector);
     if ((int)*glyph < 0) {
         *glyph = 0;
     }
diff -r e1b3def12624 src/java.desktop/share/native/libfontmanager/sunFont.c
--- a/src/java.desktop/share/native/libfontmanager/sunFont.c Wed Jun 13 06:35:04 2018 +0200 +++ b/src/java.desktop/share/native/libfontmanager/sunFont.c Wed Jun 13 14:14:08 2018 +0900
@@ -143,7 +143,7 @@

      CHECK_NULL(tmpClass = (*env)->FindClass(env, "sun/font/Font2D"));
      CHECK_NULL(sunFontIDs.f2dCharToGlyphMID =
-         (*env)->GetMethodID(env, tmpClass, "charToGlyph", "(I)I"));
+         (*env)->GetMethodID(env, tmpClass, "charToGlyph", "(II)I"));
      CHECK_NULL(sunFontIDs.getMapperMID =
          (*env)->GetMethodID(env, tmpClass, "getMapper",
                              "()Lsun/font/CharToGlyphMapper;"));
@@ -154,7 +154,7 @@

CHECK_NULL(tmpClass = (*env)->FindClass(env, "sun/font/CharToGlyphMapper"));
      CHECK_NULL(sunFontIDs.charToGlyphMID =
-        (*env)->GetMethodID(env, tmpClass, "charToGlyph", "(I)I"));
+        (*env)->GetMethodID(env, tmpClass, "charToGlyph", "(II)I"));

CHECK_NULL(tmpClass = (*env)->FindClass(env, "sun/font/PhysicalStrike"));
      CHECK_NULL(sunFontIDs.getGlyphMetricsMID =



====================
Sample (kami.java)
====================
import javax.swing.*;
import java.awt.Font;
import java.awt.BorderLayout;

public class kami extends JFrame {

  public static void main(String[] args) {
    kami frame = new kami();

    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setBounds(10, 10, 450, 250);
    frame.setVisible(true);
  }

  kami() {
    // You need to install ipamjm font
    String family = "IPAmjMincho"; // for Linux
//    String family = "IPAmj明朝"; // for Windows

    JLabel label[] = new JLabel[3];
    label[0] = new JLabel("\u795E+VS1 --> \u795E\uFE00\n"); // SVS
    label[1] = new JLabel("\u795E+VS20 --> \u795E\uDB40\uDD03\n"); // IVS
label[2] = new JLabel("\uD87A\uDF79+VS17 --> \uD87A\uDF79\uDB40\uDD01\n"); // surrogate pair+IVS

    JPanel p = new JPanel();
    for (int i=0; i<3; i++) {
      label[i].setFont(new Font(family, Font.PLAIN, 48));
      p.add(label[i]);
    }
    getContentPane().add(p, BorderLayout.CENTER);
  }
}


====================
Sample (kami2.java)
====================
import javax.swing.*;
import java.awt.Font;
import java.awt.BorderLayout;

public class kami2 extends JFrame {

  public static void main(String[] args) {
    kami2 frame = new kami2();

    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setBounds(10, 10, 450, 250);
    frame.setVisible(true);
  }

  kami2() {
    // You need to install ipamjm font
    String family = "IPAmjMincho"; // for Linux
//    String family = "IPAmj明朝"; // for Windows

    String str[] = new String[3];
    str[0] = new String("\u795E+VS1 --> \u795E\uFE00\n");
    str[1] = new String("\u795E+VS20 --> \u795E\uDB40\uDD03\n");
str[2] = new String("\uD87A\uDF79+VS17 --> \uD87A\uDF79\uDB40\uDD01\n");

    String str_for_area = new String("");
    for (int i=0; i<3; i++) {
      str_for_area += str[i].toString();
    }

    JTextArea area = new JTextArea(str_for_area, 3, 10);
    area.setFont(new Font(family, 0, 48));

    JPanel p = new JPanel();
    p.add(area);
    getContentPane().add(p, BorderLayout.CENTER);
  }
}


====================
Sample (mongol.java)
====================
import javax.swing.*;
import java.awt.Font;
import java.awt.BorderLayout;

public class mongol extends JFrame{

  public static void main(String[] args) {
    mongol frame = new mongol();

    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setBounds(10, 10, 600, 650);
    frame.setVisible(true);
  }

  mongol() {
    // http://www.mongolfont.com/en/font/mnglartotf.html
    String family = "Mongolian Art";
    JLabel label[] = new JLabel[9];

    // Correct mongolian form
    // http://www.unicode.org/versions/Unicode10.0.0/ch13.pdf#G27803
    label[0] = new JLabel("ᠤ ᠷ ᠲ ᠤ   --> ᠤᠷᠲᠤ (urtu)\n");
    label[1] = new JLabel("ᠣ ᠷ ᠳ ᠤ   --> ᠣᠷᠳᠤ (ordu)\n");
    label[2] = new JLabel("ᠡ ᠨ ᠳ ᠡ   --> ᠡᠨᠳᠡ (ende)\n");
    label[3] = new JLabel("ᠠ ᠳ ᠠ     --> ᠠᠳᠠ  (ada)\n");
    label[4] = new JLabel("ᠠ ᠪ ᠤ   --> ᠠᠪᠤ (abu)\n");
    label[5] = new JLabel("ᠣ ᠳ ᠣ   --> ᠣᠳᠣ (odo)\n");
    label[6] = new JLabel("ᠡ ᠨ ᠡ   --> ᠡᠨᠡ (ene)\n");
    label[7] = new JLabel("ᠭ ᠠ  --> ᠭᠠ (gal)\n");
    label[8] = new JLabel("ᠭ᠋ ᠠ  --> ᠭ᠋ᠠ (gal+U+180B)\n");

    JPanel p = new JPanel();
    for (int i=0; i<9; i++) {
      label[i].setFont(new Font(family, Font.PLAIN, 48));
      p.add(label[i]);
    }
    getContentPane().add(p, BorderLayout.CENTER);
  }
}



--------------------------------------
Name: Akira Nakajima
E-Mail: nakajima.ak...@nttcom.co.jp
--------------------------------------

Reply via email to