--- old/src/java.desktop/share/classes/sun/font/CMap.java 2018-05-31 15:12:50.000000000 -0700 +++ new/src/java.desktop/share/classes/sun/font/CMap.java 2018-05-31 15:12:50.000000000 -0700 @@ -140,6 +140,7 @@ * Using this saves running character coverters repeatedly. */ char[] xlat; + UVS uvs = null; static CMap initialize(TrueTypeFont font) { @@ -149,6 +150,7 @@ int three0=0, three1=0, three2=0, three3=0, three4=0, three5=0, three6=0, three10=0; + int zero5 = 0; // for Unicode Variation Sequences boolean threeStar = false; ByteBuffer cmapBuffer = font.getTableBuffer(TrueTypeFont.cmapTag); @@ -173,6 +175,12 @@ case 6: three6 = offset; break; // Johab case 10: three10 = offset; break; // MS Unicode surrogates } + } else if (platformID == 0) { + encodingID = cmapBuffer.getShort(); + offset = cmapBuffer.getInt(); + if (encodingID == 5) { + zero5 = offset; + } } } @@ -262,6 +270,10 @@ */ cmap = createCMap(cmapBuffer, cmapBuffer.getInt(8), null); } + // For Unicode Variation Sequences + if (cmap != null && zero5 != 0) { + cmap.createUVS(cmapBuffer, zero5); + } return cmap; } @@ -424,6 +436,21 @@ } } + private void createUVS(ByteBuffer buffer, int offset) { + int subtableFormat = buffer.getChar(offset); + if (subtableFormat == 14) { + long subtableLength = buffer.getInt(offset + 2) & INTMASK; + if (offset + subtableLength > buffer.capacity()) { + if (FontUtilities.isLogging()) { + FontUtilities.getLogger() + .warning("Cmap UVS subtable overflows buffer."); + } + } + this.uvs = new UVS(buffer, offset); + } + return; + } + /* final char charVal(byte[] cmap, int index) { return (char)(((0xff & cmap[index]) << 8)+(0xff & cmap[index+1])); @@ -1059,4 +1086,176 @@ } return -1; } + + static class UVS { + int numSelectors; + int[] selector; + + //for Default UVS Table + int[] numUnicodeValueRanges; + int[][] startUnicodeValue; + byte[][] additionalCount; + //for Non-Default UVS Table + int[] numUVSMapping; + int[][] unicodeValue; + char[][] glyphID; + + UVS(ByteBuffer buffer, int offset) { + numSelectors = buffer.getInt(offset+6); + selector = new int[numSelectors]; + numUnicodeValueRanges = new int[numSelectors]; + startUnicodeValue = new int[numSelectors][]; + additionalCount = new byte[numSelectors][]; + numUVSMapping = new int[numSelectors]; + unicodeValue = new int[numSelectors][]; + glyphID = new char[numSelectors][]; + + for (int i = 0; i < numSelectors; i++) { + buffer.position(offset + 10 + i * 11); + selector[i] = (buffer.get() & 0xff) << 16; //UINT24 + selector[i] += (buffer.get() & 0xff) << 8; + selector[i] += buffer.get() & 0xff; + + //for Default UVS Table + int tableOffset = buffer.getInt(offset + 10 + i * 11 + 3); + if (tableOffset == 0) { + numUnicodeValueRanges[i] = 0; + } else { + buffer.position(offset+tableOffset); + numUnicodeValueRanges[i] = buffer.getInt() & INTMASK; + + startUnicodeValue[i] = new int[numUnicodeValueRanges[i]]; + additionalCount[i] = new byte[numUnicodeValueRanges[i]]; + + for (int j = 0; j < numUnicodeValueRanges[i]; j++) { + int temp = (buffer.get() & 0xff) << 16; //UINT24 + temp += (buffer.get() & 0xff) << 8; + temp += buffer.get() & 0xff; + startUnicodeValue[i][j] = temp; + additionalCount[i][j] = buffer.get(); + } + } + + //for Non-Default UVS Table + tableOffset = buffer.getInt(offset + 10 + i * 11 + 7); + if (tableOffset == 0) { + numUVSMapping[i] = 0; + } else { + buffer.position(offset+tableOffset); + numUVSMapping[i] = buffer.getInt() & INTMASK; + unicodeValue[i] = new int[numUVSMapping[i]]; + glyphID[i] = new char[numUVSMapping[i]]; + + for (int j = 0; j < numUVSMapping[i]; j++) { + int temp = (buffer.get() & 0xff) << 16; //UINT24 + temp += (buffer.get() & 0xff) << 8; + temp += buffer.get() & 0xff; + unicodeValue[i][j] = temp; + glyphID[i][j] = buffer.getChar(); + } + } + } + } + + private int cachedCode; + private int targetCachedCode; + private int targetCachedSelector = -1; + + /* getGlyph for Variation selector + return value: + 0: A special glyph for the variation selector is Not found + -1: Default glyph should be used + 0>: A special glyph is found + */ + int getGlyph(int charCode, int variationSelector) { + synchronized(this) { + if (charCode == targetCachedCode && + variationSelector == targetCachedSelector) { + return cachedCode; + } + } + + int targetSelector = -1; + int result; + for (int i = 0; i < numSelectors; i++) { + if (selector[i] == variationSelector) { + targetSelector = i; + break; + } + } + if (targetSelector == -1) { + result = 0; + storeCache(charCode, variationSelector, result); + return result; + } + if (numUnicodeValueRanges[targetSelector] > 0) { + int index = java.util.Arrays.binarySearch( + startUnicodeValue[targetSelector], charCode); + if (index >= 0) { + result = -1; //pass through default table in actual CMAP + storeCache(charCode, variationSelector, result); + return result; + } else { + index = -index - 2; + if (index >=0 && + charCode >= startUnicodeValue[targetSelector][index] && + charCode <= startUnicodeValue[targetSelector][index] + +additionalCount[targetSelector][index]) { + result = -1; //pass through default table in actual CMAP + storeCache(charCode, variationSelector, result); + return result; + } + } + } + if (numUVSMapping[targetSelector] > 0) { + int index = java.util.Arrays.binarySearch( + unicodeValue[targetSelector], charCode); + if (index >= 0) { + result = glyphID[targetSelector][index]; + storeCache(charCode, variationSelector, result); + return result; + } + } + result = 0; + storeCache(charCode, variationSelector, result); + return result; + } + + private synchronized void storeCache(int charCode, + int variationSelector, + int glyph) { + cachedCode = glyph; + targetCachedCode = charCode; + targetCachedSelector = variationSelector; + } + + boolean hasVariationSelectorGlyph(int charCode, + int variationSelector) { + int result = getGlyph(charCode, variationSelector); + if (result == 0) { + return false; + } else { + return true; + } + } + } + + public char getGlyph(int charCode, int variationSelector) { + if (uvs == null) { + return 0; + } + int result = uvs.getGlyph(charCode, variationSelector); + if (result == -1) { + result = this.getGlyph(charCode); + } + return (char)(result & 0xFFFF); + } + + public boolean hasVariationSelectorGlyph(int charCode, + int variationSelector) { + if (uvs == null) { + return false; + } + return uvs.hasVariationSelectorGlyph(charCode, variationSelector); + } }