+ /**
+ * 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);
+ }
+}
+
+/**
+ * GlyphMaker presents unified interface to all of its supported fonts to
+ * clients.
+ */
+public class GlyphMaker {
+
+ // ------------------------------------------------------------------------
+ // Constants --------------------------------------------------------------
+ // ------------------------------------------------------------------------
+
+ /**
+ * The mono font resource filename (terminus).
+ */
+ private static final String MONO = "terminus-ttf-4.39/TerminusTTF-Bold-4.39.ttf";
+
+ /**
+ * The CJK font resource filename.
+ */
+ private static final String cjkFontFilename = "NotoSansMonoCJKtc-Regular.otf";
+
+ /**
+ * The emoji font resource filename.
+ */
+ private static final String emojiFontFilename = "OpenSansEmoji.ttf";
+
+ /**
+ * The fallback font resource filename.
+ */
+ private static final String fallbackFontFilename = "";
+
+ // ------------------------------------------------------------------------
+ // Variables --------------------------------------------------------------
+ // ------------------------------------------------------------------------
+
+ /**
+ * If true, enable debug messages.
+ */
+ private static boolean DEBUG = false;
+
+ /**
+ * Cache of font bundles by size.
+ */
+ private static HashMap<Integer, GlyphMaker> makers = new HashMap<Integer, GlyphMaker>();
+
+ /**
+ * The instance that has the mono (default) font.
+ */
+ private GlyphMakerFont makerMono;
+
+ /**
+ * The instance that has the CJK font.
+ */
+ private GlyphMakerFont makerCjk;
+
+ /**
+ * The instance that has the emoji font.
+ */
+ private GlyphMakerFont makerEmoji;
+
+ /**
+ * The instance that has the fallback font.
+ */
+ private GlyphMakerFont makerFallback;
+
+ // ------------------------------------------------------------------------
+ // Constructors -----------------------------------------------------------
+ // ------------------------------------------------------------------------
+
+ /**
+ * Create an instance with references to the necessary fonts.
+ *
+ * @param fontSize the size of these fonts in pixels
+ */
+ private GlyphMaker(final int fontSize) {
+ makerMono = new GlyphMakerFont(MONO, 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);
+ }
+
+ // ------------------------------------------------------------------------
+ // GlyphMaker -------------------------------------------------------------
+ // ------------------------------------------------------------------------
+
+ /**
+ * Obtain the GlyphMaker instance for a particular font size.
+ *
+ * @param fontSize the size of these fonts in pixels
+ * @return the instance
+ */
+ public static GlyphMaker getInstance(final int fontSize) {
+ synchronized (GlyphMaker.class) {
+ GlyphMaker maker = makers.get(fontSize);
+ if (maker == null) {
+ maker = new GlyphMaker(fontSize);
+ makers.put(fontSize, maker);
+ }
+ return maker;
+ }
+ }
+
+ /**
+ * Get a glyph image.
+ *
+ * @param cell the character to draw
+ * @param cellWidth the width of the text cell to draw into
+ * @param cellHeight the height of the text cell to draw into
+ * @return the glyph as an image
+ */
+ public BufferedImage getImage(final Cell cell, final int cellWidth,
+ final int cellHeight) {
+
+ return getImage(cell, cellWidth, cellHeight, true);
+ }
+
+ /**
+ * Get a glyph image.
+ *
+ * @param cell the character to draw
+ * @param cellWidth the width of the text cell to draw into
+ * @param cellHeight the height of the text cell to draw into
+ * @param blinkVisible if true, the cell is visible if it is blinking
+ * @return the glyph as an image
+ */
+ public BufferedImage getImage(final Cell cell, final int cellWidth,
+ final int cellHeight, final boolean blinkVisible) {
+
+ int ch = cell.getChar();
+ if (StringUtils.isCjk(ch)) {
+ if (makerCjk.canDisplay(ch)) {
+ return makerCjk.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.
+ if (makerMono.canDisplay(ch)) {
+ return makerMono.getImage(cell, cellWidth, cellHeight,
+ blinkVisible);
+ }
+
+ return makerFallback.getImage(cell, cellWidth, cellHeight,
+ blinkVisible);
+ }
+