summaryrefslogtreecommitdiff
path: root/console-client/vga-dynafont.c
diff options
context:
space:
mode:
authorMarcus Brinkmann <marcus@gnu.org>2002-09-17 12:26:10 +0000
committerMarcus Brinkmann <marcus@gnu.org>2002-09-17 12:26:10 +0000
commit09e69605b16070de8ce317d86ad736d665a58906 (patch)
tree7c0dc29f4fc660a44d2f7d6ec9d099cc4f8301a6 /console-client/vga-dynafont.c
parentdbe4c7712b652b7ad3126e94c47b00fa2bbb0a05 (diff)
2002-09-17 Marcus Brinkmann <marcus@gnu.org>
* Makefile (prog-subdirs): Add console-client. sutils/ 2002-09-17 Marcus Brinkmann <marcus@gnu.org> * MAKEDEV.sh (mkdev: vcs): New console device. (mkdev: tty[0-9a-f]|tty[0-9][0-9a-f]): Replaced with new rules for tty[1-9][0-9]. utils/ 2002-09-17 Marcus Brinkmann <marcus@gnu.org> * console-ncurses.c: File removed (the ncursesw console client is now a driver in the console-client). * Makefile: Revert 2002-08-22 change: Do not include`../config.make'. (targets) [LIBNCURSES]: Removed. (SRCS) [LIBNCURSES]: Likewise. (HURDLIBS) [LIBNCURSES]: Likewise. (console-ncurses): Target removed. (console-ncurses-CPPFLAGS): Removed. (console-ncurses-LDLIBS): Likewise. console-client/ 2002-09-17 Marcus Brinkmann <marcus@gnu.org> * Makefile, bdf.c, bdf.h, bell.h, console.c, display.h, driver.c, driver.h, generic-speaker.c, input.h, pc-kbd.c, timer.c, timer.h, unicode.h, vga.c, vga-dynacolor.c, vga-dynacolor.h, vga-dynafont.c, vga-dynafont.h, vga-hw.h, vga-support.c, vga-support.h: New file.
Diffstat (limited to 'console-client/vga-dynafont.c')
-rw-r--r--console-client/vga-dynafont.c1047
1 files changed, 1047 insertions, 0 deletions
diff --git a/console-client/vga-dynafont.c b/console-client/vga-dynafont.c
new file mode 100644
index 00000000..0df28df1
--- /dev/null
+++ b/console-client/vga-dynafont.c
@@ -0,0 +1,1047 @@
+/* vga-dynafont.c - Dynamic font handling for VGA cards.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <assert.h>
+#include <malloc.h>
+#include <wchar.h>
+#include <stdlib.h>
+#include <hurd/ihash.h>
+#include <string.h>
+
+#include <hurd/console.h>
+#include "vga-hw.h"
+#include "vga-support.h"
+#include "bdf.h"
+#include "vga-dynafont.h"
+#include "unicode.h"
+
+
+/* The currently active (visible) dynafont. The original idea was to
+ use some sort of caching for multiple dynafonts using the 8 font
+ buffers on the graphic card, but the new idea is to share a common
+ state among all virtual consoles and do a full refresh on
+ switching. However, bits and pieces of the old idea are still
+ present, in case they become useful. */
+static dynafont_t active_dynafont;
+
+
+/* One glyph in a VGA font is 8 pixels wide and 32 pixels high. Only
+ the first N lines are visible, and N depends on the VGA register
+ settings. */
+typedef char vga_font_glyph[VGA_FONT_HEIGHT];
+
+
+/* For each glyph in the VGA font, one instance of this structure is
+ held in the dynafont. */
+struct mapped_character
+{
+ /* Reference count of the mapped character. If this drops zero, we
+ can remove the mapping at any time. */
+ int refs;
+
+ /* Remember the character this glyph belongs to, so the glyph can be
+ reloaded when the font is changed. This is actually a wchar_t
+ with some text attributes mixed into the high bits. */
+#define WCHAR_BOLD ((wchar_t) 0x40000000)
+#define WCHAR_ITALIC ((wchar_t) 0x20000000)
+#define WCHAR_MASK ((wchar_t) 0x001fffff)
+ wchar_t character;
+
+ /* Used by libihash for fast removal of elements. */
+ void **locp;
+};
+
+
+struct dynafont
+{
+ /* The sorted font to take the glyphs from. */
+ bdf_font_t font;
+
+ /* The sorted font to take the italic glyphs from. */
+ bdf_font_t font_italic;
+
+ /* The sorted font to take the bold glyphs from. */
+ bdf_font_t font_bold;
+
+ /* The sorted font to take the bold and italic glyphs from. */
+ bdf_font_t font_bold_italic;
+
+ /* The size of the VGA font (256 or 512). Must be a power of 2! */
+ int size;
+
+ /* A hash containing a pointer to a struct mapped_character for each
+ UCS-4 character we map to a VGA font index. */
+ ihash_t charmap;
+
+ /* The struct mapped_characters are preallocated for all vga font
+ index values. This points to an array of SIZE such elements. */
+ struct mapped_character *charmap_data;
+
+ /* The last vga font index that had been free (or could be
+ reused). */
+ int vga_font_last_free_index;
+
+ /* The number of free slots in the VGA font. */
+ int vga_font_free_indices;
+
+ int use_lgc;
+
+ /* The last vga font index that had been free (or could be reused)
+ for horizontal line graphic characters. */
+ int vga_font_last_free_index_lgc;
+
+ /* The number of free slots in the VGA font for horizontal line
+ graphic charactes. */
+ int vga_font_free_indices_lgc;
+
+ /* The font memory as stored on the card. */
+ vga_font_glyph *vga_font;
+
+ /* The cursor size, standout or normal. */
+ int cursor_standout;
+};
+
+
+/* The VGA standard font follows IBM code page 437. The following
+ table maps this to unicode. For simplicity, a 1:1 mapping is
+ assumed. Ambiguities are special cased in create_system_font. */
+static
+wchar_t ibm437_to_unicode[VGA_FONT_SIZE] = {
+ 0, /* 0x00 */
+ UNICODE_WHITE_SMILING_FACE, /* 0x01 */
+ UNICODE_BLACK_SMILING_FACE, /* 0x02 */
+ UNICODE_BLACK_HEART_SUIT, /* 0x03 */
+ UNICODE_BLACK_DIAMOND_SUIT, /* 0x04 */
+ UNICODE_BLACK_CLUB_SUIT, /* 0x05 */
+ UNICODE_BLACK_SPADE_SUIT, /* 0x06 */
+ UNICODE_BULLET, /* 0x07 */
+ UNICODE_INVERSE_BULLET, /* 0x08 */
+ UNICODE_WHITE_CIRCLE, /* 0x09 */
+ UNICODE_INVERSE_WHITE_CIRCLE, /* 0x0a */
+ UNICODE_MALE_SIGN, /* 0x0b */
+ UNICODE_FEMALE_SIGN, /* 0x0c */
+ UNICODE_EIGHTH_NOTE, /* 0x0d */
+ UNICODE_BEAMED_EIGHTH_NOTES, /* 0x0e */
+ UNICODE_WHITE_SUN_WITH_RAYS, /* 0x0f */
+ UNICODE_BLACK_RIGHT_POINTING_TRIANGLE, /* 0x10 */
+ UNICODE_BLACK_LEFT_POINTING_TRIANGLE, /* 0x11 */
+ UNICODE_UP_DOWN_ARROW, /* 0x12 */
+ UNICODE_DOUBLE_EXCLAMATION_MARK, /* 0x13 */
+ UNICODE_PILCROW_SIGN, /* 0x14 */
+ UNICODE_SECTION_SIGN, /* 0x15 */
+ UNICODE_BLACK_RECTANGLE, /* 0x16 */
+ UNICODE_UP_DOWN_ARROW_WITH_BASE, /* 0x17 */
+ UNICODE_UPWARDS_ARROW, /* 0x18 */
+ UNICODE_DOWNWARDS_ARROW, /* 0x19 */
+ UNICODE_RIGHTWARDS_ARROW, /* 0x1a */
+ UNICODE_LEFTWARDS_ARROW, /* 0x1b */
+ UNICODE_RIGHT_ANGLE, /* 0x1c */
+ UNICODE_LEFT_RIGHT_ARROW, /* 0x1d */
+ UNICODE_BLACK_UP_POINTING_TRIANGLE, /* 0x1e */
+ UNICODE_BLACK_DOWN_POINTING_TRIANGLE, /* 0x1f */
+ ' ', '!', '"', '#', '$', '%', '&', '\'', /* 0x20 - 0x27 */
+ '(', ')', '*', '+', ',', '-', '.', '/', /* 0x28 - 0x2f */
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', /* 0x30 - 0x37 */
+ ':', ';', '<', '=', '>', '?', /* 0x38 - 0x3f */
+ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* 0x40 - 0x47 */
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', /* 0x48 - 0x4f */
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', /* 0x50 - 0x57 */
+ 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', /* 0x58 - 0x5f */
+ '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', /* 0x60 - 0x67 */
+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', /* 0x68 - 0x6f */
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', /* 0x70 - 0x77 */
+ 'x', 'y', 'z', '{', '|', '}', '~', UNICODE_HOUSE, /* 0x78 - 0x7f */
+ UNICODE_LATIN_CAPITAL_LETTER_C_WITH_CEDILLA, /* 0x80 */
+ UNICODE_LATIN_SMALL_LETTER_U_WITH_DIARESIS, /* 0x81 */
+ UNICODE_LATIN_SMALL_LETTER_E_WITH_ACUTE, /* 0x82 */
+ UNICODE_LATIN_SMALL_LETTER_A_WITH_CIRCUMFLEX, /* 0x83 */
+ UNICODE_LATIN_SMALL_LETTER_A_WITH_DIARESIS, /* 0x84 */
+ UNICODE_LATIN_SMALL_LETTER_A_WITH_GRAVE, /* 0x85 */
+ UNICODE_LATIN_SMALL_LETTER_A_WITH_RING_ABOVE, /* 0x86 */
+ UNICODE_LATIN_SMALL_LETTER_C_WITH_CEDILLA, /* 0x87 */
+ UNICODE_LATIN_SMALL_LETTER_E_WITH_CIRCUMFLEX, /* 0x88 */
+ UNICODE_LATIN_SMALL_LETTER_E_WITH_DIARESIS, /* 0x89 */
+ UNICODE_LATIN_SMALL_LETTER_E_WITH_GRAVE, /* 0x8a */
+ UNICODE_LATIN_SMALL_LETTER_I_WITH_DIARESIS, /* 0x8b */
+ UNICODE_LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX, /* 0x8c */
+ UNICODE_LATIN_SMALL_LETTER_I_WITH_GRAVE, /* 0x8d */
+ UNICODE_LATIN_CAPITAL_LETTER_A_WITH_DIARESIS, /* 0x8e */
+ UNICODE_LATIN_CAPITAL_LETTER_A_WITH_RING_ABOVE, /* 0x8f */
+ UNICODE_LATIN_CAPITAL_LETTER_E_WITH_ACUTE, /* 0x90 */
+ UNICODE_LATIN_SMALL_LETTER_AE, /* 0x91 */
+ UNICODE_LATIN_CAPITAL_LETTER_AE, /* 0x92 */
+ UNICODE_LATIN_SMALL_LETTER_O_WITH_CIRCUMFLEX, /* 0x93 */
+ UNICODE_LATIN_SMALL_LETTER_O_WITH_DIARESIS, /* 0x94 */
+ UNICODE_LATIN_SMALL_LETTER_O_WITH_GRAVE, /* 0x95 */
+ UNICODE_LATIN_SMALL_LETTER_U_WITH_CIRCUMFLEX, /* 0x96 */
+ UNICODE_LATIN_SMALL_LETTER_U_WITH_GRAVE, /* 0x97 */
+ UNICODE_LATIN_SMALL_LETTER_Y_WITH_DIARESIS, /* 0x98 */
+ UNICODE_LATIN_CAPITAL_LETTER_O_WITH_DIARESIS, /* 0x99 */
+ UNICODE_LATIN_CAPITAL_LETTER_U_WITH_DIARESIS, /* 0x9a */
+ UNICODE_CENT_SIGN, /* 0x9b */
+ UNICODE_POUND_SIGN, /* 0x9c */
+ UNICODE_YEN_SIGN, /* 0x9d */
+ UNICODE_PESETA_SIGN, /* 0x9e */
+ UNICODE_LATIN_SMALL_LETTER_F_WITH_HOOK, /* 0x9f */
+ UNICODE_LATIN_SMALL_LETTER_A_WITH_ACUTE, /* 0xa0 */
+ UNICODE_LATIN_SMALL_LETTER_I_WITH_ACUTE, /* 0xa1 */
+ UNICODE_LATIN_SMALL_LETTER_O_WITH_ACUTE, /* 0xa2 */
+ UNICODE_LATIN_SMALL_LETTER_U_WITH_ACUTE, /* 0xa3 */
+ UNICODE_LATIN_SMALL_LETTER_N_WITH_TILDE, /* 0xa4 */
+ UNICODE_LATIN_CAPITAL_LETTER_N_WITH_TILDE, /* 0xa5 */
+ UNICODE_FEMININE_ORDINAL_INDICATOR, /* 0xa6 */
+ UNICODE_MASCULINE_ORDINAL_INDICATOR, /* 0xa7 */
+ UNICODE_INVERTED_QUESTION_MARK, /* 0xa8 */
+ UNICODE_REVERSED_NOT_SIGN, /* 0xa9 */
+ UNICODE_NOT_SIGN, /* 0xaa */
+ UNICODE_VULGAR_FRACTION_ONE_HALF, /* 0xab */
+ UNICODE_VULGAR_FRACTION_ONE_QUARTER, /* 0xac */
+ UNICODE_INVERTED_EXCLAMATION_MARK, /* 0xad */
+ UNICODE_LEFT_POINTING_DOUBLE_ANGLE_QUOTATION_MARK, /* 0xae */
+ UNICODE_RIGHT_POINTING_DOUBLE_ANGLE_QUOTATION_MARK, /* 0xaf */
+ UNICODE_LIGHT_SHADE, /* 0xb0 */
+ UNICODE_MEDIUM_SHADE, /* 0xb1 */
+ UNICODE_DARK_SHADE, /* 0xb2 */
+ UNICODE_BOX_DRAWINGS_LIGHT_VERTICAL, /* 0xb3 */
+ UNICODE_BOX_DRAWINGS_LIGHT_VERTICAL_AND_LEFT, /* 0xb4 */
+ UNICODE_BOX_DRAWINGS_VERTICAL_SINGLE_AND_LEFT_DOUBLE, /* 0xb5 */
+ UNICODE_BOX_DRAWINGS_VERTICAL_DOUBLE_AND_LEFT_SINGLE, /* 0xb6 */
+ UNICODE_BOX_DRAWINGS_DOWN_DOUBLE_AND_LEFT_SINGLE, /* 0xb7 */
+ UNICODE_BOX_DRAWINGS_DOWN_SINGLE_AND_LEFT_DOUBLE, /* 0xb8 */
+ UNICODE_BOX_DRAWINGS_DOUBLE_VERTICAL_AND_LEFT, /* 0xb9 */
+ UNICODE_BOX_DRAWINGS_DOUBLE_VERTICAL, /* 0xba */
+ UNICODE_BOX_DRAWINGS_DOUBLE_DOWN_AND_LEFT, /* 0xbb */
+ UNICODE_BOX_DRAWINGS_DOUBLE_UP_AND_LEFT, /* 0xbc */
+ UNICODE_BOX_DRAWINGS_UP_DOUBLE_AND_LEFT_SINGLE, /* 0xbd */
+ UNICODE_BOX_DRAWINGS_UP_SINGLE_AND_LEFT_DOUBLE, /* 0xbe */
+ UNICODE_BOX_DRAWINGS_LIGHT_DOWN_AND_LEFT, /* 0xbf */
+ UNICODE_BOX_DRAWINGS_LIGHT_UP_AND_RIGHT, /* 0xc0 */
+ UNICODE_BOX_DRAWINGS_LIGHT_UP_AND_HORIZONTAL, /* 0xc1 */
+ UNICODE_BOX_DRAWINGS_LIGHT_DOWN_AND_HORIZONTAL, /* 0xc2 */
+ UNICODE_BOX_DRAWINGS_LIGHT_VERTICAL_AND_RIGHT, /* 0xc3 */
+ UNICODE_BOX_DRAWINGS_LIGHT_HORIZONTAL, /* 0xc4 */
+ UNICODE_BOX_DRAWINGS_LIGHT_VERTICAL_AND_HORIZONTAL, /* 0xc5 */
+ UNICODE_BOX_DRAWINGS_VERTICAL_SINGLE_AND_RIGHT_DOUBLE, /* 0xc6 */
+ UNICODE_BOX_DRAWINGS_VERTICAL_DOUBLE_AND_RIGHT_SINGLE, /* 0xc7 */
+ UNICODE_BOX_DRAWINGS_DOUBLE_UP_AND_RIGHT, /* 0xc8 */
+ UNICODE_BOX_DRAWINGS_DOUBLE_DOWN_AND_RIGHT, /* 0xc9 */
+ UNICODE_BOX_DRAWINGS_DOUBLE_UP_AND_HORIZONTAL, /* 0xca */
+ UNICODE_BOX_DRAWINGS_DOUBLE_DOWN_AND_HORIZONTAL, /* 0xcb */
+ UNICODE_BOX_DRAWINGS_DOUBLE_VERTICAL_AND_RIGHT, /* 0xcc */
+ UNICODE_BOX_DRAWINGS_DOUBLE_HORIZONTAL, /* 0xcd */
+ UNICODE_BOX_DRAWINGS_DOUBLE_VERTICAL_AND_HORIZONTAL,/* 0xce */
+ UNICODE_BOX_DRAWINGS_UP_SINGLE_AND_HORIZONTAL_DOUBLE, /* 0xcf */
+ UNICODE_BOX_DRAWINGS_UP_DOUBLE_AND_HORIZONTAL_SINGLE, /* 0xd0 */
+ UNICODE_BOX_DRAWINGS_DOWN_SINGLE_AND_HORIZONTAL_DOUBLE, /* 0xd1 */
+ UNICODE_BOX_DRAWINGS_DOWN_DOUBLE_AND_HORIZONTAL_SINGLE, /* 0xd2 */
+ UNICODE_BOX_DRAWINGS_UP_DOUBLE_AND_RIGHT_SINGLE, /* 0xd3 */
+ UNICODE_BOX_DRAWINGS_UP_SINGLE_AND_RIGHT_DOUBLE, /* 0xd4 */
+ UNICODE_BOX_DRAWINGS_DOWN_SINGLE_AND_RIGHT_DOUBLE, /* 0xd5 */
+ UNICODE_BOX_DRAWINGS_DOWN_DOUBLE_AND_RIGHT_SINGLE, /* 0xd6 */
+ UNICODE_BOX_DRAWINGS_VERTICAL_DOUBLE_AND_HORIZONTAL_SINGLE, /* 0xd7 */
+ UNICODE_BOX_DRAWINGS_VERTICAL_SINGLE_AND_HORIZONTAL_DOUBLE, /* 0xd8 */
+ UNICODE_BOX_DRAWINGS_LIGHT_UP_AND_LEFT, /* 0xd9 */
+ UNICODE_BOX_DRAWINGS_LIGHT_DOWN_AND_RIGHT, /* 0xda */
+ UNICODE_FULL_BLOCK, /* 0xdb */
+ UNICODE_LOWER_HALF_BLOCK, /* 0xdc */
+ UNICODE_LEFT_HALF_BLOCK, /* 0xdd */
+ UNICODE_RIGHT_HALF_BLOCK, /* 0xde */
+ UNICODE_UPPER_HALF_BLOCK, /* 0xdf */
+ UNICODE_GREEK_SMALL_LETTER_ALPHA, /* 0xe0 */
+ /* The next one: Also sz-ligature. */
+ UNICODE_GREEK_SMALL_LETTER_BETA, /* 0xe1 */
+ UNICODE_GREEK_CAPITAL_LETTER_GAMMA, /* 0xe2 */
+ UNICODE_GREEK_SMALL_LETTER_PI, /* 0xe3 */
+ UNICODE_GREEK_CAPITAL_LETTER_SIGMA, /* 0xe4 */
+ UNICODE_GREEK_SMALL_LETTER_SIGMA, /* 0xe5 */
+ /* The next one: Also micro. */
+ UNICODE_GREEK_SMALL_LETTER_MU, /* 0xe6 */
+ UNICODE_GREEK_SMALL_LETTER_TAU, /* 0xe7 */
+ UNICODE_GREEK_CAPITAL_LETTER_PHI, /* 0xe8 */
+ UNICODE_GREEK_CAPITAL_LETTER_OMICRON, /* 0xe9 */
+ UNICODE_GREEK_CAPITAL_LETTER_OMEGA, /* 0xea */
+ UNICODE_GREEK_SMALL_LETTER_DELTA, /* 0xeb */
+ UNICODE_INFINITY, /* 0xec */
+ UNICODE_GREEK_SMALL_LETTER_PHI, /* 0xed */
+ UNICODE_GREEK_SMALL_LETTER_EPSILON, /* 0xee */
+ UNICODE_INTERSECTION, /* 0xef */
+ UNICODE_IDENTICAL_TO, /* 0xf0 */
+ UNICODE_PLUS_MINUS_SIGN, /* 0xf1 */
+ UNICODE_GREATER_THAN_OR_EQUAL_TO, /* 0xf2 */
+ UNICODE_LESS_THAN_OR_EQUAL_TO, /* 0xf3 */
+ UNICODE_TOP_HALF_INTEGRAL, /* 0xf4 */
+ UNICODE_BOTTOM_HALF_INTEGRAL, /* 0xf5 */
+ UNICODE_DIVISION_SIGN, /* 0xf6 */
+ UNICODE_ALMOST_EQUAL_TO, /* 0xf7 */
+ UNICODE_DEGREE_SIGN, /* 0xf8 */
+ UNICODE_BULLET_OPERATOR, /* 0xf9 */
+ UNICODE_MIDDLE_DOT, /* 0xfa */
+ UNICODE_SQUARE_ROOT, /* 0xfb */
+ UNICODE_SUPERSCRIPT_LATIN_SMALL_LETTER, /* 0xfc */
+ UNICODE_SUPERSCRIPT_TWO, /* 0xfd */
+ UNICODE_BLACK_SQUARE, /* 0xfe */
+ UNICODE_NO_BREAK_SPACE /* 0xff */
+ };
+
+/* Read the VGA card's memory as IBM 437 font and create a Unicode BDF
+ font from it. If an error occurs, errno is set and NULL is
+ returned. */
+static bdf_font_t
+create_system_font (void)
+{
+ bdf_error_t bdferr;
+ bdf_font_t font;
+ unsigned char bitmap[VGA_FONT_SIZE][VGA_FONT_HEIGHT]; /* 8kB on stack. */
+ int width = 9; /* XXX Find out if we are in 8 or 9 pixel mode. */
+ int i;
+
+ /* Add the glyph at position POS to the font for character
+ ENCODING. */
+ void vga_add_glyph (int pos, int encoding)
+ {
+ char name[16];
+ snprintf (name, sizeof (name), "VGA %i", pos);
+
+ if (width == 8)
+ bdferr = bdf_add_glyph (font, name, encoding,
+ 0, 8, 16, 0, 0, bitmap[pos]);
+ else
+ {
+ int i;
+ char glyph_bitmap[32];
+
+ for (i = 0; i < 16; i++)
+ {
+ glyph_bitmap[i * 2] = bitmap[pos][i];
+ if (pos >= VGA_FONT_LGC_BEGIN
+ && pos < VGA_FONT_LGC_BEGIN + VGA_FONT_LGC_COUNT)
+ glyph_bitmap[i * 2 + 1]
+ = (bitmap[pos][i] & 1) ? 0x80 : 0;
+ else
+ glyph_bitmap[i * 2 + 1] = 0;
+ }
+ bdferr = bdf_add_glyph (font, name, encoding,
+ 0, 9, 16, 0, 0, glyph_bitmap);
+ }
+ }
+
+ /* The point size and resolution is arbitrary. */
+ bdferr = bdf_new (&font, 2, 2, "vga-system", 10, 100, 100,
+ width, 16, 0, 0, 0);
+ if (bdferr)
+ {
+ if (bdferr != BDF_SYSTEM_ERROR)
+ errno = EGRATUITOUS;
+ return NULL;
+ }
+
+ vga_read_font_buffer (0, 0, (unsigned char *) bitmap,
+ VGA_FONT_SIZE * VGA_FONT_HEIGHT);
+
+ for (i = 0; i < VGA_FONT_SIZE; i++)
+ if (ibm437_to_unicode[i])
+ {
+ vga_add_glyph (i, ibm437_to_unicode[i]);
+ if (bdferr)
+ break;
+
+ /* Some glyphs are ambivalent. */
+ if (ibm437_to_unicode[i] == UNICODE_GREEK_SMALL_LETTER_BETA)
+ vga_add_glyph (i, UNICODE_LATIN_SMALL_LETTER_SHARP_S);
+ else if (ibm437_to_unicode[i] == UNICODE_GREEK_SMALL_LETTER_MU)
+ vga_add_glyph (i, UNICODE_MICRO_SIGN);
+ if (bdferr)
+ break;
+ }
+
+ if (bdferr)
+ {
+ bdf_destroy (font);
+ if (bdferr != BDF_SYSTEM_ERROR)
+ errno = EGRATUITOUS;
+ return NULL;
+ }
+
+ return font;
+}
+
+
+#if QUAERENDO_INVENIETIS
+#define GNU_HEAD_BEGIN (UNICODE_PRIVATE_USE_AREA + 0x0f00)
+
+static void
+add_gnu_head (bdf_font_t font)
+{
+#define GNU_HEAD_WIDTH 6
+ static unsigned char gnu_head[][GNU_HEAD_WIDTH] =
+ {
+ { 255, 255, 255, 255, 255, 255 }, { 255, 0, 127, 255, 252, 31 },
+ { 252, 0, 31, 255, 224, 7 }, { 248, 0, 7, 255, 0, 3 },
+ { 240, 0, 15, 255, 128, 3 }, { 240, 31, 255, 255, 252, 1 },
+ { 224, 63, 241, 255, 255, 1 }, { 192, 127, 128, 96, 255, 129 },
+ { 192, 255, 0, 0, 63, 193 }, { 192, 254, 0, 0, 31, 193 },
+ { 192, 252, 0, 0, 15, 193 }, { 192, 248, 0, 0, 15, 193 },
+ { 192, 248, 0, 0, 7, 129 }, { 192, 96, 63, 131, 192, 1 },
+ { 192, 1, 227, 98, 112, 1 }, { 192, 3, 195, 244, 176, 3 },
+ { 224, 7, 221, 125, 248, 3 }, { 240, 15, 184, 124, 120, 7 },
+ { 240, 15, 248, 124, 60, 15 }, { 248, 15, 220, 254, 124, 127 },
+ { 252, 31, 223, 255, 254, 127 }, { 255, 159, 159, 255, 31, 191 },
+ { 255, 223, 159, 255, 35, 63 }, { 255, 191, 127, 195, 152, 127 },
+ { 255, 188, 255, 156, 199, 255 }, { 255, 96, 253, 134, 115, 255 },
+ { 254, 134, 251, 227, 251, 255 }, { 254, 46, 254, 249, 251, 255 },
+ { 255, 238, 126, 127, 231, 255 }, { 255, 239, 127, 127, 207, 255 },
+ { 255, 239, 63, 63, 231, 255 }, { 255, 247, 159, 158, 15, 255 },
+ { 255, 247, 207, 193, 159, 255 }, { 255, 247, 223, 255, 223, 255 },
+ { 255, 243, 199, 252, 31, 255 }, { 255, 251, 227, 224, 63, 255 },
+ { 255, 253, 241, 240, 255, 255 }, { 255, 252, 244, 126, 255, 255 },
+ { 255, 254, 121, 122, 255, 255 }, { 255, 255, 252, 48, 255, 255 },
+ { 255, 255, 252, 35, 255, 255 }, { 255, 255, 249, 1, 127, 255 },
+ { 255, 255, 251, 0, 127, 255 }, { 255, 255, 255, 128, 255, 255 },
+ { 255, 255, 255, 255, 255, 255 }
+ };
+ /* Height of a single glyph, truncated to fit VGA glyph slot. */
+ int height = (font->bbox.height > 32) ? 32 : font->bbox.height;
+ /* Width of a single glyph in byte. */
+ int width = (font->bbox.width + 7) / 8;
+ /* Number of rows in bitmap. */
+ int rows = sizeof (gnu_head) / sizeof (gnu_head[0]);
+ /* Number of rows of glyphs necessary. */
+ int nr = (rows + height - 1) / height;
+ int row, col;
+
+ /* Check that all those glyphs are free in the private area. */
+ if (nr * GNU_HEAD_WIDTH > GNU_HEAD_BEGIN - UNICODE_PRIVATE_USE_AREA + 1)
+ return;
+ for (int i = 0; i < nr * GNU_HEAD_WIDTH; i++)
+ if (bdf_find_glyph (font, (int) GNU_HEAD_BEGIN + i, 0)
+ || bdf_find_glyph (font, -1, (int) GNU_HEAD_BEGIN + i))
+ return;
+
+ for (row = 0; row < nr; row++)
+ for (col = 0; col < GNU_HEAD_WIDTH; col++)
+ {
+ char bitmap[font->bbox.height][width];
+ char name[] = "GNU Head ..........";
+
+ /* strlen ("GNU Head ") == 9. */
+ sprintf (&name[9], "%i", row * GNU_HEAD_WIDTH + col);
+
+ memset (bitmap, 0, sizeof (bitmap));
+ for (int j = 0; j < height && row * height + j < rows; j++)
+ bitmap[j][0] = gnu_head[row * height + j][col];
+
+ if (bdf_add_glyph (font, name,
+ GNU_HEAD_BEGIN + row * GNU_HEAD_WIDTH + col,
+ 0, font->bbox.width, font->bbox.height,
+ 0, 0, (unsigned char *) bitmap))
+ return;
+ }
+}
+#endif
+
+/* Create a new dynafont object, which uses glyphs from the font FONT
+ (which should be 8 or 9 pixels wide and 13 to 16 pixels high).
+ SIZE is either 256 or 512, and specifies the number of available
+ glyphs in the font cache. The object is returned in DYNAFONT.
+
+ The font is consumed. If FONT is the null pointer, the VGA card's
+ memory is converted to a font according to the VGA default map (IBM
+ Code Page 437). */
+error_t
+dynafont_new (bdf_font_t font, bdf_font_t font_italic, bdf_font_t font_bold,
+ bdf_font_t font_bold_italic, int size, dynafont_t *dynafont)
+{
+ error_t err = 0;
+ dynafont_t df;
+ struct bdf_glyph *glyph = NULL;
+
+ if (!font)
+ font = create_system_font ();
+ if (!font || !font->bbox.height)
+ return errno;
+
+ df = malloc (sizeof *df);
+ if (!df)
+ return ENOMEM;
+
+#if QUAERENDO_INVENIETIS
+ add_gnu_head (font);
+#endif
+ bdf_sort_glyphs (font);
+ df->font = font;
+ df->font_italic = font_italic;
+ df->font_bold = font_bold;
+ df->font_bold_italic = font_bold_italic;
+ df->size = size;
+ df->cursor_standout = 0;
+ err = ihash_create (&df->charmap);
+ if (err)
+ {
+ free (df);
+ return err;
+ }
+
+ df->charmap_data = calloc (size, sizeof (struct mapped_character));
+ if (!df->charmap_data)
+ {
+ ihash_free (df->charmap);
+ free (df);
+ return ENOMEM;
+ }
+
+ df->vga_font = malloc (sizeof (vga_font_glyph) * size);
+ if (!df->vga_font)
+ {
+ ihash_free (df->charmap);
+ free (df->charmap_data);
+ free (df);
+ return ENOMEM;
+ }
+ if (df->font->bbox.width == 9)
+ {
+ /* 32 from 256 font slots are for horizontal line graphic
+ characters. */
+ df->use_lgc = 1;
+ df->vga_font_free_indices = df->size
+ - (df->size / 256) * VGA_FONT_LGC_COUNT;
+ df->vga_font_last_free_index = 0;
+ df->vga_font_free_indices_lgc = (df->size / 256) * VGA_FONT_LGC_COUNT;
+ df->vga_font_last_free_index_lgc = VGA_FONT_LGC_BEGIN;
+ }
+ else
+ {
+ df->use_lgc = 0;
+ df->vga_font_free_indices = df->size;
+ df->vga_font_last_free_index = 0;
+ df->vga_font_free_indices_lgc = 0;
+ df->vga_font_last_free_index_lgc = 0;
+ }
+
+ /* Ensure that we always have the replacement character
+ available. */
+ {
+ struct mapped_character *chr = &df->charmap_data[FONT_INDEX_UNKNOWN];
+ df->vga_font_free_indices--;
+ chr->refs = 1;
+
+ glyph = bdf_find_glyph (df->font, UNICODE_REPLACEMENT_CHARACTER, 0);
+ if (!glyph)
+ glyph = bdf_find_glyph (df->font, -1, UNICODE_REPLACEMENT_CHARACTER);
+ if (glyph)
+ {
+ /* XXX Take glyph size into account. */
+ for (int i = 0; i < ((df->font->bbox.height > 32)
+ ? 32 : df->font->bbox.height); i++)
+ df->vga_font[FONT_INDEX_UNKNOWN][i]
+ = glyph->bitmap[i * ((df->font->bbox.width + 7) / 8)];
+ if (df->font->bbox.height < 32)
+ memset (((char *) df->vga_font[FONT_INDEX_UNKNOWN])
+ + df->font->bbox.height, 0, 32 - df->font->bbox.height);
+
+ /* Update the hash table. */
+ ihash_add (df->charmap, UNICODE_REPLACEMENT_CHARACTER,
+ chr, &chr->locp);
+ }
+ else
+ {
+ int i;
+ char *gl = df->vga_font[FONT_INDEX_UNKNOWN];
+ /* XXX Take font height into account. */
+ gl[0] = 0x7E; /* ****** */
+ gl[1] = 0xC3; /* ** ** */
+ gl[2] = 0x99; /* * ** * */
+ gl[3] = 0x99; /* * ** * */
+ gl[4] = 0xF9; /* ***** * */
+ gl[5] = 0xF3; /* **** ** */
+ gl[6] = 0xF3; /* *** *** */
+ gl[7] = 0xE7; /* *** *** */
+ gl[8] = 0xFF; /* ******** */
+ gl[9] = 0xE7; /* *** *** */
+ gl[10] = 0xE7; /* *** *** */
+ gl[11] = 0x7E; /* ****** */
+ for (i = 12; i < 32; i++)
+ gl[i] = 0;
+ }
+ }
+
+ *dynafont = df;
+ return err;
+}
+
+
+/* Release a dynafont object and its associated resources. */
+void
+dynafont_free (dynafont_t df)
+{
+ if (active_dynafont == df)
+ active_dynafont = NULL;
+
+ bdf_destroy (df->font);
+ if (df->font_italic)
+ bdf_destroy (df->font_italic);
+ if (df->font_bold)
+ bdf_destroy (df->font_bold);
+ if (df->font_bold_italic)
+ bdf_destroy (df->font_bold_italic);
+ ihash_free (df->charmap);
+ free (df->charmap_data);
+ free (df->vga_font);
+ free (df);
+}
+
+
+/* Determine if CHR is a character that needs to be continuous in the
+ horizontal direction by repeating the last (eighth) column in
+ 9-pixel-width mode. */
+static inline int
+is_lgc (wchar_t chr)
+{
+ /* This list must be sorted for bsearch! */
+ static wchar_t horiz_glyphs[] =
+ {
+ UNICODE_BOX_DRAWINGS_LIGHT_HORIZONTAL, /* 0x2500 */
+ UNICODE_BOX_DRAWINGS_HEAVY_HORIZONTAL, /* 0x2501 */
+ UNICODE_BOX_DRAWINGS_LIGHT_DOWN_AND_RIGHT, /* 0x250c */
+ UNICODE_BOX_DRAWINGS_DOWN_LIGHT_AND_RIGHT_HEAVY, /* 0x250d */
+ UNICODE_BOX_DRAWINGS_DOWN_HEAVY_AND_RIGHT_LIGHT, /* 0x250e */
+ UNICODE_BOX_DRAWINGS_HEAVY_DOWN_AND_RIGHT, /* 0x250f */
+ UNICODE_BOX_DRAWINGS_LIGHT_UP_AND_RIGHT, /* 0x2514 */
+ UNICODE_BOX_DRAWINGS_UP_LIGHT_AND_RIGHT_HEAVY, /* 0x2515 */
+ UNICODE_BOX_DRAWINGS_UP_HEAVY_AND_RIGHT_LIGHT, /* 0x2516 */
+ UNICODE_BOX_DRAWINGS_HEAVY_UP_AND_RIGHT, /* 0x2517 */
+ UNICODE_BOX_DRAWINGS_LIGHT_VERTICAL_AND_RIGHT, /* 0x251c */
+ UNICODE_BOX_DRAWINGS_VERTICAL_LIGHT_AND_RIGHT_HEAVY, /* 0x251d */
+ UNICODE_BOX_DRAWINGS_UP_HEAVY_AND_RIGHT_UP_LIGHT, /* 0x251e */
+ UNICODE_BOX_DRAWINGS_DOWN_HEAVY_AND_RIGHT_UP_LIGHT, /* 0x251f */
+ UNICODE_BOX_DRAWINGS_VERTICAL_HEAVY_AND_RIGHT_LIGHT, /* 0x2520 */
+ UNICODE_BOX_DRAWINGS_DOWN_LIGHT_AND_RIGHT_UP_HEAVY, /* 0x2521 */
+ UNICODE_BOX_DRAWINGS_UP_LIGHT_AND_RIGHT_DOWN_HEAVY, /* 0x2522 */
+ UNICODE_BOX_DRAWINGS_HEAVY_VERTICAL_AND_RIGHT, /* 0x2523 */
+ UNICODE_BOX_DRAWINGS_LIGHT_DOWN_AND_HORIZONTAL, /* 0x252c */
+ UNICODE_BOX_DRAWINGS_LEFT_HEAVY_AND_RIGHT_DOWN_LIGHT, /* 0x252d */
+ UNICODE_BOX_DRAWINGS_RIGHT_HEAVY_AND_LEFT_DOWN_LIGHT, /* 0x252e */
+ UNICODE_BOX_DRAWINGS_DOWN_LIGHT_AND_HORIZONTAL_HEAVY, /* 0x252f */
+ UNICODE_BOX_DRAWINGS_DOWN_HEAVY_AND_HORIZONTAL_LIGHT, /* 0x2530 */
+ UNICODE_BOX_DRAWINGS_RIGHT_LIGHT_AND_LEFT_DOWN_HEAVY, /* 0x2531 */
+ UNICODE_BOX_DRAWINGS_LEFT_LIGHT_AND_RIGHT_DOWN_HEAVY, /* 0x2532 */
+ UNICODE_BOX_DRAWINGS_HEAVY_DOWN_AND_HORIZONTAL, /* 0x2533 */
+ UNICODE_BOX_DRAWINGS_LIGHT_UP_AND_HORIZONTAL, /* 0x2534 */
+ UNICODE_BOX_DRAWINGS_LEFT_HEAVY_AND_RIGHT_UP_LIGHT, /* 0x2535 */
+ UNICODE_BOX_DRAWINGS_RIGHT_HEAVY_AND_LEFT_UP_LIGHT, /* 0x2536 */
+ UNICODE_BOX_DRAWINGS_UP_LIGHT_AND_HORIZONTAL_HEAVY, /* 0x2537 */
+ UNICODE_BOX_DRAWINGS_UP_HEAVY_AND_HORIZONTAL_LIGHT, /* 0x2538 */
+ UNICODE_BOX_DRAWINGS_RIGHT_LIGHT_AND_LEFT_UP_HEAVY, /* 0x2539 */
+ UNICODE_BOX_DRAWINGS_LEFT_LIGHT_AND_RIGHT_UP_HEAVY, /* 0x253a */
+ UNICODE_BOX_DRAWINGS_HEAVY_UP_AND_HORIZONTAL, /* 0x253b */
+ UNICODE_BOX_DRAWINGS_LIGHT_VERTICAL_AND_HORIZONTAL, /* 0x253c */
+ UNICODE_BOX_DRAWINGS_LEFT_HEAVY_AND_RIGHT_VERTICAL_LIGHT, /* 0x253d */
+ UNICODE_BOX_DRAWINGS_RIGHT_HEAVY_AND_LEFT_VERTICAL_LIGHT, /* 0x253e */
+ UNICODE_BOX_DRAWINGS_VERTICAL_LIGHT_AND_HORIZONTAL_HEAVY, /* 0x253f */
+ UNICODE_BOX_DRAWINGS_UP_HEAVY_AND_DOWN_HORIZONTAL_LIGHT, /* 0x2540 */
+ UNICODE_BOX_DRAWINGS_DOWN_HEAVY_AND_UP_HORIZONTAL_LIGHT, /* 0x2541 */
+ UNICODE_BOX_DRAWINGS_VERTICAL_HEAVY_AND_HORIZONTAL_LIGHT, /* 0x2542 */
+ UNICODE_BOX_DRAWINGS_LEFT_UP_HEAVY_AND_RIGHT_DOWN_LIGHT, /* 0x2543 */
+ UNICODE_BOX_DRAWINGS_RIGHT_UP_HEAVY_AND_LEFT_DOWN_LIGHT, /* 0x2544 */
+ UNICODE_BOX_DRAWINGS_LEFT_DOWN_HEAVY_AND_RIGHT_UP_LIGHT, /* 0x2545 */
+ UNICODE_BOX_DRAWINGS_RIGHT_DOWN_HEAVY_AND_LEFT_UP_LIGHT, /* 0x2546 */
+ UNICODE_BOX_DRAWINGS_DOWN_LIGHT_AND_UP_HORIZONTAL_HEAVY, /* 0x2547 */
+ UNICODE_BOX_DRAWINGS_UP_LIGHT_AND_DOWN_HORIZONTAL_HEAVY, /* 0x2548 */
+ UNICODE_BOX_DRAWINGS_RIGHT_LIGHT_AND_LEFT_VERTICAL_HEAVY, /* 0x2549 */
+ UNICODE_BOX_DRAWINGS_LEFT_LIGHT_AND_RIGHT_VERTICAL_HEAVY, /* 0x254a */
+ UNICODE_BOX_DRAWINGS_HEAVY_VERTICAL_AND_HORIZONTAL, /* 0x254b */
+ UNICODE_BOX_DRAWINGS_DOUBLE_HORIZONTAL, /* 0x2550 */
+ UNICODE_BOX_DRAWINGS_DOWN_SINGLE_AND_RIGHT_DOUBLE, /* 0x2552 */
+ UNICODE_BOX_DRAWINGS_DOWN_DOUBLE_AND_RIGHT_SINGLE, /* 0x2553 */
+ UNICODE_BOX_DRAWINGS_DOUBLE_DOWN_AND_RIGHT, /* 0x2554 */
+ UNICODE_BOX_DRAWINGS_UP_SINGLE_AND_RIGHT_DOUBLE, /* 0x2558 */
+ UNICODE_BOX_DRAWINGS_UP_DOUBLE_AND_RIGHT_SINGLE, /* 0x2559 */
+ UNICODE_BOX_DRAWINGS_DOUBLE_UP_AND_RIGHT, /* 0x255a */
+ UNICODE_BOX_DRAWINGS_VERTICAL_SINGLE_AND_RIGHT_DOUBLE, /* 0x255e */
+ UNICODE_BOX_DRAWINGS_VERTICAL_DOUBLE_AND_RIGHT_SINGLE, /* 0x255f */
+ UNICODE_BOX_DRAWINGS_DOUBLE_VERTICAL_AND_RIGHT, /* 0x2560 */
+ UNICODE_BOX_DRAWINGS_DOWN_SINGLE_AND_HORIZONTAL_DOUBLE, /* 0x2564 */
+ UNICODE_BOX_DRAWINGS_DOWN_DOUBLE_AND_HORIZONTAL_SINGLE, /* 0x2565 */
+ UNICODE_BOX_DRAWINGS_DOUBLE_DOWN_AND_HORIZONTAL, /* 0x2566 */
+ UNICODE_BOX_DRAWINGS_UP_SINGLE_AND_HORIZONTAL_DOUBLE, /* 0x2567 */
+ UNICODE_BOX_DRAWINGS_UP_DOUBLE_AND_HORIZONTAL_SINGLE, /* 0x2568 */
+ UNICODE_BOX_DRAWINGS_DOUBLE_UP_AND_HORIZONTAL, /* 0x2569 */
+ UNICODE_BOX_DRAWINGS_VERTICAL_SINGLE_AND_HORIZONTAL_DOUBLE, /* 0x256a */
+ UNICODE_BOX_DRAWINGS_VERTICAL_DOUBLE_AND_HORIZONTAL_SINGLE, /* 0x256b */
+ UNICODE_BOX_DRAWINGS_DOUBLE_VERTICAL_AND_HORIZONTAL, /* 0x256c */
+ UNICODE_BOX_DRAWINGS_LIGHT_ARC_DOWN_AND_RIGHT, /* 0x256d */
+ UNICODE_BOX_DRAWINGS_LIGHT_ARC_UP_AND_RIGHT, /* 0x2570 */
+#if 0
+ /* The diagonal lines don't look much better with or without the
+ ninth column. */
+ /* 0x2571 */
+ UNICODE_BOX_DRAWINGS_LIGHT_DIAGONAL_UPPER_RIGHT_TO_LOWER_LEFT,
+ /* 0x2572 */
+ UNICODE_BOX_DRAWINGS_LIGHT_DIAGONAL_UPPER_LEFT_TO_LOWER_RIGHT,
+ UNICODE_BOX_DRAWINGS_LIGHT_DIAGONAL_CROSS, /* 0x2573 */
+#endif
+ UNICODE_BOX_DRAWINGS_LIGHT_RIGHT, /* 0x2576 */
+ UNICODE_BOX_DRAWINGS_HEAVY_RIGHT, /* 0x257a */
+ UNICODE_BOX_DRAWINGS_LIGHT_LEFT_AND_HEAVY_RIGHT, /* 0x257c */
+ UNICODE_BOX_DRAWINGS_HEAVY_LEFT_AND_LIGHT_RIGHT, /* 0x257e */
+ UNICODE_UPPER_HALF_BLOCK, /* 0x2580 */
+ UNICODE_LOWER_ONE_EIGHTH_BLOCK, /* 0x2581 */
+ UNICODE_LOWER_ONE_QUARTER_BLOCK, /* 0x2582 */
+ UNICODE_LOWER_THREE_EIGHTHS_BLOCK, /* 0x2583 */
+ UNICODE_LOWER_HALF_BLOCK, /* 0x2584 */
+ UNICODE_LOWER_FIVE_EIGHTHS_BLOCK, /* 0x2585 */
+ UNICODE_LOWER_THREE_QUARTERS_BLOCK, /* 0x2586 */
+ UNICODE_LOWER_SEVEN_EIGHTHS_BLOCK, /* 0x2587 */
+ UNICODE_FULL_BLOCK, /* 0x2588 */
+ UNICODE_RIGHT_HALF_BLOCK, /* 0x2590 */
+#if 0
+ /* The shades don't look much better with or without the ninth
+ column. */
+ UNICODE_LIGHT_SHADE, /* 0x2591 */
+ UNICODE_MEDIUM_SHADE, /* 0x2592 */
+ UNICODE_DARK_SHADE, /* 0x2593 */
+#endif
+ UNICODE_BLACK_SQUARE, /* 0x25a0 */
+ UNICODE_UPPER_ONE_EIGHTH_BLOCK, /* 0x2594 */
+ UNICODE_RIGHT_ONE_EIGHTH_BLOCK, /* 0x2595 */
+ UNICODE_QUADRANT_LOWER_RIGHT, /* 0x2597 */
+ UNICODE_QUADRANT_UPPER_LEFT_AND_LOWER_LEFT_AND_LOWER_RIGHT, /* 0x2599 */
+ UNICODE_QUADRANT_UPPER_LEFT_AND_LOWER_RIGHT, /* 0x259a */
+ UNICODE_QUADRANT_UPPER_LEFT_AND_UPPER_RIGHT_AND_LOWER_LEFT, /* 0x259b */
+ UNICODE_QUADRANT_UPPER_LEFT_AND_UPPER_RIGHT_AND_LOWER_RIGHT, /* 0x259c */
+ UNICODE_QUADRANT_UPPER_RIGHT, /* 0x259d */
+ UNICODE_QUADRANT_UPPER_RIGHT_AND_LOWER_LEFT, /* 0x259e */
+ UNICODE_QUADRANT_UPPER_RIGHT_AND_LOWER_LEFT_AND_LOWER_RIGHT, /* 0x259f */
+ };
+
+ int cmp_wchar (const void *a, const void *b)
+ {
+ const wchar_t *wa = (const wchar_t *) a;
+ const wchar_t *wb = (const wchar_t *) b;
+ return (*wa > *wb) - (*wa < *wb);
+ }
+
+#if QUAERENDO_INVENIETIS
+ /* XXX The (maximum) size is hard coded. */
+ if (chr >= GNU_HEAD_BEGIN && chr <= GNU_HEAD_BEGIN + 50)
+ return 1;
+#endif
+
+ return bsearch (&chr, horiz_glyphs,
+ sizeof (horiz_glyphs) / sizeof (horiz_glyphs[0]),
+ sizeof (horiz_glyphs[0]), cmp_wchar) ? 1 : 0;
+}
+
+
+/* Try to look up glyph CHR in font FONT of dynafont DF with attribute
+ ATTR. This is a helper function for dynafont_lookup. Returns 1 on
+ success, 0 otherwise. */
+static int
+dynafont_lookup_internal (dynafont_t df, bdf_font_t font,
+ wchar_t wide_chr, wchar_t attr, int *rpos)
+{
+ /* When hashing the character, we mix in the font attribute. */
+ struct mapped_character *chr = ihash_find (df->charmap,
+ (int) (wide_chr | attr));
+ int lgc;
+ struct bdf_glyph *glyph;
+ int pos;
+ int found = 0;
+
+ lgc = df->use_lgc ? is_lgc (wide_chr) : 0;
+
+ if (chr)
+ {
+ if (!chr->refs++)
+ {
+ if (lgc)
+ df->vga_font_free_indices_lgc--;
+ else
+ df->vga_font_free_indices--;
+ }
+ /* Return the index of CHR. */
+ *rpos = chr - df->charmap_data;
+ return 1;
+ }
+
+ /* The character is not currently mapped. Look for an empty slot
+ and add it. */
+ if ((lgc && !df->vga_font_free_indices_lgc)
+ || (!lgc && !df->vga_font_free_indices))
+ return 0;
+
+ glyph = bdf_find_glyph (font, (int) wide_chr, 0);
+ if (!glyph)
+ glyph = bdf_find_glyph (font, -1, (int) wide_chr);
+ if (!glyph)
+ return 0;
+
+ if (lgc)
+ {
+ int start_pos = df->vga_font_last_free_index_lgc + 1;
+ if ((start_pos % VGA_FONT_SIZE)
+ == VGA_FONT_LGC_BEGIN + VGA_FONT_LGC_COUNT)
+ {
+ start_pos += VGA_FONT_SIZE - VGA_FONT_LGC_COUNT;
+ start_pos %= df->size;
+ }
+ pos = start_pos;
+
+ do
+ {
+ if (df->charmap_data[pos].refs == 0)
+ {
+ found = 1;
+ break;
+ }
+ pos++;
+ if ((pos % VGA_FONT_SIZE) == VGA_FONT_LGC_BEGIN + VGA_FONT_LGC_COUNT)
+ {
+ pos += VGA_FONT_SIZE - VGA_FONT_LGC_COUNT;
+ pos %= df->size;
+ }
+ }
+ while (pos != start_pos);
+
+ assert (found);
+ df->vga_font_free_indices_lgc--;
+ df->vga_font_last_free_index_lgc = pos;
+ }
+ else
+ {
+ int start_pos = (df->vga_font_last_free_index + 1) % df->size;
+ if (df->use_lgc && (start_pos % VGA_FONT_SIZE) == VGA_FONT_LGC_BEGIN)
+ start_pos += VGA_FONT_LGC_COUNT;
+ pos = start_pos;
+
+ do
+ {
+ if (df->charmap_data[pos].refs == 0)
+ {
+ found = 1;
+ break;
+ }
+ pos = (pos + 1) % df->size;
+ if (df->use_lgc && (pos % VGA_FONT_SIZE) == VGA_FONT_LGC_BEGIN)
+ pos += VGA_FONT_LGC_COUNT;
+ }
+ while (pos != start_pos);
+
+ assert (found);
+ df->vga_font_free_indices--;
+ df->vga_font_last_free_index = pos;
+ }
+
+ /* Ok, we found a new entry, use it. */
+ chr = &df->charmap_data[pos];
+ chr->refs = 1;
+ chr->character = (wide_chr | attr);
+
+ /* XXX Should look at glyph bbox. */
+ for (int i = 0; i < ((font->bbox.height > 32)
+ ? 32 : font->bbox.height); i++)
+ df->vga_font[pos][i]
+ = glyph->bitmap[i * ((font->bbox.width + 7) / 8)];
+ if (font->bbox.height < 32)
+ memset (((char *) df->vga_font[pos])
+ + font->bbox.height, 0, 32 - font->bbox.height);
+
+ if (active_dynafont == df)
+ vga_write_font_buffer (0, pos, df->vga_font[pos],
+ VGA_FONT_HEIGHT);
+ /* Update the hash table. */
+ if (chr->locp)
+ ihash_locp_remove (df->charmap, chr->locp);
+ ihash_add (df->charmap, (int) (wide_chr | attr), chr, &chr->locp);
+ *rpos = pos;
+ return 1;
+}
+
+/* Look up the vga font index for an UCS-4 character. If not already
+ mapped, try to find space for a new entry and add the mapping.
+ Acquires an additional reference to the character. Might return
+ the glyph for the unrepresentable character if the glyph is ot
+ available for this character or no free slot is available right
+ now. In the former case, some information gets lost (to do
+ otherwise, one would have to either assign one of the scarce font
+ indices to each undisplayable character value on screen, or to
+ store the whole scrollback buffer as wide chars as well to recover
+ the lost info from that copy of the original text. */
+int
+dynafont_lookup (dynafont_t df, conchar_t *conchr)
+{
+ wchar_t attr = (conchr->attr.italic ? WCHAR_ITALIC : 0)
+ | (conchr->attr.bold ? WCHAR_BOLD : 0);
+ int found = 0;
+ int pos = FONT_INDEX_UNKNOWN;
+
+ if (attr == (WCHAR_BOLD | WCHAR_ITALIC) && df->font_bold_italic)
+ found = dynafont_lookup_internal (df, df->font_bold_italic,
+ conchr->chr, WCHAR_BOLD | WCHAR_ITALIC,
+ &pos);
+ /* This order will prefer bold over italic if both are requested but
+ are not available at the same time. The other order is just as
+ good. XXX. */
+ if (!found && (attr & WCHAR_BOLD) && df->font_bold)
+ found = dynafont_lookup_internal (df, df->font_bold,
+ conchr->chr, WCHAR_BOLD, &pos);
+ if (!found && (attr & WCHAR_ITALIC) && df->font_italic)
+ found = dynafont_lookup_internal (df, df->font_italic,
+ conchr->chr, WCHAR_ITALIC, &pos);
+ if (!found)
+ found = dynafont_lookup_internal (df, df->font, conchr->chr, 0, &pos);
+ if (!found)
+ {
+ df->charmap_data[FONT_INDEX_UNKNOWN].refs++;
+ pos = FONT_INDEX_UNKNOWN;
+ }
+ return pos;
+}
+
+
+/* Release a reference to the glyph VGA_FONT_INDEX in dynafont DF. */
+void
+dynafont_release (dynafont_t df, int vga_font_index)
+{
+ if (! --df->charmap_data[vga_font_index].refs)
+ {
+ if (df->use_lgc
+ && is_lgc (df->charmap_data[vga_font_index].character & WCHAR_MASK))
+ df->vga_font_free_indices_lgc++;
+ else
+ df->vga_font_free_indices++;
+ }
+}
+
+
+
+/* Set the cursor to normal if STANDOUT is zero, or to a block cursor
+ otherwise. */
+void
+dynafont_set_cursor (dynafont_t df, int standout)
+{
+ int height = (df->font->bbox.height > 32) ? 32 : df->font->bbox.height;
+
+ df->cursor_standout = standout;
+
+ if (df == active_dynafont)
+ {
+ if (standout)
+ vga_set_cursor_size (1, -1);
+ else
+ vga_set_cursor_size ((height >= 2) ? height - 2 : 0, -1);
+ }
+}
+
+
+/* Load the VGA font to the card and make it active. */
+void
+dynafont_activate (dynafont_t df)
+{
+ int height = (df->font->bbox.height > 32) ? 32 : df->font->bbox.height;
+
+ vga_write_font_buffer (0, 0, (char *) df->vga_font,
+ df->size * VGA_FONT_HEIGHT);
+ vga_select_font_buffer (0, (df->size == 512) ? 1 : 0);
+
+ /* XXX Changing the font height below 13 or above 16 will cause
+ display problems for the user if we don't also program the video
+ mode timings. The standard font height for 80x25 is 16. */
+ vga_set_font_height (height);
+ vga_set_font_width (df->font->bbox.width <= 8 ? 8 : 9);
+
+ active_dynafont = df;
+ dynafont_set_cursor (df, df->cursor_standout);
+}
+
+
+#if 0
+/* XXX This code is deactivated because it needs to be changed to
+ allow the italic and bold code, too. */
+
+/* Change the font used by dynafont DF to FONT. This transformation
+ is initially loss-less, if the new font can't display some
+ characters on the screen, you can always go back to a font that
+ does and get the glyphs for those characters back. (However, the
+ comments in dynafont_lookup hold for glyphs looked up after the font
+ change.) */
+void
+dynafont_change_font (dynafont_t df, bdf_font_t font)
+{
+ int i;
+
+ df->font = font;
+ for (i = 0; i < df->size; i++)
+ {
+ /* If we don't derive the unknown or space glyph from the font,
+ we don't update it. */
+#ifndef ENCODING_UNKNOWN
+ if (i == FONT_INDEX_UNKNOWN)
+ continue;
+#endif
+ if (! df->charmap_data[i].refs)
+ {
+ /* The glyph is not used. If it is mapped, we need to
+ remove the mapping to invalidate the glyph. */
+ if (df->charmap_data[i].locp)
+ ihash_locp_remove (df->charmap, df->charmap_data[i].locp);
+ }
+
+ else
+ {
+ /* The glyph is mapped and in use. We will not destroy the
+ mapping, but just override the glyph in the VGA font.
+ This way the user can recover from loading a bad font by
+ going back to a better one. */
+ struct bdf_glyph *glyph;
+ glyph = bdf_find_glyph (df->font,
+ (int) df->charmap_data[i].character, 0);
+ if (!glyph)
+ glyph = bdf_find_glyph (df->font, -1,
+ (int) df->charmap_data[i].character);
+ if (!glyph)
+ {
+#ifdef ENCODING_UNKNOWN
+ /* The new font doesn't have a representation for the
+ unknown glyph at the desired place, so keep the old
+ one. XXX Should load the built-in one here. */
+ if (i == FONT_INDEX_UNKNOWN)
+ continue;
+#endif
+ memcpy (df->vga_font[i], df->vga_font[FONT_INDEX_UNKNOWN], 32);
+ }
+ else
+ {
+ /* XXX Take font size and glyph size into account. */
+ for (int j = 0; j < ((df->font->bbox.height > 32)
+ ? 32 : df->font->bbox.height); j++)
+ df->vga_font[i][j]
+ = glyph->bitmap[j * ((df->font->bbox.width + 7) / 8)];
+ if (df->font->bbox.height < 32)
+ memset (((char *) df->vga_font[i]) + df->font->bbox.height,
+ 0, 32 - df->font->bbox.height);
+ }
+ }
+ }
+
+ if (active_dynafont == df)
+ /* Refresh the card info. */
+ dynafont_activate (df);
+}
+#endif