import java.util.HashMap;
import jexer.bits.Cell;
+import jexer.bits.StringUtils;
/**
* GlyphMakerFont creates glyphs as bitmaps from a font.
* @param fontSize the size of font to use
*/
public GlyphMakerFont(final String filename, final int fontSize) {
+
+ if (filename.length() == 0) {
+ // Fallback font
+ font = new Font(Font.MONOSPACED, Font.PLAIN, fontSize - 2);
+ return;
+ }
+
Font fontRoot = null;
try {
ClassLoader loader = Thread.currentThread().getContextClassLoader();
InputStream in = loader.getResourceAsStream(filename);
fontRoot = Font.createFont(Font.TRUETYPE_FONT, in);
- font = fontRoot.deriveFont(Font.PLAIN, fontSize);
+ font = fontRoot.deriveFont(Font.PLAIN, fontSize - 2);
} catch (java.awt.FontFormatException e) {
- e.printStackTrace();
- font = new Font(Font.MONOSPACED, Font.PLAIN, fontSize);
+ // Ideally we would report an error here, either via System.err
+ // or TExceptionDialog. However, I do not want GlyphMaker to
+ // know about available backends, so we quietly fallback to
+ // whatever is available as MONO.
+ font = new Font(Font.MONOSPACED, Font.PLAIN, fontSize - 2);
} catch (java.io.IOException e) {
- e.printStackTrace();
- font = new Font(Font.MONOSPACED, Font.PLAIN, fontSize);
+ // See comment above.
+ font = new Font(Font.MONOSPACED, Font.PLAIN, fontSize - 2);
}
}
getFontDimensions();
}
+ if (DEBUG && !font.canDisplay(cell.getChar())) {
+ System.err.println("font " + font + " has no glyph for " +
+ String.format("0x%x", cell.getChar()));
+ }
+
BufferedImage image = null;
if (cell.isBlink() && !blinkVisible) {
image = glyphCacheBlink.get(cell);
Graphics2D gr2 = image.createGraphics();
gr2.setFont(font);
- Cell cellColor = new Cell();
- cellColor.setTo(cell);
+ Cell cellColor = new Cell(cell);
// Check for reverse
if (cell.isReverse()) {
|| (cell.isBlink() && blinkVisible)
) {
gr2.setColor(SwingTerminal.attrToForegroundColor(cellColor));
- char [] chars = new char[1];
- chars[0] = cell.getChar();
- gr2.drawChars(chars, 0, 1, textAdjustX,
+ char [] chars = Character.toChars(cell.getChar());
+ gr2.drawChars(chars, 0, chars.length, textAdjustX,
cellHeight - maxDescent + textAdjustY);
if (cell.isUnderline()) {
gr2.dispose();
// We need a new key that will not be mutated by invertCell().
- Cell key = new Cell();
- key.setTo(cell);
+ Cell key = new Cell(cell);
if (cell.isBlink() && !blinkVisible) {
glyphCacheBlink.put(key, image);
} else {
glyphCache.put(key, image);
}
+ /*
+ System.err.println("cellWidth " + cellWidth +
+ " cellHeight " + cellHeight + " image " + image);
+ */
+
return image;
}
textHeight = fontTextHeight + textAdjustHeight;
textWidth = fontTextWidth + textAdjustWidth;
+ /*
+ System.err.println("font " + font);
+ System.err.println("fontTextWidth " + fontTextWidth);
+ System.err.println("fontTextHeight " + fontTextHeight);
+ System.err.println("textWidth " + textWidth);
+ System.err.println("textHeight " + textHeight);
+ */
gotFontDimensions = true;
}
+ /**
+ * Checks if this maker's Font has a glyph for the specified character.
+ *
+ * @param codePoint the character (Unicode code point) for which a glyph
+ * is needed.
+ * @return true if this Font has a glyph for the character; false
+ * otherwise.
+ */
+ public boolean canDisplay(final int codePoint) {
+ return font.canDisplay(codePoint);
+ }
}
/**
private static final String MONO = "terminus-ttf-4.39/TerminusTTF-Bold-4.39.ttf";
/**
- * The CJKhk font resource filename.
+ * The CJK font resource filename.
*/
- // private static final String CJKhk = "NotoSansMonoCJKhk-Regular.otf";
+ private static final String cjkFontFilename = "NotoSansMonoCJKtc-Regular.otf";
/**
- * The CJKkr font resource filename.
+ * The emoji font resource filename.
*/
- // private static final String CJKkr = "NotoSansMonoCJKkr-Regular.otf";
+ private static final String emojiFontFilename = "OpenSansEmoji.ttf";
/**
- * The CJKtc font resource filename.
+ * The fallback font resource filename.
*/
- private static final String CJKtc = "NotoSansMonoCJKtc-Regular.otf";
+ private static final String fallbackFontFilename = "";
// ------------------------------------------------------------------------
// Variables --------------------------------------------------------------
private GlyphMakerFont makerMono;
/**
- * The instance that has the CJKhk font.
+ * The instance that has the CJK font.
*/
- // private GlyphMakerFont makerCJKhk;
+ private GlyphMakerFont makerCjk;
/**
- * The instance that has the CJKkr font.
+ * The instance that has the emoji font.
*/
- // private GlyphMakerFont makerCJKkr;
+ private GlyphMakerFont makerEmoji;
/**
- * The instance that has the CJKtc font.
+ * The instance that has the fallback font.
*/
- private GlyphMakerFont makerCJKtc;
+ private GlyphMakerFont makerFallback;
// ------------------------------------------------------------------------
// Constructors -----------------------------------------------------------
*/
private GlyphMaker(final int fontSize) {
makerMono = new GlyphMakerFont(MONO, fontSize);
- // makerCJKhk = new GlyphMakerFont(CJKhk, fontSize);
- // makerCJKkr = new GlyphMakerFont(CJKkr, fontSize);
- makerCJKtc = new GlyphMakerFont(CJKtc, fontSize);
+
+ String fontFilename = null;
+ fontFilename = System.getProperty("jexer.cjkFont.filename",
+ cjkFontFilename);
+ makerCjk = new GlyphMakerFont(fontFilename, fontSize);
+ fontFilename = System.getProperty("jexer.emojiFont.filename",
+ emojiFontFilename);
+ makerEmoji = new GlyphMakerFont(fontFilename, fontSize);
+ fontFilename = System.getProperty("jexer.fallbackFont.filename",
+ fallbackFontFilename);
+ makerFallback = new GlyphMakerFont(fontFilename, fontSize);
}
// ------------------------------------------------------------------------
public BufferedImage getImage(final Cell cell, final int cellWidth,
final int cellHeight, final boolean blinkVisible) {
- char ch = cell.getChar();
- /*
- if ((ch >= 0x4e00) && (ch <= 0x9fff)) {
- return makerCJKhk.getImage(cell, cellWidth, cellHeight, blinkVisible);
- }
- if ((ch >= 0x4e00) && (ch <= 0x9fff)) {
- return makerCJKkr.getImage(cell, cellWidth, cellHeight, blinkVisible);
+ int ch = cell.getChar();
+ if (StringUtils.isCjk(ch)) {
+ if (makerCjk.canDisplay(ch)) {
+ return makerCjk.getImage(cell, cellWidth, cellHeight,
+ blinkVisible);
+ }
}
- */
- if ((ch >= 0x2e80) && (ch <= 0x9fff)) {
- return makerCJKtc.getImage(cell, cellWidth, cellHeight, blinkVisible);
+ if (StringUtils.isEmoji(ch)) {
+ if (makerEmoji.canDisplay(ch)) {
+ // System.err.println("emoji: " + String.format("0x%x", ch));
+ return makerEmoji.getImage(cell, cellWidth, cellHeight,
+ blinkVisible);
+ }
}
// When all else fails, use the default.
- return makerMono.getImage(cell, cellWidth, cellHeight, blinkVisible);
+ if (makerMono.canDisplay(ch)) {
+ return makerMono.getImage(cell, cellWidth, cellHeight,
+ blinkVisible);
+ }
+
+ return makerFallback.getImage(cell, cellWidth, cellHeight,
+ blinkVisible);
}
}