Hi

That's very encourage us that the similar requirement exist.

As the starting point of discussion, I'd like to share the results of
analysis.
(This is also Steven's request.)

1) Heap usage
Akira-san's code had smaller foot print.
(Mesured by Font2Demo, IPAmj font, and RHEL7)
Akira-san's
(w/o VS) 7454464 bytes, (w/ VS) 7773472 bytes
Ours
(w/o VS) 7593096 bytes, (w/ VS) 7631088 bytes

2) Mongolian support
This works for not only FVS, but also other Mongolian glyphs.
This is separated by our patch.

3) Swing key operations
I agreed that this is another layer's issue, and dropped from my patch,
too.

4) Our code's advantages
- Composite (logical) fonts support
- Obeyed Unicode standard more strictly
    - Base character definition
    - Behavior when no VS glyph is available

I sent my latest update to Steven, which was revised based on Phil's greate
comments.

Best regards,
Toshio Nakamura, IBM Japan



From:   Nakajima Akira <nakajima.ak...@nttcom.co.jp>
To:     Phil Race <philip.r...@oracle.com>, <2d-dev@openjdk.java.net>,
            Toshio 5 Nakamura <toshi...@jp.ibm.com>, "Steven R. Loomis"
            <s...@icu-project.org>
Date:   2018/06/14 08:41
Subject:        Re: [OpenJDK 2D-Dev] JDK-8187100 [PATCH][SWING] To make display
            Variation Selector(IVS/SVS/FVS)



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.ak...@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-...@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
>> +                        }

Reply via email to