Unicode support.

This commit is contained in:
Michael Jumper 2013-05-02 14:56:20 -07:00
parent de5b945f73
commit 356e3945e9
6 changed files with 116 additions and 22 deletions

View File

@ -102,6 +102,25 @@ typedef struct 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.
*/
@ -150,7 +169,7 @@ typedef struct guac_terminal_display {
/**
* 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

View File

@ -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.
*/
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.

View File

@ -107,9 +107,9 @@ typedef struct guac_terminal_attributes {
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.

View File

@ -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,
* sending it first if necessary. The location returned is in characters,
* and thus must be multiplied by the glyph width to obtain the actual
* 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;
int location;
char utf8[5];
/* Use foreground color */
const guac_terminal_color* color =
&guac_terminal_palette[display->glyph_foreground];
@ -92,13 +154,29 @@ int __guac_terminal_get_glyph(guac_terminal_display* display, char c) {
PangoLayout* layout;
/* Return glyph if exists */
if (display->glyphs[(int) c])
return display->glyphs[(int) c] - 1;
/* Get codepoint hash */
int hashcode = __guac_terminal_hash_codepoint(codepoint);
/* 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++;
/* Otherwise, draw glyph */
/* Convert to UTF-8 */
__guac_terminal_encode_utf8(codepoint, utf8);
/* Prepare surface */
surface = cairo_image_surface_create(
CAIRO_FORMAT_ARGB32,
display->char_width, display->char_height);
@ -107,7 +185,7 @@ int __guac_terminal_get_glyph(guac_terminal_display* display, char c) {
/* Get layout */
layout = pango_cairo_create_layout(cairo);
pango_layout_set_font_description(layout, display->font_desc);
pango_layout_set_text(layout, &c, 1);
pango_layout_set_text(layout, utf8, 1);
/* Draw */
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,
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);
@ -235,10 +314,10 @@ int __guac_terminal_set_colors(guac_terminal_display* display,
* rendering the charater immediately. This bypasses the guac_terminal_display
* 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;
int location = __guac_terminal_get_glyph(display, c);
int location = __guac_terminal_get_glyph(display, codepoint);
return guac_protocol_send_copy(socket,
display->filled_glyphs,

View File

@ -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 */
guac_terminal_char guac_char;
guac_char.value = c;
guac_char.value = codepoint;
guac_char.attributes = term->current_attributes;
guac_terminal_set_columns(term, row, col, col, &guac_char);

View File

@ -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 */
guac_terminal_set(term,
term->cursor_row,
term->cursor_col,
(char) codepoint);
codepoint);
/* Advance cursor */
term->cursor_col++;