IDEA-72989 fix rendering of characters from Unicode supplementary planes

This commit is contained in:
Dmitry Batrak
2015-12-10 20:32:12 +03:00
parent cf3375848a
commit 2f0cb5aa45
3 changed files with 38 additions and 26 deletions
@@ -179,14 +179,14 @@ public class ComplementaryFontsRegistry {
}
@NotNull
public static FontInfo getFontAbleToDisplay(char c, @JdkConstants.FontStyle int style, @NotNull FontPreferences preferences) {
public static FontInfo getFontAbleToDisplay(int codePoint, @JdkConstants.FontStyle int style, @NotNull FontPreferences preferences) {
boolean tryDefaultFont = true;
List<String> fontFamilies = preferences.getEffectiveFontFamilies();
FontInfo result;
//noinspection ForLoopReplaceableByForEach
for (int i = 0, len = fontFamilies.size(); i < len; ++i) { // avoid foreach, it instantiates ArrayList$Itr, this traversal happens very often
final String fontFamily = fontFamilies.get(i);
result = doGetFontAbleToDisplay(c, preferences.getSize(fontFamily), style, fontFamily);
result = doGetFontAbleToDisplay(codePoint, preferences.getSize(fontFamily), style, fontFamily);
if (result != null) {
return result;
}
@@ -197,25 +197,25 @@ public class ComplementaryFontsRegistry {
size = preferences.getSize(fontFamilies.get(0));
}
if (tryDefaultFont) {
result = doGetFontAbleToDisplay(c, size, style, FontPreferences.DEFAULT_FONT_NAME);
result = doGetFontAbleToDisplay(codePoint, size, style, FontPreferences.DEFAULT_FONT_NAME);
if (result != null) {
return result;
}
}
return doGetFontAbleToDisplay(c, size, style);
return doGetFontAbleToDisplay(codePoint, size, style);
}
@NotNull
public static FontInfo getFontAbleToDisplay(char c, int size, @JdkConstants.FontStyle int style, @NotNull String defaultFontFamily) {
FontInfo result = doGetFontAbleToDisplay(c, size, style, defaultFontFamily);
public static FontInfo getFontAbleToDisplay(int codePoint, int size, @JdkConstants.FontStyle int style, @NotNull String defaultFontFamily) {
FontInfo result = doGetFontAbleToDisplay(codePoint, size, style, defaultFontFamily);
if (result != null) {
return result;
}
return doGetFontAbleToDisplay(c, size, style);
return doGetFontAbleToDisplay(codePoint, size, style);
}
@Nullable
private static FontInfo doGetFontAbleToDisplay(char c, int size, @JdkConstants.FontStyle int style, @NotNull String defaultFontFamily) {
private static FontInfo doGetFontAbleToDisplay(int codePoint, int size, @JdkConstants.FontStyle int style, @NotNull String defaultFontFamily) {
synchronized (lock) {
if (Patches.JDK_MAC_FONT_STYLE_DETECTION_WORKAROUND && style > 0 && style < 4) {
Pair<String, Integer>[] replacement = ourStyledFontMap.get(defaultFontFamily);
@@ -229,8 +229,8 @@ public class ComplementaryFontsRegistry {
ourSharedKeyInstance.myFamilyName != null &&
ourSharedKeyInstance.myFamilyName.equals(defaultFontFamily) &&
ourSharedDefaultFont != null &&
( c < 128 ||
ourSharedDefaultFont.canDisplay(c)
( codePoint < 128 ||
ourSharedDefaultFont.canDisplay(codePoint)
)
) {
return ourSharedDefaultFont;
@@ -248,7 +248,7 @@ public class ComplementaryFontsRegistry {
}
ourSharedDefaultFont = defaultFont;
if (c < 128 || defaultFont.canDisplay(c)) {
if (codePoint < 128 || defaultFont.canDisplay(codePoint)) {
return defaultFont;
}
else {
@@ -258,13 +258,13 @@ public class ComplementaryFontsRegistry {
}
@NotNull
private static FontInfo doGetFontAbleToDisplay(char c, int size, @JdkConstants.FontStyle int style) {
private static FontInfo doGetFontAbleToDisplay(int codePoint, int size, @JdkConstants.FontStyle int style) {
synchronized (lock) {
if (ourUndisplayableChars.contains(c)) return ourSharedDefaultFont;
if (ourUndisplayableChars.contains(codePoint)) return ourSharedDefaultFont;
final Collection<FontInfo> descriptors = ourUsedFonts.values();
for (FontInfo font : descriptors) {
if (font.getSize() == size && font.getStyle() == style && font.canDisplay(c)) {
if (font.getSize() == size && font.getStyle() == style && font.canDisplay(codePoint)) {
return font;
}
}
@@ -272,14 +272,14 @@ public class ComplementaryFontsRegistry {
for (int i = 0; i < ourFontNames.size(); i++) {
String name = ourFontNames.get(i);
FontInfo font = new FontInfo(name, size, style);
if (font.canDisplay(c)) {
if (font.canDisplay(codePoint)) {
ourUsedFonts.put(new FontKey(name, size, style), font);
ourFontNames.remove(i);
return font;
}
}
ourUndisplayableChars.add(c);
ourUndisplayableChars.add(codePoint);
return ourSharedDefaultFont;
}
@@ -156,12 +156,12 @@ public class FontInfo {
return mySymbolsToBreakDrawingIteration;
}
public boolean canDisplay(char c) {
public boolean canDisplay(int codePoint) {
try {
if (c < 128) return true;
if (mySafeCharacters.contains(c)) return true;
if (canDisplayImpl(c)) {
mySafeCharacters.add(c);
if (codePoint < 128) return true;
if (mySafeCharacters.contains(codePoint)) return true;
if (canDisplayImpl(codePoint)) {
mySafeCharacters.add(codePoint);
return true;
}
return false;
@@ -172,12 +172,13 @@ public class FontInfo {
}
}
private boolean canDisplayImpl(char c) {
private boolean canDisplayImpl(int codePoint) {
if (!Character.isValidCodePoint(codePoint)) return false;
if (USE_ALTERNATIVE_CAN_DISPLAY_PROCEDURE) {
return myFont.createGlyphVector(DUMMY_CONTEXT, new char[]{c}).getGlyphCode(0) > 0;
return myFont.createGlyphVector(DUMMY_CONTEXT, new String(new int[]{codePoint}, 0, 1)).getGlyphCode(0) > 0;
}
else {
return myFont.canDisplay(c);
return myFont.canDisplay(codePoint);
}
}
@@ -187,8 +187,9 @@ abstract class LineLayout {
}
}
@SuppressWarnings("AssignmentToForLoopParameter")
private static void addFragments(BidiRun run, Chunk chunk, char[] text, int start, int end, int fontStyle,
FontPreferences fontPreferences, FontRenderContext fontRenderContext,
FontPreferences fontPreferences, FontRenderContext fontRenderContext,
@Nullable TabFragment tabFragment) {
assert start < end;
FontInfo currentFontInfo = null;
@@ -203,12 +204,22 @@ abstract class LineLayout {
currentIndex = i + 1;
}
else {
FontInfo fontInfo = ComplementaryFontsRegistry.getFontAbleToDisplay(c, fontStyle, fontPreferences);
boolean surrogatePair = false;
int codePoint = c;
if (Character.isHighSurrogate(c) && (i + 1 < end)) {
char nextChar = text[i + 1];
if (Character.isLowSurrogate(nextChar)) {
codePoint = Character.toCodePoint(c, nextChar);
surrogatePair = true;
}
}
FontInfo fontInfo = ComplementaryFontsRegistry.getFontAbleToDisplay(codePoint, fontStyle, fontPreferences);
if (currentFontInfo == null || !fontInfo.getFont().equals(currentFontInfo.getFont())) {
addTextFragmentIfNeeded(chunk, text, currentIndex, i, currentFontInfo, fontRenderContext, run.isRtl());
currentFontInfo = fontInfo;
currentIndex = i;
}
if (surrogatePair) i++;
}
}
addTextFragmentIfNeeded(chunk, text, currentIndex, end, currentFontInfo, fontRenderContext, run.isRtl());