GUAC-718: Update display to cache and use variable-width glyphs.

This commit is contained in:
Michael Jumper 2014-06-02 12:52:42 -07:00
parent 3bd145a059
commit b5087a2a6f
2 changed files with 49 additions and 26 deletions

View File

@ -28,6 +28,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <wchar.h>
#include <guacamole/client.h> #include <guacamole/client.h>
#include <guacamole/protocol.h> #include <guacamole/protocol.h>
@ -119,15 +120,15 @@ int __guac_terminal_hash_codepoint(int codepoint) {
} }
/** /**
* Returns the location of the given character in the glyph cache layer, * Returns a cached glyph for the given codepoint, rendering and caching it first if necessary.
* 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, int codepoint) { guac_terminal_glyph* __guac_terminal_get_glyph(guac_terminal_display* display, int codepoint) {
guac_socket* socket = display->client->socket; guac_socket* socket = display->client->socket;
int cell_width = display->char_width * GUAC_TERMINAL_MAX_CHAR_WIDTH;
int location; int location;
int width;
int bytes; int bytes;
char utf8[4]; char utf8[4];
@ -147,15 +148,16 @@ int __guac_terminal_get_glyph(guac_terminal_display* display, int codepoint) {
/* Get codepoint hash */ /* Get codepoint hash */
int hashcode = __guac_terminal_hash_codepoint(codepoint); int hashcode = __guac_terminal_hash_codepoint(codepoint);
guac_terminal_glyph* glyph = &(display->glyphs[hashcode]);
/* If something already stored here, either same codepoint or collision */ /* If something already stored here, either same codepoint or collision */
if (display->glyphs[hashcode].location) { if (glyph->location) {
location = display->glyphs[hashcode].location - 1; location = glyph->location - 1;
/* If match, return match. */ /* If match, return match. */
if (display->glyphs[hashcode].codepoint == codepoint) if (glyph->codepoint == codepoint)
return location; return glyph;
/* Otherwise, reuse location */ /* Otherwise, reuse location */
@ -168,10 +170,15 @@ int __guac_terminal_get_glyph(guac_terminal_display* display, int codepoint) {
/* Convert to UTF-8 */ /* Convert to UTF-8 */
bytes = guac_terminal_encode_utf8(codepoint, utf8); bytes = guac_terminal_encode_utf8(codepoint, utf8);
/* Calculate width in columns */
width = wcwidth(codepoint);
if (width < 0)
width = 1;
/* Prepare surface */ /* Prepare surface */
surface = cairo_image_surface_create( surface = cairo_image_surface_create(
CAIRO_FORMAT_ARGB32, CAIRO_FORMAT_ARGB32,
display->char_width, display->char_height); cell_width, display->char_height);
cairo = cairo_create(surface); cairo = cairo_create(surface);
/* Get layout */ /* Get layout */
@ -195,19 +202,19 @@ int __guac_terminal_get_glyph(guac_terminal_display* display, int codepoint) {
/* Clear existing glyph (if any) */ /* Clear existing glyph (if any) */
guac_protocol_send_rect(socket, display->glyph_stroke, guac_protocol_send_rect(socket, display->glyph_stroke,
location * display->char_width, 0, location * cell_width, 0,
display->char_width, display->char_height); cell_width, display->char_height);
guac_protocol_send_cfill(socket, GUAC_COMP_ROUT, display->glyph_stroke, guac_protocol_send_cfill(socket, GUAC_COMP_ROUT, display->glyph_stroke,
0x00, 0x00, 0x00, 0xFF); 0x00, 0x00, 0x00, 0xFF);
/* Send glyph */ /* Send glyph */
guac_protocol_send_png(socket, GUAC_COMP_OVER, display->glyph_stroke, location * display->char_width, 0, surface); guac_protocol_send_png(socket, GUAC_COMP_OVER, display->glyph_stroke, location * cell_width, 0, surface);
/* Update filled glyphs */ /* Update filled glyphs */
guac_protocol_send_rect(socket, display->filled_glyphs, guac_protocol_send_rect(socket, display->filled_glyphs,
location * display->char_width, 0, location * cell_width, 0,
display->char_width, display->char_height); cell_width, display->char_height);
guac_protocol_send_cfill(socket, GUAC_COMP_OVER, display->filled_glyphs, guac_protocol_send_cfill(socket, GUAC_COMP_OVER, display->filled_glyphs,
background->red, background->red,
@ -216,16 +223,16 @@ int __guac_terminal_get_glyph(guac_terminal_display* display, int codepoint) {
0xFF); 0xFF);
guac_protocol_send_copy(socket, display->glyph_stroke, guac_protocol_send_copy(socket, display->glyph_stroke,
location * display->char_width, 0, display->char_width, display->char_height, location * cell_width, 0, cell_width, display->char_height,
GUAC_COMP_OVER, display->filled_glyphs, location * display->char_width, 0); GUAC_COMP_OVER, display->filled_glyphs, location * cell_width, 0);
display->glyphs[hashcode].location = location+1;
display->glyphs[hashcode].codepoint = codepoint;
cairo_surface_destroy(surface); cairo_surface_destroy(surface);
/* Return glyph */ /* Return glyph */
return location; glyph->location = location+1;
glyph->codepoint = codepoint;
glyph->width = width;
return glyph;
} }
@ -238,6 +245,7 @@ int __guac_terminal_set_colors(guac_terminal_display* display,
guac_socket* socket = display->client->socket; guac_socket* socket = display->client->socket;
const guac_terminal_color* background_color; const guac_terminal_color* background_color;
int cell_width = display->char_width * GUAC_TERMINAL_MAX_CHAR_WIDTH;
int background, foreground; int background, foreground;
/* Handle reverse video */ /* Handle reverse video */
@ -267,7 +275,7 @@ int __guac_terminal_set_colors(guac_terminal_display* display,
/* Colorize letter */ /* Colorize letter */
guac_protocol_send_rect(socket, display->glyph_stroke, guac_protocol_send_rect(socket, display->glyph_stroke,
0, 0, 0, 0,
display->char_width * display->next_glyph, display->char_height); cell_width * display->next_glyph, display->char_height);
guac_protocol_send_cfill(socket, GUAC_COMP_ATOP, display->glyph_stroke, guac_protocol_send_cfill(socket, GUAC_COMP_ATOP, display->glyph_stroke,
color->red, color->red,
@ -284,7 +292,7 @@ int __guac_terminal_set_colors(guac_terminal_display* display,
/* Set background */ /* Set background */
guac_protocol_send_rect(socket, display->filled_glyphs, guac_protocol_send_rect(socket, display->filled_glyphs,
0, 0, 0, 0,
display->char_width * display->next_glyph, display->char_height); cell_width * display->next_glyph, display->char_height);
guac_protocol_send_cfill(socket, GUAC_COMP_OVER, display->filled_glyphs, guac_protocol_send_cfill(socket, GUAC_COMP_OVER, display->filled_glyphs,
background_color->red, background_color->red,
@ -296,7 +304,7 @@ int __guac_terminal_set_colors(guac_terminal_display* display,
guac_protocol_send_copy(socket, display->glyph_stroke, guac_protocol_send_copy(socket, display->glyph_stroke,
0, 0, 0, 0,
display->char_width * display->next_glyph, display->char_height, cell_width * display->next_glyph, display->char_height,
GUAC_COMP_OVER, display->filled_glyphs, GUAC_COMP_OVER, display->filled_glyphs,
0, 0); 0, 0);
@ -318,11 +326,16 @@ int __guac_terminal_set_colors(guac_terminal_display* display,
int __guac_terminal_set(guac_terminal_display* display, int row, int col, int codepoint) { 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, codepoint); guac_terminal_glyph* glyph = __guac_terminal_get_glyph(display, codepoint);
int cell_width = display->char_width * GUAC_TERMINAL_MAX_CHAR_WIDTH;
/* Do nothing if glyph is empty */
if (glyph->width == 0)
return 0;
return guac_protocol_send_copy(socket, return guac_protocol_send_copy(socket,
display->filled_glyphs, display->filled_glyphs,
location * display->char_width, 0, display->char_width, display->char_height, (glyph->location-1) * cell_width, 0, glyph->width * display->char_width, display->char_height,
GUAC_COMP_OVER, GUAC_DEFAULT_LAYER, GUAC_COMP_OVER, GUAC_DEFAULT_LAYER,
display->char_width * col, display->char_width * col,
display->char_height * row); display->char_height * row);

View File

@ -31,6 +31,11 @@
#include <guacamole/client.h> #include <guacamole/client.h>
#include <pango/pangocairo.h> #include <pango/pangocairo.h>
/**
* The maximum width of any character, in columns.
*/
#define GUAC_TERMINAL_MAX_CHAR_WIDTH 2
/** /**
* The available color palette. All integer colors within structures * The available color palette. All integer colors within structures
* here are indices into this palette. * here are indices into this palette.
@ -105,6 +110,11 @@ typedef struct guac_terminal_glyph {
*/ */
int codepoint; int codepoint;
/**
* The width of this glyph, in columns.
*/
int width;
} guac_terminal_glyph; } guac_terminal_glyph;
/** /**