[pve-devel] [RFC PATCH 4/4] use unifont and add support for wide-characters and diacritics
Dominik Csapak
d.csapak at proxmox.com
Mon May 22 18:14:58 CEST 2017
this patch makes use of unifont with genfont2 and introduces support for
wide-characters and diacritics
for this we have to save the width and possible diacritic in the
textcell, which means we also have to reset them properly and give those
values also to draw_char_at
to determine the width we use the wcwidth provided by unifont
(because in unifont some characters are wide which normally are not)
we mmap the generated fontfile, and drop the glyphs.h, which reduces
the initial memory use, and shares the pages between processes
Signed-off-by: Dominik Csapak <d.csapak at proxmox.com>
---
Makefile | 19 +++++------
vncterm.c | 114 ++++++++++++++++++++++++++++++++++++++++++++------------------
vncterm.h | 2 ++
3 files changed, 92 insertions(+), 43 deletions(-)
diff --git a/Makefile b/Makefile
index e981dbb..e9de539 100644
--- a/Makefile
+++ b/Makefile
@@ -17,13 +17,6 @@ SNAP=${PACKAGE}-${VERSION}-${CDATE}.tar.gz
all: vncterm
-glyphs.h: genfont
- ./genfont > glyphs.h.tmp
- mv glyphs.h.tmp glyphs.h
-
-genfont: genfont.c
- gcc -g -O2 -o $@ genfont.c -Wall -D_GNU_SOURCE -lz
-
font.data: genfont2
./genfont2 > font.data.tmp
mv font.data.tmp font.data
@@ -40,14 +33,18 @@ ${VNCLIB} vnc: ${VNCSRC}
cd ${VNCDIR}; ./autogen.sh --without-ssl --without-websockets --without-tightvnc-filetransfer;
cd ${VNCDIR}; make
-vncterm: vncterm.c glyphs.h ${VNCLIB}
- gcc -O2 -g -o $@ vncterm.c -Wall -Wno-deprecated-declarations -D_GNU_SOURCE -I ${VNCDIR} ${VNCLIB} -lnsl -lpthread -lz -ljpeg -lutil -lgnutls -lpng
+vncterm: vncterm.c ${VNCLIB} wchardata.c
+ gcc -O2 -g -o $@ vncterm.c wchardata.c -Wall -Wno-deprecated-declarations -D_GNU_SOURCE -I ${VNCDIR} ${VNCLIB} -lnsl -lpthread -lz -ljpeg -lutil -lgnutls -lpng
+wchardata.c:
+ cp /usr/share/unifont/$@ $@
.PHONY: install
-install: vncterm vncterm.1
+install: vncterm vncterm.1 font.data
mkdir -p ${DESTDIR}/usr/share/doc/${PACKAGE}
install -m 0644 copyright ${DESTDIR}/usr/share/doc/${PACKAGE}
+ mkdir -p ${DESTDIR}/usr/share/${PACKAGE}
+ install -m 0644 font.data ${DESTDIR}/usr/share/${PACKAGE}
mkdir -p ${DESTDIR}/usr/share/man/man1
install -m 0644 vncterm.1 ${DESTDIR}/usr/share/man/man1
mkdir -p ${DESTDIR}/usr/bin
@@ -77,7 +74,7 @@ upload: ${DEB}
.PHONY: clean
clean:
- rm -rf vncterm vncterm.1 vncterm_*.deb genfont genfont2 *~ ${VNCDIR} vncterm-*.tar.gz glyph.h.tmp build *.changes font.data.tmp font.data
+ rm -rf vncterm vncterm.1 vncterm_*.deb genfont genfont2 *~ ${VNCDIR} vncterm-*.tar.gz glyph.h.tmp build *.changes wchardata.c font.data.tmp font.data *.buildinfo
.PHONY: distclean
distclean: clean
diff --git a/vncterm.c b/vncterm.c
index 5939f64..929f74e 100644
--- a/vncterm.c
+++ b/vncterm.c
@@ -26,6 +26,9 @@
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <rfb/rfb.h>
@@ -39,7 +42,6 @@
#include <locale.h>
#include "vncterm.h"
-#include "glyphs.h"
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
@@ -55,6 +57,12 @@ uint16_t screen_height = 400;
int use_x509 = 1;
+extern int wcwidth (wchar_t wc);
+unsigned char *fontdata;
+
+#define FONTFILE "/usr/share/vncterm/font.data"
+#define GLYPHLINES 16
+
static char *
urlencode(char *buf, const char *value)
{
@@ -629,21 +637,16 @@ ucs2_to_utf8 (unicode c, char *out)
static void
rfb_draw_char (rfbScreenInfoPtr rfbScreen, int x, int y,
- unsigned short c, rfbPixel col)
+ unicode c, rfbPixel col, short width)
{
- if (c > vt_font_size) {
- rfbLog ("undefined font glyph %d\n", c);
- return;
- }
-
int i,j;
- unsigned char *data= vt_font_data + c*16;
+ unsigned char *data= fontdata + c*(GLYPHLINES*2);
unsigned char d=*data;
int rowstride=rfbScreen->paddedWidthInBytes;
char *colour=(char*)&col;
- for(j = 0; j < 16; j++) {
- for(i = 0; i < 8; i++) {
+ for(j = 0; j < GLYPHLINES; j++) {
+ for(i = 0; i < 8*width; i++) {
if ((i&7) == 0) {
d=*data;
data++;
@@ -656,13 +659,16 @@ rfb_draw_char (rfbScreenInfoPtr rfbScreen, int x, int y,
}
static void
-draw_char_at (vncTerm *vt, int x, int y, unicode ch, TextAttributes attrib)
+draw_char_at (vncTerm *vt, int x, int y, unicode ch, TextAttributes attrib, short width, unicode diacritic)
{
if (x < 0 || y < 0 || x >= vt->width || y >= vt->height) { return; }
+ // non printable character
+ if (width < 1) return;
+
int rx = x*8;
int ry = y*16;
- int rxe = x*8+8;
+ int rxe = x*8+8*width;
int rye = y*16+16;
int fg, bg;
@@ -675,8 +681,6 @@ draw_char_at (vncTerm *vt, int x, int y, unicode ch, TextAttributes attrib)
fg = attrib.fgcol;
}
- int ec = vt_fontmap[ch];
-
rfbFillRect (vt->screen, rx, ry, rxe, rye, bg);
if (attrib.bold) {
@@ -685,7 +689,11 @@ draw_char_at (vncTerm *vt, int x, int y, unicode ch, TextAttributes attrib)
// unsuported attributes = (attrib.blink || attrib.unvisible)
- rfb_draw_char (vt->screen, rx, ry, ec, fg);
+ rfb_draw_char (vt->screen, rx, ry, ch, fg, width);
+
+ if (diacritic) {
+ rfb_draw_char (vt->screen, rx, ry, diacritic, fg, 1);
+ }
if (attrib.uline) {
rfbDrawLine (vt->screen, rx, ry + 14, rxe, ry + 14, fg);
@@ -707,7 +715,7 @@ vncterm_update_xy (vncTerm *vt, int x, int y)
}
if (y2 < vt->height) {
TextCell *c = &vt->cells[y1 * vt->width + x];
- draw_char_at (vt, x, y2, c->ch, c->attrib);
+ draw_char_at (vt, x, y2, c->ch, c->attrib, c->width, c->diacritic);
}
}
@@ -727,8 +735,10 @@ vncterm_clear_xy (vncTerm *vt, int x, int y)
c->attrib = vt->default_attrib;
c->attrib.fgcol = vt->cur_attrib.fgcol;
c->attrib.bgcol = vt->cur_attrib.bgcol;
+ c->width = 1;
+ c->diacritic = 0;
- draw_char_at (vt, x, y, c->ch, c->attrib);
+ draw_char_at (vt, x, y, c->ch, c->attrib, c->width, c->diacritic);
}
}
@@ -753,9 +763,9 @@ vncterm_show_cursor (vncTerm *vt, int show)
if (show) {
TextAttributes attrib = vt->default_attrib;
attrib.invers = !(attrib.invers); /* invert fg and bg */
- draw_char_at (vt, x, y, c->ch, attrib);
+ draw_char_at (vt, x, y, c->ch, attrib, c->width, c->diacritic);
} else {
- draw_char_at (vt, x, y, c->ch, c->attrib);
+ draw_char_at (vt, x, y, c->ch, c->attrib, c->width, c->diacritic);
}
}
}
@@ -771,8 +781,8 @@ vncterm_refresh (vncTerm *vt)
for(y = 0; y < vt->height; y++) {
TextCell *c = vt->cells + y1 * vt->width;
for(x = 0; x < vt->width; x++) {
- draw_char_at (vt, x, y, c->ch, c->attrib);
- c++;
+ draw_char_at (vt, x, y, c->ch, c->attrib, c->width, c->diacritic);
+ c += c->width;
}
if (++y1 == vt->total_height)
y1 = 0;
@@ -821,6 +831,8 @@ vncterm_scroll_down (vncTerm *vt, int top, int bottom, int lines)
for(j = 0; j < vt->width; j++) {
c->attrib = vt->default_attrib;
c->ch = ' ';
+ c->width = 1;
+ c->diacritic = 0;
c++;
}
}
@@ -870,6 +882,8 @@ vncterm_scroll_up (vncTerm *vt, int top, int bottom, int lines, int moveattr)
for(j = 0; j < vt->width; j++) {
c->attrib = vt->default_attrib;
c->ch = ' ';
+ c->width = 1;
+ c->diacritic = 0;
c++;
}
}
@@ -954,6 +968,8 @@ vncterm_put_lf (vncTerm *vt)
int x;
for (x = 0; x < vt->width; x++) {
c->ch = ' ';
+ c->width = 1;
+ c->diacritic = 0;
c->attrib = vt->default_attrib;
c++;
}
@@ -1176,9 +1192,7 @@ vncterm_gotoxy (vncTerm *vt, int x, int y)
if (x < 0) {
x = 0;
- }
-
- if (x >= vt->width) {
+ } else if (x >= vt->width) {
x = vt->width - 1;
}
@@ -1186,9 +1200,7 @@ vncterm_gotoxy (vncTerm *vt, int x, int y)
if (y < 0) {
y = 0;
- }
-
- if (y >= vt->height) {
+ } else if (y >= vt->height) {
y = vt->height - 1;
}
@@ -1553,6 +1565,8 @@ vncterm_putchar (vncTerm *vt, unicode ch)
*dst = *src;
vncterm_update_xy (vt, x + c, vt->cy);
src->ch = ' ';
+ src->width = 1;
+ src->diacritic = 0;
src->attrib = vt->default_attrib;
vncterm_update_xy (vt, x, vt->cy);
}
@@ -1591,6 +1605,8 @@ vncterm_putchar (vncTerm *vt, unicode ch)
*dst = *src;
vncterm_update_xy (vt, x + c, vt->cy);
src->ch = ' ';
+ src->width = 1;
+ src->diacritic = 0;
src->attrib = vt->cur_attrib;
vncterm_update_xy (vt, x, vt->cy);
}
@@ -1746,11 +1762,25 @@ vncterm_putchar (vncTerm *vt, unicode ch)
}
int y1 = (vt->y_base + vt->cy) % vt->total_height;
- TextCell *c = &vt->cells[y1*vt->width + vt->cx];
- c->attrib = vt->cur_attrib;
- c->ch = ch;
- vncterm_update_xy (vt, vt->cx, vt->cy);
- vt->cx++;
+ int width = wcwidth(ch);
+ if (width > 0) {
+ // normal/wide character
+ TextCell *c = &vt->cells[y1*vt->width + vt->cx];
+ c->attrib = vt->cur_attrib;
+ c->ch = ch;
+ c->width = width;
+ c->diacritic = 0;
+ vncterm_update_xy (vt, vt->cx, vt->cy);
+ vt->cx += width;
+ } else if (width == 0) {
+ // diacritic
+ TextCell *c = &vt->cells[y1*vt->width + vt->cx - 1];
+ c->attrib = vt->cur_attrib;
+ c->diacritic = ch;
+ vncterm_update_xy (vt, vt->cx - 1, vt->cy);
+ } else {
+ // non printable character, so we do not save them
+ }
break;
}
break;
@@ -2270,6 +2300,8 @@ main (int argc, char** argv)
int i;
char **cmdargv = NULL;
char *command = "/bin/bash"; // execute normal shell as default
+ int fontfd;
+ struct stat sb;
int pid;
int master;
char ptyname[1024];
@@ -2353,6 +2385,23 @@ main (int argc, char** argv)
rfbLogEnable (0);
#endif
+ // mmap font file
+ fontfd = open(FONTFILE, O_RDONLY);
+ if (fontfd == -1) {
+ perror("Error opening Fontfile 'FONTFILE'");
+ exit (-1);
+ }
+ if (fstat(fontfd, &sb) == -1) {
+ perror("Stat on 'FONTFILE' failed");
+ exit (-1);
+ }
+ fontdata = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fontfd, 0);
+ if (fontdata == MAP_FAILED) {
+ perror("Could not mmap 'FONTFILE'");
+ exit (-1);
+ }
+
+ close(fontfd);
vncTerm *vt = create_vncterm (argc, argv, screen_width, screen_height);
setlocale(LC_ALL, ""); // set from environment
@@ -2457,5 +2506,6 @@ main (int argc, char** argv)
int status;
waitpid(pid, &status, 0);
+ munmap(fontdata, sb.st_size);
exit (0);
}
diff --git a/vncterm.h b/vncterm.h
index 8f7d837..cfb11a0 100644
--- a/vncterm.h
+++ b/vncterm.h
@@ -17,6 +17,8 @@ typedef struct TextAttributes {
typedef struct TextCell {
unicode ch;
+ unicode diacritic;
+ short width;
TextAttributes attrib;
} TextCell;
--
2.11.0
More information about the pve-devel
mailing list