diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/ComplementaryFontsRegistry.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/ComplementaryFontsRegistry.java index 2a68653c0711..2d0960addf24 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/ComplementaryFontsRegistry.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/ComplementaryFontsRegistry.java @@ -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 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[] 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 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; } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/FontInfo.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/FontInfo.java index 5bc60cadfc42..f1c212b1ea6c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/FontInfo.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/FontInfo.java @@ -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); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/LineLayout.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/LineLayout.java index 1fde3b7d05a5..a53255ae8a64 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/LineLayout.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/LineLayout.java @@ -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());