[OpenJDK 2D-Dev] JDK-8187100 [PATCH][SWING] To make display Variation Selector(IVS/SVS/FVS)
Phil Race
philip.race at oracle.com
Wed Jun 13 18:14:56 UTC 2018
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