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 <string.h>
#include <wchar.h>
#include <guacamole/client.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,
* 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.
* Returns a cached glyph for the given codepoint, rendering and caching it first if necessary.
*/
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;
int cell_width = display->char_width * GUAC_TERMINAL_MAX_CHAR_WIDTH;
int location;
int width;
int bytes;
char utf8[4];
@ -147,15 +148,16 @@ int __guac_terminal_get_glyph(guac_terminal_display* display, int codepoint) {
/* Get codepoint hash */
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 (display->glyphs[hashcode].location) {
if (glyph->location) {
location = display->glyphs[hashcode].location - 1;
location = glyph->location - 1;
/* If match, return match. */
if (display->glyphs[hashcode].codepoint == codepoint)
return location;
if (glyph->codepoint == codepoint)
return glyph;
/* Otherwise, reuse location */
@ -168,10 +170,15 @@ int __guac_terminal_get_glyph(guac_terminal_display* display, int codepoint) {
/* Convert to UTF-8 */
bytes = guac_terminal_encode_utf8(codepoint, utf8);
/* Calculate width in columns */
width = wcwidth(codepoint);
if (width < 0)
width = 1;
/* Prepare surface */
surface = cairo_image_surface_create(
CAIRO_FORMAT_ARGB32,
display->char_width, display->char_height);
cell_width, display->char_height);
cairo = cairo_create(surface);
/* Get layout */
@ -195,19 +202,19 @@ int __guac_terminal_get_glyph(guac_terminal_display* display, int codepoint) {
/* Clear existing glyph (if any) */
guac_protocol_send_rect(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_protocol_send_cfill(socket, GUAC_COMP_ROUT, display->glyph_stroke,
0x00, 0x00, 0x00, 0xFF);
/* 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 */
guac_protocol_send_rect(socket, display->filled_glyphs,
location * display->char_width, 0,
display->char_width, display->char_height);
location * cell_width, 0,
cell_width, display->char_height);
guac_protocol_send_cfill(socket, GUAC_COMP_OVER, display->filled_glyphs,
background->red,
@ -216,16 +223,16 @@ int __guac_terminal_get_glyph(guac_terminal_display* display, int codepoint) {
0xFF);
guac_protocol_send_copy(socket, display->glyph_stroke,
location * display->char_width, 0, display->char_width, display->char_height,
GUAC_COMP_OVER, display->filled_glyphs, location * display->char_width, 0);
display->glyphs[hashcode].location = location+1;
display->glyphs[hashcode].codepoint = codepoint;
location * cell_width, 0, cell_width, display->char_height,
GUAC_COMP_OVER, display->filled_glyphs, location * cell_width, 0);
cairo_surface_destroy(surface);
/* 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;
const guac_terminal_color* background_color;
int cell_width = display->char_width * GUAC_TERMINAL_MAX_CHAR_WIDTH;
int background, foreground;
/* Handle reverse video */
@ -267,7 +275,7 @@ int __guac_terminal_set_colors(guac_terminal_display* display,
/* Colorize letter */
guac_protocol_send_rect(socket, display->glyph_stroke,
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,
color->red,
@ -284,7 +292,7 @@ int __guac_terminal_set_colors(guac_terminal_display* display,
/* Set background */
guac_protocol_send_rect(socket, display->filled_glyphs,
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,
background_color->red,
@ -296,7 +304,7 @@ int __guac_terminal_set_colors(guac_terminal_display* display,
guac_protocol_send_copy(socket, display->glyph_stroke,
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,
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) {
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,
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,
display->char_width * col,
display->char_height * row);

View File

@ -31,6 +31,11 @@
#include <guacamole/client.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
* here are indices into this palette.
@ -105,6 +110,11 @@ typedef struct guac_terminal_glyph {
*/
int codepoint;
/**
* The width of this glyph, in columns.
*/
int width;
} guac_terminal_glyph;
/**