Refactor terminal for intrinsic Unicode support

Refactor the graphical terminal server to internally represent
characters as 16-bit codepoints and handle the duplex terminal stream as
UTF-8.

- Make the Codepoint class printable to the Output interface
- Decode data received at the Terminal session from UTF-8 to a 16-bit
  character
- Pass 16-bit characters through terminal decoder and char-cell arrays
- Send Unicode through terminal session in a burst of UTF-8 bytes

Fix #3148
This commit is contained in:
Ehmry - 2019-02-08 01:26:21 +01:00 committed by Norman Feske
parent 0c24e1efdc
commit 22327b43ae
13 changed files with 94 additions and 72 deletions

View File

@ -1,9 +1,9 @@
create_boot_directory
import_from_depot genodelabs/src/[base_src] \
genodelabs/pkg/[drivers_interactive_pkg] \
genodelabs/pkg/terminal \
genodelabs/src/init
import_from_depot [depot_user]/src/[base_src] \
[depot_user]/pkg/[drivers_interactive_pkg] \
[depot_user]/pkg/terminal \
[depot_user]/src/init
install_config {
<config>

View File

@ -1,12 +1,12 @@
create_boot_directory
import_from_depot genodelabs/src/[base_src] \
genodelabs/pkg/[drivers_interactive_pkg] \
genodelabs/pkg/terminal \
genodelabs/src/nitpicker \
genodelabs/src/nit_fb \
genodelabs/src/demo \
genodelabs/src/init
import_from_depot [depot_user]/src/[base_src] \
[depot_user]/pkg/[drivers_interactive_pkg] \
[depot_user]/pkg/terminal \
[depot_user]/src/nitpicker \
[depot_user]/src/nit_fb \
[depot_user]/src/demo \
[depot_user]/src/init
install_config {
<config>

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2011-2017 Genode Labs GmbH
* Copyright (C) 2011-2019 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
@ -254,29 +254,6 @@ void Terminal::Main::_handle_input()
event.handle_press([&] (Input::Keycode, Codepoint codepoint) {
struct Utf8 { char b0, b1, b2, b3, b4; };
auto utf8_from_codepoint = [] (unsigned c) {
/* extract 'n' bits 'at' bit position of value 'c' */
auto bits = [c] (unsigned at, unsigned n) {
return (c >> at) & ((1 << n) - 1); };
return (c < 2<<7) ? Utf8 { char(bits( 0, 7)), 0, 0, 0, 0 }
: (c < 2<<11) ? Utf8 { char(bits( 6, 5) | 0xc0),
char(bits( 0, 6) | 0x80), 0, 0, 0 }
: (c < 2<<16) ? Utf8 { char(bits(12, 4) | 0xe0),
char(bits( 6, 6) | 0x80),
char(bits( 0, 6) | 0x80), 0, 0 }
: (c < 2<<21) ? Utf8 { char(bits(18, 3) | 0xf0),
char(bits(12, 6) | 0x80),
char(bits( 6, 6) | 0x80),
char(bits( 0, 6) | 0x80), 0 }
: Utf8 { };
};
Utf8 const sequence = utf8_from_codepoint(codepoint.value);
/* function-key unicodes */
enum {
CODEPOINT_UP = 0xf700, CODEPOINT_DOWN = 0xf701,
@ -321,7 +298,7 @@ void Terminal::Main::_handle_input()
if (special_sequence)
_read_buffer.add(special_sequence);
else
_read_buffer.add(&sequence.b0);
_read_buffer.add(codepoint);
});
});
}

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
* Copyright (C) 2018-2019 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
@ -105,7 +105,8 @@ class Terminal::Session_component : public Rpc_object<Session, Session_component
unsigned i = 0;
for (Utf8_ptr utf8(src); utf8.complete() && i < max; ) {
_character_consumer.consume_character(utf8.codepoint().value);
_character_consumer.consume_character(
Terminal::Character(utf8.codepoint()));
i += utf8.length();
if (i >= max)

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2011-2018 Genode Labs GmbH
* Copyright (C) 2011-2019 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
@ -198,14 +198,8 @@ class Terminal::Text_screen_surface
for (unsigned column = 0; column < _cell_array.num_cols(); column++) {
Char_cell cell = _cell_array.get_cell(column, line);
unsigned char ascii = cell.ascii;
if (ascii == 0)
ascii = ' ';
Text_painter::Codepoint const c { ascii };
_font.apply_glyph(c, [&] (Glyph_painter::Glyph const &glyph) {
_font.apply_glyph(cell.codepoint(), [&] (Glyph_painter::Glyph const &glyph) {
Color_palette::Highlighted const highlighted { cell.highlight() };
Color_palette::Inverse const inverse { cell.inverse() };
@ -274,7 +268,7 @@ class Terminal::Text_screen_surface
void apply_character(Character c)
{
/* submit character to sequence decoder */
_decoder.insert(c.c);
_decoder.insert(c);
}
void import(Snapshot const &snapshot)

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
* Copyright (C) 2018-2019 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.

View File

@ -47,9 +47,9 @@ static void convert_char_array_to_window(Cell_array<Char_cell> *cell_array,
for (unsigned column = 0; column < cell_array->num_cols(); column++) {
Char_cell cell = cell_array->get_cell(column, line);
unsigned char ascii = cell.ascii;
unsigned char ascii = cell.codepoint().value;
if (ascii == 0) {
if (ascii == 0 || ascii & 0x80) {
window.print_char(' ', false, false);
continue;
}
@ -301,10 +301,12 @@ class Terminal::Session_component : public Genode::Rpc_object<Session, Session_c
{
unsigned char *src = _io_buffer.local_addr<unsigned char>();
Terminal::Character character;
for (unsigned i = 0; i < num_bytes; i++) {
/* submit character to sequence decoder */
_decoder.insert(src[i]);
character.value = src[i];
_decoder.insert(character);
}
return num_bytes;

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2013-2017 Genode Labs GmbH
* Copyright (C) 2013-2019 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
@ -20,8 +20,9 @@
struct Char_cell
{
Genode::uint16_t value { ' ' };
unsigned char attr;
unsigned char ascii;
unsigned char color;
enum { ATTR_COLIDX_MASK = 0x07U,
@ -31,14 +32,14 @@ struct Char_cell
enum { COLOR_MASK = 0x3f }; /* 111111 */
Char_cell() : attr(0), ascii(0), color(0) { }
Char_cell() : attr(0), color(0) { }
Char_cell(unsigned char c, Font_face f,
Char_cell(Terminal::Character c, Font_face f,
int colidx, bool inv, bool highlight)
:
value(c.value),
attr(f.attr_bits() | (inv ? ATTR_INVERSE : 0)
| (highlight ? ATTR_HIGHLIGHT : 0)),
ascii(c),
color(colidx & COLOR_MASK)
{ }
@ -56,6 +57,9 @@ struct Char_cell
void clear_cursor() { attr &= ~ATTR_CURSOR; }
bool has_cursor() const { return attr & ATTR_CURSOR; }
Terminal::Codepoint codepoint() const {
return Terminal::Codepoint { value }; }
};
@ -184,7 +188,7 @@ class Char_cell_array_character_screen : public Terminal::Character_screen
if (_irm == INSERT)
_missing("insert mode");
switch (c.ascii()) {
switch (c.value) {
case '\n': /* 10 */
_new_line();
@ -215,10 +219,10 @@ class Char_cell_array_character_screen : public Terminal::Character_screen
}
default:
if (c.ascii() > 0x1f) {
if (c.value > 0x1f) {
Cursor_guard guard(*this);
_char_cell_array.set_cell(_cursor_pos.x, _cursor_pos.y,
Char_cell(c.ascii(), Font_face::REGULAR,
Char_cell(c, Font_face::REGULAR,
_color_index, _inverse, _highlight));
_cursor_pos.x++;
}

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2011-2017 Genode Labs GmbH
* Copyright (C) 2011-2019 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.

View File

@ -1,11 +1,12 @@
/*
* \brief Escape-sequence decoder
* \author Norman Feske
* \author Emery Hemingway
* \date 2011-06-06
*/
/*
* Copyright (C) 2011-2017 Genode Labs GmbH
* Copyright (C) 2011-2019 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
@ -452,8 +453,10 @@ class Terminal::Decoder
Decoder(Character_screen &screen) : _screen(screen) { }
void insert(unsigned char c)
void insert(Character character)
{
auto const c = character.value;
switch (_state) {
case STATE_IDLE:
@ -467,7 +470,7 @@ class Terminal::Decoder
/* handle special characters */
/* handle normal characters */
_screen.output(c);
_screen.output(character);
break;

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2011-2017 Genode Labs GmbH
* Copyright (C) 2011-2019 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
@ -15,6 +15,7 @@
#define _TERMINAL__READ_BUFFER_H_
#include <os/ring_buffer.h>
#include <util/utf8.h>
#include <base/signal.h>
@ -50,6 +51,19 @@ class Terminal::Read_buffer : public Genode::Ring_buffer<unsigned char, READ_BUF
Genode::Signal_transmitter(_sigh_cap).submit();
}
void add(Codepoint code)
{
/* send Unicode in a burst of UTF-8 */
Genode::String<5> utf8(code);
char const *str = utf8.string();
while (*str)
Genode::Ring_buffer<unsigned char, READ_BUFFER_SIZE>::add(*str++);
if (_sigh_cap.valid())
Genode::Signal_transmitter(_sigh_cap).submit();
}
void add(char const *str)
{
while (*str)

View File

@ -15,10 +15,11 @@
#define _TERMINAL__TYPES_H_
/* Genode includes */
#include <util/utf8.h>
#include <util/interface.h>
namespace Terminal {
using Genode::Codepoint;
struct Character;
struct Boundary;
struct Offset;
@ -34,14 +35,13 @@ namespace Terminal {
*/
struct Terminal::Character
{
unsigned char c;
Genode::uint16_t value;
Character() : c(0) { }
Character(unsigned char c) : c(c) { }
Character() : value(0) { }
Character(Codepoint cp)
: value(cp.value < 1<<16 ? cp.value : 0) { }
bool valid() const { return c != 0; }
unsigned char ascii() const { return c; }
bool valid() const { return value != 0; }
};

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
* Copyright (C) 2018-2019 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
@ -14,6 +14,7 @@
#ifndef _INCLUDE__OS__UTIL__UTF8_H_
#define _INCLUDE__OS__UTIL__UTF8_H_
#include <base/output.h>
#include <base/stdint.h>
namespace Genode {
@ -29,6 +30,32 @@ struct Genode::Codepoint
uint32_t value;
bool valid() const { return value != INVALID; }
void print(Output &output) const
{
/* extract 'n' bits 'at' bit position of value */
auto bits = [&] (unsigned at, unsigned n) {
return (char)((value >> at) & ((1 << n) - 1)); };
if (value < 1<<7) {
output.out_char(bits( 0, 7));
} else
if (value < 1<<11) {
output.out_char(bits( 6, 5) | 0xc0);
output.out_char(bits( 0, 6) | 0x80);
} else
if (value < 1<<16) {
output.out_char(bits(12, 4) | 0xe0);
output.out_char(bits( 6, 6) | 0x80);
output.out_char(bits( 0, 6) | 0x80);
} else
if (value < 0x11<<16) {
output.out_char(bits(18, 3) | 0xf0);
output.out_char(bits(12, 6) | 0x80);
output.out_char(bits( 6, 6) | 0x80);
output.out_char(bits( 0, 6) | 0x80);
}
}
};