[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