gbranden pushed a commit to branch master in repository groff. commit 9edae43657c222f630eef84e8ab38603071a033f Author: Deri James <d...@chuzzlewit.myzen.co.uk> AuthorDate: Sat May 24 00:08:28 2025 +0000
[grotty]: Add SGR 38/48 high color depth support. * src/devices/grotty/tty.cpp: Add support for devices supporting ECMA-48/ISO 6429 SGR 38 and 48 escape sequences for specifying 24-bit color values in the RGB color space. Add global Boolean variable `want_sgr_truecolor`. (class tty_glyph): Promote `back_color_idx` and `fore_color_idx` member variables from `schar` (signed char) to `long`. (class tty_printer): Promote `curr_fore_idx` and `curr_back_idx` member variables from `schar` (signed char) to `long`. Promote return value of `color_to_idx()` member function from pointer-to-`schar` to pointer-to-`long`. Promote fourth argument of `has_color()` member function from pointer-to-`schar` to pointer-to-`long`. Promote first argument of `put_color()` member function from `schar` to `long`. (tty_printer::has_color): Promote `idx` argument from pointer-to- `schar` to pointer-to-`long`. Guard existing color-definition logic behind test of `want_sgr_truecolor` for falsity; otherwise, compute `idx` using bitwise shifts and addition. (tty_printer::tty_printer): Promote `dummy` local variable from `schar` to `long`. (tty_printer::color_to_idx): Promote return value from pointer-to- `schar` to pointer-to-`long`. Promote `idx` local variable from `schar` to `long`. (tty_printer::put_color): Promote `color_index` argument from `schar` to `long`. Guard existing SGR color escape sequence emission logic (which uses SGR 30-37 and 40-47) behind test of `want_sgr_truecolor` for falsity; otherwise, emit SGR 38 and 48 sequences. (main): Recognize new `-t` option to select use of SGR 38 and 48 escape sequences. If specified, configure `want_sgr_truecolor` as true. * src/devices/grotty/grotty.1.man (Synopsis, Description, Options): * src/devices/grotty/tty.cpp (usage): Document new `-t` option. Fixes <https://savannah.gnu.org/bugs/?67153>. --- ChangeLog | 40 ++++++++++++++ src/devices/grotty/grotty.1.man | 38 +++++++++++++- src/devices/grotty/tty.cpp | 114 ++++++++++++++++++++++++---------------- 3 files changed, 145 insertions(+), 47 deletions(-) diff --git a/ChangeLog b/ChangeLog index d72025bbc..79977bd49 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,43 @@ +2025-05-24 Deri James <d...@chuzzlewit.myzen.co.uk> + + * src/devices/grotty/tty.cpp: Add support for devices supporting + ECMA-48/ISO 6429 SGR 38 and 48 escape sequences for specifying + 24-bit color values in the RGB color space. Add global Boolean + variable `want_sgr_truecolor`. + (class tty_glyph): Promote `back_color_idx` and + `fore_color_idx` member variables from `schar` (signed char) to + `long`. + (class tty_printer): Promote `curr_fore_idx` and `curr_back_idx` + member variables from `schar` (signed char) to `long`. Promote + return value of `color_to_idx()` member function from + pointer-to-`schar` to pointer-to-`long`. Promote fourth + argument of `has_color()` member function from + pointer-to-`schar` to pointer-to-`long`. Promote first argument + of `put_color()` member function from `schar` to `long`. + (tty_printer::has_color): Promote `idx` argument from + pointer-to-`schar` to pointer-to-`long`. Guard existing + color-definition logic behind test of `want_sgr_truecolor` for + falsity; otherwise, compute `idx` using bitwise shifts and + addition. + (tty_printer::tty_printer): Promote `dummy` local variable + from `schar` to `long`. + (tty_printer::color_to_idx): Promote return value from + pointer-to-`schar` to pointer-to-`long`. Promote `idx` local + variable from `schar` to `long`. + (tty_printer::put_color): Promote `color_index` argument from + `schar` to `long`. Guard existing SGR color escape sequence + emission logic (which uses SGR 30-37 and 40-47) behind test of + `want_sgr_truecolor` for falsity; otherwise, emit SGR 38 and 48 + sequences. + (main): Recognize new `-t` option to select use of SGR 38 and 48 + escape sequences. If specified, configure `want_sgr_truecolor` + as true. + * src/devices/grotty/grotty.1.man (Synopsis, Description) + (Options): + * src/devices/grotty/tty.cpp (usage): Document new `-t` option. + + Fixes <https://savannah.gnu.org/bugs/?67153>. + 2025-06-03 G. Branden Robinson <g.branden.robin...@gmail.com> * src/devices/grotty/tty.cpp (class tty_printer): Rename member diff --git a/src/devices/grotty/grotty.1.man b/src/devices/grotty/grotty.1.man index eb043d193..edac3db65 100644 --- a/src/devices/grotty/grotty.1.man +++ b/src/devices/grotty/grotty.1.man @@ -52,7 +52,7 @@ output driver for typewriter-like (terminal) devices .\" ==================================================================== . .SY grotty -.RB [ \-dfho ] +.RB [ \-dfhot ] .RB [ \-i \||\| \-r ] .RB [ \-F\~\c .IR font-directory ] @@ -146,7 +146,7 @@ reverse video [\[lq]negative image\[rq]] and colors). . -Devices supporting the appropriate sequences can view +By default, devices supporting the appropriate sequences can view .I roff documents using eight different background and foreground colors. . @@ -165,6 +165,37 @@ and cyan. Unrecognized colors are mapped to the default color, which is dependent on the settings of the terminal. . +If +.B -P-t +is passed to groff (which sets +.I grotty's +.B -t +flag - see below) it operates in TRUECOLOR mode and any +RGB colour can be used as foreground and background. +Many terminal emulators now support the TRUECOLOR extensions +if your environment includes:- +.P +.RS +COLORTERM="truecolor" +.RE +.P +You specify the RGB colours using the usual:- +.P +.RS +\&.defcolor mediumspringgreen rgb #00fa9a +.P +.RE +NOTE: only rgb colour definitions are supported. +.P +And then use \[rs]m[...] and \[rs]M[...] to specify the foreground +and background colours. +The 8 legacy, 4 bit, colours (defined above) may look different when +used with 24 bit colours. The reason is because although tty.tmac +defines "yellow" as rgb #ffff00, it uses rgb #b26818 (or #e5cb3f for +text when the bold font is selected), whereas for 24 bit colours the +full #ffff00 is used, and using the bold font just bolds the text +rather than alter the colour. +.P OSC\~8 hyperlinks are produced for these devices. . . @@ -587,6 +618,9 @@ is also specified. . . .TP +.B \-t +Use 24 bit "TRUECOLOR" extension rather than 4 bit legacy colours. +.TP .B \-u Suppress the use of underlining for italic characters in legacy output format. diff --git a/src/devices/grotty/tty.cpp b/src/devices/grotty/tty.cpp index 92bd22296..c5f8b072a 100644 --- a/src/devices/grotty/tty.cpp +++ b/src/devices/grotty/tty.cpp @@ -68,7 +68,7 @@ static bool do_sgr_italics; static bool want_reverse_video_for_italics = false; static bool do_reverse_video; static bool use_overstriking_drawing_scheme = false; - +static bool want_sgr_truecolor = false; static void update_options(); static void usage(FILE *stream); @@ -169,8 +169,8 @@ public: int hpos; unsigned int code; unsigned char mode; - schar back_color_idx; - schar fore_color_idx; + long back_color_idx; + long fore_color_idx; inline int draw_mode() { return mode & (VDRAW_MODE|HDRAW_MODE); } inline int order() { return mode & (VDRAW_MODE|HDRAW_MODE|CU_MODE|COLOR_CHANGE); } @@ -182,20 +182,20 @@ class tty_printer : public printer { int nlines; int cached_v; int cached_vpos; - schar curr_fore_idx; - schar curr_back_idx; + long curr_fore_idx; + long curr_back_idx; bool is_underlining; bool is_boldfacing; bool is_continuously_underlining; PTABLE(schar) tty_colors; void make_underline(int); void make_bold(output_character, int); - schar color_to_idx(color *); + long color_to_idx(color *); void add_char(output_character, int, int, int, color *, color *, unsigned char); void simple_add_char(const output_character, const environment *); char *make_rgb_string(unsigned int, unsigned int, unsigned int); - bool has_color(unsigned int, unsigned int, unsigned int, schar *, + bool has_color(unsigned int, unsigned int, unsigned int, long *, schar = DEFAULT_COLOR_IDX); void line(int, int, int, int, color *, color *); void draw_line(int *, int, const environment *); @@ -210,7 +210,7 @@ public: void change_color(const environment * const); void change_fill_color(const environment * const); void put_char(output_character); - void put_color(schar, int); + void put_color(long, int); void begin_page(int) { } void end_page(int); font *make_font(const char *); @@ -240,19 +240,24 @@ char *tty_printer::make_rgb_string(unsigned int r, bool tty_printer::has_color(unsigned int r, unsigned int g, - unsigned int b, schar *idx, schar value) + unsigned int b, long *idx, schar value) { bool is_known_color = true; - char *s = make_rgb_string(r, g, b); - schar *i = tty_colors.lookup(s); - if (0 /* nullptr */ == i) { - is_known_color = false; - i = new schar[1]; - *i = value; - tty_colors.define(s, i); + if (!want_sgr_truecolor) { + char *s = make_rgb_string(r, g, b); + schar *i = tty_colors.lookup(s); + if (0 /* nullptr */ == i) { + is_known_color = false; + i = new schar[1]; + *i = value; + tty_colors.define(s, i); + } + *idx = *i; + delete[] s; + } + else { + *idx=((r>>8)<<16) + ((g>>8)<<8) + (b>>8); } - *idx = *i; - delete[] s; return is_known_color; } @@ -263,7 +268,7 @@ tty_printer::tty_printer() : cached_v(0) vline_char = 0x2502; } // TODO: Skip color setup if terminfo `colors` capability is "-1". - schar dummy; + long dummy; // Create the eight ANSI X3.64/ECMA-48/ISO 6429 standard colors. // black, white (void) has_color(0, 0, 0, &dummy, 0); @@ -334,13 +339,13 @@ void tty_printer::make_bold(output_character c, int w) } } -schar tty_printer::color_to_idx(color *col) +long tty_printer::color_to_idx(color *col) { if (col->is_default()) return DEFAULT_COLOR_IDX; unsigned int r, g, b; col->get_rgb(&r, &g, &b); - schar idx; + long idx; if (!has_color(r, g, b, &idx)) { char *s = col->print_color(); error("unsupported color '%1' mapped to default", s); @@ -702,33 +707,48 @@ void tty_printer::put_char(output_character wc) putchar(wc); } -void tty_printer::put_color(schar color_index, int back) +void tty_printer::put_color(long color_index, int back) { - if (color_index == DEFAULT_COLOR_IDX) { - putstring(SGR_DEFAULT); - // set bold and underline again - if (is_boldfacing) - putstring(SGR_BOLD); - if (is_underlining) { - if (do_sgr_italics) - putstring(SGR_ITALIC); - else if (do_reverse_video) - putstring(SGR_REVERSE); + if (!want_sgr_truecolor) { + if (color_index == DEFAULT_COLOR_IDX) { + putstring(SGR_DEFAULT); + // set bold and underline again + if (is_boldfacing) + putstring(SGR_BOLD); + if (is_underlining) { + if (do_sgr_italics) + putstring(SGR_ITALIC); + else if (do_reverse_video) + putstring(SGR_REVERSE); + else + putstring(SGR_UNDERLINE); + } + // set other color again + back = !back; + color_index = back ? curr_back_idx : curr_fore_idx; + } + if (color_index != DEFAULT_COLOR_IDX) { + putstring(CSI); + if (back) + putchar('4'); else - putstring(SGR_UNDERLINE); + putchar('3'); + putchar(color_index + '0'); + putchar('m'); } - // set other color again - back = !back; - color_index = back ? curr_back_idx : curr_fore_idx; } - if (color_index != DEFAULT_COLOR_IDX) { + else { + if (color_index == DEFAULT_COLOR_IDX) { + putstring(SGR_DEFAULT); + back = !back; + color_index = back ? curr_back_idx : curr_fore_idx; + if (color_index == DEFAULT_COLOR_IDX) {return;} + } putstring(CSI); - if (back) - putchar('4'); - else - putchar('3'); - putchar(color_index + '0'); - putchar('m'); + int fb = back ? 48 : 38; + static char buf[24]; + sprintf(buf,"%d;2;%u;%u;%um",fb, color_index>>16, (color_index>>8) & 0xff, color_index & 0xff); + putstring(buf); } } @@ -959,7 +979,7 @@ int main(int argc, char **argv) { "version", no_argument, 0, 'v' }, { NULL, 0, 0, 0 } }; - while ((c = getopt_long(argc, argv, ":bBcdfF:hiI:oruUv", long_options, + while ((c = getopt_long(argc, argv, ":bBcdfF:hiI:ortuUv", long_options, NULL)) != EOF) switch(c) { case 'v': @@ -1015,6 +1035,10 @@ int main(int argc, char **argv) // Ignore \D commands. allow_drawing_commands = false; break; + case 't': + // TRUECOLOR + want_sgr_truecolor = true; + break; case CHAR_MAX + 1: // --help usage(stdout); break; @@ -1045,7 +1069,7 @@ int main(int argc, char **argv) static void usage(FILE *stream) { fprintf(stream, -"usage: %s [-dfho] [-i|-r] [-F font-directory] [file ...]\n" +"usage: %s [-dfhot] [-i|-r] [-F font-directory] [file ...]\n" "usage: %s -c [-bBdfhouU] [-F font-directory] [file ...]\n" "usage: %s {-v | --version}\n" "usage: %s --help\n", _______________________________________________ groff-commit mailing list groff-commit@gnu.org https://lists.gnu.org/mailman/listinfo/groff-commit