--- old/src/java.desktop/share/classes/sun/font/TrueTypeGlyphMapper.java 2018-06-18 09:58:58.000000000 -0700 +++ new/src/java.desktop/share/classes/sun/font/TrueTypeGlyphMapper.java 2018-06-18 09:58:58.000000000 -0700 @@ -87,7 +87,32 @@ } return (char)missingGlyph; } - } catch(Exception e) { + } catch (Exception e) { + handleBadCMAP(); + return (char) missingGlyph; + } + } + + private char getGlyphFromCMAPVS(int charCode, int variationSelector) { + if (variationSelector == 0) { + return getGlyphFromCMAP(charCode); + } + try { + char glyphCode = cmap.getGlyph(charCode, variationSelector, true); + 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) + + " for vs " + Integer.toHexString(variationSelector)); + } + return (char)missingGlyph; + } + } catch (Exception e) { handleBadCMAP(); return (char) missingGlyph; } @@ -137,7 +162,11 @@ } public void charsToGlyphs(int count, int[] unicodes, int[] glyphs) { - for (int i=0;i= HI_SURROGATE_START && + code <= HI_SURROGATE_END && i < count - 1) { + char low = unicodes[i + 1]; + + if (low >= LO_SURROGATE_START && + low <= LO_SURROGATE_END) { + code = (code - HI_SURROGATE_START) * + 0x400 + low - LO_SURROGATE_START + 0x10000; + + glyphs[i + 1] = INVISIBLE_GLYPH_ID; + step = 2; + } + } + if (i < count - step && + isVariationSelectorBMP(unicodes[i + step]) && + isVSBaseChar(code)) { + variationSelector = unicodes[i + step]; + glyphs[i] = getGlyphFromCMAPVS(code, variationSelector); + glyphs[i+step] = INVISIBLE_GLYPH_ID; + i += 1; + } else if (i < count - step -1 && + isVariationSelectorExt(unicodes[i + step], + unicodes[i + step + 1]) && + isVSBaseChar(code)) { + variationSelector = (unicodes[i + step] - HI_SURROGATE_START) + * 0x400 + unicodes[i + step + 1] + - LO_SURROGATE_START + 0x10000; + glyphs[i] = getGlyphFromCMAPVS(code, variationSelector); + glyphs[i + step] = INVISIBLE_GLYPH_ID; + glyphs[i + step + 1] = INVISIBLE_GLYPH_ID; + i += 2; + } + if (variationSelector == 0) { + glyphs[i] = getGlyphFromCMAP(code); + + if (font.checkUseNatives() && + glyphs[i] < font.glyphToCharMap.length) { + font.glyphToCharMap[glyphs[i]] = (char)code; + } + } + if (code >= 0x10000) { + i++; + } + + } + } + /* This variant checks if shaping is needed and immediately * returns true if it does. A caller of this method should be expecting * to check the return type because it needs to know how to handle @@ -192,7 +314,7 @@ */ public boolean charsToGlyphsNS(int count, char[] unicodes, int[] glyphs) { - for (int i=0; i= HI_SURROGATE_START && + code <= HI_SURROGATE_END && i < count - 1) { + char low = unicodes[i + 1]; + + if (low >= LO_SURROGATE_START && + low <= LO_SURROGATE_END) { + code = (code - HI_SURROGATE_START) * + 0x400 + low - LO_SURROGATE_START + 0x10000; + glyphs[i + 1] = INVISIBLE_GLYPH_ID; + step = 2; + } + } + + if (i < count - step && + isVariationSelectorBMP(unicodes[i + step]) && + isVSBaseChar(code)) { + variationSelector = unicodes[i + step]; + glyphs[i] = getGlyphFromCMAPVS(code, variationSelector); + glyphs[i+step] = INVISIBLE_GLYPH_ID; + i += 1; + } else if (i < count - step - 1 && + isVariationSelectorExt(unicodes[i + step], + unicodes[i + step + 1]) && + isVSBaseChar(code)) { + variationSelector = (unicodes[i + step] - HI_SURROGATE_START) + * 0x400 + unicodes[i + step + 1] + - LO_SURROGATE_START + 0x10000; + glyphs[i] = getGlyphFromCMAPVS(code, variationSelector); + glyphs[i + step] = INVISIBLE_GLYPH_ID; + glyphs[i + step + 1] = INVISIBLE_GLYPH_ID; + i += 2; + } + if (variationSelector == 0) { + glyphs[i] = getGlyphFromCMAP(code); + if (font.checkUseNatives() && + glyphs[i] < font.glyphToCharMap.length) { + font.glyphToCharMap[glyphs[i]] = (char)code; + } + } + + if (code < FontUtilities.MIN_LAYOUT_CHARCODE) { + continue; + } + else if (FontUtilities.isComplexCharCode(code)) { + return true; + } + else if (code >= 0x10000) { + i += 1; // Empty glyph slot after surrogate + continue; + } + } + + return false; + } + /* A pretty good heuristic is that the cmap we are using * supports 32 bit character codes. */ @@ -242,4 +434,8 @@ cmap instanceof CMap.CMapFormat10 || cmap instanceof CMap.CMapFormat12; } + + int getGlyphOfVS(int charCode, int variationSelector) { + return cmap.getGlyph(charCode, variationSelector, false); + } }