diff --git a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java index ec3cb318914c..fa0f805fa22d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java @@ -73,6 +73,8 @@ import org.picocontainer.MutablePicoContainer; import javax.swing.*; import java.awt.*; +import java.io.BufferedInputStream; +import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Method; diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java index 9179a8ce4f7d..4e0e3c1d6ff9 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java @@ -2628,6 +2628,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi int myCount = 0; @NotNull final FontInfo myFontType; + final boolean myHasBreakSymbols; final int spaceWidth; @Nullable private char[] myLastData; @@ -2635,6 +2636,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi private CachedFontContent(@NotNull FontInfo fontInfo) { myFontType = fontInfo; spaceWidth = fontInfo.charWidth(' ', myEditorComponent); + myHasBreakSymbols = fontInfo.hasGlyphsToBreakDrawingIteration(); } private void flushContent(@NotNull Graphics g) { @@ -2666,7 +2668,8 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi final int lastCount = count - 1; final Color lastColor = color[lastCount]; if (_data == myLastData && _start == ends[lastCount] && (_color == null || lastColor == null || _color.equals(lastColor)) - && _y == y[lastCount] /* there is a possible case that vertical position is adjusted because of soft wrap */) + && _y == y[lastCount] /* there is a possible case that vertical position is adjusted because of soft wrap */ + && (!myHasBreakSymbols || !myFontType.getSymbolsToBreakDrawingIteration().contains(_data[ends[lastCount] - 1]))) { ends[lastCount] = _end; if (lastColor == null) color[lastCount] = _color; @@ -3054,6 +3057,12 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi myForceRefreshFont = true; } endX += charWidth; + + if (newFont.hasGlyphsToBreakDrawingIteration() && newFont.getSymbolsToBreakDrawingIteration().contains(c)) { + drawCharsCached(g, text, start, j + 1, x, y, fontType, fontColor); + x = endX; + start = j + 1; + } } if (!(x < clip.x && endX < clip.x || x > clip.x + clip.width && endX > clip.x + clip.width)) { 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 9aaafa8a07b9..c7f7cbdc8d1c 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 @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,14 +17,21 @@ package com.intellij.openapi.editor.impl; import gnu.trove.TIntHashSet; import org.intellij.lang.annotations.JdkConstants; +import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.awt.*; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.image.BufferedImage; /** * @author max */ public class FontInfo { + + private final TIntHashSet mySymbolsToBreakDrawingIteration = new TIntHashSet(); + private final String myFamilyName; private final Font myFont; private final int mySize; @@ -32,12 +39,63 @@ public class FontInfo { private final TIntHashSet mySafeCharacters = new TIntHashSet(); private FontMetrics myFontMetrics = null; private final int[] charWidth = new int[128]; + private final boolean myHasGlyphsToBreakDrawingIteration; public FontInfo(final String familyName, final int size, @JdkConstants.FontStyle int style) { myFamilyName = familyName; mySize = size; myStyle = style; myFont = new Font(familyName, style, size); + + parseProblemGlyphs(); + myHasGlyphsToBreakDrawingIteration = !mySymbolsToBreakDrawingIteration.isEmpty(); + } + + private void parseProblemGlyphs() { + BufferedImage buffer = new BufferedImage(20, 20, BufferedImage.TYPE_INT_RGB); + final Graphics graphics = buffer.getGraphics(); + if (!(graphics instanceof Graphics2D)) { + return; + } + final FontRenderContext context = ((Graphics2D)graphics).getFontRenderContext(); + char[] charBuffer = new char[1]; + for (char c = 0; c < 128; c++) { + if (!myFont.canDisplay(c)) { + continue; + } + charBuffer[0] = c; + final GlyphVector vector = myFont.createGlyphVector(context, charBuffer); + final float y = vector.getGlyphMetrics(0).getAdvanceY(); + if (Math.round(y) != 0) { + mySymbolsToBreakDrawingIteration.add(c); + } + } + } + + /** + * We've experienced a problem that particular symbols from particular font are represented really weird + * by the IJ editor (IDEA-83645). + *

+ * Eventually it was found out that outline font glyphs can have a 'y advance', i.e. instruction on how the subsequent + * glyphs location should be adjusted after painting the current glyph. In terms of java that means that such a problem + * glyph should be the last symbol at the {@link Graphics#drawChars(char[], int, int, int, int) text drawing iteration}. + *

+ * Hopefully, such glyphs are exceptions from the normal processing, so, this method allows to answer whether a font + * {@link #getFont() referenced} by the current object has such a glyph. + * + * @return true if the {@link #getFont() target font} has problem glyphs; false otherwise + */ + public boolean hasGlyphsToBreakDrawingIteration() { + return myHasGlyphsToBreakDrawingIteration; + } + + /** + * @return unicode symbols which glyphs {@link #hasGlyphsToBreakDrawingIteration() have problems} + * at the {@link #getFont() target font}. + */ + @NotNull + public TIntHashSet getSymbolsToBreakDrawingIteration() { + return mySymbolsToBreakDrawingIteration; } public boolean canDisplay(char c) {