]> git.proxmox.com Git - vncterm.git/commitdiff
use unifont and add support for wide-characters and combining glyphs
authorDominik Csapak <d.csapak@proxmox.com>
Wed, 24 May 2017 09:37:51 +0000 (11:37 +0200)
committerWolfgang Bumiller <w.bumiller@proxmox.com>
Wed, 24 May 2017 10:55:19 +0000 (12:55 +0200)
this patch makes use of unifont with genfont2 and introduces support for
wide-characters and combining glyphs

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@proxmox.com>
Makefile
vncterm.c
vncterm.h

index 8b37c66da5c5906ba493acf0bf2df534502e9dbc..ecf6b438e34086ce367884f6548fc8cb968d8950 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -17,13 +17,6 @@ SNAP=${PACKAGE}-${VERSION}-${CDATE}.tar.gz
 
 all: vncterm
 
 
 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 -o font.data.tmp -i /usr/share/unifont/unifont.hex
        mv font.data.tmp font.data
 font.data: genfont2
        ./genfont2 -o font.data.tmp -i /usr/share/unifont/unifont.hex
        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
 
        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
 
 .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/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
        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:
 
 .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
 
 .PHONY: distclean
 distclean: clean
index 7fb424fb17ee2ea2d8db04f7baf92c58a1f19598..ed77f58c7ce28270e77d557a7f8e05b1bf52c884 100644 (file)
--- a/vncterm.c
+++ b/vncterm.c
@@ -26,6 +26,9 @@
 #include <stdlib.h>
 #include <sys/types.h> 
 #include <sys/socket.h>
 #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>
 #include <arpa/inet.h>
 #include <netdb.h>
 #include <rfb/rfb.h>
@@ -39,7 +42,6 @@
 #include <locale.h>
 
 #include "vncterm.h"
 #include <locale.h>
 
 #include "vncterm.h"
-#include "glyphs.h"
 
 #include <gnutls/gnutls.h>
 #include <gnutls/x509.h>
 
 #include <gnutls/gnutls.h>
 #include <gnutls/x509.h>
@@ -55,6 +57,12 @@ uint16_t screen_height = 400;
 
 int use_x509 = 1;
 
 
 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)
 {
 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,
 
 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;
   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;
 
   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++;
       if ((i&7) == 0) {
        d=*data;
        data++;
@@ -656,13 +659,16 @@ rfb_draw_char (rfbScreenInfoPtr rfbScreen, int x, int y,
 }
 
 static void
 }
 
 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 combiningglyph)
 {
   if (x < 0 || y < 0 || x >= vt->width || y >= vt->height) { return; }
 
 {
   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 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;
   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;
   }
 
     fg = attrib.fgcol;
   }
 
-  int ec = vt_fontmap[ch];
-
   rfbFillRect (vt->screen, rx, ry, rxe, rye, bg);
 
   if (attrib.bold) {
   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)
 
 
   // 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 (combiningglyph) {
+      rfb_draw_char (vt->screen, rx, ry, combiningglyph, fg, 1);
+  }
 
   if (attrib.uline) {
     rfbDrawLine (vt->screen, rx, ry + 14, rxe, ry + 14, fg);
 
   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];
   }
   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->combiningglyph);
   }
 }
 
   }
 }
 
@@ -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->attrib = vt->default_attrib;
     c->attrib.fgcol = vt->cur_attrib.fgcol;
     c->attrib.bgcol = vt->cur_attrib.bgcol;
+    c->width = 1;
+    c->combiningglyph = 0;
 
 
-    draw_char_at (vt, x, y, c->ch, c->attrib);
+    draw_char_at (vt, x, y, c->ch, c->attrib, c->width, c->combiningglyph);
   }
 }
 
   }
 }
 
@@ -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 */
     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->combiningglyph);
     } else {
     } else {
-      draw_char_at (vt, x, y, c->ch, c->attrib);
+      draw_char_at (vt, x, y, c->ch, c->attrib, c->width, c->combiningglyph);
     }
   }
 }
     }
   }
 }
@@ -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++) {
   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->combiningglyph);
+      c += c->width;
     }
     if (++y1 == vt->total_height)
       y1 = 0;
     }
     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 = ' ';
     for(j = 0; j < vt->width; j++) {
       c->attrib = vt->default_attrib;
       c->ch = ' ';
+      c->width = 1;
+      c->combiningglyph = 0;
       c++;
     }
   }
       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 = ' ';
     for(j = 0; j < vt->width; j++) {
       c->attrib = vt->default_attrib;
       c->ch = ' ';
+      c->width = 1;
+      c->combiningglyph = 0;
       c++;
     }
   }
       c++;
     }
   }
@@ -954,6 +968,8 @@ vncterm_put_lf (vncTerm *vt)
     int x;
     for (x = 0; x < vt->width; x++) {
       c->ch = ' ';
     int x;
     for (x = 0; x < vt->width; x++) {
       c->ch = ' ';
+      c->width = 1;
+      c->combiningglyph = 0;
       c->attrib = vt->default_attrib;
       c++;
     }
       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 < 0) {
     x = 0;
-  }
-
-  if (x >= vt->width) {
+  } else if (x >= vt->width) {
     x = vt->width - 1;
   }
 
     x = vt->width - 1;
   }
 
@@ -1186,9 +1200,7 @@ vncterm_gotoxy (vncTerm *vt, int x, int y)
 
   if (y < 0) {
     y = 0;
 
   if (y < 0) {
     y = 0;
-  }
-
-  if (y >= vt->height) {
+  } else if (y >= vt->height) {
     y = vt->height - 1;
   }
 
     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 = ' ';
        *dst = *src;
        vncterm_update_xy (vt, x + c, vt->cy);
        src->ch = ' ';
+       src->width = 1;
+       src->combiningglyph = 0;
        src->attrib = vt->default_attrib;
        vncterm_update_xy (vt, x, vt->cy);
       }
        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 = ' ';
        *dst = *src;
        vncterm_update_xy (vt, x + c, vt->cy);
        src->ch = ' ';
+       src->width = 1;
+       src->combiningglyph = 0;
        src->attrib = vt->cur_attrib;
        vncterm_update_xy (vt, x, vt->cy);
       }
        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;
       }
 
       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->combiningglyph = 0;
+         vncterm_update_xy (vt, vt->cx, vt->cy);
+         vt->cx += width;
+      } else if (width == 0) {
+         // combiningglyph
+         TextCell *c = &vt->cells[y1*vt->width + vt->cx - 1];
+         c->attrib = vt->cur_attrib;
+         c->combiningglyph = ch;
+         vncterm_update_xy (vt, vt->cx - 1, vt->cy);
+      } else {
+         // non printable character, so we do not save them
+      }
       break;
     }
     break;
       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 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];
   int pid;
   int master;
   char ptyname[1024];
@@ -2353,6 +2385,23 @@ main (int argc, char** argv)
   rfbLogEnable (0);
 #endif
 
   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
   vncTerm *vt = create_vncterm (argc, argv, screen_width, screen_height);
 
   setlocale(LC_ALL, ""); // set from environment
@@ -2453,9 +2502,12 @@ main (int argc, char** argv)
     }
   }
 
     }
   }
 
+  rfbScreenCleanup(vt->screen);
+
   kill (pid, 9);
   int status;
   waitpid(pid, &status, 0);
 
   kill (pid, 9);
   int status;
   waitpid(pid, &status, 0);
 
+  munmap(fontdata, sb.st_size);
   exit (0);
 }
   exit (0);
 }
index 8f7d8375f5489abccb9491e3424004ab6ce9b8b2..9a8b1e3f5b7385cdc78f1280262736d131761ce6 100644 (file)
--- a/vncterm.h
+++ b/vncterm.h
@@ -17,6 +17,8 @@ typedef struct TextAttributes {
 
 typedef struct TextCell {
   unicode ch;
 
 typedef struct TextCell {
   unicode ch;
+  unicode combiningglyph;
+  short width;
   TextAttributes attrib;
 } TextCell;
 
   TextAttributes attrib;
 } TextCell;