Unicode support.
This commit is contained in:
parent
de5b945f73
commit
356e3945e9
@ -102,6 +102,25 @@ typedef struct guac_terminal_operation {
|
|||||||
|
|
||||||
} guac_terminal_operation;
|
} guac_terminal_operation;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A cached glyph.
|
||||||
|
*/
|
||||||
|
typedef struct guac_terminal_glyph {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The location within the glyph layer that this glyph can be found.
|
||||||
|
*/
|
||||||
|
int location;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The codepoint currently stored at that location.
|
||||||
|
*/
|
||||||
|
int codepoint;
|
||||||
|
|
||||||
|
} guac_terminal_glyph;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set of all pending operations for the currently-visible screen area.
|
* Set of all pending operations for the currently-visible screen area.
|
||||||
*/
|
*/
|
||||||
@ -150,7 +169,7 @@ typedef struct guac_terminal_display {
|
|||||||
/**
|
/**
|
||||||
* Index of locations for each glyph in the stroke and fill layers.
|
* Index of locations for each glyph in the stroke and fill layers.
|
||||||
*/
|
*/
|
||||||
int glyphs[256];
|
guac_terminal_glyph glyphs[512];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Color of glyphs in copy buffer
|
* Color of glyphs in copy buffer
|
||||||
|
@ -190,7 +190,7 @@ int guac_terminal_write(guac_terminal* term, const char* c, int size);
|
|||||||
/**
|
/**
|
||||||
* Sets the character at the given row and column to the specified value.
|
* Sets the character at the given row and column to the specified value.
|
||||||
*/
|
*/
|
||||||
int guac_terminal_set(guac_terminal* term, int row, int col, char c);
|
int guac_terminal_set(guac_terminal* term, int row, int col, int codepoint);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears the given region within a single row.
|
* Clears the given region within a single row.
|
||||||
|
@ -107,9 +107,9 @@ typedef struct guac_terminal_attributes {
|
|||||||
typedef struct guac_terminal_char {
|
typedef struct guac_terminal_char {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The character value of the character to display.
|
* The Unicode codepoint of the character to display.
|
||||||
*/
|
*/
|
||||||
char value;
|
int value;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The attributes of the character to display.
|
* The attributes of the character to display.
|
||||||
|
@ -68,17 +68,79 @@ const guac_terminal_color guac_terminal_palette[16] = {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Maps any codepoint onto a number between 0 and 511 inclusive */
|
||||||
|
int __guac_terminal_hash_codepoint(int codepoint) {
|
||||||
|
|
||||||
|
/* If within one byte, just return codepoint */
|
||||||
|
if (codepoint <= 0xFF)
|
||||||
|
return codepoint;
|
||||||
|
|
||||||
|
/* Otherwise, map to next 256 values */
|
||||||
|
return (codepoint & 0xFF) + 0x100;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int __guac_terminal_encode_utf8(int codepoint, char* utf8) {
|
||||||
|
|
||||||
|
int i;
|
||||||
|
int mask, bytes;
|
||||||
|
|
||||||
|
/* Determine size and initial byte mask */
|
||||||
|
if (codepoint <= 0x007F) {
|
||||||
|
mask = 0x00;
|
||||||
|
bytes = 1;
|
||||||
|
}
|
||||||
|
else if (codepoint <= 0x7FF) {
|
||||||
|
mask = 0xC0;
|
||||||
|
bytes = 2;
|
||||||
|
}
|
||||||
|
else if (codepoint <= 0xFFFF) {
|
||||||
|
mask = 0xE0;
|
||||||
|
bytes = 3;
|
||||||
|
}
|
||||||
|
else if (codepoint <= 0x1FFFFF) {
|
||||||
|
mask = 0xF0;
|
||||||
|
bytes = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise, invalid codepoint */
|
||||||
|
else {
|
||||||
|
*(utf8++) = '?';
|
||||||
|
*(utf8++) = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Offset buffer by size */
|
||||||
|
utf8 += bytes;
|
||||||
|
*(utf8--) = 0;
|
||||||
|
|
||||||
|
/* Add trailing bytes, if any */
|
||||||
|
for (i=1; i<bytes; i++) {
|
||||||
|
*(utf8--) = 0x80 | (codepoint & 0x3F);
|
||||||
|
codepoint >>= 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set initial byte */
|
||||||
|
*utf8 = mask | codepoint;
|
||||||
|
|
||||||
|
/* Done */
|
||||||
|
return bytes;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the location of the given character in the glyph cache layer,
|
* Returns the location of the given character in the glyph cache layer,
|
||||||
* sending it first if necessary. The location returned is in characters,
|
* sending it first if necessary. The location returned is in characters,
|
||||||
* and thus must be multiplied by the glyph width to obtain the actual
|
* and thus must be multiplied by the glyph width to obtain the actual
|
||||||
* location within the glyph cache layer.
|
* location within the glyph cache layer.
|
||||||
*/
|
*/
|
||||||
int __guac_terminal_get_glyph(guac_terminal_display* display, char c) {
|
int __guac_terminal_get_glyph(guac_terminal_display* display, int codepoint) {
|
||||||
|
|
||||||
guac_socket* socket = display->client->socket;
|
guac_socket* socket = display->client->socket;
|
||||||
int location;
|
int location;
|
||||||
|
|
||||||
|
char utf8[5];
|
||||||
|
|
||||||
/* Use foreground color */
|
/* Use foreground color */
|
||||||
const guac_terminal_color* color =
|
const guac_terminal_color* color =
|
||||||
&guac_terminal_palette[display->glyph_foreground];
|
&guac_terminal_palette[display->glyph_foreground];
|
||||||
@ -92,13 +154,29 @@ int __guac_terminal_get_glyph(guac_terminal_display* display, char c) {
|
|||||||
|
|
||||||
PangoLayout* layout;
|
PangoLayout* layout;
|
||||||
|
|
||||||
/* Return glyph if exists */
|
/* Get codepoint hash */
|
||||||
if (display->glyphs[(int) c])
|
int hashcode = __guac_terminal_hash_codepoint(codepoint);
|
||||||
return display->glyphs[(int) c] - 1;
|
|
||||||
|
|
||||||
|
/* If something already stored here, either same codepoint or collision */
|
||||||
|
if (display->glyphs[hashcode].location) {
|
||||||
|
|
||||||
|
/* If match, return match. */
|
||||||
|
if (display->glyphs[hashcode].codepoint == codepoint)
|
||||||
|
return display->glyphs[hashcode].location - 1;
|
||||||
|
|
||||||
|
/* Otherwise, reuse location */
|
||||||
|
location = display->glyphs[hashcode].location;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If no collision, allocate new glyph location */
|
||||||
|
else
|
||||||
location = display->next_glyph++;
|
location = display->next_glyph++;
|
||||||
|
|
||||||
/* Otherwise, draw glyph */
|
/* Convert to UTF-8 */
|
||||||
|
__guac_terminal_encode_utf8(codepoint, utf8);
|
||||||
|
|
||||||
|
/* Prepare surface */
|
||||||
surface = cairo_image_surface_create(
|
surface = cairo_image_surface_create(
|
||||||
CAIRO_FORMAT_ARGB32,
|
CAIRO_FORMAT_ARGB32,
|
||||||
display->char_width, display->char_height);
|
display->char_width, display->char_height);
|
||||||
@ -107,7 +185,7 @@ int __guac_terminal_get_glyph(guac_terminal_display* display, char c) {
|
|||||||
/* Get layout */
|
/* Get layout */
|
||||||
layout = pango_cairo_create_layout(cairo);
|
layout = pango_cairo_create_layout(cairo);
|
||||||
pango_layout_set_font_description(layout, display->font_desc);
|
pango_layout_set_font_description(layout, display->font_desc);
|
||||||
pango_layout_set_text(layout, &c, 1);
|
pango_layout_set_text(layout, utf8, 1);
|
||||||
|
|
||||||
/* Draw */
|
/* Draw */
|
||||||
cairo_set_source_rgba(cairo,
|
cairo_set_source_rgba(cairo,
|
||||||
@ -140,7 +218,8 @@ int __guac_terminal_get_glyph(guac_terminal_display* display, char c) {
|
|||||||
location * display->char_width, 0, display->char_width, display->char_height,
|
location * display->char_width, 0, display->char_width, display->char_height,
|
||||||
GUAC_COMP_OVER, display->filled_glyphs, location * display->char_width, 0);
|
GUAC_COMP_OVER, display->filled_glyphs, location * display->char_width, 0);
|
||||||
|
|
||||||
display->glyphs[(int) c] = location+1;
|
display->glyphs[hashcode].location = location+1;
|
||||||
|
display->glyphs[hashcode].codepoint = codepoint;
|
||||||
|
|
||||||
cairo_surface_destroy(surface);
|
cairo_surface_destroy(surface);
|
||||||
|
|
||||||
@ -235,10 +314,10 @@ int __guac_terminal_set_colors(guac_terminal_display* display,
|
|||||||
* rendering the charater immediately. This bypasses the guac_terminal_display
|
* rendering the charater immediately. This bypasses the guac_terminal_display
|
||||||
* mechanism and is intended for flushing of updates only.
|
* mechanism and is intended for flushing of updates only.
|
||||||
*/
|
*/
|
||||||
int __guac_terminal_set(guac_terminal_display* display, int row, int col, char c) {
|
int __guac_terminal_set(guac_terminal_display* display, int row, int col, int codepoint) {
|
||||||
|
|
||||||
guac_socket* socket = display->client->socket;
|
guac_socket* socket = display->client->socket;
|
||||||
int location = __guac_terminal_get_glyph(display, c);
|
int location = __guac_terminal_get_glyph(display, codepoint);
|
||||||
|
|
||||||
return guac_protocol_send_copy(socket,
|
return guac_protocol_send_copy(socket,
|
||||||
display->filled_glyphs,
|
display->filled_glyphs,
|
||||||
|
@ -115,11 +115,11 @@ void guac_terminal_free(guac_terminal* term) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int guac_terminal_set(guac_terminal* term, int row, int col, char c) {
|
int guac_terminal_set(guac_terminal* term, int row, int col, int codepoint) {
|
||||||
|
|
||||||
/* Build character with current attributes */
|
/* Build character with current attributes */
|
||||||
guac_terminal_char guac_char;
|
guac_terminal_char guac_char;
|
||||||
guac_char.value = c;
|
guac_char.value = codepoint;
|
||||||
guac_char.attributes = term->current_attributes;
|
guac_char.attributes = term->current_attributes;
|
||||||
|
|
||||||
guac_terminal_set_columns(term, row, col, col, &guac_char);
|
guac_terminal_set_columns(term, row, col, col, &guac_char);
|
||||||
|
@ -139,15 +139,11 @@ int guac_terminal_echo(guac_terminal* term, char c) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For now, render all but basic latin as '?' */
|
|
||||||
if (codepoint > 0x7F)
|
|
||||||
codepoint = '?';
|
|
||||||
|
|
||||||
/* Write character */
|
/* Write character */
|
||||||
guac_terminal_set(term,
|
guac_terminal_set(term,
|
||||||
term->cursor_row,
|
term->cursor_row,
|
||||||
term->cursor_col,
|
term->cursor_col,
|
||||||
(char) codepoint);
|
codepoint);
|
||||||
|
|
||||||
/* Advance cursor */
|
/* Advance cursor */
|
||||||
term->cursor_col++;
|
term->cursor_col++;
|
||||||
|
Loading…
Reference in New Issue
Block a user