ref: 5305f09a87d6e6ab4a05008eb5bd51b08205886a
parent: 9edd90dc0a5357595d9d44bfb4bc7bcd03cdef7d
author: Ali Gholami Rudi <ali@rudi.ir>
date: Mon Sep 9 15:36:18 EDT 2013
trfn: support arabic and arbitrary ligatures
--- a/trfn.c
+++ b/trfn.c
@@ -10,7 +10,8 @@
#define WX(w) (((w) < 0 ? (w) - trfn_div / 2 : (w) + trfn_div / 2) / trfn_div)
#define LEN(a) ((sizeof(a) / sizeof((a)[0])))
#define HEXDIGS "0123456789abcdef"
-#define GNLEN 32
+#define NCHAR 8
+#define GNLEN 64
#define AGLLEN (8 * 1024)
static struct sbuf sbuf_char; /* charset section */
@@ -18,7 +19,7 @@
static int trfn_div; /* divisor of widths */
static int trfn_swid; /* space width */
static int trfn_special; /* special flag */
-static char trfn_ligs[1024]; /* font ligatures */
+static char trfn_ligs[8192]; /* font ligatures */
static char trfn_trname[256]; /* font troff name */
static char trfn_psname[256]; /* font ps name */
@@ -32,8 +33,41 @@
static struct tab *tab_alts;
static struct tab *tab_ctyp;
-static void pututf8(char **d, int c)
+static int utf8len(int c)
{
+ if (c > 0 && c <= 0x7f)
+ return 1;
+ if (c >= 0xfc)
+ return 6;
+ if (c >= 0xf8)
+ return 5;
+ if (c >= 0xf0)
+ return 4;
+ if (c >= 0xe0)
+ return 3;
+ if (c >= 0xc0)
+ return 2;
+ return c != 0;
+}
+
+static int utf8get(char **src)
+{
+ int result;
+ int l = 1;
+ char *s = *src;
+ if (~((unsigned char) **src) & 0xc0)
+ return (unsigned char) *(*src)++;
+ while (l < 6 && (unsigned char) *s & (0x40 >> l))
+ l++;
+ result = (0x3f >> l) & (unsigned char) *s++;
+ while (l--)
+ result = (result << 6) | ((unsigned char) *s++ & 0x3f);
+ *src = s;
+ return result;
+}
+
+static void utf8put(char **d, int c)
+{
int l;
if (c > 0xffff) {
*(*d)++ = 0xf0 | (c >> 18);
@@ -70,7 +104,7 @@
static int agl_read(char *path)
{
FILE *fin = fopen(path, "r");
- char ln[GNLEN * 8];
+ char ln[GNLEN];
char val[GNLEN];
char *s, *d;
int i;
@@ -85,7 +119,7 @@
while (s && *s) {
while (*s == ' ')
s++;
- pututf8(&d, hexval(s, 6));
+ utf8put(&d, hexval(s, 6));
s = strchr(s, ' ');
}
*d = '\0';
@@ -127,15 +161,48 @@
return 0;
}
+static int achar_shape(int c, int pjoin, int njoin)
+{
+ int i;
+ for (i = 0; i < LEN(achars); i++) {
+ struct achar *a = &achars[i];
+ if (a->c == c) {
+ if (!pjoin && !njoin)
+ return a->c;
+ if (!pjoin && njoin)
+ return a->i ? a->i : a->c;
+ if (pjoin && njoin)
+ return a->m ? a->m : a->c;
+ if (pjoin && !njoin)
+ return a->f ? a->f : a->c;
+ }
+ }
+ return c;
+}
+
+static void ashape(char *str, char *ext)
+{
+ int s[NCHAR];
+ char *src = str;
+ int i, l;
+ int bjoin = !strcmp(".medi", ext) || !strcmp(".fina", ext);
+ int ejoin = !strcmp(".medi", ext) || !strcmp(".init", ext);
+ for (l = 0; l < NCHAR && *src; l++)
+ s[l] = utf8get(&src);
+ for (i = 0; i < l; i++)
+ s[i] = achar_shape(s[i], i > 0 || bjoin, i < l - 1 || ejoin);
+ for (i = 0; i < l; i++)
+ utf8put(&str, s[i]);
+}
+
static int trfn_name(char *dst, char *src)
{
char ch[GNLEN];
+ char *d = dst;
char *s;
int i;
if (src[0] == '.')
return 1;
- if (src[1] && strchr(src, '.'))
- return 1; /* ignore opentype features for now */
while (*src && *src != '.') {
s = ch;
if (src[0] == '_')
@@ -144,28 +211,34 @@
*s++ = *src++;
*s = '\0';
if (agl_map(ch)) {
- strcpy(dst, agl_map(ch));
+ strcpy(d, agl_map(ch));
for (i = 0; i < LEN(agl_exceptions); i++)
- if (!strcmp(agl_exceptions[i][0], dst))
- strcpy(dst, agl_exceptions[i][1]);
- dst = strchr(dst, '\0');
+ if (!strcmp(agl_exceptions[i][0], d))
+ strcpy(d, agl_exceptions[i][1]);
+ d = strchr(d, '\0');
} else if (ch[0] == 'u' && ch[1] == 'n' && ch[2] == 'i') {
for (i = 0; strlen(ch + 3 + 4 * i) >= 4; i++)
- pututf8(&dst, hexval(ch + 3 + 4 * i, 4));
+ utf8put(&d, hexval(ch + 3 + 4 * i, 4));
} else if (ch[0] == 'u' && ch[1] && strchr(HEXDIGS, tolower(ch[1]))) {
- pututf8(&dst, hexval(ch + 1, 6));
+ utf8put(&d, hexval(ch + 1, 6));
} else if (achar_map(ch)) {
- pututf8(&dst, achar_map(ch));
+ utf8put(&d, achar_map(ch));
} else {
return 1;
}
}
- return src[0];
+ ashape(dst, src);
+ return src[0] == '.' && strcmp(".init", src) &&
+ strcmp(".fina", src) && strcmp(".medi", src);
}
static void trfn_lig(char *c)
{
int i;
+ if (c[0] && c[1] && strlen(c) > utf8len((unsigned char) c[0])) {
+ sprintf(strchr(trfn_ligs, '\0'), "%s ", c);
+ return;
+ }
for (i = 0; i < LEN(ligs); i++)
if (!strcmp(ligs[i], c))
sprintf(strchr(trfn_ligs, '\0'), "%s ", c);
@@ -184,12 +257,13 @@
char **a;
if (trfn_name(uc, c))
strcpy(uc, "---");
- if (strchr(uc, ' ')) { /* space not allowed in character names */
+ if (strchr(uc, ' ')) { /* space not allowed in char names */
if (!trfn_swid && !strcmp(" ", uc))
trfn_swid = WX(wid);
return;
}
- trfn_lig(uc);
+ if (strcmp("---", uc))
+ trfn_lig(uc);
if (typ < 0)
typ = trfn_type(uc);
strcpy(pos, c);
@@ -230,7 +304,7 @@
if (trfn_psname[0])
printf("fontname %s\n", trfn_psname);
printf("spacewidth %d\n", trfn_swid);
- printf("ligatures %s 0\n", trfn_ligs);
+ printf("ligatures %s0\n", trfn_ligs);
if (trfn_special)
printf("special\n");
printf("charset\n");