Permalink
Browse files

Fix some issues with double width characters and emoji rendering

  • Loading branch information...
mikehearn committed May 19, 2017
1 parent e254a86 commit 331a005d6793e52cefc9e2cec6774e62d5a546b1
@@ -1048,17 +1048,26 @@ public void fillScreen(final char c) {
@NotNull
private CharBuffer newCharBuf(char[] str) {
int wdcCount = CharUtils.countDoubleWidthCharacters(str, 0, str.length, myDisplay.ambiguousCharsAreDoubleWidth());
int dwcCount = CharUtils.countDoubleWidthCharacters(str, 0, str.length, myDisplay.ambiguousCharsAreDoubleWidth());
char[] buf;
if (wdcCount > 0) {
buf = new char[wdcCount * 2 + str.length - wdcCount];
if (dwcCount > 0) {
// Leave gaps for the private use "DWC" character, which simply tells the rendering code to advance one cell.
buf = new char[str.length + dwcCount];
int j = 0;
for (int i = 0; i < str.length; i++) {
buf[j] = str[i];
if (CharUtils.isDoubleWidthCharacter(str[i], myDisplay.ambiguousCharsAreDoubleWidth())) {
int codePoint = Character.codePointAt(str, i);
boolean doubleWidthCharacter = CharUtils.isDoubleWidthCharacter(codePoint, myDisplay.ambiguousCharsAreDoubleWidth());
if (Character.charCount(Character.codePointAt(str, i)) == 2) {
// Copy the next character too before adding the DWC.
i++;
j++;
buf[j] = str[i];
}
if (doubleWidthCharacter) {
j++;
buf[j] = CharUtils.DWC;
}
@@ -660,7 +660,9 @@ private void establishFontMetrics() {
myDescent = fo.getDescent();
myCharSize.width = fo.charWidth('W');
myCharSize.height = fo.getHeight() + (int) (lineSpace * 2);
// The magic +2 here is to give lines a tiny bit of extra height to avoid clipping when rendering some Apple
// emoji, which are slightly higher than the font metrics reported character height :(
myCharSize.height = fo.getHeight() + (int) (lineSpace * 2) + 2;
myDescent += lineSpace;
myMonospaced = isMonospaced(fo);
@@ -1189,8 +1191,8 @@ private void drawChars(int x, int y, CharBuffer buf, TextStyle style, Graphics2D
gfx.setClip(xCoord,
yCoord,
Math.min(textLength * myCharSize.width, getWidth() - xCoord),
Math.min(myCharSize.height, getHeight() - yCoord));
getWidth() - xCoord,
getHeight() - yCoord);
gfx.setColor(getPalette().getColor(myStyleState.getForeground(style.getForegroundForRun())));
@@ -1,11 +1,10 @@
package com.jediterm.terminal.util;
import com.google.common.base.Ascii;
import com.google.common.base.CharMatcher;
import com.jediterm.terminal.emulator.charset.CharacterSets;
import com.jediterm.terminal.model.CharBuffer;
import com.google.common.base.*;
import com.jediterm.terminal.emulator.charset.*;
import com.jediterm.terminal.model.*;
import java.util.Arrays;
import java.util.*;
/**
* @author traff
@@ -54,7 +53,8 @@ public static String getNonControlCharacters(int maxChars, char[] buf, int offse
public static int countDoubleWidthCharacters(char[] buf, int start, int length, boolean ambiguousIsDWC) {
int cnt = 0;
for (int i = 0; i < length; i++) {
if (isDoubleWidthCharacter(buf[i + start], ambiguousIsDWC)) {
int ucs = Character.codePointAt(buf, i + start);
if (isDoubleWidthCharacter(ucs, ambiguousIsDWC)) {
cnt++;
}
}
@@ -106,15 +106,6 @@ public static void appendBuf(final StringBuilder sb, final char[] bs, final int
return bytes;
}
public static boolean hasDoubleWidthChar(char[] buffer, int start, int length, boolean ambiguousIsDWC) {
for (int i = start; i < start + length; i++) {
if (isDoubleWidthCharacter(buffer[i], false)) {
return true;
}
}
return false;
}
/**
* Computes text length as sum of characters length, treating double-width(full-width) characters as 2, normal-width(half-width) as 1
* (Read http://en.wikipedia.org/wiki/Halfwidth_and_fullwidth_forms)
@@ -127,9 +118,8 @@ public static int getTextLengthDoubleWidthAware(char[] buffer, int start, int le
return result;
}
public static boolean isDoubleWidthCharacter(char c, boolean ambiguousIsDWC) {
if (c == DWC || c <= 0xa0 ||
(c > 0x452 && c < 0x1100)) {
public static boolean isDoubleWidthCharacter(int c, boolean ambiguousIsDWC) {
if (c == DWC || c <= 0xa0 || (c > 0x452 && c < 0x1100)) {
return false;
}
@@ -271,7 +261,7 @@ else if (ucs < table[mid][0])
return 0;
}
private static int mk_wcwidth(char ucs, boolean ambiguousIsDoubleWidth) {
private static int mk_wcwidth(int ucs, boolean ambiguousIsDoubleWidth) {
/* sorted list of non-overlapping intervals of non-spacing characters */
/* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */
@@ -282,14 +272,14 @@ private static int mk_wcwidth(char ucs, boolean ambiguousIsDoubleWidth) {
return -1;
if (ambiguousIsDoubleWidth) {
if (bisearch(ucs, AMBIGUOUS, AMBIGUOUS.length-1) > 0) {
if (bisearch((char)ucs, AMBIGUOUS, AMBIGUOUS.length-1) > 0) {
return 2;
}
}
/* binary search in table of non-spacing characters */
if (bisearch(ucs, COMBINING, COMBINING.length-1) > 0) {
if (bisearch((char)ucs, COMBINING, COMBINING.length-1) > 0) {
return 0;
}
@@ -298,6 +288,7 @@ private static int mk_wcwidth(char ucs, boolean ambiguousIsDoubleWidth) {
return 1 +
((ucs >= 0x1100 &&
(ucs <= 0x115f || /* Hangul Jamo init. consonants */
isEmoji(ucs) ||
ucs == 0x2329 || ucs == 0x232a ||
(ucs >= 0x2e80 && ucs <= 0xa4cf &&
ucs != 0x303f) || /* CJK ... Yi */
@@ -310,5 +301,21 @@ private static int mk_wcwidth(char ucs, boolean ambiguousIsDoubleWidth) {
(ucs >= 0x20000 && ucs <= 0x2fffd) ||
(ucs >= 0x30000 && ucs <= 0x3fffd))) ? 1 : 0);
}
private static boolean isEmoji(int ucs) {
// There is still more work to do here in order to support the flags, which use combining characters.
Character.UnicodeBlock block = Character.UnicodeBlock.of(ucs);
return (block != null) && (
block.equals(Character.UnicodeBlock.DINGBATS) ||
block.equals(Character.UnicodeBlock.ENCLOSED_ALPHANUMERICS) ||
block.equals(Character.UnicodeBlock.ENCLOSED_ALPHANUMERIC_SUPPLEMENT) ||
block.equals(Character.UnicodeBlock.MISCELLANEOUS_SYMBOLS) ||
block.equals(Character.UnicodeBlock.MISCELLANEOUS_SYMBOLS_AND_ARROWS) ||
block.equals(Character.UnicodeBlock.MISCELLANEOUS_SYMBOLS_AND_PICTOGRAPHS) ||
block.equals(Character.UnicodeBlock.MISCELLANEOUS_TECHNICAL) ||
block.equals(Character.UnicodeBlock.ARROWS) ||
block.equals(Character.UnicodeBlock.SUPPLEMENTAL_ARROWS_A) ||
block.equals(Character.UnicodeBlock.SUPPLEMENTAL_ARROWS_B)
);
}
}

0 comments on commit 331a005

Please sign in to comment.