AnalogTerm2: Make glyph remapping dynamic and add ATC 65551 to manage it.
authorMatthew Mondor <mmondor@pulsar-zone.net>
Sat, 3 Jun 2023 07:31:40 +0000 (07:31 +0000)
committerMatthew Mondor <mmondor@pulsar-zone.net>
Sat, 3 Jun 2023 07:31:40 +0000 (07:31 +0000)
mmsoftware/analogterm2/README.txt
mmsoftware/analogterm2/TODO.txt
mmsoftware/analogterm2/src/font.c
mmsoftware/analogterm2/src/font.h
mmsoftware/analogterm2/src/state.c

index 1e7a63c..00667fe 100644 (file)
@@ -63,11 +63,25 @@ $ printf '\033[?658467;192;255;255h'
 Apply alternative scanline emulator intensity parameters.
 $ printf '\033[?658467;65539;0;100h\033[?658467;65539;1;18h\033[?658467;65539;2;230h\033[?658467;65539;3;13h\033[?658467;65539;4;0h'
 
+Font editing:
+
 Alter "1" to have a serif foot.  Some custom fonts can be loaded
 using cat(1) on supplied example files.
 $ printf '\033[?658467;65540;49;7;28h'
 
-Reset to the default font:
+Create a new glyph remap table and add a custom entry to map NBSP to space.
+These maps can be useful to for instance render unsupported unicode curly
+quote characters as supported ASCII straight punctuation glyphs, merge
+redundant equivalent graphics characters together without needing to define
+each copy in the font, etc.  In this particular case, this allows to make NBSP
+transparent with a font defining the glyph U+00a0 in a way to be visible.
+$ printf '\033[?658467;65551;0h'
+$ printf '\033[?658467;65551;160;32h'
+
+Reset glyph remapping to the AnalogTerm2 default table:
+$ printf '\033[?658467;65551h'
+
+Reset to the default font, also restoring the default glyph remap table:
 $ printf '\033[?658467;65540h'
 
 
index 786d12f..3b38bf9 100644 (file)
@@ -2,11 +2,6 @@
   last one in color mode.
 - Maybe generate common graphics characters programmatically, so that they
   always work independent of font size and leading...
-- When loading custom fonts we may not want to use the internal mappings
-  designed for the internal font.  Perhaps a sequence could activate/disable
-  that automatic mapping.  We may want to rework the mapping to also verify if
-  a glyph is implemented before attempting to substitute it to a another
-  supported one.
 - The uses of lastcol in state.c are inconsistent, likely a source of bugs.
 - Interestingly despite our goto implementation attempting to remember to
   update the last and new lines for proper refresh including of the cursor,
index 1737599..4a91a5d 100644 (file)
@@ -66,16 +66,16 @@ const uint32_t decgfx_unicode_table[128] = {
        16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
        32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
        /* 43 - 48, '+' - '0' Linux console extensions */
-       0x2192, 0x2190, 0x2191, 0x2193, 47, 0x25ae,
+       0x2192, 0x2190, 0x2191, 0x2193, 47, 0x25AE,
        49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
        64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
        80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
        /* 95 - 126, '_' - '~' VT100 DEC Special Graphics */
-       0x00a0,
-       0x25c6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, 0x00b1,
-       0x2424, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x23ba,
-       0x23bb, 0x2500, 0x23bc, 0x23bd, 0x251c, 0x2524, 0x2534, 0x252c,
-       0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7,
+       0x00A0,
+       0x25C6, 0x2592, 0x2409, 0x240C, 0x240D, 0x240A, 0x00B0, 0x00B1,
+       0x2424, 0x240B, 0x2518, 0x2510, 0x250C, 0x2514, 0x253C, 0x23BA,
+       0x23BB, 0x2500, 0x23BC, 0x23BD, 0x251C, 0x2524, 0x2534, 0x252c,
+       0x2502, 0x2264, 0x2265, 0x03C0, 0x2260, 0x00A3, 0x00B7,
        127
 };
 
@@ -120,14 +120,45 @@ static uint32_t iso8859_14_characters[27] = {
 
 /* Various characters including DEC Special Graphics and ISO-8859-15/16 */
 static const uint32_t misc_characters[44] = {
-       0x2192, 0x2190, 0x2191, 0x2193, 0x25c6, 0x2409, 0x240c, 0x240d,
-       0x240a, 0x2424, 0x240b, 0x23ba, 0x23bb, 0x23bc, 0x23bd, 0x2264,
-       0x2265, 0x03c0, 0x2260, 0x20AC, 0x01A9, 0x0283, 0x02D0, 0x0186,
+       0x2192, 0x2190, 0x2191, 0x2193, 0x25C6, 0x2409, 0x240C, 0x240D,
+       0x240A, 0x2424, 0x240B, 0x23BA, 0x23BB, 0x23BC, 0x23BD, 0x2264,
+       0x2265, 0x03C0, 0x2260, 0x20AC, 0x01A9, 0x0283, 0x02D0, 0x0186,
        0x0254, 0x039B, 0x03BB, 0x221E, 0x2122, 0x2026, 0x226E, 0x226F,
        0x25A0, 0x25A1, 0x201E, 0xFFFD, 0x203E, 0x0152, 0x0153, 0x0178,
        0x2018, 0x201C, 0x201D, 0x2022
 };
 
+static uint32_t remap_default[][2] = {
+       { 0x01FE, 0xD8 },       /* ISO-8859-15 O stroke accute to O stroke */
+       { 0x01FF, 0xF8 },       /* ISO-8859-15 o stroke accute to o stroke */
+       { 0x0218, 0x015E },     /* ISO-8859-16 S comma -> S cedilla */
+       { 0x0219, 0x015F },     /* ISO-8859-16 s comma -> s cedilla */
+       { 0x021A, 0x0162 },     /* ISO-8859-16 T comma -> T cedilla */
+       { 0x021B, 0x0163 },     /* ISO-8859-16 t comma -> t cedilla */
+       { 0x1D27, 0x039B },     /* Capital lambda */
+       { 0x2010, '-' },        /* Hyphen */
+       { 0x2013, '-' },        /* " */
+       { 0x2014, 0x1FB78 },    /* Long dash */
+       { 0x2015, 0x1FB78 },    /* " */
+       { 0x2019, 0xB4 },       /* Close single quote */
+       { 0x2032, 0xB4 },       /* " */
+       { 0x2033, 0x201D },     /* Straight double quote */
+       { 0x226A, 0xAB },       /* Much less than */
+       { 0x226B, 0xBB },       /* Much greater than */
+       { 0x25AE, 0x25A0 },     /* Black square, vertical rectangle */
+       { 0x25AF, 0x25A1 },     /* White square, vertical rectangle */
+       { 0x25B2, 0x1FB6F },    /* Black up-pointing triangle */
+       { 0x25BC, 0x1FB6D },    /* Black down-pointing triangle */
+       { 0x25B7, 0x1FB6C },    /* White right-pointing triangle */
+       { 0x2A7D, 0x2264 },     /* Less or equal */
+       { 0x2A7E, 0x2265 },     /* Slanted greater than or equal */
+       { 0x2C96, 0x03BB },     /* Small lambda */
+       { 0x2C97, 0x03BB },     /* " */
+};
+
+static uint32_t        (*remap_table)[2] = remap_default;
+static int     remap_entries = sizeof(remap_default) / sizeof(uint32_t) / 2;
+
 static screen_t        *scr = NULL;
 
 
@@ -472,12 +503,17 @@ font_init(state_t *state, screen_t *screen)
                }
                g->defined = true;
        }
+
+       /* Character glyph remapping */
+       map_reset();
 }
 
 void
 font_cleanup(state_t *state)
 {
 
+       map_reset();
+
        ftable_free(state->ftable->next->next->next->next->next);
        state->ftable->next->next->next->next->next = NULL;
        state->ftable_user = NULL;
@@ -555,85 +591,16 @@ font_glyph(state_t *state, uint32_t c, bool decgfx, bool raw)
        else if (cfg_uppercaseview && c > 96 && c < 123)
                c -= 32;
 
-       /*
-        * Map unsupported glyphs to supported ones where relevant.
-        * XXX May need a more generic mapping table eventually.
-        * Also, we may want to disable this when not using 7x9 fonts, or when
-        * requested by loading a font, etc.
-        */
-       switch (c) {
-       case 0x00A0:    /* Non-breaking space */
-               c = ' ';
-               break;
-       case 0x01FE:    /* ISO-8859-15 O stroke accute to O stroke */
-               c = 0xD8;
-               break;
-       case 0x01FF:    /* ISO-8859-15 o stroke accute to o stroke */
-               c = 0xF8;
-               break;
-       case 0x0218:    /* ISO-8859-16 S comma -> S cedilla */
-               c = 0x015E;
-               break;
-       case 0x0219:    /* ISO-8859-16 s comma -> s cedilla */
-               c = 0x015F;
-               break;
-       case 0x021A:    /* ISO-8859-16 T comma -> T cedilla */
-               c = 0x0162;
-               break;
-       case 0x021B:    /* ISO-8859-16 t comma -> t cedilla */
-               c = 0x0163;
-               break;
-       case 0x1D27:    /* Capital lambda */
-               c = 0x039B;
-               break;
-       case 0x2C96:    /* Small lambda */
-       case 0x2C97:    /* FALLTHROUGH */
-               c = 0x03BB;
-               break;
-       case 0x2010:    /* Hyphen */
-       case 0x2013:    /* FALLTHROUGH */
-               c = '-';
-               break;
-       case 0x2014:    /* Long dash */
-       case 0x2015:    /* FALLTHROUGH */
-               c = 0x1FB78;
-               break;
-       case 0x2019:    /* Close single quote */
-       case 0x2032:    /* FALLTHROUGH Prime */
-               c = 0xB4;
-               break;
-       case 0x2033:    /* Straight double quote */
-               c = 0x201D;
-               break;
-       case 0x25B2:    /* Black up-pointing triangle */
-               c = 0x1FB6F;
-               break;
-       case 0x25BC:    /* Black down-pointing triangle */
-               c = 0x1FB6D;
-               break;
-       case 0x25B7:    /* White right-pointing triangle */
-               c = 0x1FB6C;
-               break;
-       case 0x2a7d:    /* Less or equal */
-               c = 0x2264;
-               break;
-       case 0x2a7e:
-               c = 2265;
-               break;
-       case 0x226A:    /* Much less than */
-               c = 0xAB;
-               break;
-       case 0x226B:    /* Much greater than */
-               c = 0xBB;
-               break;
-       case 0x25AE:    /* Black square, vertical rectangle */
-               c = 0x25A0;
-               break;
-       case 0x25AF:    /* White square, vertical rectangle */
-               c = 0x25A1;
-               break;
-       default:
-               break;
+       /* Remap character to supported glyph if needed */
+       if (remap_table != NULL) {
+               int i;
+
+               for (i = 0; i < remap_entries; i++) {
+                       if (c == remap_table[i][0]) {
+                               c = remap_table[i][1];
+                               break;
+                       }
+               }
        }
 
 raw:
@@ -699,3 +666,65 @@ font_edit(state_t *state, uint32_t c, int l, int v)
                    ((v & (1 << i)) != 0 ? 255 : 0);
        gl->defined = true;
 }
+
+void
+map_reset(void)
+{
+
+       if (remap_table != remap_default) {
+               if (remap_table != NULL)
+                       free(remap_table);
+               remap_table = remap_default;
+               remap_entries = sizeof(remap_default) / sizeof(uint32_t) / 2;
+       }
+}
+
+void
+map_clear(void)
+{
+
+       map_reset();
+       remap_table = NULL;
+       remap_entries = 0;
+}
+
+void
+map_add(uint32_t from, uint32_t to)
+{
+       uint32_t (*t)[2] = NULL;
+       int i;
+
+       /* Invalid */
+       if (from == 0 || to == 0)
+               return;
+
+       /* Ignore unless explicitly cleared for user map */
+       if (remap_table == remap_default)
+               return;
+
+       /* Empty table, create and add entry */
+       if (remap_table == NULL) {
+               if ((remap_table = malloc(sizeof(uint32_t) * 2)) == NULL)
+                       err(EXIT_FAILURE, "map_add()");
+               remap_table[0][0] = from;
+               remap_table[0][1] = to;
+               remap_entries = 1;
+               return;
+       }
+
+       /* Remap if exists */
+       for (i = 0; i < remap_entries; i++) {
+               if (from == remap_table[i][0]) {
+                       remap_table[i][1] = to;
+                       return;
+               }
+       }
+
+       /* Grow and add entry */
+       if ((t = realloc(remap_table, sizeof(uint32_t) * 2 *
+           (remap_entries + 1))) == NULL)
+               err(EXIT_FAILURE, "map_add()");
+       remap_table = t;
+       remap_table[remap_entries][0] = from;
+       remap_table[remap_entries++][1] = to;
+}
index a63550a..eb51be8 100644 (file)
@@ -66,6 +66,9 @@ void  font_cleanup(state_t *);
 void   font_reset(state_t *);
 void   *font_glyph(state_t *, uint32_t, bool, bool);
 void   font_edit(state_t *, uint32_t, int, int);
+void   map_reset(void);
+void   map_clear(void);
+void   map_add(uint32_t, uint32_t);
 
 
 extern const uint32_t decgfx_unicode_table[128];
index 17b8e75..5166bcb 100644 (file)
@@ -1222,6 +1222,10 @@ state_emul_printc(state_t *st, uint8_t c)
                                                        draw_blink_reset();
                                                        state_update_cursor(
                                                            st);
+                                               } else if (p == 65551) {
+                                                       map_reset();
+                                                       st->text_updateall =
+                                                           true;
                                                }
                                        } else if ((state->curparam == 2 &&
                                                    state->csiparam[1] ==
@@ -1332,6 +1336,20 @@ state_emul_printc(state_t *st, uint8_t c)
                                                        goto endh;
                                                font_edit(st, g, l, b);
                                                st->text_updateall = true;
+                                       } else if (state->curparam > 1 &&
+                                           state->csiparam[1] == 65551) {
+                                               switch (state->curparam) {
+                                               case 2:
+                                                       if (state->csiparam[2]
+                                                           == 0)
+                                                               map_clear();
+                                                       break;
+                                               case 3:
+                                                       map_add(state->csiparam[2],
+                                                           state->csiparam[3]);
+                                                       break;
+                                               }
+                                               st->text_updateall = true;
                                        } else if (state->curparam == 3) {
                                                /* Custom foreground color */
                                                draw_custom_rgb(