[OpenJDK 2D-Dev] JDK-8187100 [PATCH][SWING] To make display Variation Selector(IVS/SVS/FVS)

Nakajima Akira nakajima.akira at nttcom.co.jp
Wed Jun 13 23:41:10 UTC 2018


Hello Phil.

Thanks for your reply and suggestion.

 > http://www.oracle.com/technetwork/community/oca-486395.html

Signed OCA is listed as
NTT Comware Corporation - OpenJDK


--------------------------------------
Company: NTT Comware Corporation
Name: Akira Nakajima
E-Mail: nakajima.akira at nttcom.co.jp
--------------------------------------


On 2018/06/14 3:14, Phil Race wrote:
> Hi Akira,
>
> It seems that maybe we should be looking at what you propose and
> comparing it
> to see if one or the other approach is better and if one missed
> something the other spotted.
> I'd like to ask Steven and Toshio to take the lead on that.
>
> However for any of your patch to be included it is imperative that you
> FIRST
> have a signed OCA accepted. Please see
> http://www.oracle.com/technetwork/community/oca-486395.html
> where your name is not present ...
>
> -phil.
>
> On 06/13/2018 12:53 AM, Nakajima Akira wrote:
>> 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-dev at 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.akira at nttcom.co.jp
>> --------------------------------------


More information about the 2d-dev mailing list